package com.queplix.tools.fkchecker.kernel.sources;

import com.queplix.tools.fkchecker.kernel.exceptions.SourceException;
import com.queplix.tools.fkchecker.kernel.types.ForeignKey;
import com.queplix.tools.fkchecker.kernel.types.KeyPair;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

/**
 * @author dmitry.antonov
 */
public class XmlSource implements ForeignKeysSource {


    private final File xmlFile;
    private int currentReferenceNo = 0;
    private NodeList references;

    public static XmlSource[] createSources(Properties properties) {
        File xmlDir = new File(properties.getProperty("xmlFile"));
        if (!xmlDir.exists()) {
            throw new IllegalArgumentException("Property \'xmlFile\' must reference to existing file or directory!");
        }
        if (xmlDir.isDirectory()) {
            //if it's a directory - read all files from and create sources
            File[] files = xmlDir.listFiles();
            List<ForeignKeysSource> result = new ArrayList<ForeignKeysSource>();
            for (File file : files) {
                if (file.getName().endsWith(".xml")) {
                    result.add(new XmlSource(file));
                }
            }
            return (XmlSource[]) result.toArray(new XmlSource[0]);
        }
        else {
            //if param is a single file - use it as is
            return new XmlSource[]{new XmlSource(xmlDir)};
        }
    }

    private XmlSource(File xmlFile) {
        this.xmlFile = xmlFile;
    }

    public void openSource() throws SourceException {
        try {
            DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
            Document doc = db.parse(xmlFile);
            references = doc.getElementsByTagName("dataschema");
        }
        catch (Exception e) {
            throw new SourceException(e);
        }
    }

    public boolean hasNextForeignKey() {
        return currentReferenceNo < references.getLength();
    }

    private KeyPair handleTable(Node node) {
        Element table = (Element) node;
        return new KeyPair(table.getAttribute("name"), table.getElementsByTagName("key").item(0).getTextContent());
    }

    public ForeignKey nextForeignKey() {
        Element e = (Element) references.item(currentReferenceNo++);
        NodeList tables = e.getElementsByTagName("table");
        return new ForeignKey(e.getAttribute("name"),
                handleTable(tables.item(0)), handleTable(tables.item(1)));
    }

    public void closeSource() {
        //there is nothing to do
    }
}
