package org.etsi.t3d;


import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.GnuParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.ParseException;
import org.etsi.t3d.config.T3DConfig;
import org.etsi.t3d.config.DocumentationProfile;
import org.etsi.t3d.config.T3DOptionsHandler;
import org.etsi.t3d.visitor.DependencyVisitor;
import org.etsi.t3d.visitor.ImportVisitor;
import org.etsi.t3d.visitor.T3DVisitor;
import org.etsi.common.InputInterface;
import org.etsi.common.MiscTools;
import org.etsi.common.configuration.ConfigTools;
import org.etsi.common.exceptions.TerminationException;
import org.etsi.common.logging.LoggingInterface;
import org.etsi.common.logging.LoggingInterface.LogLevel;
import org.xml.sax.SAXException;

import antlr.MismatchedTokenException;
import antlr.RecognitionException;
import antlr.TokenStreamException;
import de.ugoe.cs.swe.trex.core.analyzer.rfparser.LocationAST;
import de.ugoe.cs.swe.trex.core.analyzer.rfparser.TTCN3Analyzer;
import de.ugoe.cs.swe.trex.core.analyzer.rfparser.TTCN3AnalyzerFlyweightFactory;
import de.ugoe.cs.swe.trex.core.analyzer.rfparser.TTCN3Parser;
import de.ugoe.cs.swe.trex.core.visitor.TTCN3BehaviorException;
import de.ugoe.cs.swe.trex.core.visitor.TTCN3ParserException;

public class T3D {

	public static String versionNumber = "v1.0.3";
	//set during automated server builds
	private static String buildStamp = "---BUILD_STAMP---";
	public static DocumentationProfile activeProfile = null;
	private String configurationClassName = T3DConfig.class.getName();
	private String configurationProfileClassName = DocumentationProfile.class.getName();
	private String configurationFilename;
	private String selectedProfileName = null;
	private static LogLevel logLevel = LogLevel.INFORMATION;

	private HashMap<String, String> argsMap = new HashMap<String, String>();
	private ArrayList<String> inputPaths = new ArrayList<String>();
	private String destinationPath = null;

	private HashMap<String, Integer> linesOfCodeMap = new HashMap<String, Integer>();
	private int totalLoc = 0;

	private boolean generateNewConfiguration = false;
	
	private static boolean generateMainXML = false;
	private static boolean generateDependenciesXML = false;
	private static boolean generateHTML = false;
	
	private static XMLPrinter xmlPrinter;
	private static ImportPrinter importPrinter;
	private static DependencyPrinter depPrinter;
	//TODO: START HERE, remove and substitute by a method that derives the names based on the TTCN3ParserTokenTypes
	//WHAT ABOUT EXTERNAL FUNCTIONS???
	//public final static String elementTypes[] = {"Module", "Function", "Testcase", "Group", "Altstep", "Constant", "Module Parameter", "Template", "Type", "Signature"};
	private static final String documentationLogFile = "log.xml";
	private static final String documentationXmlFile = "project.xml";
	private static final String dependencyXmlFile = "dependencies.xml";
	private static final String importXmlFile = "imports.xml";
	private String xsdFile = System.getenv("T3D_HOME")+"/xsd/project_schema.xsd";

	//private static T3DLoggingInterface loggingInterface = new T3DLoggingInterface();

	//TODO: TEMPORARY SOLUTION UNTIL MAJOR OTHER ISSUES ARE RESOLVED
	private static LoggingInterface logger = null;
	
	public T3D() {
	}

//	public static void printLog(int LEVEL, String filename, int startLine, int endLine, int type, String output){
//		loggingInterface.printLog(LEVEL, filename, startLine, endLine, type, output);
//	}

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

	public void showHelp() {
		System.out.println("\nHelp:");
//		System.out.println("  t3d[.bat] [options] (path | filename)+");
//		System.out.println("");
//		System.out.println("  Options (specify in any order): ");
//		System.out.println("    --help - prints this screen");
//		System.out.println("    --profile [profilename] - allows manual profile selection, overriding the selected default profile");
//		System.out.println("");
		HelpFormatter formatter = new HelpFormatter();
		formatter.setOptionComparator(new Comparator<Option>() {
			
			@Override
			public int compare(Option o1, Option o2) {
				if (o1.getId() > o2.getId()) {
					return 1;
				} else {
					return -1;
				}
			}
		});
		formatter.setSyntaxPrefix("  Usage: ");
//		formatter.setWidth(74);
		formatter.printHelp("t3d [options] ((--html | --xml-only) | --local-dependencies)+ (filename | path)+", "  Options: (in any order, config and at least one output format are required)",
				new T3DOptionsHandler().getOptions(), "");
		System.out.println("");
	}
	
	// --------------------------------------------------------------------------
	private void showDebugInfo(String[] args) {
		if (getLogLevel().equals(LogLevel.DEBUG)) {
			System.out.println("==================ARGS:===================");
			for (int a = 0; a < args.length; a++) {
				System.out.println("" + args[a]);
			}
			System.out.println("==================PROPERTIES:=============");
			for(Object key : System.getProperties().keySet()) {
				System.out.println("   "+key.toString() + " : "+System.getProperty(key.toString()));
			}
			System.out.println("==========================================");
		}
	}
	// --------------------------------------------------------------------------

	public void run(String[] args) {
		System.out.println("T3D " + getVersionNumber());
		System.out.println("Build " + getBuildStamp());
		System.out.println("  TTCN-3 version supported: "
				+ TTCN3Parser.getSupportedVersion());
		System.out.println("==========================================");
		try {
			if (handleCommandLineArguments(args) == false) {
				return;
			}
			showDebugInfo(args);
			if (selectedProfileName != null) {
				handleConfig(selectedProfileName);
			} else {
				handleConfig(null);
			}
		} catch (TerminationException e) {
			// TODO: handle exception
			System.out.println("ERRORING OUT!");
		}
		
		TTCN3Parser.disableStatementBlockCompatibilityMode();
		TTCN3Parser.enableStatementBlockCompatibilityMode();
		
		List<String> ttcn3Resources = new InputInterface(T3D.activeProfile.getResourceExtensionsRegExp(), T3D.activeProfile.getProjectExtension(),
				T3D.activeProfile.isSettingRecursiveProcessing()).getInputFromParameterList(inputPaths);
		ttcn3Resources = InputInterface.filterAbsoluteDuplicates(ttcn3Resources); 

		if (ttcn3Resources.isEmpty()) {
			// Terminate
			System.out.println("No ttcn3 files found!");
			showHelp();
			return;
		}

		long startTime = System.currentTimeMillis();
		TTCN3Analyzer analyzer = null;
		
		try {
			System.out.println("Parsing files...");
			for (int i = 0; i < ttcn3Resources.size(); i++) {
				String resourcePath = ttcn3Resources.get(i);
				analyzeFile(resourcePath);
				TTCN3AnalyzerFlyweightFactory analyzerFactory = TTCN3AnalyzerFlyweightFactory
						.getInstance();
				analyzer = analyzerFactory.getTTCN3Analyzer(ttcn3Resources
						.get(i));
				if (analyzer.getExceptions().size() > 0) {
					String exceptionMessage = "Error while parsing file "
						+ analyzer.getFilename(); 

					for (int i1 = 0; i1 < analyzer.getExceptions().size(); i1++) {
						String className = analyzer.getExceptions().get(i1).getStackTrace()[0].getClassName();
						String methodName = analyzer.getExceptions().get(i1).getStackTrace()[0].getMethodName();
						//moved from below, migrate to t3d as well
						String lineMessage = "Line "
								+ analyzer.getExceptions().get(i1).getLine()
								+ ": "
								+ analyzer.getExceptions().get(i1).getMessage();
						exceptionMessage+="\n  "+className.substring(className.lastIndexOf(".")+1)+" : "+methodName +"\n    "+lineMessage;
					}

					// TODO: in eclipse the error stream seems to be delayed
					// somewhat
					// -> Investigate
					// -> The terminal seems to handle this properly in contrast
					if (T3D.activeProfile.isSettingAbortOnError()) {
						throw new TTCN3ParserException(exceptionMessage);
					} else {
						try {
							throw new TTCN3ParserException(exceptionMessage);
						} catch (TTCN3ParserException e) {
							System.err.println(e.getLocalizedMessage());
							// e.printStackTrace();
						}
					}
				}			
			}
			long endTime = System.currentTimeMillis();
			long elapsed = endTime - startTime;
			double elapsedMinutes = ((double) elapsed) / 1000.0 / 60.0;
			System.out.println("Done parsing in " + elapsed + "ms ("
					+ MiscTools.doubleToString(elapsedMinutes) + " minutes).");
			
			if (T3D.activeProfile.isStatShowLOC()) {
				System.out.println("Total lines of code parsed: " + totalLoc);
			}
			
			TTCN3AnalyzerFlyweightFactory analyzerFactory = TTCN3AnalyzerFlyweightFactory
			.getInstance();
			
			System.out.println("Postprocessing...");
			startTime = System.currentTimeMillis();
			analyzerFactory.postProcess();
			endTime = System.currentTimeMillis();
			elapsed = endTime - startTime;
			elapsedMinutes = ((double) elapsed) / 1000.0 / 60.0;
			System.out.println("Done processing in " + elapsed + "ms ("
					+ MiscTools.doubleToString(elapsedMinutes) + " minutes).");
			startTime = System.currentTimeMillis();

			System.out.println("==========================================");
			//TODO: up to here mostly identical, make reusable
			
			//TODO: custom functionality
			initialize();
			handlePaths();
			
			//TODO: core functionality, encapsulate, split, and extract
			for (int i = 0; i < ttcn3Resources.size(); i++) {
				if (MiscTools.regExpMatch(activeProfile.getIgnoredResourceRegExp() , ttcn3Resources.get(i))){
					System.out.println("Preparing documentation for " + ttcn3Resources.get(i) + " (Skipped) "); //TODO: may need to use analyzer.getFilename for consistency
				} else {
					analyzer = analyzerFactory.getTTCN3Analyzer(ttcn3Resources
							.get(i));
					System.out.println("Preparing documentation for "
							+ analyzer.getFilename());
	//TODO: review logging interface
					//loggingInterface.setCurrentTTCN3File(analyzer.getFilename());
					T3D.getLoggingInterface().setLogSourceName(analyzer.getFilename());
					if (isGenerateMainXML() || isGenerateHTML()) {
						T3DVisitor visitor = new T3DVisitor(xmlPrinter);
						visitor.setFilename(analyzer.getFilename());
						ImportVisitor importVisitor = new ImportVisitor(importPrinter);
						importVisitor.setFilename(analyzer.getFilename());
	//					xmlPrinter.setCurrentTTCN3File(analyzer.getFilename());
						// visitor.setFilename(analyzer.getFilename());
						visitor.acceptDFS((LocationAST) analyzer.getParser().getAST());
						importVisitor.acceptDFS((LocationAST) analyzer.getParser().getAST());
					}
					if (isGenerateDependenciesXML()) {
						DependencyVisitor dependencyVisitor = new DependencyVisitor(depPrinter);
						depPrinter.setCurrentTTCN3File(analyzer.getFilename());
						dependencyVisitor.acceptDFS((LocationAST) analyzer.getParser().getAST());
					}
				}

			}
			endTime = System.currentTimeMillis();
			elapsed = endTime - startTime;
			elapsedMinutes = ((double) elapsed) / 1000.0 / 60.0;
			System.out.println("Documentation preparation finished in "
					+ elapsed + "ms (" + MiscTools.doubleToString(elapsedMinutes)
					+ " minutes).");

			if (T3D.activeProfile.isStatShowLOC()) {
				System.out
						.println("Total lines of code processed: " + totalLoc);
			}

			//TODO: custom functionality
			handleOutput();

			//TODO: move summary here
			if (T3D.activeProfile.isStatShowSummary()) {
//				System.out.println("Brief statistics summary of occurences in message classes:");
//				for (MessageClass m : MessageClass.values()) {
//					System.out.println("\t" + m.getDescription() + " : "
//							+ m.getOccurenceCount());
//				}
			}
		} catch (TTCN3BehaviorException e) {
			System.err.println(e.getLocalizedMessage());
		} catch (TTCN3ParserException e) {
			// Default setting where processing is terminated in the event of a
			// parsing error
			System.err.println(e.getLocalizedMessage());
			// TODO: Isolate different steps and implement a recovery mechanism:

		}
		//TODO: move to common, use in T3D as well
		if (getLogLevel().equals(LogLevel.DEBUG)) {
			int mb = 1024*1024;
			Runtime.getRuntime().maxMemory();
			Runtime runtime = Runtime.getRuntime();
			System.out.println();
			System.out.println("============Memory statistics:===========");
			// Print used memory
			System.out.println("Used Memory:\t"
					+ (runtime.totalMemory() - runtime.freeMemory()) / mb+" MB");
			// Print free memory
			System.out.println("Free Memory:\t" + runtime.freeMemory() / mb+" MB");
			// Print total available memory
			System.out.println("Total Memory:\t" + runtime.totalMemory() / mb+" MB");
			// Print maximum available memory
			System.out.println("Max Memory:\t" + runtime.maxMemory() / mb+" MB");
		}

	}

	private void initialize() {
		T3D.setLoggingInterface(new LoggingInterface(T3D.activeProfile.getLoggingConfiguration()));
		if (isGenerateMainXML() || isGenerateHTML()) {
			xmlPrinter = new XMLPrinter();
			importPrinter = new ImportPrinter();
		}
		if (isGenerateDependenciesXML()) {
			depPrinter = new DependencyPrinter();
		}
		
	}

	private void handlePaths() {
		String finalOutputPath = getFinalOutputPath(this.getDestinationPath());
		
		String finalXMLfilePath = finalOutputPath + File.separator + documentationXmlFile;
		String finalDependencyfilePath = finalOutputPath + File.separator + dependencyXmlFile;
		String finalImportfilePath = finalOutputPath + File.separator + importXmlFile;
		String finalLogfilePath = finalOutputPath + File.separator + documentationLogFile;
		//System.out.println("*********" + finalXMLfilePath);
		
		System.out.println("Output path: "+finalOutputPath);
		
		if (!(new File(finalOutputPath).isDirectory())) {
			new File(finalOutputPath).mkdirs();
		}
		if (isGenerateMainXML() || isGenerateHTML()) {
			xmlPrinter.setXMLPath(finalXMLfilePath);
			importPrinter.setXMLPath(finalImportfilePath);
		}
		if (isGenerateDependenciesXML()) {
			depPrinter.setXMLPath(finalDependencyfilePath);
		}
		//TODO: revise XML usage
		//loggingInterface.setXMLPath(finalLogfilePath);
	}

	
	private void handleOutput() {
		//TODO: this is duplicated in handlePaths
		String finalOutputPath = getFinalOutputPath(this.getDestinationPath());
		generateXML();
		// TODO: uncomment
		//validateXMLoutput(finalOutputPath);
		handleTransformation(finalOutputPath);
	}

	private String getFinalOutputPath(String outputDirectory) {
		return MiscTools.getProperOutputPath(outputDirectory) + File.separator + MiscTools.getSubPath(inputPaths.get(0));
	}

	private void generateXML() {
		if (isGenerateMainXML() || isGenerateHTML()) {
			xmlPrinter.finishXML();
			importPrinter.finishXML();
		}
		if (isGenerateDependenciesXML()) {
			depPrinter.finishXML();
		}
		// TODO: what do we do with this one?
		//loggingInterface.finishXML();
	}

	private void validateXMLoutput(String finalOutputPath) {
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();

		factory.setValidating(true);

		factory.setAttribute(
				"http://java.sun.com/xml/jaxp/properties/schemaLanguage",
				"http://www.w3.org/2001/XMLSchema");
		factory.setAttribute(
				"http://java.sun.com/xml/jaxp/properties/schemaSource",
				new File(xsdFile));
		try {
			factory.newDocumentBuilder().parse("file:///"+
					new File(finalOutputPath + "/" + documentationXmlFile).getAbsolutePath());
		} catch (ParserConfigurationException e) {
			System.out.println("Parser not configured: " + e.getMessage());
		} catch (SAXException e) {
			System.out.print("Parsing XML failed due to a "
					+ e.getClass().getName() + ":");
			System.out.println(e.getMessage());
		} catch (IOException e) {
			System.out.println("Validation failed due to an IO Error!" +
					"\n  File: "+new File(finalOutputPath + "/" + documentationXmlFile).getAbsolutePath());
			e.printStackTrace();
		}
	}

	private void handleTransformation(String outputPath) {
		long start;
		long end;
		long dur;
		double durMinutes;
		if (isGenerateHTML()) {
			start = System.currentTimeMillis();
			System.out.print("Generating html...");
			xml2html(outputPath, documentationXmlFile, T3D.activeProfile.getXsltFileHTML());
			xml2html(outputPath, importXmlFile, T3D.activeProfile.getXsltFileImport());
			end = System.currentTimeMillis();
			dur = end - start;
			durMinutes = ((double) dur) / 1000.0 / 60.0;
			System.out.println(" Generated " + (xmlPrinter.getFileCount())
					+ " HTML files in " + dur + "ms (" + MiscTools.doubleToString(durMinutes)
					+ "minutes),");

			MiscTools.streamCopyFile(T3D.activeProfile.getCssFile(),
					outputPath
							+ "/html/css/"
							+ new File(T3D.activeProfile.getCssFile())
									.getName());
			MiscTools.streamCopyFile(T3D.activeProfile.getJsFile(),
					outputPath
							+ "/html/js/"
							+ new File(T3D.activeProfile.getJsFile())
									.getName());
		}
	}
	
    private void xml2html(String foldername, String xmlFileName, String xsltFileName){    	
    	System.setProperty("javax.xml.transform.TransformerFactory",
    	"net.sf.saxon.TransformerFactoryImpl");
    	
    	TransformerFactory tfactory = TransformerFactory.newInstance();
    	Transformer transformer;
		try {
			transformer = tfactory.newTransformer(new StreamSource(new File(xsltFileName)));
			transformer.setParameter("folder", foldername);
			if(activeProfile.isIncludeConstructBody())
				transformer.setParameter("includeconstructbodies", "true");
			else 
				transformer.setParameter("includeconstructbodies", "false");
			if(activeProfile.isHideConstructBody())
				transformer.setParameter("hideconstructbodies", "true");
			else 
				transformer.setParameter("hideconstructbodies", "false");
			if(activeProfile.isShowOriginalT3DocTags())
				transformer.setParameter("showOriginalT3DocTags", "true");
			else 
				transformer.setParameter("showOriginalT3DocTags", "false");
			
	    	transformer.transform(new StreamSource(new File(foldername + "/" + xmlFileName)),
	    	    	new StreamResult(new FileOutputStream(foldername + "/xsltlog.txt")));
		} catch (TransformerConfigurationException e) {
			e.printStackTrace();
		} catch (TransformerException e) {
			e.printStackTrace();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
   	}
	//TODO: DUPLICATED MOSTLY
	private boolean handleCommandLineArguments(String[] args) throws TerminationException {
		//parseCommandLineArguments(args);
		CommandLine commandLine = parseCommandLineArguments(args);
		if (commandLine == null) {
			return false;
		}
		String arguments[] = evaluateCommandLineOptions(commandLine);

		if (commandLine.hasOption("help")) {
			showHelp();
			return false;
		}

		if (commandLine.hasOption("config") && arguments.length < 1) {
			System.out.println("ERROR: Missing input location(s)");
			showHelp();
			return false;
		}

		for (String arg : arguments) {
			//TODO: add validity checks
			inputPaths.add(arg);
		}
		
		return true;
	}

	// --------------------------------------------------------------------------
	//TODO: DUPLICATE
	private CommandLine parseCommandLineArguments(String[] args) {
		CommandLineParser parser = new GnuParser();
		T3DOptionsHandler optionsHandler = new T3DOptionsHandler();
		CommandLine commandLine = null;
		try {
			commandLine = parser.parse(optionsHandler.getOptions(), args);
		} catch (ParseException e) {
			System.out.println("ERROR: " + e.getMessage() );
			showHelp();
		}
		return commandLine;
	}

	// --------------------------------------------------------------------------
	//TODO: DUPLICATED MOSTLY
	private String[] evaluateCommandLineOptions(CommandLine commandLine) throws TerminationException {
		this.setConfigurationFilename(commandLine.getOptionValue("config"));
		if (commandLine.hasOption("generate-config")) {
			this.setConfigurationFilename(commandLine.getOptionValue("generate-config"));
			this.setGenerateNewConfiguration(true);
		} else if (commandLine.hasOption("config")) {
			this.setConfigurationFilename(commandLine.getOptionValue("config"));
		} else {
			System.out.println("ERROR: No configuration file selected!");
			showHelp();
			throw new TerminationException("");
		}
		
		if (commandLine.hasOption("profile")) {
			this.setSelectedProfileName(commandLine.getOptionValue("profile"));
		}
		boolean targetFormatSet = false;
		if (commandLine.hasOption("local-dependencies")){
			setGenerateDependenciesXML(true);
			targetFormatSet = true;
		}
		if (commandLine.hasOption("html")){
			setGenerateHTML(true);
			targetFormatSet = true;
		}
		if (commandLine.hasOption("xml-only")){
			setGenerateMainXML(true);
			targetFormatSet = true;
		}
		
		if (!targetFormatSet && !this.isGenerateNewConfiguration()) {
			System.out.println("ERROR: No target output format set!");
			showHelp();
			System.exit(1);
		}
		
		if (commandLine.hasOption("verbosity")){
			this.selectLogLevel(commandLine.getOptionValue("verbosity"));
		}

		if (commandLine.hasOption("output-path")){
			this.setDestinationPath(commandLine.getOptionValue("output-path"));
		}

		return commandLine.getArgs();
	}
	
	// --------------------------------------------------------------------------

	//TODO: THIS SHALL BE DEPRECATED NOW 
//	private void parseCommandLineArguments(String[] args) {
//		String key = "";
//		String value = "";
//		//inputPath = "";
//
//		boolean lastKey = false;
//		for (int i = 0; i < args.length; i++) {
//			if (args[i].startsWith("--")) {
//				key = args[i].replaceAll("--", "").toLowerCase();
//
//				if (lastKey) {
//					argsMap.put(key, "true");
//					key = null;
//					value = null;
//					lastKey = false;
//				}
//
//				lastKey = true;
//			} else {
//				value = args[i];
//				if ((key != null) && (argsMap.get(key) == null)
//						&& (key.length() > 0)) {
//					argsMap.put(key, value);
//					key = null;
//					value = null;
//				} else {
//					inputPaths.add(value);
//				}
//				lastKey = false;
//			}
//		}
//
//		if (key != null) {
//			if ((argsMap.get(key) == null) && (key.length() > 0)) {
//				argsMap.put(key, "true");
//			}
//		}
//	}

	// --------------------------------------------------------------------------
	//TODO: DUPLICATE MOSTLY
	private void handleConfig(String specifiedProfile) throws TerminationException {
		ConfigTools configTools = new ConfigTools(configurationClassName, configurationProfileClassName);
		configTools.setToolVersion(getVersionNumber());
		
		try {
			if (isGenerateNewConfiguration()) {
				configTools.initializeNewDefaultConfig(getConfigurationFilename());
				System.exit(0);
			} else {
				configTools.loadConfig(getConfigurationFilename());
				activeProfile = (DocumentationProfile) configTools.selectProfile(specifiedProfile);
				if (this.getDestinationPath()==null) {
					setDestinationPath(T3D.activeProfile.getOutputDirectory());
				}
			}
		} catch (InstantiationException e) {
			throw new TerminationException("ERROR: Instantiation problems encountered while loading configuration profile. "+e.getMessage());
		} catch (IllegalAccessException e) {
			throw new TerminationException("ERROR: Instantiation problems encountered while loading configuration profile. "+e.getMessage());
		} catch (ClassNotFoundException e) {
			throw new TerminationException("ERROR: Instantiation problems encountered while loading configuration profile. "+e.getMessage());
		}
		
		if (!isProfileVersionValid()) {
			System.out.println("\nERROR: Selected profile \"" + activeProfile.getProfileName()
					+ "\" has a mismatching or no version (required: \""+getVersionNumber()+"\").\n" +
							"  Consider upgrading the profile by transfering the relevant parts to an auto-generated profile or selecting a different profile.\n");
			throw new TerminationException("");
		}
	}
	//TODO: DUPLICATE 
	private boolean isProfileVersionValid() {
		if (activeProfile.getProfileVersion() != null && activeProfile.getProfileVersion().equals(getVersionNumber())){
			return true;
		} else {
			return false;
		}
	}
	//TODO: DUPLICATE 
	private void selectLogLevel(String logLevel) throws TerminationException{
		boolean selected = false;
		String possibleValues ="";
		for (LogLevel l : LogLevel.values()){
			if (l.toString().equals(logLevel)){
				setLogLevel(l);
				selected = true;
				System.out.println("Selected log level \""+logLevel+"\"");
			}
			if (!l.toString().equals("FIXME") && !l.toString().equals("DEBUG"))
			possibleValues+=l.toString()+", ";
		}
		if (!selected){
			System.out.println("\nERROR: No valid log level provided! Possible values are (in ascending inclusive order): "+ possibleValues.substring(0,possibleValues.length()-2)+".");
			throw new TerminationException("");
		}
		
	}

	


	// --------------------------------------------------------------------------
//	//TODO: should be obsolete now?
//	List<String> findTTCN3Resources(String directory) {
//		List<String> files = new LinkedList<String>();
//
//		File f = new File(directory);
//
//		File[] fileNames = f.listFiles(new FileFilter() {
//			public boolean accept(File pathname) {
//				if (pathname.getPath().endsWith(".ttcn3")
//						|| pathname.getPath().endsWith(".ttcn")
//						|| pathname.getPath().endsWith(".3mp"))
//					return true;
//				return false;
//			}
//		});
//
//		for (int i = 0; i < fileNames.length; i++) {
//			files.add(fileNames[i].getPath());
//		}
//
//		File[] directories = f.listFiles(new FileFilter() {
//			public boolean accept(File pathname) {
//				if (pathname.isDirectory())
//					return true;
//				return false;
//			}
//		});
//
//		for (int i = 0; i < directories.length; i++) {
//			files.addAll(findTTCN3Resources(directories[i].getPath()));
//		}
//
//		return files;
//	}

	// --------------------------------------------------------------------------
	//TODO: DUPLICATED
	private TTCN3Analyzer analyzeFile(String filename) {
		TTCN3AnalyzerFlyweightFactory analyzerFactory = TTCN3AnalyzerFlyweightFactory
				.getInstance();
		analyzerFactory.setStandaloneUsage(true);
		System.out.print("  Parsing file: " + filename); 
		
		String code = MiscTools.readFile(filename);
		int loc = MiscTools.getLOC(filename);
		linesOfCodeMap.put(filename, loc);
		totalLoc += loc;

		System.out.println(" (LOC: "		+ linesOfCodeMap.get(filename) + ") ...");
		long startTime = System.currentTimeMillis();

		TTCN3Analyzer analyzer = analyzerFactory.getTTCN3Analyzer(filename,
				code);
		try {
			analyzer.analyze();
		} catch (MismatchedTokenException e) {
			e.printStackTrace();
		} catch (RecognitionException e) {
			e.printStackTrace();
		} catch (TokenStreamException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
		long endTime = System.currentTimeMillis();
		long elapsed = endTime - startTime;
		double elapsedMinutes = ((double) elapsed) / 1000.0 / 60.0;

		System.out.println("    ...done in " + elapsed + "ms ("
				+ MiscTools.doubleToString(elapsedMinutes) + " minutes).");

		return analyzer;
	}

	// --------------------------------------------------------------------------
	//TODO: DUPLICATE
	public static void setVersionNumber(String versionNumber) {
		T3D.versionNumber = versionNumber;
	}
	//TODO: DUPLICATE	
	public static String getVersionNumber() {
		return versionNumber;
	}

	public static void main(String[] args) {
		try{
			T3D tool = new T3D();
			tool.run(args);
		} catch (Exception e) {
			if (getLogLevel()==LogLevel.DEBUG){
				e.printStackTrace();
				
			} else {
				String stacktrace = "";
				for (StackTraceElement ste : e.getStackTrace()){
					stacktrace+="\n    "+ste.toString();
				}
				System.err.println("ERROR: A problem occurred while running T3D" +
						"\n  Problem type: " + 
						e +
						"\n  Stacktrace:" +
						stacktrace + 
						"\n  Run T3D with --verbosity=DEBUG for a more detailed report" );
			}
		}
	}
	//TODO: DUPLICATE
	public void setConfigurationFilename(String configurationFilename) {
		this.configurationFilename = configurationFilename;
	}
	//TODO: DUPLICATE
	public String getConfigurationFilename() {
		return configurationFilename;
	}
	//TODO: DUPLICATE
	public void setSelectedProfileName(String selectedProfileName) {
		this.selectedProfileName = selectedProfileName;
	}
	//TODO: DUPLICATE
	public String getSelectedProfileName() {
		return selectedProfileName;
	}
	//TODO: DUPLICATE
	public static void setLogLevel(LogLevel logLevel) {
		T3D.logLevel = logLevel;
	}
	//TODO: DUPLICATE
	public static LogLevel getLogLevel() {
		return logLevel;
	}

	public static void setGenerateDependenciesXML(boolean generateDependenciesXML) {
		T3D.generateDependenciesXML = generateDependenciesXML;
	}

	public static boolean isGenerateDependenciesXML() {
		return generateDependenciesXML;
	}

	public static void setGenerateMainXML(boolean generateMainXML) {
		T3D.generateMainXML = generateMainXML;
	}

	public static boolean isGenerateMainXML() {
		return generateMainXML;
	}

	public static void setGenerateHTML(boolean generateHTML) {
		T3D.generateHTML = generateHTML;
	}

	public static boolean isGenerateHTML() {
		return generateHTML;
	}

	public static void setLoggingInterface(LoggingInterface logger) {
		T3D.logger = logger;
	}

	public static LoggingInterface getLoggingInterface() {
		return T3D.logger;
	}

	public void setGenerateNewConfiguration(boolean generateNewConfiguration) {
		this.generateNewConfiguration = generateNewConfiguration;
	}

	public boolean isGenerateNewConfiguration() {
		return generateNewConfiguration;
	}

	public void setDestinationPath(String destinationPath) {
		this.destinationPath = destinationPath;
	}

	public String getDestinationPath() {
		return destinationPath;
	}

	public static void setBuildStamp(String buildStamp) {
		T3D.buildStamp = buildStamp;
	}

	public static String getBuildStamp() {
		return buildStamp;
	}

}
