package me.xdrop.ensurej;

import java.lang.reflect.InvocationTargetException;

public class ResultEval<T extends ParamCheckFailedException, E extends Handler<T,E>> {

    enum Operation {
        AND {
            boolean op(boolean lhs, boolean rhs) {
                return lhs && rhs;
            }
        },
        OR {
            boolean op(boolean lhs, boolean rhs) {
                return lhs || rhs;
            }
        };

        abstract boolean op(boolean lhs, boolean rhs);
    }

    private Boolean result = null;
    private Operation op;
    private String msg;
    private E chain;

    private Class<T> exceptionClass;

    ResultEval(boolean res, String msg, Class<T> exceptionClass, E chain) {
        this.result = res;
        this.msg = msg;
        this.exceptionClass = exceptionClass;
        this.chain = chain;
    }

    ResultEval(boolean res, Class<T> exceptionClass, E chain) {
        this.result = res;
        this.exceptionClass = exceptionClass;
        this.chain = chain;
    }

    void eval(boolean rhs){
        result = op.op(result, rhs);
        msg = "Aggregate condition " + op.toString() + " failed.";
    }



    public E and(){
        if (!result){
            chain.setToShortCircuit(this);
            result = false;
        }
        op = Operation.AND;
        chain.setResultRoot(this);
        return chain;
    }

    public E or(){
        if (result){
            chain.setToShortCircuit(this);
            result = true;
        }
        op = Operation.OR;
        chain.setResultRoot(this);
        return chain;
    }

    public boolean andEval(){
        return result;
    }

    public boolean e(){
        return result;
    }

    public boolean get(){
        return result;
    }

    public void t() throws T{
        andThrow();
    }

    void andThrow() throws T {
        if(!result && msg!=null) throwGeneric(msg);
        if(!result && msg==null) throwGeneric();
    }

    private void throwGeneric() throws T {
        try {
            throw exceptionClass.newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    private void throwGeneric(String message) throws T {
        try {
            throw exceptionClass.getConstructor(String.class).newInstance(message);
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }

}

@@ -1813,24 +1813,31 @@
 %0A    %7D%0A%0A    
+public 
 void andThro
@@ -1968,68 +1968,529 @@
    p
-rivate void throwGeneric() throws T %7B%0A        try %7B
+ublic %3CE extends Exception%3E void andThrow(Class%3CE%3E ex) throws E%7B%0A        if(!result && msg!=null) throwCustom(ex, msg);%0A        if(!result && msg==null) throwCustom(ex);%0A    %7D%0A%0A    private %3CE extends Throwable%3E void throwCustom(Class%3CE%3E ex, String message) throws E%7B%0A        throwGeneric(ex, message);
 %0A    
+%7D%0A%0A
     
+private void throwGeneric(String message) throws T %7B%0A        this.throwGeneric(exceptionClass, message);%0A    %7D%0A%0A    private %3CE extends Exception%3E void throwCustom(Class%3CE%3E ex) throws E%7B%0A        try %7B%0A        
     
@@ -2497,28 +2497,16 @@
 throw ex
-ceptionClass
 .newInst
@@ -2678,32 +2678,33 @@
        %7D%0A    %7D%0A%0A
+%0A
     private void
@@ -2690,32 +2690,54 @@
  %7D%0A%0A%0A    private
+ %3CE extends Throwable%3E
  void throwGener
@@ -2731,32 +2731,45 @@
 id throwGeneric(
+Class%3CE%3E ex, 
 String message) 
@@ -2767,33 +2767,33 @@
 message) throws 
-T
+E
  %7B%0A        try %7B
@@ -2813,28 +2813,16 @@
 throw ex
-ceptionClass
 .getCons
@@ -3196,10 +3196,288 @@
 %0A    %7D%0A%0A
+    private void throwGeneric() throws T %7B%0A        try %7B%0A            throw exceptionClass.newInstance();%0A        %7D catch (InstantiationException e) %7B%0A            e.printStackTrace();%0A        %7D catch (IllegalAccessException e) %7B%0A            e.printStackTrace();%0A        %7D%0A    %7D%0A%0A
 %7D%0A

Add custom exception support