/*
 * @author Ranides Atterwim <ranides@gmail.com>
 * @copyright Ranides Atterwim
 * @license WTFPL
 * @url http://ranides.net/projects/assira
 */
package net.ranides.assira.reflection;

import java.io.Serializable;

public abstract class ResolveStrategy implements Serializable {

    private static final long serialVersionUID = 1L;
        
    public static final ResolveStrategy THROW = new EHThrow();
    
    public static final ResolveStrategy FORMAT = new EHFormat();
    
    public static final ResolveStrategy SILENT = new EHSilent();
    
    public static final ResolveStrategy NULL = new EHDefault(null);
    
    protected ResolveStrategy() {
        // do nothing
    }
    
    public static ResolveStrategy withDefault(Object value) {
        return new EHDefault(value);
    }

    public abstract Object get(ResolvePattern resolver);

    public abstract Object get(ResolvePattern resolver, String token);

    public abstract Object replace(ResolvePattern resolver);

    public abstract void set(ResolvePattern resolver);

    public abstract IClass<?> type(ResolvePattern resolver);

    public abstract IClass<?> type(ResolvePattern resolver, String token);
    
    private static class EHSilent extends ResolveStrategy {
        
        private static final long serialVersionUID = 1L;
        
        @Override
        public Object get(ResolvePattern resolver) {
            return null;
        }
        
        @Override
        public Object get(ResolvePattern resolver, String token) {
            return null;
        }
        
        @Override
        public IClass<?> type(ResolvePattern resolver) {
            return IClass.NULL;
        }
        
        @Override
        public IClass<?> type(ResolvePattern resolver, String token) {
            return IClass.NULL;
        }
        
        @Override
        public Object replace(ResolvePattern resolver) {
            return null;
        }
        
        @Override
        public void set(ResolvePattern resolver) {
            // do nothing
        }
        
    }
    
    private static class EHThrow extends ResolveStrategy {
        
        private static final long serialVersionUID = 1L;
        
        @Override
        public Object get(ResolvePattern resolver) {
            throw new ResolveException("Unknown value of expression: {" + resolver.expression()+"}");
        }
        
        @Override
        public Object get(ResolvePattern resolver, String token) {
            throw new ResolveException("Invalid expression: {" + resolver.expression() + "} at {" + token+"}");
        }
        
        @Override
        public IClass<?> type(ResolvePattern resolver) {
            throw new ResolveException("Unknown type of expression: {" + resolver.expression() + "}");
        }
        
        @Override
        public IClass<?> type(ResolvePattern resolver, String token) {
            throw new ResolveException("Invalid expression: {" + resolver.expression() + "} at {" + token + "}");
        }
        
        @Override
        public Object replace(ResolvePattern resolver) {
            throw new ResolveException("No replaceable expression: {" + resolver.expression() + "}");
        }
        
        @Override
        public void set(ResolvePattern resolver) {
            throw new ResolveException("No writable expression: {" + resolver.expression() + "}");
        }
        
    }

    private static class EHFormat extends EHThrow {
        
        private static final long serialVersionUID = 1L;
        
        private static final IClass<String> STRING = IClass.typeinfo(String.class);

        @Override
        public Object get(ResolvePattern resolver) {
            return "{"+resolver.expression()+"}";
        }
        
        @Override
        public Object get(ResolvePattern resolver, String token) {
            return "{"+resolver.expression()+"}";
        }
        
        @Override
        public IClass<?> type(ResolvePattern resolver) {
            return STRING;
        }
        
        @Override
        public IClass<?> type(ResolvePattern resolver, String token) {
            return STRING;
        }
        
    }
    
    private static class EHDefault extends EHThrow {
        
        private static final long serialVersionUID = 1L;
        
        final Object value;

        public EHDefault(Object value) {
            this.value = value;
        }

        @Override
        public Object get(ResolvePattern resolver) {
            return value;
        }
        
        @Override
        public IClass<?> type(ResolvePattern resolver) {
            return IClass.typefor(value);
        }
        
    }
    
}
