package org.deft.extension.tools.tokentrimmer;

import java.io.File;
import java.util.HashMap;
import java.util.Set;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.apache.log4j.ConsoleAppender;
import org.apache.log4j.Logger;
import org.apache.log4j.SimpleLayout;
import org.deft.extension.tools.astlayouter.ASTLayouter;
import org.deft.repository.ast.TreeNode;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

//REFAC
//TEST Timer
//TODO Fehlertoleranz in XML
public class TokenAutoTrimmer {

	private static enum TrimDirection {
		NONE, LEFT, RIGHT, BEFORE, AFTER, BOTH
	};

	private static class TrimPair {
		public TrimDirection h = TrimDirection.NONE;
		public TrimDirection v = TrimDirection.NONE;
	};

	private static final Logger LOGGER = Logger
			.getLogger(TokenAutoTrimmer.class);

	static private HashMap<String, HashMap<String, TrimPair>> trimMaps = new HashMap<String, HashMap<String, TrimPair>>();
	static private String currentTrimMapID = null;

	static {
		// OPT LOGGER
		LOGGER.addAppender(new ConsoleAppender(new SimpleLayout()));
	}

	public static void create(String id, String trimerDescriptionFile) {
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		DocumentBuilder builder;
		Document document;
		try {
			builder = factory.newDocumentBuilder();
			document = builder.parse(new File(trimerDescriptionFile));
		} catch (Exception e) {
			throw new TrimmerException(e.toString());
		}
		trimMaps.put(id, load(document));
		currentTrimMapID = id;
	}

	public static void set(String id) {
		if (trimMaps.containsKey(id))
			currentTrimMapID = id;
		else
			throw new TrimmerException("Trimming " + id + " unknown");
	}

	private static HashMap<String, TrimPair> load(Document document) {
		HashMap<String, TrimPair> trimMap = new HashMap<String, TrimPair>();
		NodeList nl = document.getElementsByTagName("trim");

		for (int i = 0; i < nl.getLength(); i++) {
			Node n = nl.item(i);
			TrimPair tp = new TrimPair();
			tp.v = toEnum(n.getAttributes().getNamedItem("v").getNodeValue());
			tp.h = toEnum(n.getAttributes().getNamedItem("h").getNodeValue());

			String content = n.getTextContent();
			String[] tokens = content.split(",");
			for (int c = 0, s = tokens.length; c < s; c++) {
				trimMap.put(tokens[c].trim(), tp);
			}
		}
		return trimMap;
	}

	private static TrimDirection toEnum(String nodeValue) {
		if (nodeValue.equals("left")) {
			return TrimDirection.LEFT;
		}
		if (nodeValue.equals("right")) {
			return TrimDirection.RIGHT;
		}
		if (nodeValue.equals("before")) {
			return TrimDirection.BEFORE;
		}
		if (nodeValue.equals("after")) {
			return TrimDirection.AFTER;
		}
		if (nodeValue.equals("both")) {
			return TrimDirection.BOTH;
		}
		return TrimDirection.NONE;
	}

	private ASTLayouter tl;

	public TokenAutoTrimmer(TreeNode root) {

		tl = new ASTLayouter(root.serialize());

	}

	public void trim(TreeNode tn) {
		System.out.println(currentTrimMapID);
		if (currentTrimMapID == null)
			return;
		HashMap<String, TrimPair> trimMap = trimMaps.get(currentTrimMapID);
		TrimPair tp = trimMap.get(tn.getName());
		// TODO entfernen
		if (tp == null) {
			LOGGER.warn("Unhandled trim: " + tn.getName() + "["
					+ tn.getFirstTokenNode().getName() + ","
					+ tn.getLastTokenNode().getName() + "] in "
					+ currentTrimMapID);
			return;
		}
		switch (tp.h) {
		case LEFT:
			tl.trimLeft(tn.getFirstToken());
			break;
		case RIGHT:
			tl.trimRight(tn.getLastToken());
			break;
		case BOTH:
			tl.trimLeft(tn.getFirstToken());
			tl.trimRight(tn.getLastToken());
			break;
		default:
			break;
		}
		switch (tp.v) {
		case BEFORE:
			tl.trimLinesBefore(tn.getFirstToken());
			break;
		case AFTER:
			tl.trimLinesAfter(tn.getLastToken());
			break;
		case BOTH:
			tl.trimLinesBefore(tn.getFirstToken());
			tl.trimLinesAfter(tn.getLastToken());
			break;
		default:
			break;
		}
	}
}
