/* FichothequeLib_Tools - Copyright (c) 2013-2015 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.importation;

import java.util.AbstractList;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.RandomAccess;
import java.util.Set;
import net.fichotheque.importation.LiensImport;
import net.fichotheque.include.IncludeKey;
import net.fichotheque.utils.FichothequeUtils;


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

    private final Set<IncludeKey> removedIncludeKeySet = new HashSet<IncludeKey>();
    private final Set<IncludeKey> replaceIncludeKeySet = new HashSet<IncludeKey>();
    private final List<LiensImport.LienImport> replaceList = new ArrayList<LiensImport.LienImport>();
    private final List<LiensImport.LienImport> appendList = new ArrayList<LiensImport.LienImport>();
    private int liageStatus = 0;

    public LiensImportBuilder() {

    }

    public void setLiageRemoved() {
        this.liageStatus = Math.max(this.liageStatus, 1);
    }

    public void addRemovedIncludeKey(IncludeKey includeKey) {
        if (!replaceIncludeKeySet.contains(includeKey)) {
            removedIncludeKeySet.add(includeKey);
        }
    }

    public void addReplaceLienImport(LiensImport.LienImport lienImport) {
        if (lienImport.isLiageOrigin()) {
            liageStatus = 2;
        } else {
            IncludeKey includeKey = lienImport.getOriginIncludeKey();
            removedIncludeKeySet.remove(includeKey);
            replaceIncludeKeySet.add(includeKey);
        }
        replaceList.add(lienImport);
    }

    public void addAppendLienImport(LiensImport.LienImport lienImport) {
        appendList.add(lienImport);
    }

    public void merge(LiensImportBuilder otherLiensImportBuilder) {
        for (IncludeKey otherIncludeKey : otherLiensImportBuilder.removedIncludeKeySet) {
            addRemovedIncludeKey(otherIncludeKey);
        }
        for (LiensImport.LienImport lienImport : otherLiensImportBuilder.replaceList) {
            addReplaceLienImport(lienImport);
        }
        for (LiensImport.LienImport lienImport : otherLiensImportBuilder.appendList) {
            addAppendLienImport(lienImport);
        }
        this.liageStatus = Math.max(this.liageStatus, otherLiensImportBuilder.liageStatus);
    }

    public LiensImport toLiensImport() {
        List<IncludeKey> removedIncludeKeyList = FichothequeUtils.wrap(removedIncludeKeySet.toArray(new IncludeKey[removedIncludeKeySet.size()]));
        return new InternalLiensImport((liageStatus == 1), removedIncludeKeyList, wrap(replaceList), wrap(appendList));
    }

    private static List<LiensImport.LienImport> wrap(List<LiensImport.LienImport> list) {
        return new LienImportList(list.toArray(new LiensImport.LienImport[list.size()]));
    }


    private static class InternalLiensImport implements LiensImport {

        private final boolean liageRemoved;
        private final List<IncludeKey> removedIncludeKeyList;
        private final List<LiensImport.LienImport> replaceList;
        private final List<LiensImport.LienImport> appendList;

        private InternalLiensImport(boolean liageRemoved, List<IncludeKey> removedIncludeKeyList, List<LiensImport.LienImport> replaceList, List<LiensImport.LienImport> appendList) {
            this.liageRemoved = liageRemoved;
            this.removedIncludeKeyList = removedIncludeKeyList;
            this.replaceList = replaceList;
            this.appendList = appendList;
        }

        @Override
        public boolean isLiageRemoved() {
            return liageRemoved;
        }

        @Override
        public List<IncludeKey> getRemovedIncludeKeyList() {
            return removedIncludeKeyList;
        }

        @Override
        public List<LiensImport.LienImport> getReplaceLienImportList() {
            return replaceList;
        }

        @Override
        public List<LiensImport.LienImport> getAppendLienImportList() {
            return appendList;
        }

    }


    private static class LienImportList extends AbstractList<LiensImport.LienImport> implements RandomAccess {

        private final LiensImport.LienImport[] array;

        private LienImportList(LiensImport.LienImport[] array) {
            this.array = array;
        }

        @Override
        public int size() {
            return array.length;
        }

        @Override
        public LiensImport.LienImport get(int index) {
            return array[index];
        }

    }

}
