/* BdfServer - Copyright (c) 2006-2042 Vincent Calame - Exemole
 * Logiciel libre donné sous triple licence :
 * 1) selon les termes de la CeCILL V2
 * 2) selon les termes de l’EUPL V.1.1
 * 3) selon les termes de la GNU GPLv3
 * Voir le fichier licences.txt
 */


package fr.exemole.bdfserver.tools.balayage.dom;

import fr.exemole.bdfserver.tools.balayage.BalayageBuilder;
import java.text.ParseException;
import net.fichotheque.Fichotheque;
import net.fichotheque.exportation.balayage.BalayageConstants;
import net.fichotheque.selection.FicheQuery;
import net.fichotheque.tools.exportation.balayage.BalayageOutputBuilder;
import net.fichotheque.tools.exportation.balayage.BalayageUnitBuilder;
import net.fichotheque.tools.exportation.balayage.SiteMapOptionBuilder;
import net.fichotheque.tools.selection.SelectionDOMUtils;
import net.mapeadores.util.localisation.Lang;
import net.mapeadores.util.localisation.Langs;
import net.mapeadores.util.localisation.LangsUtils;
import net.mapeadores.util.localisation.ListLangContextBuilder;
import net.mapeadores.util.text.AccoladePattern;
import net.mapeadores.util.text.StringUtils;
import net.mapeadores.util.xml.XMLUtils;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;


/**
 *
 * @author Vincent Calame
 */
public class BalayageDOMReader {

    private final Fichotheque fichotheque;
    private final BalayageBuilder balayageBuilder;

    public BalayageDOMReader(Fichotheque fichotheque, BalayageBuilder builder) {
        this.fichotheque = fichotheque;
        this.balayageBuilder = builder;
    }

    public void readBalayage(Element element_xml) {
        NodeList liste = element_xml.getChildNodes();
        boolean metadone = false;
        for (int i = 0; i < liste.getLength(); i++) {
            Node nd = liste.item(i);
            if (nd.getNodeType() == Node.ELEMENT_NODE) {
                Element el = (Element) nd;
                String tagname = el.getTagName();
                if ((!metadone) && (tagname.equals("metadata"))) {
                    metadone = true;
                    readMetadata(el);
                } else if ((tagname.equals("global-fiche-query")) || (tagname.equals("global-fiche-select"))) {
                    FicheQuery ficheQuery = SelectionDOMUtils.getFicheConditionEntry(fichotheque, el).getFicheQuery();
                    if (!ficheQuery.isEmpty()) {
                        balayageBuilder.addGlobalFicheQuery(ficheQuery);
                    }
                } else if (tagname.equals("corpus-balayage")) {
                    addCorpusBalayageUnit(el);
                } else if (tagname.equals("fiche-balayage")) {
                    addFicheBalayageUnit(el);
                } else if (tagname.equals("thesaurus-balayage")) {
                    addThesaurusBalayageUnit(el);
                } else if (tagname.equals("motcle-balayage")) {
                    addMotcleBalayageUnit(el);
                } else if (tagname.equals("unique-balayage")) {
                    addUniqueBalayageUnit(el);
                } else if (tagname.equals("document-balayage")) {
                    addDocumentBalayageUnit(el);
                } else if ((tagname.equals("illustration-balayage")) || (tagname.equals("album-balayage"))) {
                    addIllustrationBalayageUnit(el);
                } else if (tagname.equals("sitemap")) {
                    setSiteMapOption(el);
                } else if (tagname.equals("postscriptum")) {
                    initPostscriptum(el);
                }
            }
        }
    }

    private void initPostscriptum(Element element_xml) {
        NodeList liste = element_xml.getChildNodes();
        for (int i = 0; i < liste.getLength(); i++) {
            Node nd = liste.item(i);
            if (nd.getNodeType() == Node.ELEMENT_NODE) {
                Element el = (Element) nd;
                String tagname = el.getTagName();
                if (tagname.equals("command")) {
                    String command = XMLUtils.getData(el);
                    if (command.length() > 0) {
                        balayageBuilder.addPostscriptumExternalScript(command);
                    }
                } else if (tagname.equals("scrutari")) {
                    String scrutari = XMLUtils.getData(el);
                    if (scrutari.length() > 0) {
                        balayageBuilder.addPostscriptumScrutariExport(scrutari);
                    }
                } else if (tagname.equals("sql")) {
                    String sql = XMLUtils.getData(el);
                    if (sql.length() > 0) {
                        balayageBuilder.addPostscriptumSqlExport(sql);
                    }
                }
            }
        }
    }

    public void readIncludeCatalog(Element element_xml) {
        NodeList liste = element_xml.getChildNodes();
        for (int i = 0; i < liste.getLength(); i++) {
            Node nd = liste.item(i);
            if (nd.getNodeType() == Node.ELEMENT_NODE) {
                Element el = (Element) nd;
                String tagname = el.getTagName();
                if (tagname.equals("fragment")) {
                    String key = el.getAttribute("key");
                    //balayageBuilder.addIncludeFragment(key, el.getChildNodes());
                }
            }
        }
    }

    private void setSiteMapOption(Element element_xml) {
        SiteMapOptionBuilder siteMapOptionBuilder = new SiteMapOptionBuilder();
        siteMapOptionBuilder.setBaseUrl(element_xml.getAttribute("base-url"));
        siteMapOptionBuilder.setPath(element_xml.getAttribute("path"));
        siteMapOptionBuilder.setFileName(element_xml.getAttribute("file-name"));
        balayageBuilder.setSiteMapOption(siteMapOptionBuilder.toSiteMapOption());
    }

    private void readMetadata(Element element_xml) {
        String root = element_xml.getAttribute("root");
        if (root.length() > 0) {
            balayageBuilder.setRootName(root);
        }
        String path = element_xml.getAttribute("path");
        if (path.length() > 0) {
            balayageBuilder.setPath(path);
        }
        String param = element_xml.getAttribute("transform");
        if (param.equals("false")) {
            balayageBuilder.setWithTransformation(false);
        } else {
            balayageBuilder.setWithTransformation(true);
        }
        String postCommand = element_xml.getAttribute("post-command").trim();
        if (postCommand.length() > 0) {
            balayageBuilder.addPostscriptumExternalScript(postCommand);
        }
        String defaultLangOption = element_xml.getAttribute("default-lang-option");
        try {
            balayageBuilder.setDefaultLangOption(defaultLangOption);
        } catch (IllegalArgumentException iae) {
        }
        String langs = element_xml.getAttribute("langs");
        if (langs.length() > 0) {
            Lang[] langArray = LangsUtils.toCleanLangArray(langs);
            if (langArray.length > 0) {
                balayageBuilder.setLangContext(ListLangContextBuilder.build(langArray));
            }
        }
    }

    private void addCorpusBalayageUnit(Element element_xml) {
        BalayageUnitBuilder balayageUnitBuilder = balayageBuilder.addBalayageUnitBuilder(BalayageConstants.CORPUS_TYPE);
        commonBalayageUnit(balayageUnitBuilder, element_xml);
        balayageUnitBuilder.setFicheQuery(SelectionDOMUtils.getFicheConditionEntry(fichotheque, element_xml).getFicheQuery());
    }

    private void addFicheBalayageUnit(Element element_xml) {
        BalayageUnitBuilder balayageUnitBuilder = balayageBuilder.addBalayageUnitBuilder(BalayageConstants.FICHE_TYPE);
        commonBalayageUnit(balayageUnitBuilder, element_xml);
        balayageUnitBuilder.setFicheQuery(SelectionDOMUtils.getFicheConditionEntry(fichotheque, element_xml).getFicheQuery());
    }

    private void addThesaurusBalayageUnit(Element element_xml) {
        BalayageUnitBuilder balayageUnitBuilder = balayageBuilder.addBalayageUnitBuilder(BalayageConstants.THESAURUS_TYPE);
        commonBalayageUnit(balayageUnitBuilder, element_xml);
        balayageUnitBuilder.setMotcleQuery(SelectionDOMUtils.getMotcleConditionEntry(fichotheque, element_xml).getMotcleQuery());
    }

    private void addMotcleBalayageUnit(Element element_xml) {
        BalayageUnitBuilder balayageUnitBuilder = balayageBuilder.addBalayageUnitBuilder(BalayageConstants.MOTCLE_TYPE);
        commonBalayageUnit(balayageUnitBuilder, element_xml);
        balayageUnitBuilder.setMotcleQuery(SelectionDOMUtils.getMotcleConditionEntry(fichotheque, element_xml).getMotcleQuery());
    }

    private void addUniqueBalayageUnit(Element element_xml) {
        BalayageUnitBuilder balayageUnitBuilder = balayageBuilder.addBalayageUnitBuilder(BalayageConstants.UNIQUE_TYPE);
        commonBalayageUnit(balayageUnitBuilder, element_xml);
    }

    private void addDocumentBalayageUnit(Element element_xml) {
        BalayageUnitBuilder balayageUnitBuilder = balayageBuilder.addBalayageUnitBuilder(BalayageConstants.DOCUMENT_TYPE);
        commonBalayageUnit(balayageUnitBuilder, element_xml);
        balayageUnitBuilder.setFicheQuery(SelectionDOMUtils.getFicheConditionEntry(fichotheque, element_xml).getFicheQuery());
        balayageUnitBuilder.setDocumentQuery(SelectionDOMUtils.getDocumentConditionEntry(element_xml).getDocumentQuery());
        NodeList liste = element_xml.getChildNodes();
        for (int i = 0; i < liste.getLength(); i++) {
            Node nd = liste.item(i);
            if (nd.getNodeType() == Node.ELEMENT_NODE) {
                Element el = (Element) nd;
                String tagname = el.getTagName();
                if (tagname.equals("extension")) {
                    String extension = XMLUtils.getData(el);
                    if (extension.length() > 0) {
                        balayageUnitBuilder.addExtension(extension);
                    }
                }
            }
        }
    }

    private void addIllustrationBalayageUnit(Element element_xml) {
        BalayageUnitBuilder balayageUnitBuilder = balayageBuilder.addBalayageUnitBuilder(BalayageConstants.ILLUSTRATION_TYPE);
        commonBalayageUnit(balayageUnitBuilder, element_xml);
        balayageUnitBuilder.setIllustrationQuery(SelectionDOMUtils.getIllustrationConditionEntry(element_xml).getIllustrationQuery());
    }

    private void commonBalayageUnit(BalayageUnitBuilder balayageUnitBuilder, Element element_xml) {
        balayageUnitBuilder
                .setName(element_xml.getAttribute("name"))
                .setExtractionPath(element_xml.getAttribute("extraction"));
        String globalselect = element_xml.getAttribute("global-select");
        if (globalselect.equals("false")) {
            balayageUnitBuilder.setGlobalSelect(false);
        }
        NodeList liste = element_xml.getChildNodes();
        for (int i = 0; i < liste.getLength(); i++) {
            Node nd = liste.item(i);
            if (nd.getNodeType() == Node.ELEMENT_NODE) {
                Element el = (Element) nd;
                String tagname = el.getTagName();
                if (tagname.equals("output")) {
                    BalayageOutputBuilder outputBuilder = balayageUnitBuilder.addOutputBuilder();
                    parseOutput(el, outputBuilder);
                }
            }
        }
        String mode = element_xml.getAttribute("mode");
        String[] tokens = StringUtils.getTechnicalTokens(mode, true);
        for (String token : tokens) {
            balayageUnitBuilder.addMode(token);
        }

    }

    private void parseOutput(Element element_xml, BalayageOutputBuilder outputBuilder) {
        outputBuilder.setName(element_xml.getAttribute("name"));
        String xsltPath = element_xml.getAttribute("xslt");
        if (xsltPath.length() > 0) {
            outputBuilder.setXsltPath(xsltPath);
        }
        String mode = element_xml.getAttribute("mode");
        if (mode.length() > 0) {
            outputBuilder.setMode(mode);
        }
        String posttransform = element_xml.getAttribute("posttransform");
        if (posttransform.length() > 0) {
            outputBuilder.setPosttransform(posttransform);
        }
        boolean cleanBefore = StringUtils.isTrue(element_xml.getAttribute("clean"));
        outputBuilder.setCleanBefore(cleanBefore);
        String patternString = element_xml.getAttribute("pattern");
        if (patternString.length() > 0) {
            try {
                AccoladePattern pattern = new AccoladePattern(patternString);
                outputBuilder.setPattern(pattern);
            } catch (ParseException pe) {
                //balayageLog.addOutputWarning(balayageUnitIndex, outputIndex, "pattern", BalayageLog.WRONG_PATTERN, pattern);
            }
        }
        String langs = element_xml.getAttribute("langs");
        if (langs.length() > 0) {
            Langs langArray = LangsUtils.toCleanLangs(langs);
            /*if (!langArray.length > 0) {
                outputBuilder.setLangContext(ListLangContextBuilder.build(langArray));
            }*/
        }
        String path = normalizePath(element_xml.getAttribute("path"));
        if (path != null) {
            if (path.equals("_inc_/")) {
                outputBuilder.setIncludeOutput(true);
            } else {
                outputBuilder.setIncludeOutput(false);
                try {
                    AccoladePattern outputPathPattern = new AccoladePattern(path);
                    outputBuilder.setOutputPathPattern(outputPathPattern);
                } catch (ParseException pe) {
                    //balayageLog.addOutputWarning(balayageUnitIndex, outputIndex, "path", BalayageLog.WRONG_PATH, path);
                }
            }

        }
        String langOption = element_xml.getAttribute("lang-option");
        try {
            outputBuilder.setLangOption(langOption);
        } catch (IllegalArgumentException iae) {
        }
        NodeList liste = element_xml.getChildNodes();
        for (int i = 0; i < liste.getLength(); i++) {
            Node nd = liste.item(i);
            if (nd.getNodeType() == Node.ELEMENT_NODE) {
                Element el = (Element) nd;
                String tagname = el.getTagName();
                if (tagname.equals("param")) {
                    String name = el.getAttribute("name");
                    if (name.length() > 0) {
                        String value = el.getAttribute("value");
                        outputBuilder.addOutputParam(name, value);
                    }
                }
            }
        }
    }

    private String normalizePath(String path) {
        int length = path.length();
        if (length == 0) {
            return null;
        }
        if (path.charAt(0) == '/') {
            return normalizePath(path.substring(1));
        }
        char lastChar = path.charAt(length - 1);
        if (lastChar != '/') {
            path = path + '/';
        }
        return path;
    }

}
