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

import java.util.AbstractList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.RandomAccess;
import net.fichotheque.importation.ParseResult;
import net.mapeadores.util.localisation.Message;
import net.mapeadores.util.logging.LineLogs;
import net.mapeadores.util.logging.LineLogsBuilder;
import net.mapeadores.util.logging.LineMessageHandler;
import net.mapeadores.util.logging.SourceLog;
import net.mapeadores.util.logging.SourceLogBuilder;


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

    private final String type;
    private final SourceLogBuilder columnLogBuilder = new SourceLogBuilder("init");
    private final LineLogsBuilder lineLogsBuilder = new LineLogsBuilder();
    private final Map<String, ParseResult.ResultItem> resultItemMap = new LinkedHashMap<String, ParseResult.ResultItem>();
    private String path = "";

    public ParseResultBuilder(String type) {
        this.type = type;
    }

    public LineMessageHandler getLineMessageHandler() {
        return lineLogsBuilder;
    }

    public ParseResultBuilder missingColumn(String columnName) {
        columnLogBuilder.addMessage(ParseResult.SEVERE_COLUMN, "_ error.empty.tableimport.column", columnName);
        return this;
    }

    public ParseResultBuilder missingColumns(String columnName1, String columnName2) {
        columnLogBuilder.addMessage(ParseResult.SEVERE_COLUMN, "_ error.empty.tableimport.columns", columnName1, columnName2);
        return this;
    }

    public ParseResultBuilder duplicateColumn(String columnName) {
        columnLogBuilder.addMessage(ParseResult.WARNING_COLUMN, "_ error.unsupported.tableimport.duplicatecolumn", columnName);
        return this;
    }

    public ParseResultBuilder unknownColumn(String columnName) {
        columnLogBuilder.addMessage(ParseResult.WARNING_COLUMN, "_ error.unknown.tableimport.column", columnName);
        return this;
    }

    public ParseResultBuilder unknownSubset(String subsetName) {
        columnLogBuilder.addMessage(ParseResult.WARNING_COLUMN, "_ error.unknown.subset", subsetName);
        return this;
    }

    public ParseResultBuilder wrongColumn(String columnName) {
        columnLogBuilder.addMessage(ParseResult.WARNING_COLUMN, "_ error.wrong.tableimport.column", columnName);
        return this;
    }

    public ParseResultBuilder notUsableIdalpha(String columnName) {
        columnLogBuilder.addMessage(ParseResult.WARNING_COLUMN, "_ error.unsupported.tableimport.notusableidalpha", columnName);
        return this;
    }

    public ParseResultBuilder notAvailableColumn(String columnName) {
        columnLogBuilder.addMessage(ParseResult.WARNING_COLUMN, "_ error.unsupported.tableimport.notavailablecolumn", columnName);
        return this;
    }

    public ParseResultBuilder addParseErrorMessage(int lineNumber, Message message) {
        lineLogsBuilder.addMessage(ParseResult.SEVERE_PARSE, lineNumber, message);
        return this;
    }

    public ParseResultBuilder missingIdColumn(int lineNumber) {
        lineLogsBuilder.addMessage(ParseResult.SEVERE_PARSE, lineNumber, "_ error.empty.tableimport.missingidcolumn");
        return this;
    }

    public ParseResultBuilder unknownId(int lineNumber, String idstring) {
        lineLogsBuilder.addMessage(ParseResult.SEVERE_FICHOTHEQUE, lineNumber, "_ error.unknown.id", idstring);
        return this;
    }

    public ParseResultBuilder unknownIdalpha(int lineNumber, String idalpha) {
        lineLogsBuilder.addMessage(ParseResult.SEVERE_FICHOTHEQUE, lineNumber, "_ error.unknown.idalpha", idalpha);
        return this;
    }

    public ParseResultBuilder notIntegerId(int lineNumber, String idstring) {
        lineLogsBuilder.addMessage(ParseResult.SEVERE_PARSE, lineNumber, "_ error.wrong.tableimport.notintegerid", idstring);
        return this;
    }

    public ParseResultBuilder existingId(int lineNumber, String idstring) {
        lineLogsBuilder.addMessage(ParseResult.SEVERE_FICHOTHEQUE, lineNumber, "_ error.existing.id", idstring);
        return this;
    }

    public ParseResultBuilder existingIdalpha(int lineNumber, String idalpha) {
        lineLogsBuilder.addMessage(ParseResult.SEVERE_FICHOTHEQUE, lineNumber, "_ error.existing.idalpha", idalpha);
        return this;
    }

    public ParseResultBuilder selfParent(int lineNumber, String parentIdalpha) {
        lineLogsBuilder.addMessage(ParseResult.SEVERE_FICHOTHEQUE, lineNumber, "_ error.unsupported.selfparent");
        return this;
    }

    public ParseResultBuilder unknownStatus(int lineNumber, String status) {
        lineLogsBuilder.addMessage(ParseResult.SEVERE_FICHOTHEQUE, lineNumber, "_ error.unknown.status", status);
        return this;
    }

    public ParseResultBuilder wrongDate(int lineNumber, String dateString) {
        lineLogsBuilder.addMessage(ParseResult.SEVERE_PARSE, lineNumber, "_ error.wrong.date", dateString);
        return this;
    }

    public boolean checkDoublon(String idString, int lineNumber) {
        ParseResult.ResultItem currentResultItem = resultItemMap.get(idString);
        if (currentResultItem != null) {
            lineLogsBuilder.addMessage(ParseResult.SEVERE_PARSE, lineNumber, "_ error.existing.tableimport.duplicate", String.valueOf(currentResultItem.getLineNumber()));
            return true;
        } else {
            return false;
        }
    }

    public ParseResultBuilder addResult(String idString, Object key, Object value, int lineNumber) {
        ParseResult.ResultItem resultItem = new InternalResultItem(key, value, lineNumber);
        resultItemMap.put(idString, resultItem);
        return this;
    }

    public ParseResultBuilder setPath(String path) {
        this.path = path;
        return this;
    }

    public ParseResult toParseResult() {
        List<ParseResult.ResultItem> resultItemList = new ResultItemList(resultItemMap.values().toArray(new ParseResult.ResultItem[resultItemMap.size()]));
        SourceLog initLog = columnLogBuilder.toSourceLog();
        LineLogs lineLogs = lineLogsBuilder.toLineLogs();
        return new InternalParseResult(type, resultItemList, path, initLog, lineLogs);
    }

    public static ParseResultBuilder init(String type) {
        return new ParseResultBuilder(type);
    }


    private static class InternalParseResult implements ParseResult {

        private final String type;
        private final List<ParseResult.ResultItem> resultItemList;
        private final SourceLog initLog;
        private final LineLogs lineLogs;
        private final String path;

        private InternalParseResult(String type, List<ParseResult.ResultItem> resultItemList, String path, SourceLog initLog, LineLogs lineLogs) {
            this.type = type;
            this.resultItemList = resultItemList;
            this.path = path;
            this.initLog = initLog;
            this.lineLogs = lineLogs;
        }

        @Override
        public String getType() {
            return type;
        }

        @Override
        public SourceLog getColumnLog() {
            return initLog;
        }

        @Override
        public LineLogs getLineLogs() {
            return lineLogs;
        }

        @Override
        public String getPath() {
            return path;
        }

        @Override
        public List<ResultItem> getResultItemList() {
            return resultItemList;
        }

    }


    private static class InternalResultItem implements ParseResult.ResultItem {

        private final Object keyObject;
        private final Object valueObject;
        private final int lineNumber;

        private InternalResultItem(Object keyObject, Object valueObject, int lineNumber) {
            this.keyObject = keyObject;
            this.valueObject = valueObject;
            this.lineNumber = lineNumber;
        }

        @Override
        public Object getKeyObject() {
            return keyObject;
        }

        @Override
        public Object getValueObject() {
            return valueObject;
        }

        @Override
        public int getLineNumber() {
            return lineNumber;
        }

    }


    private static class ResultItemList extends AbstractList<ParseResult.ResultItem> implements RandomAccess {

        private final ParseResult.ResultItem[] array;

        private ResultItemList(ParseResult.ResultItem[] array) {
            this.array = array;
        }

        @Override
        public int size() {
            return array.length;
        }

        @Override
        public ParseResult.ResultItem get(int index) {
            return array[index];
        }

    }

}
