/* FichothequeLib_Tools - Copyright (c) 2010-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.extraction;

import java.text.ParseException;
import net.fichotheque.corpus.metadata.FieldKey;
import net.fichotheque.extraction.ExtractionConstants;
import net.fichotheque.extraction.def.GroupParams;
import net.fichotheque.extraction.run.FicheItemGroupParams;
import net.fichotheque.extraction.run.FieldsGroupParams;
import net.mapeadores.util.instruction.Argument;
import net.mapeadores.util.instruction.Instruction;
import net.mapeadores.util.instruction.InstructionParser;
import net.mapeadores.util.text.StringUtils;


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

    private final static String ALPHABET_MODE = "alphabet";
    private final static String MODE_KEY = "mode";
    private final static String FIELDS_KEY = "fields";
    private final static String FIELD_KEY = "field";

    public static GroupParams parse(String groupType, String paramsString) {
        Instruction instruction = InstructionParser.parse(paramsString, null);
        if (instruction == null) {
            return null;
        }
        switch (groupType) {
            case ExtractionConstants.WEIGHT_TYPE:
            case ExtractionConstants.POSITION_TYPE:
                return null;
            case ExtractionConstants.TITLE_TYPE:
                return parseTitreGroupParams(instruction);
            case ExtractionConstants.YEAR_TYPE:
            case ExtractionConstants.LANG_TYPE:
            case ExtractionConstants.COUNTRY_TYPE:
                return parseFicheItemGroupParams(instruction);
            case ExtractionConstants.FIELDS_TYPE:
                return parseFieldsGroupParams(instruction);
            default:
                return null;
        }
    }

    public static FieldsGroupParams parseFieldsGroupParams(Instruction instruction) {
        return internalParseFieldsGroupParams(instruction, true);
    }

    public static FieldsGroupParams parseTitreGroupParams(Instruction instruction) {
        return internalParseFieldsGroupParams(instruction, false);
    }

    public static FicheItemGroupParams parseFicheItemGroupParams(Instruction instruction) {
        FieldKey fieldKey = null;
        for (Argument argument : instruction) {
            String key = argument.getKey();
            String value = argument.getValue();
            if (key.equals(FIELD_KEY)) {
                if (value != null) {
                    try {
                        fieldKey = FieldKey.parse(value);
                    } catch (java.text.ParseException pe) {
                    }
                }
            } else if (value == null) {
                try {
                    fieldKey = FieldKey.parse(key);
                } catch (java.text.ParseException pe) {
                }
            }
        }
        if (fieldKey == null) {
            return null;
        }
        if (!isValidFicheItemField(fieldKey)) {
            return null;
        }
        return new InternalFicheItemGroupParams(fieldKey);
    }

    private static boolean isValidFicheItemField(FieldKey fieldKey) {
        switch (fieldKey.getCategory()) {
            case FieldKey.PROP_CATEGORY:
            case FieldKey.INFO_CATEGORY:
                return true;
            case FieldKey.SPECIAL_CATEGORY:
                switch (fieldKey.getKeyString()) {
                    case FieldKey.SPECIAL_LANG:
                        return true;
                    default:
                        return false;
                }
            default:
                return false;
        }
    }

    private static FieldsGroupParams internalParseFieldsGroupParams(Instruction instruction, boolean testFields) {
        short mode = FieldsGroupParams.DEFAULT_MODE;
        FieldKey[] fieldKeyArray = null;
        for (Argument argument : instruction) {
            String key = argument.getKey();
            String value = argument.getValue();
            if (key.equals(ALPHABET_MODE)) {
                mode = FieldsGroupParams.ALPHABET_MODE;
            } else if (key.equals(MODE_KEY)) {
                if (value != null) {
                    if (value.equals(ALPHABET_MODE)) {
                        mode = FieldsGroupParams.ALPHABET_MODE;
                    } else {
                        mode = FieldsGroupParams.DEFAULT_MODE;
                    }
                }
            } else if (key.equals(FIELDS_KEY)) {
                if ((testFields) && (value != null)) {
                    fieldKeyArray = parseFieldArray(value);
                }
            }
        }
        if (!testFields) {
            fieldKeyArray = new FieldKey[1];
            fieldKeyArray[0] = FieldKey.TITLE;
        }
        if (fieldKeyArray == null) {
            return null;
        }
        return new InternalFieldsGroupParams(mode, fieldKeyArray);
    }

    private static FieldKey[] parseFieldArray(String s) {
        String[] tokenArray = StringUtils.getTechnicalTokens(s, true);
        int length = tokenArray.length;
        if (length == 0) {
            return null;
        }
        FieldKey[] fieldArray = new FieldKey[length];
        for (int i = 0; i < length; i++) {
            try {
                FieldKey fieldKey = FieldKey.parse(tokenArray[i]);
                if (testFieldKey(fieldKey)) {
                    fieldArray[i] = fieldKey;
                } else {
                    return null;
                }
            } catch (ParseException pe) {
                return null;
            }
        }
        return fieldArray;
    }

    private static boolean testFieldKey(FieldKey fieldKey) {
        switch (fieldKey.getCategory()) {
            case FieldKey.PROP_CATEGORY:
            case FieldKey.INFO_CATEGORY:
                return true;
            case FieldKey.SPECIAL_CATEGORY:
                switch (fieldKey.getKeyString()) {
                    case FieldKey.SPECIAL_TITLE:
                    case FieldKey.SPECIAL_SUBTITLE:
                        return true;
                }
            default:
                return false;
        }
    }


    private static class InternalFieldsGroupParams implements FieldsGroupParams {

        private final short mode;
        private final FieldKey[] fieldKeyArray;

        InternalFieldsGroupParams(short mode, FieldKey[] fieldKeyArray) {
            this.mode = mode;
            this.fieldKeyArray = fieldKeyArray;
        }

        @Override
        public short getMode() {
            return mode;
        }

        @Override
        public FieldKey[] getFieldKeyArray() {
            return fieldKeyArray;
        }

        @Override
        public String toString() {
            StringBuilder buf = new StringBuilder();
            buf.append(FIELDS_KEY);
            buf.append('=');
            int length = fieldKeyArray.length;
            for (int i = 0; i < length; i++) {
                if (i > 0) {
                    buf.append(" ");
                }
                buf.append(fieldKeyArray[i].getKeyString());
            }
            if (mode != DEFAULT_MODE) {
                buf.append(',');
                buf.append(MODE_KEY);
                buf.append('=');
                buf.append(ALPHABET_MODE);
            }
            return buf.toString();
        }

    }


    private static class InternalFicheItemGroupParams implements FicheItemGroupParams {

        private final FieldKey fieldKey;

        InternalFicheItemGroupParams(FieldKey fieldKey) {
            this.fieldKey = fieldKey;
        }

        @Override
        public FieldKey getFieldKey() {
            return fieldKey;
        }

        @Override
        public String toString() {
            return FIELD_KEY + "=" + fieldKey.getKeyString();
        }

    }

}
