package wayerr.co.util;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Утилита разбора аргументов
 *
 * @author rad
 */
public final class Args {

    public static final class Arg {

        /**
         * Short arg
         */
        private final Character shortName;
        /**
         * Long arg
         */
        private final String longName;
        private final boolean hasParams;

        public Arg(Character shortName, String longName, boolean hasParams) {
            this.shortName = shortName;
            this.longName = longName;
            this.hasParams = hasParams;
        }

        public boolean isHasParams() {
            return hasParams;
        }

        public String getLongName() {
            return longName;
        }

        public Character getShortName() {
            return shortName;
        }

        @Override
        public boolean equals(Object obj) {
            if(obj == null) {
                return false;
            }
            if(getClass() != obj.getClass()) {
                return false;
            }
            final Arg other = (Arg)obj;
            if((this.shortName == null) ? (other.shortName != null) : !this.shortName.equals(other.shortName)) {
                return false;
            }
            if((this.longName == null) ? (other.longName != null) : !this.longName.equals(other.longName)) {
                return false;
            }
            if(this.hasParams != other.hasParams) {
                return false;
            }
            return true;
        }

        @Override
        public int hashCode() {
            int hash = 3;
            hash = 37 * hash + (this.shortName != null ? this.shortName.hashCode() : 0);
            hash = 37 * hash + (this.longName != null ? this.longName.hashCode() : 0);
            hash = 37 * hash + (this.hasParams ? 1 : 0);
            return hash;
        }
    }

    public static final class ArgsBuilder {

        private final List<Arg> args = new ArrayList<Arg>();

        public ArgsBuilder() {
        }

        public ArgsBuilder add(Character s, String l, boolean params) {
            args.add(new Arg(s, l, params));
            return this;
        }

        public ArgsBuilder add(Character s, String l) {
            return add(s, l, false);
        }

        public Args build(String cmdLine[]) {
            Map<String, Arg> stoa = new HashMap<>();
            Map<Character, Arg> ctoa = new HashMap<>();
            for(Arg a : args) {//заполняем словари
                stoa.put(a.getLongName(), a);
                ctoa.put(a.getShortName(), a);
            }
            Map<Arg, List<String>> map = new HashMap<>();
            Arg a = null;
            List<String> list = null;
            for(String arg : cmdLine) {
                if(arg.startsWith("-")) {//аргумент
                    if(arg.length() == 2) {
                        a = ctoa.get(arg.charAt(1));
                    } else {
                        // полагается что длинные аргмуенты начинаются с --
                        a = stoa.get(arg.substring(2));
                    }
                    list = map.get(a);
                    if(list == null) {
                        list = new ArrayList<>();
                        map.put(a, list);
                    }
                } else if(list != null) {
                    list.add(arg);
                }
            }
            return new Args(map, ctoa, stoa);
        }
    }

    private final Map<Arg, List<String>> argsMap;
    private final Map<Character, Arg> ctoa;
    private final Map<String, Arg> stoa;

    private Args(Map<Arg, List<String>> argsMap, Map<Character, Arg> ctoa, Map<String, Arg> stoa) {
        this.argsMap = argsMap;
        this.ctoa = ctoa;
        this.stoa = stoa;
    }

    public static ArgsBuilder builder() {
        return new ArgsBuilder();
    }

    public boolean has(String arg) {
        return has(arg(arg));
    }

    public boolean has(Character arg) {
        return has(arg(arg));
    }

    public boolean has(Arg a) {
        return a != null && argsMap.containsKey(a);
    }

    public Arg arg(String s) {
        return stoa.get(s);
    }

    public Arg arg(Character c) {
        return ctoa.get(c);
    }

    public String get(String arg) {
        return get(arg(arg));
    }

    public String get(Character arg) {
        return get(arg(arg));
    }

    public String get(Arg arg) {
        List<String> l = argsMap.get(arg);
        if(l == null || l.isEmpty()) {
            return null;
        }
        return l.get(0);
    }
}
