/* FichothequeLib_API - Copyright (c) 2011-2023 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.utils;

import java.io.IOException;
import java.util.List;
import net.fichotheque.corpus.metadata.FieldKey;
import net.fichotheque.format.FichothequeFormatConstants;
import net.fichotheque.format.FichothequeFormatDef;
import net.fichotheque.format.FormatSourceKey;
import net.mapeadores.util.format.FormatConstants;
import net.mapeadores.util.format.FormatDef;
import net.mapeadores.util.format.FormatUtils;
import net.mapeadores.util.instruction.InstructionUtils;


/**
 *
 * @author Vincent Calame
 */
public final class FichothequeFormatUtils {

    private FichothequeFormatUtils() {
    }

    public static FieldKey toFieldKey(Object value) {
        if (value == null) {
            return null;
        }
        try {
            return (FieldKey) value;
        } catch (ClassCastException cce) {
            return null;
        }
    }

    public static String toLines(FichothequeFormatDef formatDef) {
        StringBuilder buf = new StringBuilder();
        try {
            appendLines(formatDef, buf);
        } catch (IOException ioe) {
        }
        return buf.toString();
    }

    public static void appendLines(FichothequeFormatDef formatDef, Appendable appendable) throws IOException {
        String[] array = FichothequeFormatUtils.toStringArray(formatDef);
        appendable.append(array[0]);
        appendable.append('\n');
        String format = array[1];
        String param = array[2];
        if (format == null) {
            if (param != null) {
                appendable.append("-\n");
            }
        } else {
            appendable.append(format);
            appendable.append('\n');
        }
        if (param != null) {
            appendable.append(param);
            appendable.append('\n');
        }
    }

    public static String[] toStringArray(FichothequeFormatDef formatDef) {
        StringBuilder buf = new StringBuilder();
        for (FormatSourceKey formatSourceKey : formatDef.getFormatSourceKeyList()) {
            if (buf.length() > 0) {
                buf.append(',');
            }
            buf.append(formatSourceKey);
        }
        String[] result = new String[3];
        result[0] = buf.toString();
        result[1] = formatPatternListToString(formatDef);
        result[2] = paramToString(formatDef);
        return result;
    }

    public static String getFormatPatternBySourceIndex(FichothequeFormatDef formatDef, int sourceIndex) {
        List<FormatDef.Pattern> patternList = formatDef.getPatternList();
        int size = patternList.size();
        if (size == 0) {
            return null;
        }
        if (sourceIndex >= size) {
            sourceIndex = size - 1;
        }
        return getFormatPattern(patternList, sourceIndex);
    }

    private static String getFormatPattern(List<FormatDef.Pattern> patternList, int i) {
        FormatDef.Pattern formatPattern = patternList.get(i);
        if (!formatPattern.isDefault()) {
            return formatPattern.getPattern();
        }
        if (i == 0) {
            return null;
        }
        return getFormatPattern(patternList, i - 1);
    }

    public static String formatPatternListToString(FichothequeFormatDef formatDef) {
        List<FormatDef.Pattern> patternList = formatDef.getPatternList();
        if (patternList.isEmpty()) {
            return null;
        }
        StringBuilder buf = new StringBuilder();
        for (FormatDef.Pattern pattern : patternList) {
            if (buf.length() > 0) {
                buf.append("||");
            }
            if (pattern.isDefault()) {
                buf.append(' ');
            } else {
                buf.append(pattern.getPattern());
            }
        }
        return buf.toString();
    }

    public static String paramToString(FichothequeFormatDef formatDef) {
        ParamStringBuilder stringBuilder = new ParamStringBuilder(formatDef);
        String result = stringBuilder.toString();
        if (result.length() == 0) {
            return null;
        }
        return result;
    }

    public static boolean isSame(FichothequeFormatDef formatDef1, FichothequeFormatDef formatDef2) {
        String stg1 = toLines(formatDef1);
        String stg2 = toLines(formatDef2);
        return stg1.equals(stg2);
    }


    private static class ParamStringBuilder {

        StringBuilder buf;
        boolean suite = false;
        FichothequeFormatDef formatDef;

        ParamStringBuilder(FichothequeFormatDef formatDef) {
            this.formatDef = formatDef;
            buf = new StringBuilder();
            initSum();
            initInstructionString(FormatConstants.POSTTRANSFORM_PARAMKEY);
            initInstructionString(FormatConstants.PREFIX_PARAMKEY);
            initInstructionString(FormatConstants.SUFFIX_PARAMKEY);
            initCast();
            initBoolean(FormatConstants.JSONARRAY_PARAMKEY);
            initInteger(FormatConstants.MAXLENGTH_PARAMKEY);
            initInteger(FormatConstants.FIXEDLENGTH_PARAMKEY);
            initFixedChar();
            initBoolean(FormatConstants.FIXEDEMPTY_PARAMKEY);
            initPosition();
            initInteger(FormatConstants.LIMIT_PARAMKEY);
            initBoolean(FormatConstants.UNIQUETEST_PARAMKEY);
            initInstructionString(FormatConstants.SEPARATOR_PARAMKEY);
            initInstructionString(FormatConstants.DEFAULTVALUE_PARAMKEY);
            initBoolean(FormatConstants.EMPTYTONULL_PARAMKEY);
            initGlobalSelect();
            initBoolean(FormatConstants.COLUMNSUM_PARAMKEY);
            initFormula();
            for (FormatDef.InnerSeparator innerSeparator : formatDef.getInnerSeparatorList()) {
                testSuite();
                buf.append(FormatConstants.SEPARATOR_PARAMKEY);
                buf.append(innerSeparator.getSourceIndex() + 1);
                buf.append('=');
                appendInstructionString(innerSeparator.getSeparator());
            }
            for (FormatDef.SourceSeparator sourceSeparator : formatDef.getSourceSeparatorList()) {
                testSuite();
                buf.append(FormatConstants.SEPARATOR_PARAMKEY);
                buf.append(sourceSeparator.getSourceIndex1() + 1);
                buf.append('_');
                buf.append(sourceSeparator.getSourceIndex2() + 1);
                buf.append('=');
                appendInstructionString(sourceSeparator.getSeparator());
            }
            Object fieldKeyValue = formatDef.getParameterValue(FichothequeFormatConstants.DEFAULTPROP_PARAMKEY);
            if (fieldKeyValue != null) {
                testSuite();
                buf.append(FichothequeFormatConstants.DEFAULTPROP_PARAMKEY);
                buf.append('=');
                buf.append(((FieldKey) fieldKeyValue).getKeyString());
            }
            initBoolean(FichothequeFormatConstants.NOITEM_PARAMKEY);
            initBoolean(FichothequeFormatConstants.ONLYITEM_PARAMKEY);
            initBoolean(FichothequeFormatConstants.IDSORT_PARAMKEY);
        }

        @Override
        public String toString() {
            return buf.toString();
        }

        private void initBoolean(String name) {
            if (FormatUtils.getBoolean(formatDef, name)) {
                testSuite();
                buf.append(name);
            }
        }

        private void initInstructionString(String name) {
            Object value = formatDef.getParameterValue(name);
            if (value != null) {
                testSuite();
                buf.append(name);
                buf.append('=');
                appendInstructionString((String) value);
            }
        }

        private void initInteger(String name) {
            Object value = formatDef.getParameterValue(name);
            if (value != null) {
                testSuite();
                buf.append(name);
                buf.append('=');
                buf.append(((Integer) value).toString());
            }
        }

        private void initCast() {
            Object value = formatDef.getParameterValue(FormatConstants.CAST_PARAMKEY);
            if (value != null) {
                String cast = ((String) value);
                if (!cast.isEmpty()) {
                    testSuite();
                    buf.append(FormatConstants.CAST_PARAMKEY);
                    buf.append('=');
                    buf.append(cast);
                }
            }
        }

        private void initFixedChar() {
            Object value = formatDef.getParameterValue(FormatConstants.FIXEDCHAR_PARAMKEY);
            if (value != null) {
                testSuite();
                buf.append(FormatConstants.FIXEDCHAR_PARAMKEY);
                buf.append('=');
                buf.append(((Character) value));
            }
        }

        private void initSum() {
            Object value = formatDef.getParameterValue(FormatConstants.SUM_PARAMKEY);
            if (value != null) {
                testSuite();
                buf.append(FormatConstants.SUM_PARAMKEY);
                String sumCast = ((String) value);
                if (!sumCast.isEmpty()) {
                    buf.append('=');
                    buf.append(sumCast);
                }
            }
        }

        private void initFormula() {
            Object value = formatDef.getParameterValue(FormatConstants.FORMULA_PARAMKEY);
            if (value != null) {
                testSuite();
                buf.append(FormatConstants.FORMULA_PARAMKEY);
                String formulaCast = ((String) value);
                if (!formulaCast.isEmpty()) {
                    buf.append('=');
                    buf.append(formulaCast);
                }
            }
        }

        private void initPosition() {
            Object value = formatDef.getParameterValue(FormatConstants.POSITION_PARAMKEY);
            if (value != null) {
                testSuite();
                int position = ((Integer) value);
                buf.append(FormatConstants.POSITION_PARAMKEY);
                buf.append('=');
                if (position == FormatConstants.MAX_POSITION) {
                    buf.append(FormatConstants.LAST_PARAMVALUE);
                } else {
                    buf.append(position + 1);
                }
            }
        }

        private void initGlobalSelect() {
            Object value = formatDef.getParameterValue(FormatConstants.GLOBALSELECT_PARAMKEY);
            if (value != null) {
                testSuite();
                buf.append(FormatConstants.GLOBALSELECT_PARAMKEY);
                if (!((Boolean) value)) {
                    buf.append("=0");
                }
            }
        }

        private void appendInstructionString(String s) {
            try {
                InstructionUtils.appendInstructionString(s, buf);
            } catch (IOException ioe) {

            }
        }

        private void testSuite() {
            if (suite) {
                buf.append(',');
            } else {
                suite = true;
            }
        }

    }

}
