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

import java.text.ParseException;
import net.fichotheque.corpus.Corpus;
import net.fichotheque.corpus.FicheChange;
import net.fichotheque.corpus.FicheMeta;
import net.fichotheque.corpus.fiche.Fiche;
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.corpus.FicheChangeBuilder;
import net.fichotheque.utils.CorpusUtils;
import net.mapeadores.util.request.RequestMap;


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

    public final static short NONE_TYPE = 0;
    public final static short REPLACE_TYPE = 1;
    public final static short UPDATE_TYPE = 2;

    private FicheParseEngine() {
    }

    public static Fiche run(FicheParser.Parameters ficheParserParameters, FicheMeta ficheMeta, RequestMap requestMap, short type) {
        Corpus corpus = ficheMeta.getCorpus();
        CorpusMetadata corpusMetadata = corpus.getCorpusMetadata();
        FicheChangeBuilder ficheChangeBuilder = new FicheChangeBuilder();
        FicheParser ficheParser = new FicheParser(ficheParserParameters, corpus, ficheChangeBuilder);
        for (String paramName : requestMap.getParameterNameSet()) {
            boolean subfieldDone = parseSubfield(corpusMetadata, ficheParser, paramName, requestMap);
            if (!subfieldDone) {
                parseCorpusField(ficheParserParameters, corpusMetadata, ficheParser, paramName, requestMap);
            }
        }
        ficheParser.flushParsedSubfields();
        FicheChange ficheChange = ficheChangeBuilder.toFicheChange();
        if (type == REPLACE_TYPE) {
            return CorpusUtils.toFiche(ficheChange);
        } else {
            Fiche originalFiche = ficheMeta.getCorpus().getFiche(ficheMeta);
            CorpusUtils.updateFiche(originalFiche, ficheChange);
            return originalFiche;
        }
    }

    private static boolean parseCorpusField(FicheParser.Parameters ficheParseParameters, CorpusMetadata corpusMetadata, FicheParser ficheParser, String paramName, RequestMap requestMap) {
        try {
            FieldKey fieldKey = FieldKey.parse(paramName);
            CorpusField corpusField = corpusMetadata.getCorpusField(fieldKey);
            if (corpusField != null) {
                String value = concatParameterValues(ficheParseParameters, corpusField, paramName, requestMap);
                ficheParser.parseCorpusField(corpusField, value);
            }
            return true;
        } catch (ParseException pe) {
            return false;
        }
    }

    private static boolean parseSubfield(CorpusMetadata corpusMetadata, FicheParser ficheParser, String paramName, RequestMap requestMap) {
        try {
            SubfieldKey subfieldKey = SubfieldKey.parse(paramName);
            FieldKey fieldKey = subfieldKey.getFieldKey();
            CorpusField corpusField = corpusMetadata.getCorpusField(fieldKey);
            if (corpusField != null) {
                String value = requestMap.getParameter(paramName);
                ficheParser.parseSubfield(corpusField, subfieldKey, value);
            }
            return true;
        } catch (ParseException pe) {
            return false;
        }
    }

    private static String concatParameterValues(FicheParser.Parameters ficheParseParameters, CorpusField corpusField, String paramName, RequestMap requestMap) {
        char delimiter = getDelimiter(ficheParseParameters, corpusField);
        String[] paramValues = requestMap.getParameterValues(paramName);
        int length = paramValues.length;
        if (length == 1) {
            return paramValues[0];
        }
        StringBuilder buf = new StringBuilder();
        buf.append(paramValues[0]);
        for (int i = 1; i < length; i++) {
            if (delimiter != 0) {
                buf.append(delimiter);
            }
            buf.append(paramValues[i]);
        }
        return buf.toString();
    }

    private static char getDelimiter(FicheParser.Parameters ficheParseParameters, CorpusField corpusField) {
        switch (corpusField.getCategory()) {
            case FieldKey.INFO_CATEGORY:
                return ficheParseParameters.getItemListSeparateur();
            case FieldKey.SECTION_CATEGORY:
                return '\n';
            case FieldKey.SPECIAL_CATEGORY:
                switch (corpusField.getFieldString()) {
                    case FieldKey.SPECIAL_OWNERS:
                        return ficheParseParameters.getItemListSeparateur();
                }
            default:
                return 0;
        }
    }

}
