package com.ericsson.uecontrol.core.util;

import org.apache.log4j.Logger;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;

/**
 * Created by ezivkoc on 2014-07-24.
 */
public class Configurator {
    private static final Logger log = Logger.getLogger(Configurator.class);
    /**
     * Sets a field in a class as externally configurable.
     */
    @Retention(RetentionPolicy.RUNTIME) // Make this annotation accessible at runtime via reflection.
    @Target({ElementType.FIELD})       // This annotation can only be applied to class fields.
    public static @interface Configurable{
        /* Nice name of this parameter */
        String value();
        /* Defines the order the parameters, in ascending order */
        int order() default Integer.MAX_VALUE;
    }

    public static enum ConfigType{
        STRING, INT, BOOLEAN
    }


    private Object obj;
    private ConfigurationParam[] params;

    public Configurator(Object obj){
        this.obj = obj;
        this.params = getConfiguration(obj);
    }

    public ConfigurationParam[] getConfiguration(){
        return params;
    }

    protected ConfigurationParam[] getConfiguration(Object obj){
        Class c = obj.getClass();
        ArrayList<ConfigurationParam> conf = new ArrayList<ConfigurationParam>();

        Field[] all = c.getDeclaredFields();
        for(Field f : all){
            if(f.isAnnotationPresent(Configurable.class) &&
                    !Modifier.isStatic(f.getModifiers()) && !Modifier.isTransient(f.getModifiers())) {
                try {
                    conf.add(new ConfigurationParam(f));
                } catch (IllegalAccessException e) {
                    log.warn(null, e);
                }
            }
        }

        ConfigurationParam[] list = conf.toArray(new ConfigurationParam[conf.size()]);
        Arrays.sort(list);
        return list;
    }

    public void setConfiguration(){
        for(ConfigurationParam param : params){
            try {
                param.set();
            } catch (IllegalAccessException e) {
                log.warn(null, e);
            }
        }
    }


    public class ConfigurationParam implements Comparable<ConfigurationParam>{
        protected Field field;
        protected String name;
        protected String niceName;
        protected ConfigType type;
        protected Object value;
        protected int order;


        protected ConfigurationParam(Field f) throws IllegalAccessException {
            field = f;
            field.setAccessible(true);
            name = field.getName();
            niceName = field.getAnnotation(Configurable.class).value();
            value = field.get(obj);
            order = field.getAnnotation(Configurable.class).order();

            if     (f.getType() == String.class) type = ConfigType.STRING;
            else if(f.getType() == int.class)    type = ConfigType.INT;
            else if(f.getType() == boolean.class)type = ConfigType.BOOLEAN;

        }

        public String getName(){return name;}
        public String getNiceName(){return niceName;}
        public ConfigType getType(){return type;}

        public String getString(){
            if(value == null)
                return null;
            return value.toString();}

        public void setString(String v){
            switch(type){
                case STRING:
                    value = v; break;
                case INT:
                    value = Integer.parseInt(v); break;
                case BOOLEAN:
                    value = Boolean.parseBoolean(v); break;
            }
        }

        protected void set() throws IllegalAccessException {
            field.set(obj, value);
        }


        @Override
        public int compareTo(ConfigurationParam configurationParam) {
            return this.order - configurationParam.order;
        }
    }
}
