/* FichothequeLib_Tools - Copyright (c) 2015-2025 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.parsers.corpus;

import java.text.ParseException;
import java.util.LinkedHashMap;
import java.util.Map;
import net.fichotheque.Fichotheque;
import net.fichotheque.FichothequeConstants;
import net.fichotheque.corpus.Corpus;
import net.fichotheque.corpus.metadata.CorpusField;
import net.fichotheque.corpus.metadata.CorpusMetadata;
import net.fichotheque.corpus.metadata.FieldKey;
import net.fichotheque.corpus.metadata.SubfieldKey;
import net.fichotheque.tools.importation.ParseResultBuilder;
import net.fichotheque.tools.importation.corpus.CorpusImportBuilder;
import net.fichotheque.tools.importation.parsers.handlers.AttributeHandler;
import net.fichotheque.tools.importation.parsers.handlers.JunctionHandlers;
import net.fichotheque.tools.importation.parsers.handlers.FicheHandler;
import net.mapeadores.util.attr.AttributeKey;


/**
 *
 * @author Vincent Calame
 */
class CorpusColumns {

    private final int idIndex;
    private final FicheHandler[] ficheHandlerArray;
    private final AttributeHandler[] attributeHandlerArray;
    private final JunctionHandlers junctionHandlers;
    private final int creationDateIndex;

    private CorpusColumns(int idIndex, FicheHandler[] ficheHandlerArray, AttributeHandler[] attributeHandlerArray, JunctionHandlers junctionHandlers, int creationDateIndex) {
        this.idIndex = idIndex;
        this.ficheHandlerArray = ficheHandlerArray;
        this.attributeHandlerArray = attributeHandlerArray;
        this.junctionHandlers = junctionHandlers;
        this.creationDateIndex = creationDateIndex;
    }

    public int getIdIndex() {
        return idIndex;
    }

    public boolean hasFicheHandler() {
        return (ficheHandlerArray != null);
    }

    public FicheHandler[] getFicheHandlerArray() {
        return ficheHandlerArray;
    }

    public boolean hasColumn(FieldKey fieldKey) {
        if (ficheHandlerArray == null) {
            return false;
        }
        for (FicheHandler ficheHandler : ficheHandlerArray) {
            if (ficheHandler.getCorpusField().getFieldKey().equals(fieldKey)) {
                return true;
            }
        }
        return false;
    }

    public boolean hasAttributeHandler() {
        return (attributeHandlerArray != null);
    }

    public AttributeHandler[] getAttributeHandlerArray() {
        return attributeHandlerArray;
    }

    public boolean hasJunctionHandler() {
        return !junctionHandlers.isEmpty();
    }

    public JunctionHandlers getJunctionHandlers() {
        return junctionHandlers;
    }

    public int getCreationDateIndex() {
        return creationDateIndex;
    }

    static CorpusColumns parse(String[] fieldArray, CorpusImportBuilder corpusImportBuilder, ParseResultBuilder parseResultBuilder) {
        Corpus corpus = corpusImportBuilder.getCorpus();
        Fichotheque fichotheque = corpus.getFichotheque();
        CorpusMetadata corpusMetadata = corpus.getCorpusMetadata();
        int idIndex = -1;
        int creationDateIndex = -1;
        int length = fieldArray.length;
        Map<Object, FicheHandler> ficheHandlerMap = new LinkedHashMap<Object, FicheHandler>();
        Map<AttributeKey, AttributeHandler> attributeHandlerMap = new LinkedHashMap<AttributeKey, AttributeHandler>();
        JunctionHandlers junctionHandlers = new JunctionHandlers(true, true);
        for (int i = 0; i < length; i++) {
            String field = fieldArray[i].trim();
            try {
                FieldKey fieldKey = FieldKey.parse(field);
                if (isIdField(fieldKey)) {
                    if (idIndex == -1) {
                        idIndex = i;
                    } else {
                        parseResultBuilder.duplicateColumn(field);
                    }
                } else {
                    addFieldKey(corpusMetadata, fieldKey, i, ficheHandlerMap, parseResultBuilder);
                }
            } catch (ParseException pe) {
                try {
                    SubfieldKey subfieldKey = SubfieldKey.parse(field);
                    addSubfieldKey(corpusMetadata, subfieldKey, i, ficheHandlerMap, parseResultBuilder);
                } catch (ParseException pe2) {
                    try {
                        AttributeKey attributeKey = AttributeKey.parse(field);
                        AttributeHandler attributeHandler = attributeHandlerMap.get(attributeKey);
                        if (attributeHandler == null) {
                            attributeHandler = new AttributeHandler(attributeKey);
                            attributeHandlerMap.put(attributeKey, attributeHandler);
                        }
                        attributeHandler.addIndex(i);
                    } catch (ParseException pe3) {
                        if (field.equals(FichothequeConstants.DATECREATION_NAME)) {
                            if (creationDateIndex != -1) {
                                parseResultBuilder.duplicateColumn(field);
                            } else {
                                creationDateIndex = i;
                            }
                            continue;
                        } else if (field.equals(FichothequeConstants.DATEMODIFICATION_NAME)) {
                            continue;
                        }
                        if (!junctionHandlers.testJunctionHandlerCandidate(fichotheque, field, i, parseResultBuilder)) {
                            parseResultBuilder.wrongColumn(field);
                        }
                    }
                }
            }
        }
        FicheHandler[] ficheHandlerArray = null;
        int ficheHandlerSize = ficheHandlerMap.size();
        if (ficheHandlerSize > 0) {
            ficheHandlerArray = ficheHandlerMap.values().toArray(new FicheHandler[ficheHandlerSize]);
        }
        AttributeHandler[] attributeHandlerArray = null;
        int attributeHandlerSize = attributeHandlerMap.size();
        if (attributeHandlerSize > 0) {
            attributeHandlerArray = attributeHandlerMap.values().toArray(new AttributeHandler[attributeHandlerSize]);
        }
        return new CorpusColumns(idIndex, ficheHandlerArray, attributeHandlerArray, junctionHandlers, creationDateIndex);
    }

    private static void addFieldKey(CorpusMetadata corpusMetadata, FieldKey fieldKey, int index, Map<Object, FicheHandler> ficheHandlerMap, ParseResultBuilder parseResultBuilder) {
        CorpusField corpusField = corpusMetadata.getCorpusField(fieldKey);
        if (corpusField == null) {
            parseResultBuilder.unknownColumn(fieldKey.getKeyString());
        } else {
            FicheHandler ficheHandler = ficheHandlerMap.get(fieldKey);
            if (ficheHandler == null) {
                ficheHandler = FicheHandler.fromCorpusField(corpusField);
                ficheHandlerMap.put(fieldKey, ficheHandler);
            }
            boolean done = ficheHandler.addIndex(index);
            if (!done) {
                parseResultBuilder.duplicateColumn(fieldKey.getKeyString());
            }
        }
    }

    private static void addSubfieldKey(CorpusMetadata corpusMetadata, SubfieldKey subfieldKey, int index, Map<Object, FicheHandler> ficheHandlerMap, ParseResultBuilder parseResultBuilder) {
        CorpusField corpusField = corpusMetadata.getCorpusField(subfieldKey.getFieldKey());
        if (corpusField == null) {
            parseResultBuilder.unknownColumn(subfieldKey.getFieldKey().getKeyString());
        } else {
            FicheHandler ficheHandler = ficheHandlerMap.get(subfieldKey);
            if (ficheHandler == null) {
                ficheHandler = FicheHandler.fromSubfield(corpusField, subfieldKey);
                ficheHandlerMap.put(subfieldKey, ficheHandler);
            }
            boolean done = ficheHandler.addIndex(index);
            if (!done) {
                parseResultBuilder.duplicateColumn(subfieldKey.getFieldKey().getKeyString());
            }
        }
    }

    private static boolean isIdField(FieldKey fieldKey) {
        switch (fieldKey.getKeyString()) {
            case FieldKey.SPECIAL_ID:
                return true;
            default:
                return false;
        }
    }


}
