package hiro.yoshioka.sql.notes.ddl;

import hiro.yoshioka.sdh.ResultSetDataHolder;
import hiro.yoshioka.util.FileUtil;

import java.io.File;
import java.io.StringReader;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

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

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

public class NotesDXLParser2 {
	static DocumentBuilderFactory factory;
	DocumentBuilder builder;
	private boolean processingForm;
	private boolean processingSubForm;
	private boolean processingPar;
	private boolean processingCode;
	private Form form;
	private List<Form> formList;
	private Map<Pardef, String> final_reset_SubFormMap = new LinkedHashMap<Pardef, String>();
	private Map<String, Map<Integer, Pardef>> subFormMap = new LinkedHashMap<String, Map<Integer, Pardef>>();
	private Map<String, String> aliasMap = new LinkedHashMap<String, String>();
	private Par par;
	private PardefElement pardef_element;
	private String eventName, formulaCode;
	private StringBuilder fValueBuffer = new StringBuilder();
	String dxl;
	Set<String> parseTargetFormSets;

	private NotesDXLParser2(String dxl, Set<String> parseTargetFormSets) {
		this.dxl = dxl;
		this.parseTargetFormSets = parseTargetFormSets;
	}

	private NotesDXLParser2(String dxl) {
		this.dxl = dxl;
	}

	private void init() throws ParserConfigurationException, SAXException {
		if (builder == null) {
			factory = DocumentBuilderFactory.newInstance();
		}
		builder = factory.newDocumentBuilder();
		builder.setErrorHandler(new DefaultHandler());
	}

	public static Database parseDxl(String dxl, Set<String> parseTargetFormSets) {
		NotesDXLParser2 obj = new NotesDXLParser2(dxl, parseTargetFormSets);
		try {
			obj.init();
			return obj.parse();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}

	public static hiro.yoshioka.sql.notes.ddl.Document parseDxl(String dxl,
			String itemName) {
		NotesDXLParser2 obj = new NotesDXLParser2(dxl);
		try {
			obj.init();
			return obj.parseItem(itemName);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}

	public static void main(String[] args) {
		// parse(FileUtil.getText(new File("C:/a.dxl"), "UTF-8"));
		// Set<String> formSet = new LinkedHashSet<String>();
		// formSet.add("Response");
		// formSet.add("RRREDoc000");
		String dxl = FileUtil.getText(new File(
				"C:/tmp/xm_8a9bdcfd-9168-426b-94e4-3a6521b740e2.xml"), "sjis");
		hiro.yoshioka.sql.notes.ddl.Document db = NotesDXLParser2.parseDxl(dxl,
				"richtext1");
		System.out.println("=== html ===");
		String text = NotesDXLParser2.toHtmlString(db);
		System.out.println(text);
		FileUtil.writeFile(new File("C:/tmp/hh.html"), text, "sjis");
	}

	public static synchronized String toHtmlString(
			hiro.yoshioka.sql.notes.ddl.Document document) {
		StringBuilder buf = new StringBuilder();
		buf.append(String.format("<html>%n"));
		buf.append(String.format("<head>%n"));
		buf.append(String
				.format("  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">%n"));
		buf.append(String.format("  <style type=\"text/css\">%n  <!--%n"));

		buf.append(String.format("%s%n", document.toCssString()));

		buf.append(String.format("  -->%n  </style>%n%n"));
		buf.append(String.format("</head>%n"));
		buf.append(String.format("<body>%n"));

		buf.append(String.format("%s%n", document.itemToHtmlString()));

		buf.append(String.format("%n</body>%n</html>"));
		return buf.toString();
	}

	public static synchronized String toHtmlString(ResultSetDataHolder rdh,
			int row, Database db, Form form, File imgDir) {
		if (imgDir == null) {
			imgDir = FileUtil.TMP_DIR;
		}
		StringBuilder buf = new StringBuilder();
		buf.append(String.format("<html>%n"));
		buf.append(String.format("<head>%n"));
		buf.append(String
				.format("  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">%n"));
		buf.append(String.format("  <style type=\"text/css\">%n  <!--%n"));

		buf.append(String.format("   .hukidasi_box{                     %n"));
		buf.append(String.format("	    position:relative;              %n"));
		buf.append(String.format("	 }                                  %n"));
		buf.append(String.format("                                      %n"));
		buf.append(String.format("	 .hukidasi_box span{ display:none;} %n"));
		buf.append(String.format("	                                    %n"));
		buf.append(String.format("	 a:hover span{ display:block;}      %n"));
		buf.append(String.format("                                      %n"));
		buf.append(String.format("	 .hukidasi{                         %n"));
		buf.append(String.format("	    z-index:10;                     %n"));
		buf.append(String.format("	    font-size:x-small;              %n"));
		buf.append(String.format("	    width:350px;                    %n"));
		buf.append(String.format("	    padding:5px 5px 5px 10px;       %n"));
		buf.append(String.format("	    background-color:green;         %n"));
		buf.append(String.format("	    color:#fff;                     %n"));
		buf.append(String.format("	    position:absolute;              %n"));
		buf.append(String.format("	    top:30px;                       %n"));
		buf.append(String.format("	    left:-5px;                      %n"));
		buf.append(String.format("	 }                                  %n"));

		buf.append(String.format("%s%n", form.toCssString()));

		buf.append(String.format("  -->%n  </style>%n%n"));
		buf.append(String.format("</head>%n"));
		buf.append(String.format("<body>%n"));

		buf.append(String.format("%s%n", form.toHtmlString(rdh, row, imgDir)));

		buf.append(String.format("%n</body>%n</html>"));
		return buf.toString();
	}

	public hiro.yoshioka.sql.notes.ddl.Document parseItem(String itemName) {

		try {
			builder = factory.newDocumentBuilder();
			builder.setErrorHandler(new DefaultHandler());
			Document domDoc = builder.parse(new InputSource(new StringReader(
					dxl)));

			Element element = domDoc.getDocumentElement();

			NodeList itemNodes = element.getElementsByTagName("item");
			int numOfPictures = itemNodes.getLength();

			hiro.yoshioka.sql.notes.ddl.Document db = null;
			for (int k = 0; k < numOfPictures; k++) {
				Node item = itemNodes.item(k);
				if (itemName.equals(item.getAttributes().getNamedItem("name")
						.getNodeValue())) {
					// Node richtext = item.getFirstChild();
					db = new hiro.yoshioka.sql.notes.ddl.Document(item);
				}
			}

			return db;
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;

	}

	public Database parse() {
		try {
			builder = factory.newDocumentBuilder();
			builder.setErrorHandler(new DefaultHandler());
			Document domDoc = builder.parse(new InputSource(new StringReader(
					dxl)));

			Element element = domDoc.getDocumentElement();
			System.out.println("element=" + element);
			if (!"database".equals(element.getTagName())) {
				return null;
			}
			Database db = new Database(element, this.parseTargetFormSets);

			// find all the inline images in the richtext fields get the
			// picture
			// nodes
			//
			// gif
			// // tags
			// System.out.println("k[" + k + "] picChildren=" +
			// picChildren);
			// int numOfNodes = picChildren.getLength();
			// for (int i = 0; i < numOfNodes; i++) { // loop through the
			// <gif>
			// // tags
			// Node binaryNode = picChildren.item(i).getFirstChild();
			// System.out
			// .println("k[" + k + "] i[" + i + "]" + binaryNode);
			// String base64Stream = binaryNode.getNodeValue();
			//
			// FileOutputStream fo = new FileOutputStream(new File(
			// "c:/tmp/p/" + UUID.randomUUID().toString() + "."
			// + "gif"));
			// InputStream in = MimeUtility.decode(
			// new ByteArrayInputStream(base64Stream.getBytes()),
			// "base64");
			//
			// int len;
			// byte[] buf = new byte[1024];
			//
			// while ((len = in.read(buf)) != -1) {
			// fo.write(buf, 0, len);
			// }
			//
			// in.close();
			// fo.flush();
			// fo.close();
			// }
			// }

			return db;
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}

}
