/* FichothequeLib_API - Copyright (c) 2026 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.HashSet;
import java.util.Set;
import net.fichotheque.FichothequeConstants;
import net.fichotheque.corpus.metadata.FieldKey;
import net.fichotheque.format.FichothequeFormatConstants;
import net.fichotheque.format.FichothequeFormatDef;
import net.fichotheque.namespaces.FormatSpace;
import net.fichotheque.namespaces.TableSpace;
import net.mapeadores.util.attr.Attribute;
import net.mapeadores.util.attr.AttributeKey;
import net.mapeadores.util.date.DateConstants;
import net.mapeadores.util.format.FormatConstants;
import net.mapeadores.util.format.FormatDef;
import net.mapeadores.util.instruction.InstructionUtils;


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

    private final FichothequeFormatDef formatDef;
    private final StringBuilder buf = new StringBuilder();
    private final Set<AttributeKey> doneSet = new HashSet<AttributeKey>();
    private boolean suite = false;


    private ParamLineConverter(FichothequeFormatDef formatDef) {
        this.formatDef = formatDef;
    }

    private void convert() {
        addWithCastShortcut(FormatSpace.SUM_KEY, "sum");
        initInstructionString(FormatConstants.POSTTRANSFORM_PARAMKEY);
        initInstructionString(FormatConstants.PREFIX_PARAMKEY);
        initInstructionString(FormatConstants.SUFFIX_PARAMKEY);
        initCast();
        addDateStyle();
        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);
        addWithTrueShortcut(FormatSpace.EMPTYTONULL_KEY, "null");
        initGlobalSelect();
        addWithTrueShortcut(TableSpace.COLUMNSUM_KEY, "columnsum");
        addWithCastShortcut(TableSpace.FORMULA_KEY, "formula");
        addWithShortcut(FormatSpace.CALCULATION_KEY, "calc");
        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);
        addWithWidthShortcut(TableSpace.COLUMNSTYLE_KEY, "width");
        for (Attribute attribute : formatDef.getAttributes()) {
            if (!doneSet.contains(attribute.getAttributeKey())) {
                addAttribute(attribute);
            }
        }
    }

    private void initBoolean(String name) {
        if (formatDef.getBoolean(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 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 addAttribute(Attribute attribute) {
        testSuite();
        buf.append(attribute.getAttributeKey().toString());
        buf.append('=');
        buf.append(getAttributeValuesString(attribute));
    }

    private void addDateStyle() {
        Attribute attribute = formatDef.getAttributes().getAttribute(FormatSpace.DATESTYLE_KEY);
        if (attribute == null) {
            return;
        }
        boolean done = false;
        if (attribute.size() == 1) {
            try {
                String value = DateConstants.checkDateStyle(attribute.getFirstValue());
                testSuite();
                buf.append("datestyle");
                buf.append('=');
                buf.append(value);
                done = true;
            } catch (IllegalArgumentException iae) {

            }
        }
        if (!done) {
            addAttribute(attribute);
        }
        doneSet.add(FormatSpace.DATESTYLE_KEY);
    }

    private void addWithShortcut(AttributeKey attributeKey, String shortcut) {
        Attribute attribute = formatDef.getAttributes().getAttribute(attributeKey);
        if (attribute == null) {
            return;
        }
        if (attribute.size() == 1) {
            testSuite();
            buf.append(shortcut);
            buf.append('=');
            buf.append(attribute.getFirstValue());
        } else {
            addAttribute(attribute);
        }
        doneSet.add(attributeKey);
    }

    private void addWithTrueShortcut(AttributeKey attributeKey, String trueShortcut) {
        Attribute attribute = formatDef.getAttributes().getAttribute(attributeKey);
        if (attribute == null) {
            return;
        }
        if ((attribute.size() == 1) && (attribute.isTrue())) {
            testSuite();
            buf.append(trueShortcut);
        } else {
            addAttribute(attribute);
        }
        doneSet.add(attributeKey);
    }

    private void addWithCastShortcut(AttributeKey attributeKey, String castShortcut) {
        Attribute attribute = formatDef.getAttributes().getAttribute(attributeKey);
        if (attribute == null) {
            return;
        }
        boolean done = false;
        if (attribute.size() == 1) {
            if (attribute.isTrue()) {
                testSuite();
                buf.append(castShortcut);
                done = true;
            } else {
                String castValue = attribute.getFirstValue();
                try {
                    castValue = FormatConstants.checkCastType(castValue);
                    testSuite();
                    buf.append(castShortcut);
                    buf.append('=');
                    buf.append(castValue);
                    done = true;
                } catch (IllegalArgumentException iae) {

                }
            }
        }
        if (!done) {
            addAttribute(attribute);
        }
        doneSet.add(attributeKey);
    }

    private void addWithWidthShortcut(AttributeKey attributeKey, String widthShortcut) {
        Attribute attribute = formatDef.getAttributes().getAttribute(attributeKey);
        if (attribute == null) {
            return;
        }
        boolean done = false;
        if (attribute.size() == 1) {
            String widthValue = attribute.getFirstValue();
            try {
                widthValue = FichothequeConstants.checkWidth(widthValue);
                testSuite();
                buf.append(widthShortcut);
                buf.append('=');
                buf.append(widthValue);
                done = true;
            } catch (IllegalArgumentException iae) {

            }
        }
        if (!done) {
            addAttribute(attribute);
        }
        doneSet.add(attributeKey);
    }

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

    private String getAttributeValuesString(Attribute attribute) {
        int valueLength = attribute.size();
        if (valueLength == 1) {
            String firstValue = attribute.getFirstValue();
            if (!mustBeQuoted(firstValue)) {
                return firstValue;
            }
        }
        StringBuilder buf2 = new StringBuilder();
        buf2.append('"');
        for (int j = 0; j < valueLength; j++) {
            if (j > 0) {
                buf2.append(';');
            }
            String value = attribute.get(j);
            int length = value.length();
            for (int k = 0; k < length; k++) {
                char carac = value.charAt(k);
                switch (carac) {
                    case '\\':
                    case '"':
                    case ';':
                        buf2.append('\\');
                }
                buf2.append(carac);
            }
        }
        buf2.append('"');
        return buf2.toString();
    }

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

        }
    }

    public static String convert(FichothequeFormatDef formatDef) {
        ParamLineConverter converter = new ParamLineConverter(formatDef);
        converter.convert();
        return converter.buf.toString();
    }

    private static boolean mustBeQuoted(String value) {
        int length = value.length();
        for (int k = 0; k < length; k++) {
            switch (value.charAt(k)) {
                case '\\':
                case '"':
                case ';':
                    return true;
            }
        }
        return false;
    }

}
