package jp.ac.osaka_u.ist.sel.similarity.xml;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;


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

/**
 * XML parser for input file list.
 * 
 * @author ysk-ssk
 *
 */
public class FileMapXmlParser  {
    /**
     * is an utility class.
     */
    private FileMapXmlParser() {
    }
    
    public static Map<String,Set<String>> parseXml(String xmlPath) throws ParserConfigurationException, SAXException, IOException {
        Map<String,Set<String>> filePathMap = new HashMap<String,Set<String>>();
        
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();
        Document document = builder.parse(xmlPath);
        
        Element rootElement = document.getDocumentElement();
        if (!rootElement.getTagName().equals(RegisterTarget._elementName)) {
            throw new RuntimeException("Unknown tag: " + rootElement.getTagName());
        }
        NodeList domainElements = rootElement.getElementsByTagName(RegisterTarget.Domain._elementName);
        for (int i = 0; i < domainElements.getLength(); i++) {
            Element domainElement = (Element) domainElements.item(i);
            String basepath;
            if (domainElement.hasAttribute(RegisterTarget.Domain._basepath)) {
                basepath = domainElement.getAttribute(RegisterTarget.Domain._basepath);
            } else {
                throw new RuntimeException("basepath attribute not found in domain tag.");
            }

            Set<String> filePathSet = new HashSet<String>();
            NodeList fileElements = domainElement.getElementsByTagName(RegisterTarget.Domain.File._elementName);
            for (int j = 0; j < fileElements.getLength(); j++) {
                Element fileElement = (Element) fileElements.item(j);
                String path;
                if (fileElement.hasAttribute(RegisterTarget.Domain.File._path)) {
                    path = fileElement.getAttribute(RegisterTarget.Domain.File._path);
                } else {
                    throw new RuntimeException("path attribute not found in file tag.");
                }
                filePathSet.add(path);
            }
            
            filePathMap.put(basepath, filePathSet);
        }
        
        return filePathMap;
    }

    public static void outputXml(Map<String,Set<String>> filePathMap, String xmlPath) throws IOException, XMLStreamException {
        XMLOutputFactory factory = XMLOutputFactory.newInstance();
        FileWriter fileWriter = null;
        XMLStreamWriter xmlWriter = null;
        
        File xmlFile = new File(xmlPath);
        if (xmlFile.exists() && !xmlFile.canWrite()) {
            throw new RuntimeException("Can not write: " + xmlPath);
        }
        try {
            fileWriter = new FileWriter(xmlPath);
            xmlWriter = factory.createXMLStreamWriter(fileWriter);

            xmlWriter.writeStartDocument("UTF-8","1.0");
            xmlWriter.writeStartElement(RegisterTarget._elementName);
            for (String basepath : filePathMap.keySet()) {
                xmlWriter.writeStartElement(RegisterTarget.Domain._elementName);
                xmlWriter.writeAttribute(RegisterTarget.Domain._basepath, basepath);
                
                Set<String> filePathSet = filePathMap.get(basepath);
                for (String path : filePathSet) {
                    xmlWriter.writeEmptyElement(RegisterTarget.Domain.File._elementName);
                    xmlWriter.writeAttribute(RegisterTarget.Domain.File._path, path);
                }
                
                xmlWriter.writeEndElement();
            }
            xmlWriter.writeEndElement();
            xmlWriter.writeEndDocument();
        } finally {
            try {
                if (xmlWriter != null) {
                    xmlWriter.close();
                }
                if (fileWriter != null) {
                    fileWriter.close();
                }
            } catch (XMLStreamException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

}

