package it.micegroup.voila2.cartridge.library.javaservice;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;
import org.apache.tools.ant.DirectoryScanner;
import org.apache.tools.ant.types.FilterSet;
import org.apache.tools.ant.types.FilterSetCollection;
import org.apache.tools.ant.types.selectors.SelectorUtils;
import org.apache.tools.ant.util.FileUtils;
import org.eclipse.core.runtime.Platform;
import org.osgi.framework.Bundle;

public class CopyFolderUtils {

	private static final String REFERENCE_FILE = "reference:file:/";

	/**
	 * static logger.
	 */
	private static Logger logger = Logger.getLogger(CopyFolderUtils.class);

	private static final String COMPONENT_NAME = "Copy Folder Workflow Component";

	public static Boolean copyFolder(String inputFolder, String outputFolder, String bundleName, String outputFolderSuffix, String includeFilter, String excludeFilter, String antProcessFilter, Boolean excludeDefaultExt, String tokenValuePairs, String renameList, String extensionRenameList) {
		try {
			if (excludeDefaultExt == null) {
				excludeDefaultExt = true;
			}
			String inputFolderFull = getInputFolder(inputFolder, bundleName);
			Map<String, String> renameListMap = buildRenameList(renameList);
			Map<String, String> extensionRenameListMap = buildRenameList(extensionRenameList);
			List<ValuePair> tokenValuePairsMap = buildTokenValuePairs(tokenValuePairs);
			
			if (logger.isInfoEnabled()) {
				logger.info(COMPONENT_NAME + " ready to copy from: " + inputFolderFull + " to: " + outputFolder);
			}
			File outputFolderFile = new File(GeneralUtils.getOutputDir() + File.separator + outputFolder + File.separator);
			outputFolderFile.mkdirs();
			
			String[] antProcessFilterArray = prepareAntProcessFilerArray(antProcessFilter);

			DirectoryScanner ds = buildDirectoryScanner(inputFolderFull, includeFilter, excludeFilter, excludeDefaultExt);
			ds.scan();

			FilterSetCollection fsc = buildFilterSet(tokenValuePairsMap);

			String[] files = ds.getIncludedFiles();
			FileUtils fileUtils = FileUtils.getFileUtils();
			
			if (logger.isDebugEnabled()) {
				logger.debug("Template files to be processed:");
			}
			for (int i = 0; i < files.length; i++) {
			    String inputCompleteFileName = inputFolderFull + File.separator + files[i];
				if (logger.isDebugEnabled()) {
				    logger.debug("Processing file:" + inputCompleteFileName);
				}
			    String outputFileName = determineOutputFileName(files[i], renameListMap, extensionRenameListMap, outputFolderSuffix, tokenValuePairsMap);
			    String outputCompleteFileName = outputFolderFile.getAbsolutePath() + File.separator + outputFileName;

			    boolean needsAntProcessing = false;

		        if (isToBeFiltered(files[i], antProcessFilterArray)) {
		            needsAntProcessing = true;
		        }
		        //check if we need velocity processing...
		        if (needsAntProcessing) {
		            //velocity filtering was performed, perform ant velocity by taking pre-processed input file by velocity
		            fileUtils.copyFile(inputCompleteFileName, outputCompleteFileName, fsc, true);
					if (logger.isDebugEnabled()) {
			            logger.debug("FILTERED WITH ANT:" + files[i]);
					}
		        } else {
		            fileUtils.copyFile(inputCompleteFileName, outputCompleteFileName, null, true);
					if (logger.isDebugEnabled()) {
			            logger.debug("NO FILTERED WITH ANT:" + files[i]);
					}
		        }
			}
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
		return true;
	}
	

	public static String getInputFolder(String inputFolder, String bundleName) {
		if (bundleName == null) {
			return inputFolder;
		}
        Bundle[] stackBundle = Platform.getBundles(bundleName, null);
		String bundleFolder;
		try {
			//String separator = FileSystems.getDefault().getSeparator();
			bundleFolder = org.eclipse.core.runtime.FileLocator.getBundleFile(stackBundle[0]).getAbsolutePath() + "\\";
		} catch (IOException e) {
			bundleFolder = stackBundle[0].getLocation();
			if (bundleFolder.startsWith(REFERENCE_FILE)) {
				bundleFolder = bundleFolder.substring(REFERENCE_FILE.length());
			}
		}

        return bundleFolder + inputFolder;
    }

    private static List<ValuePair> buildTokenValuePairs(String tokenValuePairs) {
    	List<ValuePair> result = new ArrayList<ValuePair>();
    	if (tokenValuePairs != null) {
            String[] parts = tokenValuePairs.split(",");
            for (String part : parts) {
            	String[] subParts = part.split("=");
            	if(subParts.length < 2) {
            		ConsoleUtils.consoleMessage(SeverityLevels.ERROR, "Per la proprietà " +  subParts[0] + " manca il corrispettivo valore");
            	}
            	
            	String key = subParts[0];
            	String value = subParts[1];
            	ValuePair vp = new ValuePair();
            	vp.name = key;
            	vp.value = value;
            	result.add(vp);
            }
    	}
		return result;
	}


	private static Map<String, String> buildRenameList(String renameList) {
		Map<String, String> result = new HashMap<String, String>();
		if (renameList != null) {
	        String[] parts = renameList.split(",");
	        for (String part : parts) {
	        	String[] subParts = part.split("=");
	        	String key = subParts[0];
	        	String value = subParts[1];
	        	result.put(key, value);
	        }
		}
		return result;
	}

	/**
     * Determine the output file name by processing renameList and extensionRenameList rules.
     * @param inputFile input file name.
	 * @param renameListMap 
	 * @param extensionRenameListMap 
	 * @param outputFolderSuffix 
	 * @param tokenValuePairsMap 
     * @return the output file name processed.
     */
    private static String determineOutputFileName(String inputFile, Map<String, String> renameListMap, Map<String, String> extensionRenameListMap, String outputFolderSuffix, List<ValuePair> tokenValuePairsMap) {
        String outputFileName = inputFile;
        if (renameListMap.get(inputFile) != null) {
            outputFileName = (String)renameListMap.get(inputFile);
			if (logger.isDebugEnabled()) {
	            logger.debug("Renamed file " + inputFile + " to " + outputFileName);
			}
        }
        //Check for extension renaming...
        int extPos = outputFileName.lastIndexOf(".");
        if (extPos > -1) {
            String extension = outputFileName.substring(extPos);
            if (extensionRenameListMap.get(extension) != null) {
                outputFileName = outputFileName.substring(0, extPos) + extensionRenameListMap.get(extension);
    			if (logger.isDebugEnabled()) {
                    logger.debug("Renamed extension " + extension + " to " + extensionRenameListMap.get(extension) + " for filename:" + outputFileName);
    			}
            }
        }
        if (outputFolderSuffix != null) {
        	int pos = outputFileName.lastIndexOf(File.separator);
        	outputFileName = outputFileName.substring(0, pos) + File.separator + outputFolderSuffix + File.separator + outputFileName.substring(pos);
        }
        for (Iterator iterator = tokenValuePairsMap.iterator(); iterator.hasNext();) {
			ValuePair valuePair = (ValuePair) iterator.next();
			outputFileName = outputFileName.replaceAll("@" + valuePair.name + "@", valuePair.value);
		}
        return outputFileName;
    }

    private static String[] prepareAntProcessFilerArray(String antProcessFilter) {
        String[] antProcessFilterArray = null;
        if (antProcessFilter != null && antProcessFilter.trim().length() > 0) {
            antProcessFilterArray = antProcessFilter.split(",");
        }
        return antProcessFilterArray;
    }

    private static boolean isToBeFiltered(String file, String[] processFilterArray) {
        String normalizedFile = file.replace('\\', '/');

        if (processFilterArray != null) {
            for (int i = 0; i<processFilterArray.length; i++) {
                if (SelectorUtils.matchPath(processFilterArray[i], normalizedFile)) {
                    return true;
                }
            }
        }
        return false;
    }

    private static DirectoryScanner buildDirectoryScanner(String inputFolder, String includeFilter, String excludeFilter, Boolean excludeDefaultExt) {
        DirectoryScanner ds = new DirectoryScanner();
        ds.setBasedir(inputFolder);
        if (includeFilter != null && includeFilter.trim().length() > 0) {
            ds.setIncludes(includeFilter.split(","));
        }
        if (excludeFilter != null && excludeFilter.trim().length() > 0) {
            ds.setExcludes(excludeFilter.split(","));
        }
        if (excludeDefaultExt) {
            ds.addDefaultExcludes();
        }
        return ds;
    }

    private static FilterSetCollection buildFilterSet(List<ValuePair> tokenValuePairsMap) {
        FilterSetCollection fsc = new FilterSetCollection();
        FilterSet fs = new FilterSet();
        Iterator<ValuePair> i = tokenValuePairsMap.iterator();
        while (i.hasNext()) {
        	CopyFolderUtils.ValuePair tokenValuePair = (CopyFolderUtils.ValuePair) i
					.next();
            fs.addFilter(tokenValuePair.getName().toUpperCase(), tokenValuePair.getValue());
		}
        fsc.addFilterSet(fs);
        return fsc;
    }

	public static class ValuePair {
		private String name;
		private String value;

		public String getName() {
			return name;
		}

		public void setName(String name) {
			this.name = name;
		}

		public String getValue() {
			return value;
		}

		public void setValue(String value) {
			this.value = value;
		}
	}

}
