package smart_gs.logical;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import javax.xml.parsers.DocumentBuilder;
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.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import smart_gs.GSConstants;
import smart_gs.GSVersion;

import smart_gs.reasoning_web.desktop.logical.ShortCut;

//2011/06/03 kukita 
public class OldGSFileConverter {
	
	private static final String HEADER = GSConstants.URI_HEADER;
	private static final String SEP1 = URIObject.SEP1;
	private static final String SEP2 = URIObject.SEP2;
	private static final String SEP3 = URIObject.SEP3;
	private static final String SEP4 = URIObject.SEP4;
	
	private File file;
	private Document document;
	private HashMap<String, String> uriMap;

	public OldGSFileConverter(File file) {
		this.file = file;
		this.uriMap = new HashMap<String, String>();
	}
	public Document getDocumentFromGSFile() {
		DocumentBuilder builder;
		Document document = null;
		try {
			builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
			document = builder.parse(file);
		} catch (ParserConfigurationException e) {
			e.printStackTrace();
		} catch (SAXException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return document;
	}
	public File convertGSFile() {
		File gsxFile = new File(this.file.getAbsolutePath()+"_converted.gsx");
		this.document = getDocumentFromGSFile();
		convertDocument();
		TransformerFactory factory = TransformerFactory.newInstance();
		try {
			Transformer transformer = factory.newTransformer();
			transformer.setOutputProperty("encoding", "UTF-8");
			transformer.setOutputProperty("standalone", "yes");
			transformer.setOutputProperty("indent", "yes");

			DOMSource source = new DOMSource(document);
			StringWriter output = new StringWriter();
			transformer.transform(source, new StreamResult(output));
			String string = output.toString();
			int p = string.indexOf("?>") + 2;
			String former = string.substring(0, p);
			String latter = string.substring(p + 1);
			String newstring = former + "\n<!DOCTYPE rootElement>" + latter;
			ZipOutputStream writer = new ZipOutputStream(new FileOutputStream(gsxFile));
			writer.putNextEntry(new ZipEntry("spread.xml"));
			writer.write(newstring.getBytes("UTF-8"));
			writer.close();
			transformer = null;
			source = null;
		} catch (TransformerConfigurationException e1) {
			e1.printStackTrace();
		} catch (TransformerException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		factory = null;
		return gsxFile;
	}

	private void convertDocument() {

		Element rootElement = document.getDocumentElement();
		Element spreadTree = (Element) rootElement
			.getElementsByTagName("spreadTree").item(0);
		convertSpreadTree(spreadTree);
		
		Element presentationTree = (Element) rootElement
			.getElementsByTagName("presentationTree").item(0);
		if (presentationTree == null) {
			presentationTree = (Element) rootElement
				.getElementsByTagName("noteTree").item(0);
		}
		convertPresentationTree(presentationTree);
		
		Element rwElement = (Element) rootElement
			.getElementsByTagName("reasoning_web").item(0);
		convertRWElements(rwElement);
	}
	
	private Element getExpNotes() {
		Element rwElement = (Element) document.getDocumentElement()
			.getElementsByTagName("reasoning_web").item(0);
		return (Element)rwElement.getElementsByTagName("expNotes").item(0);
	}

	private void convertSpreadTree(Element element) {
		Element dir = (Element) element
			.getElementsByTagName("directory").item(0);
		convertSpreadDirectory(dir, HEADER + URIObject.SPREAD_DIRECTORY + SEP1);
	}
	private void convertSpreadDirectory(Element element, String path) {
		String name = URICreator.modifyName(element.getAttribute("name"));
		String oldURI = element.getAttribute("uri");
		String uri = path + name + SEP1 + URICreator.getURIExtension();
		setURIandVersion(element,oldURI,uri);
		NodeList directoryList = element.getElementsByTagName("directory");
		NodeList spreadList = element.getElementsByTagName("spread");		
		for (int i = 0; i < directoryList.getLength(); i++) {
			convertSpreadDirectory((Element) directoryList.item(i), URIObject.chopLast(uri));
		}
		for (int i = 0; i < spreadList.getLength(); i++) {
			convertSpread((Element)spreadList.item(i),chopHeader(uri));
		}
	}

	private void convertSpread(Element element, String path) {
		String name = URICreator.modifyName(extractNameFromSpread(element.getAttribute("filename")));
		element.setAttribute(GSResource.NAME, name);
		String oldURI = element.getAttribute("uri");
		String done = element.getAttribute("done");
		if (done.equals("true")) {
			return;
		}
		String uri = HEADER + URIObject.SPREAD + SEP1 + name + SEP1
			+ URICreator.getURIExtension() + SEP2 + path;

		setURIandVersion(element,oldURI,uri);
		NodeList regionList = element.getElementsByTagName("region");
		for (int i = 0; i < regionList.getLength(); i++) {
			convertRegion((Element)regionList.item(i), chopHeader(uri));
		}
		NodeList spreadDocumentList = element.getElementsByTagName("spreadDocument");
		for (int i = 0; i < spreadDocumentList.getLength(); i++) {
			convertSpreadDocument((Element)spreadDocumentList.item(i), chopHeader(uri));
		}
		element.setAttribute("done", "true");
	}

	private static String extractNameFromSpread(String filename) {
		char sep = File.separatorChar;
		int beginIndex = filename.lastIndexOf(sep);
		int endIndex = filename.lastIndexOf(".");
		return filename.substring(beginIndex+1, endIndex);
	}
	private void convertSpreadDocument(Element element, String path) {
		String oldURI = element.getAttribute("uri");
		String uri = "";
		String origSource = element.getAttribute("leftSource");
		String convertedSource = "";
		if(origSource.startsWith("<xml><left><html>") && origSource.endsWith("</html></left></xml>")){
			origSource = origSource.substring("<xml><left><html>".length(),origSource.length() - "</html></left></xml>".length());
			convertedSource = "<xml><html>" + origSource + "</html></xml>";
		}
		element.setAttribute("source", convertedSource);
		element.removeAttribute("leftSource");
		element.removeAttribute("rightSource");

		int typeInt = Integer.parseInt(element.getAttribute("type"));
		String type = "";
		if (typeInt == 1) {
			type = URIObject.FIRST_IDAT;
		} else if (typeInt == 2) {
			type = URIObject.SECOND_IDAT;
		} else {
			type = URIObject.THIRD_IDAT;
		}
		uri = HEADER + type + SEP1 + URICreator.getURIExtension() + SEP2 + path;
		setURIandVersion(element,oldURI,uri);
		NodeList segmentList = element.getElementsByTagName("segment");
		for (int i = 0; i < segmentList.getLength(); i++) {
			Element segment = (Element)segmentList.item(i);
			convertTextSegment(segment, chopHeader(uri));
		}
	}


	private void convertRegion(Element element, String path) {
		String oldURI = element.getAttribute("uri");
		Element view = (Element)element.getElementsByTagName("view").item(0);
		String type = view.getAttribute("type");
		if (type.equals("lasso")) {
			view.setAttribute("type", URIObject.POLYGON);
		}
		String uri = HEADER + URIObject.POLYGON + SEP1 + URICreator.getURIExtension() + SEP2 + path;
		setURIandVersion(element,oldURI,uri);
	}

	private void convertTextSegment(Element element, String path) {
		String oldURI = element.getAttribute("uri");
		String type = URIObject.TEXT_SEGMENT;
		String uri = HEADER + type + SEP1 + URICreator.getURIExtension()
			+ SEP2 + path;
		setURIandVersion(element,oldURI,uri);
	}
	
	private void convertPresentationTree(Element element) {
		Element usersNoteTree = document.createElement("usersNoteTree");
		
		Element directory = document.createElement(URIObject.USERS_NOTE_DIRECTORY);
		String directoryName = "root";
		String directoryURI = HEADER + URIObject.USERS_NOTE_DIRECTORY 
			+ SEP1 + directoryName + SEP1 + URICreator.getURIExtension();
		directory.setAttribute(GSResource.NAME, directoryName);
		directory.setAttribute(GSResource.ORIGINAL_URI, directoryURI);
		directory.setAttribute(GSResource.URI, directoryURI);
		directory.setAttribute(GSResource.VERSION, GSVersion.getVersion());
		
		NodeList list = element.getElementsByTagName("presentation");
		if (list.getLength() == 0) {
			list = element.getElementsByTagName("note");
		}
		String path = chopHeader(directoryURI);
		for (int i = 0; i < list.getLength(); i++) {
			Element usersNote = getUsersNoteFromPresentation((Element)list.item(i),path);
			directory.appendChild(usersNote);
		}
		
		usersNoteTree.appendChild(directory);
		document.getDocumentElement().replaceChild(usersNoteTree,element);
	}

	
	private Element getUsersNoteFromPresentation(Element element, String path) {
		String oldURI = element.getAttribute("uri");
		Element usersNote = document.createElement("usersNote");
		usersNote.setAttribute("source", element.getAttribute("source"));
		usersNote.setAttribute(GSResource.NAME, element.getAttribute("name"));
		usersNote.setAttribute(GSResource.ID, element.getAttribute("id") + "");
		String uri = HEADER + URIObject.USERS_NOTE + SEP1 + element.getAttribute("name") + SEP1
			+ URICreator.getURIExtension() + SEP2 + path;		
		setURIandVersion(usersNote, oldURI, uri);
		NodeList list = element.getElementsByTagName("segment");
		for (int i = 0; i < list.getLength(); i++) {
			Element segment = (Element)list.item(i);
			Element segmentClone = (Element)(segment.cloneNode(true));
			convertTextSegment(segmentClone, chopHeader(uri));
			usersNote.appendChild(segmentClone);
		}		
		return usersNote;
	}
	
	private void convertRWElements(Element element) {
		Element expNotes = (Element) element
			.getElementsByTagName("expNotes").item(0);
		convertExpNotes(expNotes);

		Element desktop = (Element) element
			.getElementsByTagName("desktop").item(0);
		convertDesktop(desktop);
		
		NodeList connectionList = element.getElementsByTagName("connection");
		for (int i = 0; i < connectionList.getLength(); i++) {
			convertConnection((Element)connectionList.item(i));
		}		
	}

	private void convertConnection(Element element) {
		String name = URICreator.modifyName(element.getAttribute("name"));
		NodeList pointerList = element.getElementsByTagName("pointer");
		Element sourcePointer = null;
		Element targetPointer = null;
		if (((Element)pointerList.item(0)).getAttribute("type").equals("source")) {
			sourcePointer = (Element) pointerList.item(0);
			targetPointer = (Element) pointerList.item(1);
		} else {
			sourcePointer = (Element) pointerList.item(1);
			targetPointer = (Element) pointerList.item(0);
		}
		String sourceOldURI = sourcePointer.getAttribute("uri");
		String targetOldURI = targetPointer.getAttribute("uri");
		String sourceURI = uriMap.get(sourceOldURI);
		String targetURI = uriMap.get(targetOldURI);
		sourcePointer.setAttribute("uri", sourceURI);
		targetPointer.setAttribute("uri", targetURI);
		String uri = HEADER + URIObject.CONNECTION + SEP1 + name + SEP1 
			+ URICreator.getURIExtension()
			+ SEP3 + sourceURI
			+ SEP4 + targetURI;
		String oldURI = element.getAttribute("uri");
		setURIandVersion(element,oldURI,uri); 
		Element expNote = (Element) element.getElementsByTagName("explanatory").item(0);
		convertExplanatoryNote(expNote);
		
		String id = expNote.getAttribute("id");
		NodeList notes = this.getExpNotes().getElementsByTagName("explanatory");
		for (int i = 0; i < notes.getLength(); i++) {
			Element note = (Element) notes.item(i);
			if (id.equals(note.getAttribute("id"))) {
				convertExplanatoryNote(note);
			}
		}
	}

	private void convertDesktop(Element element) {
		NodeList folderList = element.getElementsByTagName("desktopFolder");
		for (int i = 0; i < folderList.getLength(); i++) {
			convertFolder((Element)folderList.item(i), HEADER + URIObject.DESKTOP_FOLDER +SEP1);
		}
	}
	

	private void convertFolder(Element element, String path) {
		String name = URICreator.modifyName(element.getAttribute("name"));
		String uri = path + name + SEP1 + URICreator.getURIExtension();
		String oldURI = element.getAttribute("uri");
		setURIandVersion(element,oldURI,uri);
		NodeList folderList = element.getElementsByTagName("desktopFolder");
		for (int i = 0; i < folderList.getLength(); i++) {
			convertFolder((Element)folderList.item(i), URIObject.chopLast(uri));
		}
		NodeList shortcutList = element.getElementsByTagName("shortcut");
		for (int i = 0; i < shortcutList.getLength(); i++) {
			Element shortcut = (Element)shortcutList.item(i);
			if (!(shortcut.getAttribute("done").equals("true"))) {
				convertShortcut(shortcut);
			}
		}
	}
	private void convertShortcut(Element element) {
		String uri = HEADER + URIObject.SHORTCUT + SEP1
			+ URICreator.getURIExtension();
		String oldURI = element.getAttribute("uri");
		setURIandVersion(element,oldURI,uri);
		Element bucket = (Element)element.getElementsByTagName("bucket").item(0);
		if (bucket == null) {
			bucket = (Element)element.getElementsByTagName("backet").item(0);
		}
		Element bucket2 = getBucketFromBacket(bucket);
		element.replaceChild(bucket2,bucket);
		NodeList queryList = element.getElementsByTagName("query");
		for (int i = 0; i < queryList.getLength(); i++) {
			Element query = (Element)queryList.item(i);
			if (!(query.getAttribute("done").equals("true"))) {
				convertQuery(query);
			}
		}
		element.setAttribute("done", "true");

	}
	
	private Element getBucketFromBacket(Element element) {
		String oldURI = element.getAttribute("uri");
		Element bucket = document.createElement(URIObject.BUCKET);
		bucket.setAttribute("source", element.getAttribute("source"));
		bucket.setAttribute(GSResource.NAME, element.getAttribute("name"));
		String uri = HEADER + URIObject.BUCKET + SEP1 + URICreator.getURIExtension();
		setURIandVersion(bucket, oldURI, uri);
		return bucket;
	}

	
	private void convertQuery(Element element) {
		String hasSpread = element.getAttribute("hasSpread");
		String done = element.getAttribute("done");
		if (done.equals("true")) {
			return;
		}
		String oldURI = element.getAttribute("uri");
		String ext = "";
		if (hasSpread.equals("true")) {
			String oldSpreadURI = element.getAttribute("spreadURI");
			String spreadURI = uriMap.get(oldSpreadURI);
			if (spreadURI != null) {
				element.setAttribute("spreadURI", spreadURI);
				ext = SEP2 + chopHeader(spreadURI);
			}
		}
		String name = URIObject.modifyName(element.getAttribute("name"));
		String uri = HEADER + URIObject.GSQUERY + SEP1 + name + SEP1 + URICreator.getURIExtension() + ext;
		setURIandVersion(element,oldURI,uri);
		element.setAttribute("done", "true");
	}
	private void convertExpNotes(Element element) {
//		NodeList expNoteList = element.getElementsByTagName("explanatory");
//		for (int i = 0; i < expNoteList.getLength(); i++) {
//			Element note = (Element)expNoteList.item(i);
//			convertExplanatoryNote(note, "");
//			String path = chopHeader(note.getAttribute("uri"));
//			NodeList segmentList = note.getElementsByTagName("segment");
//			for (int j = 0; j < segmentList.getLength(); j++) {
//				convertTextSegment((Element)segmentList.item(i), path);
//			}
//		}
	}

	private void convertExplanatoryNote(Element element) {
		String id = element.getAttribute("id");
		String name = URICreator.modifyName(element.getAttribute("name"));
		String oldURI = element.getAttribute("uri");
		String uri = HEADER + URICreator.EXPLANATORY_NOTE + SEP1 + name 
			+ SEP1 + URICreator.getURIExtension();
		setURIandVersion(element,oldURI,id,uri); 
		NodeList segmentList = element.getElementsByTagName("segment");
		for (int j = 0; j < segmentList.getLength(); j++) {
			convertTextSegment((Element)segmentList.item(j), chopHeader(uri));
		}
	}	



	private void setURIandVersion(Element element, String oldURI, String id,
			String uri) {
		element.setAttribute(GSResource.URI, uri);
		element.setAttribute(GSResource.ORIGINAL_URI, uri);
		element.setAttribute(GSResource.OLD_VERSION_URI,oldURI);
		element.setAttribute(GSResource.VERSION, GSVersion.getVersion());
		this.uriMap.put(id, uri);
	}
	private static String chopHeader(String uri) {
		return uri.substring(HEADER.length());
	}
	
	private void setURIandVersion(Element element, String oldURI, String uri) {
		element.setAttribute(GSResource.URI, uri);
		element.setAttribute(GSResource.ORIGINAL_URI, uri);
		element.setAttribute(GSResource.OLD_VERSION_URI,oldURI);
		element.setAttribute(GSResource.VERSION, GSVersion.getVersion());
		this.uriMap.put(oldURI, uri);
	}
	
}
