package org.prganalysis.walker;

import java.util.*;

//import org.prganalysis.external.*;
import org.prganalysis.graph.*;
import org.prganalysis.settings.*;

import barat.*;
import barat.collections.*;
import barat.reflect.*;
import com.ibm.graph.*;

public class ParseVisitor extends DescendingVisitor { //implements Runnable {
    TGraph graph;
    StmtStack stsStack;
    KernelPGAnalyzer kernel;
    private int edgeIsCondition = 0; //0=No 1=True 2=False
    private boolean setAssignAllEdge = false;
    private int scope = 0;
    private ProgramNonRuntimeResults programNonRuntimeResults;
    private ParameterArrayList vParaList = new ParameterArrayList();
    int binOper=0;
   
    public ParseVisitor(KernelPGAnalyzer kernelPGAnalyzer) {
        kernel = kernelPGAnalyzer;
    }

    public void run() {
        programNonRuntimeResults = new ProgramNonRuntimeResults();
        kernel.setProgramNonRuntimeResults(programNonRuntimeResults);
        barat.reflect.CompilationUnit myClass = Barat.parseCompilationUnit(
                kernel.getTestFile());
        programNonRuntimeResults.setComplUnit(myClass);
        programNonRuntimeResults.getStrData(new String(myClass.toString()));
        stsStack = new StmtStack();
        graph = new TGraph("ParseVisitor");
        
        TVertex vStart = graph.addVertex("Start");
        // stsStack.add(vStart);
        this.stsStack.push(new VertexWithCondition(vStart, true));
        graph.setUniqueRoot(vStart);
        graph.setRoot(vStart, true);
        myClass.accept(this);
        programNonRuntimeResults.setGraph(graph);
        TVertex vEnd = graph.addVertex("End");
        setAssignAllEdge = true;
        //      assignAllEdgeWithNode(vEnd);

        VertexWithCondition vertexWithCondition = stsStack.
                                                  popVertexWithCondition();
        TEdge edgeIn = graph.addEdge(vertexWithCondition.vex, vEnd);
        edgeIn.addElement("" + vertexWithCondition.isTrue);
        edgeIn.setBooleanValue(vertexWithCondition.isTrue);

        programNonRuntimeResults.setVParamList(vParaList);
        for (int x = 0; x < this.graph.sizeVertices(); x++) {
            if (graph.vertexAt(x).getName().startsWith("If_Exit")) {
                java.util.Enumeration enuml = graph.vertexAt(x).
                                              enumerateIncomingDirectedEdges();

                java.util.Enumeration enum2 = graph.vertexAt(x).
                                              enumerateOutgoingDirectedEdges();
                TEdge tedge2 = (TEdge) enum2.nextElement();
                while (enuml.hasMoreElements()) {
                    TEdge tEdge = (TEdge) enuml.nextElement();

                    try {
                        tEdge.setToVertex(tedge2.getToVertex());
                    } catch (EdgeSharedException ex) {
                        ex.printStackTrace();
                    }
                }
                graph.removeVertexAt(x);
                x = x - 1;
            }
        }
         for (int x = 0; x < this.graph.sizeVertices(); x++) {
             TVertex tvertex=(TVertex)graph.vertexAt(x);
             if (tvertex.getNodeElement() instanceof barat.reflect.Return){
                TEdge tedge=(TEdge) tvertex.enumerateOutgoingDirectedEdges().nextElement();
                try {
                    tedge.setToVertex(vEnd);
                } catch (EdgeSharedException ex1) {
                    ex1.printStackTrace();
                }
             }

         }

    }


    /*public void checkEdgeIfCondition(TEdge edge) {
        if (edgeIsCondition == 1) {
            edge.addElement("True");
            edge.setBooleanValue(true);
            edgeIsCondition = 0;
        } else if (edgeIsCondition == 2) {
            edge.addElement("False");
            edge.setBooleanValue(false);
            edgeIsCondition = 0;
        }
         }*/

    /*public void assignAllEdgeWithNode(TVertex vertex) {
        TVertex vertexOld;
        TEdge edgeIn;
        while (!stsStack.isEmpty()) {
            vertexOld = (TVertex)this.stsStack.pop();
            edgeIn = graph.addEdge(vertexOld, vertex);
            checkEdgeIfCondition(edgeIn);
            if (!setAssignAllEdge) {
                return;
            }
        }
        setAssignAllEdge = false;
         }*/

    public void visitLiteral(barat.reflect.Literal o) {
        super.visitLiteral(o);
    }

    public void visitCaseBranch(barat.reflect.CaseBranch o) {
        super.visitCaseBranch(o);
    }

    public void visitInterface(barat.reflect.Interface o) {
        super.visitInterface(o);
    }


    public void visitClass(barat.reflect.Class o) {
        super.visitClass(o);
    }

    public void visitPackage(barat.reflect.Package o) {
        super.visitPackage(o);
    }


    public void visitCompilationUnit(barat.reflect.CompilationUnit o) {
        super.visitCompilationUnit(o);
    }

    public void visitAbstractMethod(barat.reflect.AbstractMethod o) {
        super.visitAbstractMethod(o);
    }

    public void visitParameter(barat.reflect.Parameter o) {
        TVertex vertexNew = new TVertex(o);
        graph.add(vertexNew);
        VertexWithCondition vertexWithCondition = stsStack.
                                                  popVertexWithCondition();
        TEdge edgeIn = graph.addEdge(vertexWithCondition.vex, vertexNew);
        edgeIn.addElement("" + vertexWithCondition.isTrue);
        edgeIn.setBooleanValue(vertexWithCondition.isTrue);
        // assignAllEdgeWithNode(vertex);
        this.stsStack.push(new VertexWithCondition(vertexNew, true));
        super.visitParameter(o);
        vParaList.add(o);
    }

    public void visitBlock(barat.reflect.Block o) {
        if (o.container() instanceof If) {
            //   TDebugger.debug("***VISIT BLOCK(IF)*** " + o.line_number(), 1);

            super.visitBlock(o);

            //  TDebugger.debug("***EXIT BLOCK(IF)*** " + o.line_number(), 1);

        } else {
            super.visitBlock(o);
        }

        //  TDebugger.debug("***EXIT BLOCK*** " + o.line_number(), 1);
    }

    /* 3. o.toString print "init"*/
    public void visitConstructor(barat.reflect.Constructor o) {
        super.visitConstructor(o);
    }

    public void visitConcreteMethod(barat.reflect.ConcreteMethod o) {
        super.visitConcreteMethod(o);
    }

    public void visitForInitDeclaration(barat.reflect.ForInitDeclaration o) {
        // TDebugger.debug("visitForInitDeclaration : " + o, 1);
        super.visitForInitDeclaration(o);
        //  TDebugger.debug("exitForInitDeclaration  ", 1);
    }

    public void visitVariableDeclaration(barat.reflect.VariableDeclaration o) {

        TVertex vertexNew = new TVertex(o);
        graph.add(vertexNew);

        //  assignAllEdgeWithNode(vertex);
        //  this.stsStack.push(vertex);

        VertexWithCondition vertexWithCondition = stsStack.
                                                  popVertexWithCondition();
        TEdge edgeIn = graph.addEdge(vertexWithCondition.vex, vertexNew);
        edgeIn.addElement("" + vertexWithCondition.isTrue);
        edgeIn.setBooleanValue(vertexWithCondition.isTrue);
        this.stsStack.push(new VertexWithCondition(vertexNew, true));
        // assignAllEdgeWithNode(vertex);
        super.visitVariableDeclaration(o);
        //vDeclarationList.add(o);

    }

    public void visitLocalVariable(barat.reflect.LocalVariable o) {
        //TDebugger.debug("visitLocalVariable : " + o, 1);
        super.visitLocalVariable(o);
    }

    public void visitField(barat.reflect.Field o) {
        //  TDebugger.debug("visitField : " + o, 1);
        super.visitField(o);
    }

    public void visitThis(barat.reflect.This o) {
        //  TDebugger.debug("visitThis : " + o, 1);
        super.visitThis(o);
    }

    public void visitCatch(barat.reflect.Catch o) {
        //   TDebugger.debug("visitCatch : " + o, 1);
        super.visitCatch(o);
    }

    public void visitFinally(barat.reflect.Finally o) {
        //  TDebugger.debug("visitFinally : " + o, 1);
        super.visitFinally(o);
    }

    public void visitSynchronized(barat.reflect.Synchronized o) {
        //  TDebugger.debug("visitSynchronized : " + o, 1);
        super.visitSynchronized(o);
    }

    public void visitConstructorCall(barat.reflect.ConstructorCall o) {
        //  TDebugger.debug("visitConstructorCall : " + o, 1);
        super.visitConstructorCall(o);
    }

    public void visitObjectAllocation(barat.reflect.ObjectAllocation o) {
        // TDebugger.debug("visitObjectAllocation : " + o, 1);
        super.visitObjectAllocation(o);
    }

    public void visitTry(barat.reflect.Try o) {
        //  TDebugger.debug("visitTry : " + o, 1);
        super.visitTry(o);
    }

    public void visitArrayAccess(barat.reflect.ArrayAccess o) {
        //   TDebugger.debug("visitArrayAccess : " + o, 1);
        super.visitArrayAccess(o);
    }

    public void visitArrayAllocation(barat.reflect.ArrayAllocation o) {
        //  TDebugger.debug("visitArrayAllocation : " + o, 1);
        super.visitArrayAllocation(o);
    }

    public void visitArrayInitializer(barat.reflect.ArrayInitializer o) {
        //  TDebugger.debug("visitArrayInitializer : " + o, 1);
        super.visitArrayInitializer(o);
    }

    public void visitAssignment(barat.reflect.Assignment o) {
        //  TDebugger.debug("visitAssignment : " + o, 1);
        super.visitAssignment(o);
    }

    public void visitBinaryOperation(barat.reflect.BinaryOperation o) {
        //  TDebugger.debug("visitBinaryOperation : " + o, 1);
        String operatorStr = o.operator();
       if (operatorStr.equals("<") ||
           operatorStr.equals("<=") || operatorStr.equals(">")
           ||
           operatorStr.equals(">=") ||
           operatorStr.equals("==") ||
           operatorStr.equals("!=")) {
           binOper++;
           System.out.println("binaryOperator "+binOper);

       }
       System.out.println("bvvvvvvvvvvvv");
        super.visitBinaryOperation(o);
    }

    public void visitCast(barat.reflect.Cast o) {
        // TDebugger.debug("visitCast : " + o, 1);
        super.visitCast(o);
    }

    public void visitConditional(barat.reflect.Conditional o) {
        //   TDebugger.debug("visitConditional : " + o, 1);
        super.visitConditional(o);
    }

    public void visitContinue(barat.reflect.Continue o) {

        TVertex vertexNew = new TVertex(o);
        graph.add(vertexNew);

        VertexWithCondition vertexWithCondition = stsStack.
                                                  popVertexWithCondition();
        TEdge edgeIn = graph.addEdge(vertexWithCondition.vex, vertexNew);
        edgeIn.addElement("" + vertexWithCondition.isTrue);
        edgeIn.setBooleanValue(vertexWithCondition.isTrue);
        this.stsStack.push(new VertexWithCondition(vertexNew, true));

        // assignAllEdgeWithNode(vertex);


        //   this.stsStack.push(vertexNew);

        super.visitContinue(o);
    }

    public void visitDefaultBranch(barat.reflect.DefaultBranch o) {
        //  TDebugger.debug("visitDefaultBranch : " + o, 1);
        super.visitDefaultBranch(o);
    }

    public void visitDo(barat.reflect.Do o) {
        //  TDebugger.debug("visitDo : " + o, 1);
        super.visitDo(o);
    }

    public void visitEmptyStatement(barat.reflect.EmptyStatement o) {
        // TDebugger.debug("visitEmptyStatement : " + o, 1);
        super.visitEmptyStatement(o);
    }

    public void visitExpressionStatement(barat.reflect.ExpressionStatement o) {
//    TDebugger.debug("visitExpressionStatement : " + o, 1);

        TVertex vertexNew = new TVertex(o);
        graph.add(vertexNew);

        VertexWithCondition vertexWithCondition = stsStack.
                                                  popVertexWithCondition();
        TEdge edgeIn = graph.addEdge(vertexWithCondition.vex, vertexNew);
        edgeIn.addElement("" + vertexWithCondition.isTrue);
        edgeIn.setBooleanValue(vertexWithCondition.isTrue);
        this.stsStack.push(new VertexWithCondition(vertexNew, true));

        //  assignAllEdgeWithNode(vertex);

        // this.stsStack.push(vertexNew);

        super.visitExpressionStatement(o);
    }

    public void visitFor(barat.reflect.For o) {
        //TDebugger.debug("1.visitFor : " + o);
        //For(**
        AForInit aforInit = o.getForInit();
        System.out.println("" + o.getForInit());
        visitAnyNode(aforInit);
        //*******  TVertex vertexOld = (TVertex)this.stsStack.pop();
         //For (int x=0,**
         TVertex vertexIn = new TVertex(o.getExpression());
        System.out.println("" + o.getExpression());
        graph.add(vertexIn);
        //******  TEdge edgeIn = graph.addEdge(vertexOld, vertexIn);
         //*****  checkEdgeIfCondition(edgeIn);
          VertexWithCondition vertexWithCondition = stsStack.
                  popVertexWithCondition();
        TEdge edgeIn = graph.addEdge(vertexWithCondition.vex, vertexIn);
        edgeIn.addElement("" + vertexWithCondition.isTrue);
        edgeIn.setBooleanValue(vertexWithCondition.isTrue);
        this.stsStack.push(new VertexWithCondition(vertexIn, true));

        //   assignAllEdgeWithNode(vertexIn);
        // this.stsStack.push(vertexIn);
        edgeIsCondition = 1;
        //Body
        //******visitAnyNode(o.getExpression()); Whhat is that
         visitAnyNode(o.getBody());
        //For (int x=0,x<12,**
        barat.collections.AExpressionListIterator aExpressionListIterator = o.
                getUpdateExpressions().listIterator();
        while (aExpressionListIterator.hasNext()) {
            AExpression aExpress = aExpressionListIterator.next();
            visitAnyNode(aExpress);
            System.out.println("" + aExpress);
        }
        //*******TVertex vertexForUpdate = (TVertex)this.stsStack.pop();
         //**** TEdge edgeForUpdate = graph.addEdge(vertexForUpdate, vertexIn);

          VertexWithCondition vertexWithCondition2 = stsStack.
                  popVertexWithCondition();
        TEdge edgeIn2 = graph.addEdge(vertexWithCondition2.vex, vertexIn);
        edgeIn2.addElement("" + vertexWithCondition2.isTrue);
        edgeIn2.setBooleanValue(vertexWithCondition2.isTrue);
        this.stsStack.push(new VertexWithCondition(vertexIn, false));
        //  assignAllEdgeWithNode(vertexIn);

        //Vertex x<12 push again
        // this.stsStack.push(vertexIn);
        edgeIsCondition = 2;
        //TDebugger.debug("4.Exit For ");
    }

    public void visitForInitExpression(barat.reflect.ForInitExpression o) {
//    TDebugger.debug("visitForInitExpression : " + o, 1);
        super.visitForInitExpression(o);
    }

    public void visitIf(barat.reflect.If o) {

        TVertex vertexCondition = new TVertex(o.getExpression());
        graph.add(vertexCondition);
        // TVertex vertexOld = (TVertex)this.stsStack.pop();
        //  TEdge edgeIn = graph.addEdge(vertexOld, vertexCondition);
        // edgeIsCondition = 1;
        //  this.stsStack.push(vertexCondition);
        VertexWithCondition vertexWithCondition = stsStack.
                                                  popVertexWithCondition();
        TEdge edgeIn = graph.addEdge(vertexWithCondition.vex, vertexCondition);
        edgeIn.addElement("" + vertexWithCondition.isTrue);
        edgeIn.setBooleanValue(vertexWithCondition.isTrue);
        this.stsStack.push(new VertexWithCondition(vertexCondition, true));

        AStatement ast = o.getThenBranch();
        visitAnyNode(ast);
        VertexWithCondition vertexWithConditionvertexLastNodeThen = stsStack.
                popVertexWithCondition();
        //   TVertex vertexLastNodeThen = (TVertex)this.stsStack.pop();
        TVertex vertexLastNodeThen = vertexWithConditionvertexLastNodeThen.vex;
        // this.stsStack.push(vertexCondition);
        //  edgeIsCondition = 2;
        this.stsStack.push(new VertexWithCondition(vertexCondition, false));
        if (o.getElseBranch() != null) {
            AStatement ast2 = o.getElseBranch();
            visitAnyNode(ast2);
        }

        VertexWithCondition vertexWithCondition2 = stsStack.
                popVertexWithCondition();
        TVertex vertexLastNodeElse = vertexWithCondition2.vex;
        //  TVertex vertexLastNodeElse = (TVertex)this.stsStack.pop();
        TVertex vertexOut = graph.addVertex("If_Exit" +
                                            vertexLastNodeElse.hashCode());

        TEdge edgeOut2 = graph.addEdge(vertexLastNodeElse, vertexOut);

        edgeOut2.addElement("" + vertexWithCondition2.isTrue);
        edgeOut2.setBooleanValue(vertexWithCondition2.isTrue);
        this.stsStack.push(new VertexWithCondition(vertexOut, true));
        // TEdge edgeOut2 = graph.addEdge(vertexLastNodeElse, vertexOut);
        graph.addEdge(vertexLastNodeThen, vertexOut);
        //  if (o.getElseBranch() == null) {
        //     edgeOut2.addElement("False");
        //  }

        // this.stsStack.push(vertexOut);

    }

    public void visitInstanceFieldAccess(barat.reflect.InstanceFieldAccess o) {
        // TDebugger.debug("visitInstanceFieldAccess : " + o, 1);
        super.visitInstanceFieldAccess(o);
    }

    public void visitInstanceMethodCall(barat.reflect.InstanceMethodCall o) {
        //   TDebugger.debug("visitInstanceMethodCall : " + o, 1);
        super.visitInstanceMethodCall(o);
    }

    public void visitArrayLengthAccess(barat.reflect.ArrayLengthAccess o) {
        //TDebugger.debug("visitArrayLengthAccess : " + o, 1);
        super.visitArrayLengthAccess(o);
    }

    public void visitParenExpression(barat.reflect.ParenExpression o) {
        //  TDebugger.debug("visitParenExpression : " + o, 1);
        super.visitParenExpression(o);
    }

    public void visitReturn(barat.reflect.Return o) {
        TVertex vertexNew = new TVertex(o);
        graph.add(vertexNew);
        VertexWithCondition vertexWithCondition = stsStack.
                                                  popVertexWithCondition();
        TEdge edgeIn = graph.addEdge(vertexWithCondition.vex, vertexNew);
        edgeIn.addElement("" + vertexWithCondition.isTrue);
        edgeIn.setBooleanValue(vertexWithCondition.isTrue);
        this.stsStack.push(new VertexWithCondition(vertexNew, true));
        super.visitReturn(o);
    }

    public void visitStaticFieldAccess(barat.reflect.StaticFieldAccess o) {
        //   TDebugger.debug("visitStaticFieldAccess : " + o, 1);
        super.visitStaticFieldAccess(o);
    }

    public void visitInstanceof(barat.reflect.Instanceof o) {

        super.visitInstanceof(o);
    }

    public void visitStaticMethodCall(barat.reflect.StaticMethodCall o) {

        super.visitStaticMethodCall(o);
    }

    public void visitBreak(barat.reflect.Break o) {

        super.visitBreak(o);
    }

    public void visitSwitch(barat.reflect.Switch o) {

        super.visitSwitch(o);
    }

    public void visitUnaryOperation(barat.reflect.UnaryOperation o) {

        /*  TVertex vertexNew = new TVertex(o);
          graph.add(vertexNew);


              VertexWithCondition vertexWithCondition = stsStack.
                         popVertexWithCondition();
         TEdge edgeIn = graph.addEdge(vertexWithCondition.vex, vertexNew);
         edgeIn.addElement(""+vertexWithCondition.isTrue);
         edgeIn.setBooleanValue(vertexWithCondition.isTrue);
         this.stsStack.push(new VertexWithCondition(vertexNew, true));
         */

        super.visitUnaryOperation(o);
    }

    public void visitThrow(barat.reflect.Throw o) {

        super.visitThrow(o);
    }

    public void visitVariableAccess(barat.reflect.VariableAccess o) {

        super.visitVariableAccess(o);
        /* TDebugger.debug("VAs :"+ o.attributeValue(new me()));
          TDebugger.debug("Aspect2 :"+ o.getVariable().qualifiedName());*/
    }

    public void visitWhile(barat.reflect.While o) {

        TVertex vertexIn = new TVertex(o.getExpression());
        VertexWithCondition vertexWithCondition = stsStack.
                                                  popVertexWithCondition();
        TEdge edgeIn = graph.addEdge(vertexWithCondition.vex, vertexIn);
        edgeIn.addElement("" + vertexWithCondition.isTrue);
        edgeIn.setBooleanValue(vertexWithCondition.isTrue);
        this.stsStack.push(new VertexWithCondition(vertexIn, true));
        //body
        visitAnyNode(o.getBody());

        VertexWithCondition vertexWithCondition2 = stsStack.
                popVertexWithCondition();
        TEdge edgeIn2 = graph.addEdge(vertexWithCondition2.vex, vertexIn);
        edgeIn.addElement("" + vertexWithCondition.isTrue);
        edgeIn.setBooleanValue(vertexWithCondition.isTrue);

        this.stsStack.push(new VertexWithCondition(vertexIn, false));

    }

    public void visitAnonymousAllocation(barat.reflect.AnonymousAllocation o) {
        //TDebugger.debug("visitAnonymousAllocation : " + o, 1);
        super.visitAnonymousAllocation(o);
    }

    public void visitUserTypeDeclaration(barat.reflect.UserTypeDeclaration o) {
        //TDebugger.debug("visitUserTypeDeclaration : " + o, 1);
        super.visitUserTypeDeclaration(o);
    }

    public void visitClassExpression(barat.reflect.ClassExpression o) {
        //TDebugger.debug("visitClassExpression : " + o, 1);
        super.visitClassExpression(o);
    }

    public void visitAnyNode(Node o) {
        this.acceptIfPresent(o);
    }

    /*public VariableDeclarationArrayList getVariableDeclarationArrayList()
       {
      return this.vDeclarationList;
       }*/

}


class me {

    public boolean equals(Object obj) {
        return true;
    }
}
