/* FichothequeLib_Tools - Copyright (c) 2019-2024 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 net.fichotheque.tools.exportation.balayage;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
import net.fichotheque.exportation.balayage.BalayageContentDescription;
import net.fichotheque.exportation.balayage.BalayageDef;
import net.fichotheque.exportation.balayage.BalayageDescription;
import net.fichotheque.utils.BalayageUtils;
import net.mapeadores.util.xml.DocumentFragmentHolder;
import net.mapeadores.util.xml.XMLUtils;


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

    private final BalayageDef balayageDef;
    private final SortedMap<String, BalayageContentDescription> mainMap = new TreeMap<String, BalayageContentDescription>();
    private final Map<String, SubdirBuilder> subdirBuilderMap = new HashMap<String, SubdirBuilder>();
    private DocumentFragmentHolder includeCatalog = XMLUtils.EMPTY_DOCUMENTFRAGMENTHOLDER;


    public BalayageDescriptionBuilder(BalayageDef balayageDef) {
        this.balayageDef = balayageDef;
    }

    public BalayageDescriptionBuilder addBalayageContentDescription(BalayageContentDescription balayageContentDescription) {
        String path = balayageContentDescription.getPath();
        mainMap.put(path, balayageContentDescription);
        int idx = path.indexOf("/");
        String subdir;
        if (idx == -1) {
            subdir = "";
        } else {
            subdir = path.substring(0, idx);
        }
        SubdirBuilder builder = subdirBuilderMap.get(subdir);
        if (builder == null) {
            builder = new SubdirBuilder(subdir);
            subdirBuilderMap.put(subdir, builder);
        }
        builder.add(balayageContentDescription);
        return this;
    }

    public BalayageDescriptionBuilder setIncludeCatalog(DocumentFragmentHolder includeCatalog) {
        if (includeCatalog == null) {
            includeCatalog = XMLUtils.EMPTY_DOCUMENTFRAGMENTHOLDER;
        }
        this.includeCatalog = includeCatalog;
        return this;
    }


    public BalayageDescription toBalayageDescription() {
        Map<String, Subdir> subdirMap = new HashMap<String, Subdir>();
        for (Map.Entry<String, SubdirBuilder> entry : subdirBuilderMap.entrySet()) {
            subdirMap.put(entry.getKey(), entry.getValue().toSubdir());
        }
        BalayageContentDescription[] finalArray = mainMap.values().toArray(new BalayageContentDescription[mainMap.size()]);
        List<BalayageContentDescription> finalList = BalayageUtils.wrap(finalArray);
        String state = BalayageDescription.OK_STATE;
        for (BalayageContentDescription balayageContentDescription : finalArray) {
            if (balayageContentDescription.getState() != BalayageContentDescription.OK_STATE) {
                state = BalayageDescription.CONTAINS_ERRORS_STATE;
                break;
            }
        }
        return new InternalBalayageDescription(balayageDef, finalList, subdirMap, state, includeCatalog);
    }

    public static BalayageDescriptionBuilder init(BalayageDef balayageDef) {
        return new BalayageDescriptionBuilder(balayageDef);
    }


    private static class InternalBalayageDescription implements BalayageDescription {

        private final BalayageDef balayageDef;
        private final List<BalayageContentDescription> contentDescriptionList;
        private final Map<String, Subdir> subdirMap;
        private final String state;
        private final DocumentFragmentHolder includeCatalog;


        private InternalBalayageDescription(BalayageDef balayageDef, List<BalayageContentDescription> contentDescriptionList, Map<String, Subdir> subdirMap, String state, DocumentFragmentHolder includeCatalog) {
            this.balayageDef = balayageDef;
            this.contentDescriptionList = contentDescriptionList;
            this.subdirMap = subdirMap;
            this.state = state;
            this.includeCatalog = includeCatalog;
        }

        @Override
        public BalayageDef getBalayageDef() {
            return balayageDef;
        }

        @Override
        public String getState() {
            return state;
        }

        @Override
        public List<BalayageContentDescription> getBalayageContentDescriptionList() {
            return contentDescriptionList;
        }

        @Override
        public List<BalayageContentDescription> getBalayageContentDescriptionList(String subdirName) {
            Subdir subdir = subdirMap.get(subdirName);
            if (subdir != null) {
                return subdir.getList();
            } else {
                return BalayageUtils.EMPTY_BALAYAGECONTENTDESCRIPTIONLIST;
            }
        }

        @Override
        public DocumentFragmentHolder getIncludeCatalog() {
            return includeCatalog;
        }

    }


    private static class SubdirBuilder {

        private final SortedMap<String, BalayageContentDescription> map = new TreeMap<String, BalayageContentDescription>();
        private final String name;

        private SubdirBuilder(String name) {
            this.name = name;
        }

        private void add(BalayageContentDescription balayageContentDescription) {
            map.put(balayageContentDescription.getPath(), balayageContentDescription);
        }

        private Subdir toSubdir() {
            List<BalayageContentDescription> list = BalayageUtils.wrap(map.values().toArray(new BalayageContentDescription[map.size()]));
            return new Subdir(list);
        }

    }


    private static class Subdir {

        private final List<BalayageContentDescription> list;

        private Subdir(List<BalayageContentDescription> list) {
            this.list = list;
        }

        private List<BalayageContentDescription> getList() {
            return list;
        }

    }


}
