/* FichothequeLib_Tools - Copyright (c) 2007-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 java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import net.fichotheque.corpus.fiche.Atts;


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

    public final static List<Atts> EMPTY_ATTSLIST = Collections.emptyList();
    public final static String LINENUMBER_DATA = "data-bdf-linenumber";
    private final List<Atts> attsList;
    private final String cleanedLine;
    private final boolean attsError;

    private LineInfo(String line, List<Atts> attsList, boolean attsError) {
        this.cleanedLine = line;
        this.attsList = attsList;
        this.attsError = attsError;
    }

    public boolean isCleanedLineEmpty() {
        return (cleanedLine.length() == 0);
    }

    public List<Atts> getAttsList() {
        return attsList;
    }

    public Atts getFirstAtts() {
        if (attsList.isEmpty()) {
            return null;
        } else {
            return attsList.get(0);
        }
    }

    public Atts getSecondAtts() {
        if (attsList.size() < 2) {
            return null;
        } else {
            return attsList.get(1);
        }
    }

    public String getCleanedLine() {
        return cleanedLine;
    }

    public boolean hasAttsError() {
        return attsError;
    }

    public LineInfo deriveWithoutAttsList() {
        if ((attsList.isEmpty()) && (!attsError)) {
            return this;
        }
        return new LineInfo(cleanedLine, EMPTY_ATTSLIST, false);
    }

    public static LineInfo parse(String line, int lineIndex) {
        String lineNumber = null;
        if (lineIndex > -1) {
            lineNumber = String.valueOf(lineIndex + 1);
        }
        if (line.length() == 0) {
            return new LineInfo("", toAttsList(lineNumber), false);
        }
        if (!line.startsWith("[(")) {
            return new LineInfo(line, toAttsList(lineNumber), false);
        }
        try {
            return parseWithAttsList(line, lineNumber);
        } catch (ParseException pe) {
            return new LineInfo(line, toAttsList(lineNumber), true);
        }
    }

    public static Atts getAutomaticAtts(int lineIndex) {
        if (lineIndex > -1) {
            return new LineNumberAtts(String.valueOf(lineIndex + 1));
        } else {
            return null;
        }
    }

    private static LineInfo parseWithAttsList(String line, String lineNumber) throws ParseException {
        List<Atts> attsList = new ArrayList<Atts>();
        int startIndex = 2;
        int closeIndex = -1;
        while (true) {
            AttsParser parser = new AttsParser(line, startIndex);
            if (lineNumber != null) {
                parser.addAtt(LINENUMBER_DATA, lineNumber);
            }
            parser.run();
            closeIndex = parser.getCloseIndex();
            if (closeIndex == (line.length() - 1)) {
                throw new ParseException("Missing closing ]", closeIndex);
            }
            attsList.add(parser.getAtts());
            char nextChar = line.charAt(closeIndex + 1);
            if (nextChar == ']') {
                break;
            } else if (nextChar == '(') {
                startIndex = closeIndex + 2;
            } else {
                throw new ParseException("Missing ] or (", closeIndex + 1);
            }
        }
        String newLine;
        if ((line.length() > (closeIndex + 2)) && (line.charAt(closeIndex + 2) == ' ')) {
            newLine = line.substring(closeIndex + 3);
        } else {
            newLine = line.substring(closeIndex + 2);
        }
        return new LineInfo(newLine, attsList, false);
    }

    private static List<Atts> toAttsList(String lineNumber) {
        if (lineNumber != null) {
            return Collections.singletonList(new LineNumberAtts(lineNumber));
        } else {
            return EMPTY_ATTSLIST;
        }
    }


    private static class LineNumberAtts implements Atts {

        private final String lineNumber;

        private LineNumberAtts(String lineNumber) {
            this.lineNumber = lineNumber;
        }

        @Override
        public int size() {
            return 1;
        }

        @Override
        public String getName(int index) {
            return LINENUMBER_DATA;
        }

        @Override
        public String getValue(int index) {
            return lineNumber;
        }

        @Override
        public boolean hasOnlyAutomaticAtts() {
            return true;
        }

    }


}
