package de.uni_hildesheim.sse.trans.convert;

import java.util.HashSet;
import java.util.Set;

import de.uni_hildesheim.sse.model.cst.Comment;
import de.uni_hildesheim.sse.model.cst.CompoundAccess;
import de.uni_hildesheim.sse.model.cst.CompoundInitializer;
import de.uni_hildesheim.sse.model.cst.ConstantValue;
import de.uni_hildesheim.sse.model.cst.ConstraintSyntaxTree;
import de.uni_hildesheim.sse.model.cst.ContainerInitializer;
import de.uni_hildesheim.sse.model.cst.ContainerOperationCall;
import de.uni_hildesheim.sse.model.cst.IConstraintTreeVisitor;
import de.uni_hildesheim.sse.model.cst.IfThen;
import de.uni_hildesheim.sse.model.cst.Let;
import de.uni_hildesheim.sse.model.cst.OCLFeatureCall;
import de.uni_hildesheim.sse.model.cst.Parenthesis;
import de.uni_hildesheim.sse.model.cst.UnresolvedExpression;
import de.uni_hildesheim.sse.model.cst.Variable;
import de.uni_hildesheim.sse.model.varModel.datatypes.OclKeyWords;

/**
 * Will find positive and negative declarations in a disjunction term.
 * If a operation is not supported, this visitor will throw a {@link RuntimeException}.
 * @author El-Sharkawy
 *
 */
class LiteralFinder implements IConstraintTreeVisitor {
    
    private static final String NEGATIVE_PREFIX = "not(";
    private static final String NEGATIVE_SUFFIX = ")";
    private boolean isPositive;
    private Set<String> declarations;

    /**
     * Sole constructor for this class, starts the search.
     * @param cst The {@link ConstraintSyntaxTree} where declarations shall be found.
     */
    public LiteralFinder(ConstraintSyntaxTree cst) {
        isPositive = true;
        declarations = new HashSet<String>();
        cst.accept(this);
    }
    
    /**
     * Returns all found declarations inside of the given constraint.
     * @return All declarations, negated declarations will be returned as negated declarations.
     */
    public Set<String> getDeclarations() {
        return declarations;
    }
    
    @Override
    public void visitConstantValue(ConstantValue value) {
        throw new RuntimeException("Not Supported Operation");
    }

    @Override
    public void visitVariable(Variable variable) {
        if (isPositive) {
            declarations.add(variable.getVariable().getName());
        } else {
            declarations.add(NEGATIVE_PREFIX + variable.getVariable().getName() + NEGATIVE_SUFFIX);
        }
    }

    @Override
    public void visitParenthesis(Parenthesis parenthesis) {
        throw new RuntimeException("Not Supported Operation");
    }

    @Override
    public void visitComment(Comment comment) {
        throw new RuntimeException("Not Supported Operation");
    }

    @Override
    public void visitOclFeatureCall(OCLFeatureCall call) {
        if (OclKeyWords.OR.equals(call.getOperation())) {
            call.getOperand().accept(this);
            for (int i = 0, n = call.getParameterCount(); i < n; i++) {
                call.getParameter(i).accept(this);
            }
        } else if (OclKeyWords.NOT.equals(call.getOperation())) {
            isPositive = !isPositive;
            call.getOperand().accept(this);
            for (int i = 0, n = call.getParameterCount(); i < n; i++) {
                call.getParameter(i).accept(this);
            }
            isPositive = !isPositive;
        } else {
            throw new RuntimeException("Not Supported Operation");
        }
    }

    @Override
    public void visitLet(Let let) {
        throw new RuntimeException("Not Supported Operation");
    }

    @Override
    public void visitIfThen(IfThen ifThen) {
        throw new RuntimeException("Not Supported Operation");
    }

    @Override
    public void visitContainerOperationCall(ContainerOperationCall call) {
        throw new RuntimeException("Not Supported Operation");
    }

    @Override
    public void visitCompoundAccess(CompoundAccess access) {
        throw new RuntimeException("Not Supported Operation");
    }

    @Override
    public void visitUnresolvedExpression(UnresolvedExpression expression) {
        throw new RuntimeException("Not Supported Operation");
    }

    @Override
    public void visitCompoundInitializer(CompoundInitializer initializer) {
        throw new RuntimeException("Not Supported Operation");
    }

    @Override
    public void visitContainerInitializer(ContainerInitializer initializer) {
        throw new RuntimeException("Not Supported Operation");
    }

}
