/* UtilLib - Copyright (c) 2015-2019 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.mapeadores.util.instruction;

import java.io.IOException;
import java.util.AbstractList;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import net.mapeadores.util.text.StringUtils;


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

    public final static InstructionErrorHandler DEFAULT_ERROR_HANDLER = new DefaultInstructionErrorHandler();
    public final static Map<String, Object> EMPTY_OPTIONS = Collections.emptyMap();

    private InstructionUtils() {

    }

    public static Argument toArgument(String key, String value) {
        if ((key == null) || (key.length() == 0)) {
            throw new IllegalArgumentException("key is null or empty");
        }
        if ((value != null) && (value.length() == 0)) {
            value = null;
        }
        return new InternalArgument(key, value);
    }

    public static Instruction toInstruction(Collection<Argument> col) {
        int size = col.size();
        if (size == 0) {
            throw new IllegalArgumentException();
        }
        return new InternalInstruction(col.toArray(new Argument[size]));
    }

    public static void appendInstructionString(String s, Appendable buf) throws IOException {
        int length = s.length();
        if (length == 0) {
            buf.append("\"\"");
        } else if (StringUtils.isValidAsciiString(s)) {
            buf.append(s);
        } else {
            buf.append('\"');
            for (int i = 0; i < length; i++) {
                char carac = s.charAt(i);
                switch (carac) {
                    case '"':
                        buf.append("\\\"");
                        break;
                    case '\\':
                        buf.append("\\\\");
                        break;
                    case '\n':
                        buf.append("\\n");
                        break;
                    case '\t':
                        buf.append("\\t");
                        break;
                    case '\r':
                        buf.append("\\r");
                        break;
                    default:
                        buf.append(carac);
                }
            }
            buf.append('\"');
        }
    }


    private static class InternalInstruction extends AbstractList<Argument> implements Instruction {

        private final Argument[] array;

        private InternalInstruction(Argument[] array) {
            this.array = array;
        }

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

        @Override
        public Argument get(int i) {
            return array[i];
        }

    }


    private static class InternalArgument implements Argument {

        private final String key;
        private final String value;

        private InternalArgument(String key, String value) {
            this.key = key;
            this.value = value;
        }

        @Override
        public String getKey() {
            return key;
        }

        @Override
        public String getValue() {
            return value;
        }

    }


    public static class DefaultInstructionErrorHandler implements InstructionErrorHandler {

        private DefaultInstructionErrorHandler() {

        }

        @Override
        public void invalidAsciiCharacterError(String part, int row, int col) {
        }

        @Override
        public void invalidEndCharacterError(String part, int row, int col) {
        }

        @Override
        public void invalidSeparatorCharacterError(String part, int row, int col) {
        }

    }

}
