/* $Id: DictionaryXML.java 339 2011-09-07 03:01:03Z shayashi $ */
package smart_gs.dictionary;

import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.TreeMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

import javax.swing.JOptionPane;
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.logical.GSResource;
import smart_gs.logical.Region;
import smart_gs.logical.Spread;
import smart_gs.logical.SpreadTree;
import smart_gs.logical.XML2ResourceConverter;
import smart_gs.swingui.WorkspaceWindow;
import smart_gs.util.GSStandardPath;

public class DictionaryXML {
	
	protected static DictionaryXML singleton;
	protected TreeMap<String, Dictionary> dictionaryMap = new TreeMap<String, Dictionary>();
	protected List<Spread> loadSpreads = new ArrayList<Spread>();
	private String dictionaryString;
	protected static boolean warning = false;
	
//	public static void main(String args[]){
//		new DictionaryXML().load();
//	}

	protected DictionaryXML(){
		
	}
	
	public static DictionaryXML getInstance(){
		if(singleton == null){
			singleton = new DictionaryXML();
		}
		return singleton;
	}
	
	public void setWarning(boolean flg){
		warning = flg;
	}
	
	public void load() {
		this.load(WorkspaceWindow.getInstance().getCurrentFile());
	}

	public void load(File file){
		loadSpreads.clear();
		dictionaryMap.clear();
		// Spread用のMapを作成
		HashMap<String, Spread> spreadMap = new HashMap<String, Spread>();
		
		List<Spread> spreadlist = SpreadTree.getInstance().getSpreads();
		for(int i=0;i<spreadlist.size();i++){
			Spread spread = spreadlist.get(i);
			spreadMap.put(spread.getURI(), spread);
		}
		
		DocumentBuilder builder;

		try {
			if(file == null) {
				return;
			}

			ZipFile gsxFile = new ZipFile(file);
			ZipEntry gsxDictionary = gsxFile.getEntry("dictionary/default.xml");
			if(gsxDictionary == null || gsxDictionary.getSize() <= 0){
				return;
			}

			builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
			Document document = builder.parse(gsxFile.getInputStream(gsxDictionary));
			Element rootElement = document.getDocumentElement();
			
			NodeList list = rootElement.getElementsByTagName("index");
			for (int i=0; i < list.getLength() ; i++) {
				Element element = (Element)list.item(i);
				String word = element.getAttribute("word");

				// Spreadを取得
				NodeList spreadList = element.getElementsByTagName("spread");
				Dictionary dictionary = new Dictionary();
				dictionary.setWord(word);
				for (int j=0; j < spreadList.getLength() ; j++) {
					Element spreadElement = (Element)spreadList.item(j);
					String uri = spreadElement.getAttribute(GSResource.URI);
					Spread spread  = spreadMap.get(uri);
					if(spread != null){
//						if(loadSpreadsmode){
							if(!loadSpreads.contains(spread)){
								loadSpreads.add(spread);
							}
//						}
						NodeList regionList = spreadElement.getElementsByTagName("region");
						Element regionElement = (Element)regionList.item(0);
						Region region = XML2ResourceConverter.getRegion(spread, regionElement);
						
						DictionaryRegion dictionaryRegion = new DictionaryRegion();
						dictionaryRegion.setImageFile("C:/a");
						dictionaryRegion.setRegion(region);
						dictionary.addDictionaryRegionList(dictionaryRegion);
					}else{
						if(!warning){
							JOptionPane.showMessageDialog(WorkspaceWindow.getInstance(),"A part of image is not able to be displayed because the image file did not exist","Waring",JOptionPane.WARNING_MESSAGE);
							warning = true;
						}
					}
				}
				dictionaryMap.put(word, dictionary);
			}
		} catch (ParserConfigurationException e) {
			e.printStackTrace();
		} catch (SAXException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}		
	}
	
	public List<Spread> getLoadSpreads(){
		return loadSpreads;
	}

	public TreeMap<String, Dictionary> getDictionaryMap(){
		return dictionaryMap;
	}

	public TreeMap<String, Dictionary> getDictionaryMap(String filter){
		TreeMap<String, Dictionary> resultMap = new TreeMap<String, Dictionary>();
		Iterator<String> itr = dictionaryMap.keySet().iterator();
		while(itr.hasNext()){
			String word = itr.next();
			if(word.startsWith(filter)){
				resultMap.put(word, dictionaryMap.get(word));
			}
		}
		return resultMap;
	}
	public TreeMap<String, Dictionary> getDictionaryMapByregularExpressions(String filter){
		TreeMap<String, Dictionary> resultMap = new TreeMap<String, Dictionary>();
		Iterator<String> itr = dictionaryMap.keySet().iterator();
		Pattern p = Pattern.compile(filter);

		
		while(itr.hasNext()){
			String word = itr.next();
			Matcher m = p.matcher(word);
		    while(m.find()){
				resultMap.put(word, dictionaryMap.get(word));
		    }
		}
		return resultMap;
	}

	public ArrayList<String> getWordList(String matchstr){
		if(dictionaryMap.size() == 0){
			return null;
		}
		ArrayList<String> wordList = new ArrayList<String>();
		Iterator<String> itr = dictionaryMap.keySet().iterator();
		while(itr.hasNext()){
			String word = itr.next();
			if(word.startsWith(matchstr)){
				wordList.add(word);
			}
		}
		return wordList;
	}
	public void add(String word,Region region){
		WorkspaceWindow.setUpdated(true);
		if(dictionaryMap.containsKey(word)){
			Dictionary dictionary = dictionaryMap.get(word);

			DictionaryRegion dictionaryRegion = new DictionaryRegion();
			dictionaryRegion.setImageFile("C:/a");
			dictionaryRegion.setRegion(region);
			dictionary.addDictionaryRegionList(dictionaryRegion);
		}else{
			Dictionary dictionary = new Dictionary();
			dictionary.setWord(word);
			
			DictionaryRegion dictionaryRegion = new DictionaryRegion();
			dictionaryRegion.setImageFile("C:/a");
			dictionaryRegion.setRegion(region);
			dictionary.addDictionaryRegionList(dictionaryRegion);
			
			dictionaryMap.put(word, dictionary);
		}
	}
	public void add(String word,Dictionary newDictionary){
		WorkspaceWindow.setUpdated(true);
		if(dictionaryMap.containsKey(word)){
			Dictionary dictionary = dictionaryMap.get(word);
			ArrayList<DictionaryRegion> list = newDictionary.getDictionaryRegionList();
			for(int i=0;i<list.size();i++){
				dictionary.addDictionaryRegionList(list.get(i));
			}
		}else{
			dictionaryMap.put(word, newDictionary);
		}
	}
	
	public void deleteRegion(String word,int index){
		if(dictionaryMap.containsKey(word)){
			Dictionary dictionary = dictionaryMap.get(word);
			dictionary.deleteDictionaryRegionList(index);
			ArrayList<DictionaryRegion> list = dictionary.getDictionaryRegionList();
			if(list.size() == 0){
				dictionaryMap.remove(word);
			}
		}
	}
	public void delete(String word){
		if(dictionaryMap.containsKey(word)){
			dictionaryMap.remove(word);
		}
	}
	public Dictionary getDictionary(String word){
		if(dictionaryMap.containsKey(word)){
			return dictionaryMap.get(word);
		}
		return null;
	}
	
	public synchronized void write() throws ParserConfigurationException{
		Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
		Element rootElement = document.createElement("dictionary");
		document.appendChild(rootElement);

		Iterator<String> itr = dictionaryMap.keySet().iterator();
		while(itr.hasNext()){
			String word = itr.next();

			Element indexElement = document.createElement("index");
			indexElement.setAttribute("word", word);
			
			Dictionary dictionary = dictionaryMap.get(word);
			ArrayList<DictionaryRegion> dictionaryRegionList = dictionary.getDictionaryRegionList();
			
			for(int i=0;i<dictionaryRegionList.size();i++){
				DictionaryRegion dictionaryRegion = dictionaryRegionList.get(i);
				Region region = dictionaryRegion.getRegion();
				Spread spread = region.getSpread();
				
				Element spreadElement = document.createElement("spread");
				spreadElement.setAttribute(GSResource.NAME, spread.getName());
				spreadElement.setAttribute(GSResource.URI, spread.getURI());
				spreadElement.setAttribute(GSResource.ORIGINAL_URI, spread.getOriginalURI());
//				String filepath = spread.getFile().getAbsolutePath();
				String filepath = spread.getFile().getPath();
//				changed by shayashi 2011.05.26
				spreadElement.setAttribute("filename", GSStandardPath.standardizeFileName(filepath));
//				this.isAbsolutePath(filepath, spreadElement);

				Element element = document.createElement("region");
				element.setAttribute(GSResource.NAME, region.getName());
				element.setAttribute(GSResource.URI, region.getURI());
				element.setAttribute(GSResource.ORIGINAL_URI, region.getOriginalURI());
				// kazuhiro kobayashi
				element.setAttribute("protection", region.isProtected());
				element.appendChild(region.getView().createXMLElement(document));
				spreadElement.appendChild(element);
				
				indexElement.appendChild(spreadElement);

			}
			rootElement.appendChild(indexElement);
		}
		
		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));
			this.dictionaryString = output.toString();

			transformer = null;
			source = null;
		} catch (TransformerConfigurationException e1) {
			e1.printStackTrace();
		} catch (TransformerException e) {
			e.printStackTrace();
		}
		factory = null;
	}

	public String getDictionaryString() {
		return dictionaryString;
	}

	public void init() {
		dictionaryMap.clear();
		try {
			this.write();
		} catch (ParserConfigurationException e) {
			e.printStackTrace();
		}
	}

}
