package railo.transformer.bytecode.statement;

import java.util.ArrayList;
import java.util.Iterator;

import railo.transformer.bytecode.Body;
import railo.transformer.bytecode.BytecodeContext;
import railo.transformer.bytecode.BytecodeException;
import railo.transformer.bytecode.Position;
import railo.transformer.bytecode.Statement;
import railo.transformer.bytecode.expression.ExprBoolean;
import railo.transformer.bytecode.expression.Expression;
import railo.transformer.bytecode.literal.LitBoolean;
import railo.transformer.bytecode.util.ExpressionUtil;
import railo.transformer.bytecode.visitor.ConditionVisitor;

public final class Condition extends StatementBaseNoFinal implements HasBodies {
    
    private ArrayList<Pair> ifs=new ArrayList<Pair>();
    private Pair _else;

    /**
     * Constructor of the class
     * @param condition
     * @param body
     * @param line
     */
    public Condition(Position start,Position end) {
        super(start,end);
    }
    
    /**
     * Constructor of the class
     * @param condition
     * @param body
     * @param line
     */
    public Condition(ExprBoolean condition, Statement body, Position start,Position end) {
        super(start,end);
        addElseIf(condition,body,start,end);
        
        body.setParent(this);
    }
    
    public Condition(boolean b, Statement body, Position start,Position end) {
		this(LitBoolean.toExprBoolean(b),body,start,end);
	}

	/**
     * adds a else statement
     * @param condition
     * @param body
     */
    public Pair addElseIf(ExprBoolean condition, Statement body, Position start,Position end) {
    	Pair pair;
    	ifs.add(pair=new Pair(condition,body,start,end));
        body.setParent(this);
        return pair;
    }
    
    /**
     * sets the else Block of the condition
     * @param body
     */
    public Pair setElse(Statement body, Position start,Position end) {
    	_else=new Pair(null,body,start,end);
    	body.setParent(this);
    	return _else;
    }
    
    public final class Pair {
        private ExprBoolean condition;
        private Statement body;
        private Position start;
        public Position end;

        public Pair(ExprBoolean condition, Statement body, Position start,Position end) {
            this.condition=condition;
            this.body=body;
            this.start=start;
            this.end=end;
        }
    }
    
    

    public void _writeOut(BytecodeContext bc) throws BytecodeException {
    	Iterator<Pair> it = ifs.iterator();
        Pair pair;
        ConditionVisitor cv=new ConditionVisitor();
        cv.visitBefore();
        	// ifs
        	while(it.hasNext()) {
        		pair=it.next();
        		ExpressionUtil.visitLine(bc, pair.start);
        		cv.visitWhenBeforeExpr();
        			pair. condition.writeOut(bc,Expression.MODE_VALUE);
        		cv.visitWhenAfterExprBeforeBody(bc);
        			pair.body.writeOut(bc);
        		cv.visitWhenAfterBody(bc);
        		if(pair.end!=null)ExpressionUtil.visitLine(bc, pair.end);
        	}
        	// else
        	if(_else!=null && _else.body!=null) {
        		cv.visitOtherviseBeforeBody();
        			_else.body.writeOut(bc);
        		cv.visitOtherviseAfterBody();
        	}
        	
        cv.visitAfter(bc);
    }

	/**
	 * @see railo.transformer.bytecode.statement.HasBodies#getBodies()
	 */
	public Body[] getBodies() {
		int len=ifs.size(),count=0;
		if(_else!=null)len++;
		Body[] bodies=new Body[len];
		Pair p;
		Iterator<Pair> it = ifs.iterator();
		while(it.hasNext()) {
			p=it.next();
			bodies[count++]=(Body) p.body;
		}
		if(_else!=null)bodies[count++]=(Body) _else.body;
		
		return bodies;
	}
}
