import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class FileUtils {

	public static boolean visitAllFiles(File f, ArrayList<T3ScriptFile> files) {
		boolean bRes = false;
		if (f.isDirectory()) {
			String[] children = f.list();
			ArrayList<File> t3Files = null, xsdFiles = null, directories = null;
			File xmlFile = null;
			for (int i = 0; i < children.length; i++) {
				File localFile = new File(f, children[i]);
				if (localFile.isDirectory()) {
					if (!visitAllFiles(localFile, files)) {
						if (directories == null)
							directories = new ArrayList<File>();
						directories.add(localFile);
					}
				}
				else {
					String fileName = localFile.toString();
					if (fileName.endsWith(".ttcn")) {
						if (t3Files == null) 
							t3Files = new ArrayList<File>();
						t3Files.add(localFile);
					} else if (fileName.endsWith(".xsd")) {
						if (xsdFiles == null) 
							xsdFiles = new ArrayList<File>();
						xsdFiles.add(localFile);
					} else if (fileName.endsWith(".xml")) {
						xmlFile = localFile;
					}
				}
			}
			if (t3Files == null)
				return false;
			for(File t3File : t3Files) {
				files.add(new T3ScriptFile(t3File, xsdFiles, xmlFile, directories));
				bRes = true;
			}
		} else if (f.toString().endsWith(".ttcn")) {				
				files.add(new T3ScriptFile(f, null, null, null));
				bRes = true;
		}
		return bRes;
	}

	// -----------------------------------------------------------------------------------------------

	public static void loadConfig(Properties config) throws IOException {
		FileInputStream fis = new FileInputStream(
				"resources/TestCastTester.properties");
		config.load(fis);
		fis.close();
		if ((config.get("TestCastCommandLineTool") == null)
				|| (config.get("LoopbackAdapterPath") == null)
				|| (config.get("TempPath") == null)
				|| (config.get("LogPath") == null)
				|| (config.get("ATSPath") == null)) {
			throw new IOException();
		}
	}

	// -----------------------------------------------------------------------------------------------

	public static void copyFile(File in, File out) throws IOException {
		FileChannel inChannel = new FileInputStream(in).getChannel();
		FileChannel outChannel = new FileOutputStream(out).getChannel();
		try {
			inChannel.transferTo(0, inChannel.size(), outChannel);
		} catch (IOException e) {
			throw e;
		} finally {
			if (inChannel != null)
				inChannel.close();
			if (outChannel != null)
				outChannel.close();
		}
	}
	
	public static void copyDirectory(File sourceLocation , File targetLocation)
		    throws IOException {

        if (sourceLocation.isDirectory()) {
            if (!targetLocation.exists()) {
                targetLocation.mkdir();
            }

            String[] children = sourceLocation.list();
            for (int i = 0; i < children.length; i++) {
                copyDirectory(new File(sourceLocation, children[i]),
                        new File(targetLocation, children[i]));
            }
        } else {
        	copyFile(sourceLocation, targetLocation);
        }
	}
	
	public static void deleteDirectoryContent(File dir) {
	    File[] files = dir.listFiles();
	    if(files != null) { //some JVMs return null for empty dirs
	        for(File f: files) {
	            if(f.isDirectory()) {
	                deleteDirectoryContent(f);
	            } 
	            f.delete();
	        }
	    }
	}

	// -----------------------------------------------------------------------------------------------

	public static int countT3Modules(File f) {
		if (f.toString().endsWith(".xsd"))
			return 1;
		int moduleCount = 0;
		try {
			FileInputStream fs = new FileInputStream(f.getAbsolutePath());
			DataInputStream in = new DataInputStream(fs);
			BufferedReader br = new BufferedReader(new InputStreamReader(in));

			String strLine = "";
			while ((strLine = br.readLine()) != null) {
				if (strLine.matches("^\\s*module\\s+\\w+\\s*.*")) {
					moduleCount++;
				}
			}
			in.close();
			fs.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return moduleCount;
	}

	// -----------------------------------------------------------------------------------------------

	private static Pattern s_verdictPassMatch = Pattern.compile("^^\\s*\\*\\*\\s*@verdict\\s*pass\\s*(.*)");
	private static Pattern s_verdictMatch = Pattern.compile("^\\s*\\*\\*\\s*@verdict\\s*.*");
	private static Pattern s_configMatch = Pattern.compile("^\\s*\\*\\*\\s*@configuration\\s*(.*)");
	public static T3ExpectedOutput extractExpectedOutput(File f) {
		T3ExpectedOutput t3ExpectedOutput = new T3ExpectedOutput();
		
		try {
			FileInputStream fs = new FileInputStream(f.getAbsolutePath());
			DataInputStream in = new DataInputStream(fs);
			BufferedReader br = new BufferedReader(new InputStreamReader(in));

			String strLine = "";
			Matcher configMatch;
			while ((strLine = br.readLine()) != null) {
				if (s_verdictMatch.matcher(strLine).matches()) {
					Matcher matcher = s_verdictPassMatch.matcher(strLine);
					if (matcher.find()) {
						String result = matcher.group(1);
						String[] split = result.split(",");
						t3ExpectedOutput.setExpectedOutput(split[0].trim());
						if (split.length > 1)
							t3ExpectedOutput.setExecutionResult(split[1].trim());
					}
					
//					System.out.println(strLine);
				} else if ((configMatch = s_configMatch.matcher(strLine)).matches()) {
					t3ExpectedOutput.setConfiguration(configMatch.group(1));
				}
			}
			in.close();
			fs.close();
		} catch (IOException e) {
			e.printStackTrace();
		}

		return t3ExpectedOutput;
	}
	
	// -----------------------------------------------------------------------------------------------

	public static ArrayList<File> splitT3ModuleFiles(File f) {
		ArrayList<File> files = new ArrayList<File>();
		StringBuffer current = new StringBuffer();
		File newFile = new File(f.getParent() + "//temp.ttcn");
		if (f.exists()) {
			f.renameTo(newFile);
		}
				
		try {
			FileInputStream fs = new FileInputStream(newFile.getAbsolutePath());
			DataInputStream in = new DataInputStream(fs);
			BufferedReader br = new BufferedReader(new InputStreamReader(in));

			String strLine = "";
			int moduleCounter = 0;
			String currentModuleName = "";
						
			while ((strLine = br.readLine()) != null) {
				if (strLine.matches("^\\s*module\\s+\\w+\\s*.*")) {
					moduleCounter++;
					if (moduleCounter > 1) { // write file
						String targetFilename = f.getParent() + "//" + currentModuleName + ".ttcn";
						FileWriter fw = new FileWriter(targetFilename);
						fw.write(current.toString());
						fw.close();
						current = new StringBuffer();
						files.add(new File(targetFilename));
					}
					Matcher matcher = Pattern.compile("^\\s*module\\s+(\\w+)\\s*.*").matcher(strLine);
					if (matcher.find()) {
						currentModuleName = matcher.group(1);
					}
				}
				current.append(strLine + "\n");
			}
			// write file
			String targetFilename = f.getParent() + "//" + currentModuleName + ".ttcn";
			FileWriter fw = new FileWriter(targetFilename);
			fw.write(current.toString());
			fw.close();
			in.close();
			fs.close();
			files.add(new File(targetFilename));
			newFile.delete();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		return files;
	}

	public static ArrayList<String> readExclusionList(File f) {
		ArrayList<String> files = new ArrayList<String>();
				
		try {
			FileInputStream fs = new FileInputStream(f.getAbsolutePath());
			DataInputStream in = new DataInputStream(fs);
			BufferedReader br = new BufferedReader(new InputStreamReader(in));

			String strLine = "";
			while ((strLine = br.readLine()) != null) {
				if (strLine.trim().length() > 0)
					files.add(strLine);
			}
			return files;
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		return null;
	}
	
}
