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

public class TestPurposeGenerator {

	public static Properties config = new Properties();
	public static Properties references = new Properties();
	private ArrayList<File> files = new ArrayList<File>();
	private HashMap<String, ArrayList<ClauseEntry>> clauseMapPositiveSemantical = new HashMap<String, ArrayList<ClauseEntry>>();
	private HashMap<String, ArrayList<ClauseEntry>> clauseMapNegativeSemantical = new HashMap<String, ArrayList<ClauseEntry>>();
	
	// -----------------------------------------------------------------------------------------------

	public TestPurposeGenerator() {
	}

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

	public void run() {
		System.out.println("STF475 Tools: Test Purpose Generator v0.1");
		try {
			FileUtils.loadConfig(config);
			FileUtils.loadReferences(references);
		} catch (IOException e) {
			System.err
					.println("[ERROR] Cannot load config file or config file is incomplete.");
			return;
		}

		List<Clause> myList = new ArrayList<Clause>();
		Iterator<Object> it = references.keySet().iterator();
		System.out.println("----");
		while (it.hasNext()) {
			Object value = it.next();
			if (value instanceof String) {
				myList.add(new Clause((String) value));
			}
		}
		
		Collections.sort(myList);

		String atsPath = config.get("ATSPath").toString();
		System.out.println("Gathering files...");
		FileUtils.visitAllFiles(new File(atsPath), files);
		
		System.out.println("Processing files...");
		for (int i=0; i < files.size(); i++) {
//			File tempFile = new File(config.get("TempPath") + "/" + files.get(i).getName());
			File currentFile = files.get(i);
			System.out.println("processing " + currentFile.getName());
//			System.out.println(tempFile.getAbsolutePath());
			T3Purpose purpose = FileUtils.extractPurpose(currentFile);
			
			if (purpose.getClauseStructured() == null || purpose.getClause() == null) {
				System.err.println("Skipping file: Error processing purpose for file "+currentFile.getAbsolutePath());
				continue;
			}
			
			T3ExpectedOutput expected = FileUtils.extractExpectedOutput(currentFile);
			

			if (files.get(i).getName().toLowerCase().startsWith("neg")) {
				ArrayList<ClauseEntry> clauseEntries = clauseMapNegativeSemantical.get(purpose.getClauseStructured().toString());
				if (clauseEntries == null)
					clauseEntries = new ArrayList<ClauseEntry>();
				
				ClauseEntry clauseEntry = new ClauseEntry();
				clauseEntry.setFile(currentFile);
				clauseEntry.setPurpose(purpose);
				clauseEntry.setExpected(expected);
				clauseEntries.add(clauseEntry);
				clauseMapNegativeSemantical.put(purpose.getClauseStructured().toString(), clauseEntries);
			} else { // pos
				ArrayList<ClauseEntry> clauseEntries = clauseMapPositiveSemantical.get(purpose.getClauseStructured().toString());
				if (clauseEntries == null)
					clauseEntries = new ArrayList<ClauseEntry>();
				
				ClauseEntry clauseEntry = new ClauseEntry();
				clauseEntry.setFile(currentFile);
				clauseEntry.setPurpose(purpose);
				clauseEntry.setExpected(expected);
				clauseEntries.add(clauseEntry);
				clauseMapPositiveSemantical.put(purpose.getClauseStructured().toString(), clauseEntries);
			}
		}
		
		try {
			String tpFileHead = FileUtils.loadFileToString(new File("resources/tp-file-head.html"));
			String tpFileFooter = FileUtils.loadFileToString(new File("resources/tp-file-foot.html"));
			String tpSectionHead = FileUtils.loadFileToString(new File("resources/tp-section-head.html"));
			String tpSectionFoot = FileUtils.loadFileToString(new File("resources/tp-section-foot.html"));
			String tpTable = FileUtils.loadFileToString(new File("resources/tp-table.html"));
			
			StringBuffer result = new StringBuffer();
			result.append(tpFileHead);
			
			int clauseCounter = 1;
			for (int i=0; i < myList.size(); i++) {
				Clause clause = myList.get(i);
				ArrayList<ClauseEntry> clauseEntriesPositiveSemantical = null;
				ArrayList<ClauseEntry> clauseEntriesNegativeSemantical = null;
				
				clauseEntriesPositiveSemantical = clauseMapPositiveSemantical.get(clause.toString());
				clauseEntriesNegativeSemantical = clauseMapNegativeSemantical.get(clause.toString());

				int totalEntries = 0;
				if (clauseEntriesPositiveSemantical != null)
					totalEntries += clauseEntriesPositiveSemantical.size();
				if (clauseEntriesNegativeSemantical != null)
					totalEntries += clauseEntriesNegativeSemantical.size();
				
				if (totalEntries > 0) {
//					result.append(createSection(tpSectionHead, "A.2." + Integer.toString(clauseCounter), references.getProperty(clause.toString()) + " (Clause " + clause.toString() + ")"));
					result.append(createSection(tpSectionHead, "A.2." + Integer.toString(clauseCounter), references.getProperty(clause.toString())));

					if (clauseEntriesPositiveSemantical != null) {
						for (int j=0; j < clauseEntriesPositiveSemantical.size(); j++) {
							ClauseEntry clauseEntries = clauseEntriesPositiveSemantical.get(j);
							createTestPurposeEntry(tpTable, result,
									clauseEntries);
						}
					}
					
					if (clauseEntriesNegativeSemantical != null) {
						for (int j=0; j < clauseEntriesNegativeSemantical.size(); j++) {
							ClauseEntry clauseEntries = clauseEntriesNegativeSemantical.get(j);
							createTestPurposeEntry(tpTable, result,
									clauseEntries);
						}
					}
					
					
					result.append(tpSectionFoot);
					clauseCounter++;
				}
				
				
			}
			
			result.append(tpFileFooter);
			FileUtils.saveStringToFile(new File(config.getProperty("DeliverableATSPath")+"/stf475-tp.html"), result.toString());
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		System.out.println("done.");
	}

	private void createTestPurposeEntry(String tpTable, StringBuffer result,
			ClauseEntry clauseEntries) {
		T3ExpectedOutput expected = clauseEntries.getExpected();
		T3Purpose purpose = clauseEntries.getPurpose();
		String tpId = "TP_" + clauseEntries.getFile().getName().replaceAll("\\.ttcn", "");
		String reference = expandPartReference(purpose.getPartReference()) + ", Clause " + purpose.getClauseStructured().toString();
		String ics = "None";
		String dependencies = "None";
		String summary = purpose.getPurposeText();
		String expectedText = expandExpected(expected);
		String notes = "";
		result.append(createTestPurpose(tpTable, tpId, reference, ics, dependencies, summary, expectedText, notes));
	}
	
	private String expandExpected(T3ExpectedOutput e) {
		if (e.getExpectedOutput().toLowerCase().contains("accept")) {
			String result = "The TTCN-3 module shall be accepted by the tool ";
			if (e.getExecutionResult().toLowerCase().contains("ttcn3verdict")) {
				String v = e.getExecutionResult().toLowerCase().substring(e.getExecutionResult().toLowerCase().indexOf(':')+1);
				result += "and all test cases have to produce the verdict <b>" + v + "</b> after execution.";
			} else if (e.getExecutionResult().toLowerCase().contains("noexecution")) {
				result += "without execution.";
			}
			return result;
		} else if (e.getExpectedOutput().toLowerCase().contains("reject")) {
			return "The TTCN-3 module shall be rejected by the validator or after/during execution.";
		}
		
		return "FIXME";
	}
	
	private String expandPartReference(int i) {
		if (i==1) {
			return "ES 201 873-1 [1]";
		}
		else if (i==4) {
			return "ES 201 873-4 [1]";
		}
		else if (i==9) {
			return "ES 201 873-9 [1]";
		}

		return "FIXME";
	}
	
	private String createSection(String sectionString, String chapterNumber, String chapterString) {
		return sectionString.replaceAll("\\{\\{CHAPTERNUMBER\\}\\}", chapterNumber).replaceAll("\\{\\{CHAPTERTITLE\\}\\}", chapterString);
	}

	private String createTestPurpose(String tableString, String tpId, String ref, String ics, String dependencies, String summary, String expected, String notes) {
		return tableString.replaceAll("\\{\\{TESTPURPOSEID\\}\\}", tpId)
				.replaceAll("\\{\\{REFERENCE\\}\\}", ref)
				.replaceAll("\\{\\{ICS\\}\\}", ics)
				.replaceAll("\\{\\{DEPENDENCIES\\}\\}", dependencies)
				.replaceAll("\\{\\{SUMMARY\\}\\}", summary)
				.replaceAll("\\{\\{EXPECTEDOUTPUT\\}\\}", expected)
				.replaceAll("\\{\\{NOTES\\}\\}", notes);
	}
	
	@SuppressWarnings("unused")
	private void createTable(List<Clause> myList, String tableNumber, String tableDescription, String tssSectionHead,
			String tssSectionFoot, HashMap<String, ArrayList<ClauseEntry>> clauseMap, StringBuffer result) {
		result.append(createSectionHead(tssSectionHead, tableNumber, tableDescription));
		TSSTable table = new TSSTable();
		
		TSSRow row = null;
		for (int i=0; i < myList.size(); i++) {
			Clause clause = myList.get(i);
			
			ArrayList<ClauseEntry> clauseEntries = null;
			if (!clause.toString().contains(".")) { // top level
				if (row != null) {
					table.addRow(row);
					row = null;
				}
				
				clauseEntries = clauseMap.get(clause.toString());
				
				row = new TSSRow();
				row.setChapter(clause.toString() + " " + references.getProperty(clause.toString()));

				if ((clauseEntries != null) && (clauseEntries.size() > 0)) {
					TSSClause tssClause = new TSSClause();
					tssClause.setClauseName("Top level");
					for (int j=0; j < clauseEntries.size(); j++) {
						ClauseEntry entry = clauseEntries.get(j);
						tssClause.addTestCase(entry.getFile().getName().replaceAll("\\.ttcn", ""));
					}

					row.addClause(tssClause);
				}
			} else {
				clauseEntries = clauseMap.get(clause.toString());
				
				if ((clauseEntries != null) && (clauseEntries.size() > 0)) {
					TSSClause tssClause = new TSSClause();
					tssClause.setClauseName(clause.toString() + " " + references.getProperty(clause.toString()));
					for (int j=0; j < clauseEntries.size(); j++) {
						ClauseEntry entry = clauseEntries.get(j);
						tssClause.addTestCase(entry.getFile().getName().replaceAll("\\.ttcn", ""));
					}
					row.addClause(tssClause);
				}					
			}
		}
		result.append(table.toHtml());
		result.append(tssSectionFoot);
	}

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

//	private String createTableRow(String tableRow, int number, String purpose, String clause, String status, String tpRef) throws IOException {
//		String icsTableRow = tableRow.replaceAll("\\{\\{NUMBER\\}\\}", Integer.toString(number));
//		icsTableRow = icsTableRow.replaceAll("\\{\\{PURPOSE\\}\\}", purpose);
//		icsTableRow = icsTableRow.replaceAll("\\{\\{CLAUSE\\}\\}", clause);
//		icsTableRow = icsTableRow.replaceAll("\\{\\{STATUS\\}\\}", status);
//		icsTableRow = icsTableRow.replaceAll("\\{\\{TCTPREF\\}\\}", tpRef);
//		
//		return icsTableRow;
//		
//	}
	
	private String createSectionHead(String sectionHead, String tableNumber, String tableDescription) {
		String newSectionHead = sectionHead.replaceAll("\\{\\{TABLENUMBER\\}\\}", tableNumber);
		newSectionHead = newSectionHead.replaceAll("\\{\\{TABLEDESCRIPTION\\}\\}", tableDescription);
		return newSectionHead;
	}
	
	// -----------------------------------------------------------------------------------------------

	public static void main(String[] args) {
		new TestPurposeGenerator().run();
	}

}
