package org.etsi.t3q.visitor;

import java.util.LinkedList;

import org.etsi.t3q.T3Q;

import de.ugoe.cs.swe.trex.core.analyzer.rfparser.LocationAST;
import de.ugoe.cs.swe.trex.core.visitor.AbstractVisitor;
import de.ugoe.cs.swe.trex.core.visitor.TTCN3BehaviorException;

//TODO: substitute with upstream abstract visitor
public class T3QVisitor extends AbstractVisitor {

	private LinkedList<LocationAST> functionStatementOrDefNodes = new LinkedList<LocationAST>();
	private QualityChecker checker = new QualityChecker(this);
	private NamingConventionsChecker namingConventionsChecker = new NamingConventionsChecker(
			checker);

	private String filename;
	
	@Override
	public void finish() {
	}

	@Override
	public void init() {
		//TODO: Document feature
		checker.getLoggingInterface().setLogSourceName(this.getFilename());
		checker.stringLevelChecks(this.getFilename());
	}

	public ContinueStatus visitTTCN3Module(LocationAST node)
			throws TTCN3BehaviorException {
		if (T3Q.activeProfile.isCheckModuleSize()) {
			checker.checkModuleSize(node);
		}

		return ContinueStatus.getInstance(true, true);
	}

	public ContinueStatus visitModuleDefinition(LocationAST node)
			throws TTCN3BehaviorException {
		if (T3Q.activeProfile.isCheckNoDuplicatedModuleDefinitionIdentifiers()) {
			checker.checkNoDuplicatedModuleDefinitionIdentifiers(node);
		}
		if (T3Q.activeProfile.isCheckZeroReferencedModuleDefinitions()) {
			checker.checkZeroReferencedModuleDefinitions(node);
		}
		if (T3Q.activeProfile.isCheckLocalDefinitionsComeFirst()) {
			checker.checkLocalDefinitionsComeFirst(node);
		}
		if (T3Q.activeProfile.isCheckNoUnusedLocalDefinitions()) {
			checker.checkNoUnusedLocalDefinitions(node);
		}

		return ContinueStatus.getInstance(true, true);
	}

	public ContinueStatus visitSingleConstDef(LocationAST node)
			throws TTCN3BehaviorException {
		if (T3Q.activeProfile.isCheckNamingConventions()) {
			namingConventionsChecker.checkConstant(node);
		}

		return ContinueStatus.getInstance(true, true);
	}

	public ContinueStatus visitExtConstDef(LocationAST node)
			throws TTCN3BehaviorException {
		if (T3Q.activeProfile.isCheckNamingConventions()) {
			namingConventionsChecker.checkExtConstant(node);
		}

		return ContinueStatus.getInstance(true, true);
	}

	public ContinueStatus visitGroupDef(LocationAST node)
			throws TTCN3BehaviorException {
		if (T3Q.activeProfile.isCheckTypeDefOrderInGroup()) {
			checker.checkTypeDefOrderInGroup(node);
		}
		if (T3Q.activeProfile.isCheckNamingConventions()) {
			namingConventionsChecker.checkGroup(node);
		}
		return ContinueStatus.getInstance(true, true);
	}

	public ContinueStatus visitPortDef(LocationAST node)
			throws TTCN3BehaviorException {
		if (T3Q.activeProfile.isCheckNoAllKeywordInPortDefinitions()) {
			checker.checkNoAllKeywordInPortDefinitions(node);
		}

		if (T3Q.activeProfile.isCheckPortMessageGrouping()) {
			checker.checkPortMessageGrouping(node);
		}

		return ContinueStatus.getInstance(true, true);
	}

	public ContinueStatus visitPortInstance(LocationAST node)
			throws TTCN3BehaviorException {
		if (T3Q.activeProfile.isCheckNamingConventions()) {
			namingConventionsChecker.checkPortInstance(node);
		}

		return ContinueStatus.getInstance(true, true);
	}

	public ContinueStatus visitModuleParList(LocationAST node)
			throws TTCN3BehaviorException {
		if (T3Q.activeProfile.isCheckNamingConventions()) {
			namingConventionsChecker.checkModuleParameter(node);
		}
		return ContinueStatus.getInstance(true, true);
	}

	public ContinueStatus visitTTCN3ModuleId(LocationAST node) {
		if (T3Q.activeProfile.isFeatureListImportingModuleNames()) {
			checker.listImportingModuleNames(node);
		}
		if (T3Q.activeProfile.isFeatureListImportingModuleFileNames()) {
			checker.listImportingModuleFileNames(node);
		}
	
		if (T3Q.activeProfile.isCheckImportsComeFirst()) {
			checker.checkImportsComeFirst(node);
		}

		if (T3Q.activeProfile
				.isCheckTypesAndValuesModuleImportsLibNames()) {
			checker.checkTypesAndValuesModuleImportsLibCommon(node);
		}

		if (T3Q.activeProfile
				.isCheckTestcasesModuleImportsLibCommon_Sync()) {
			checker.checkTestcasesModuleImportsLibCommon_Sync(node);
		}

		if (T3Q.activeProfile
				.isCheckTypesAndValuesModuleContainmentCheck()) {
			checker.checkModuleContainment(node, "TypesAndValues");
		}
		if (T3Q.activeProfile.isCheckTemplatesModuleContainmentCheck()) {
			checker.checkModuleContainment(node, "Templates");
		}
		if (T3Q.activeProfile.isCheckFunctionsModuleContainmentCheck()) {
			checker.checkModuleContainment(node, "Functions");
		}
		if (T3Q.activeProfile.isCheckTestcasesModuleContainmentCheck()) {
			checker.checkModuleContainment(node, "Testcases");
		}
		if (T3Q.activeProfile.isCheckModuleParamsModuleContainmentCheck()) {
			checker.checkModuleContainment(node, "ModuleParams");
		}
		if (T3Q.activeProfile.isCheckInterfaceModuleContainmentCheck()) {
			checker.checkModuleContainment(node, "Interface");
		}
		if (T3Q.activeProfile.isCheckTestSystemModuleContainmentCheck()) {
			checker.checkModuleContainment(node, "TestSystem");
		}
		if (T3Q.activeProfile.isCheckTestControlModuleContainmentCheck()) {
			checker.checkModuleContainment(node, "TestControl");
		}
		if (T3Q.activeProfile.isCheckNamingConventions()) {
			namingConventionsChecker.checkModule(node);
		}
		return ContinueStatus.getInstance(true, true);
	}

	public ContinueStatus visitAltConstruct(LocationAST node)
			throws TTCN3BehaviorException {

		if (T3Q.activeProfile.isCheckNoNestedAltStatements()) {
			checker.checkNoNestedAltStatements(node);
		}

		return ContinueStatus.getInstance(true, true);
	}

	public ContinueStatus visitRunsOnSpec(LocationAST node)
			throws TTCN3BehaviorException {
		if (T3Q.activeProfile.isCheckNoOverSpecificRunsOnClauses()) {
			checker.checkNoOverSpecificRunsOnClauses(node);
		}

		return ContinueStatus.getInstance(true, true);
	}

	public ContinueStatus visitImportDef(LocationAST node)
			throws TTCN3BehaviorException {

		if (T3Q.activeProfile.isFeatureListImportedModuleNames()) {
			checker.listImportedModuleNames(node);
		}
		if (T3Q.activeProfile.isFeatureListImportedModuleFileNames()) {
			checker.listImportedModuleFileNames(node);
		}

		if (T3Q.activeProfile.isCheckNoUnusedImports()) {
			checker.checkNoUnusedImports(node);
		}

		return ContinueStatus.getInstance(true, true);
	}

	
	public ContinueStatus visitAnyTypeKeyword(LocationAST node)
			throws TTCN3BehaviorException {

		if (T3Q.activeProfile.isCheckNoAnyTypeKeyword()) {
			checker.checkNoAnyTypeKeyword(node);
		}

		return ContinueStatus.getInstance(true, true);
	}

	public ContinueStatus visitVarInstance(LocationAST node)
			throws TTCN3BehaviorException {
		if (T3Q.activeProfile.isCheckNamingConventions()) {
			namingConventionsChecker.checkVariable(node);
		}

		return ContinueStatus.getInstance(true, true);
	}

	public ContinueStatus visitTimerInstance(LocationAST node)
			throws TTCN3BehaviorException {
		if (T3Q.activeProfile.isCheckNamingConventions()) {
			namingConventionsChecker.checkTimer(node);
		}

		return ContinueStatus.getInstance(true, true);
	}

	public ContinueStatus visitInLineTemplate(LocationAST node)
			throws TTCN3BehaviorException {
		if (T3Q.activeProfile.isCheckNoInlineTemplates()) {
			checker.checkNoInlineTemplates(node);
		}

		return ContinueStatus.getInstance(true, true);
	}

	public ContinueStatus visitTemplateDef(LocationAST node)
			throws TTCN3BehaviorException {
		if (T3Q.activeProfile.isCheckNamingConventions()) {
			namingConventionsChecker.checkMessageTemplate(node);
		}
		if (T3Q.activeProfile.isCheckNamingConventions()) {
			namingConventionsChecker.checkSTF160Template(node);
		}

		return ContinueStatus.getInstance(true, true);
	}

	public ContinueStatus visitDerivedDef(LocationAST node)
			throws TTCN3BehaviorException {

		if (T3Q.activeProfile
				.isCheckNoModifiedTemplateOfModifiedTemplate()) {

			checker.checkNoModifiedTemplateOfModifiedTemplate(node);
		}

		return ContinueStatus.getInstance(true, true);
	}

	public ContinueStatus visitExtFunctionDef(LocationAST node)
			throws TTCN3BehaviorException {
		if (T3Q.activeProfile.isCheckNamingConventions()) {
			namingConventionsChecker.checkExtFunction(node);
		}

		return ContinueStatus.getInstance(true, true);
	}

	public ContinueStatus visitSignatureDef(LocationAST node)
			throws TTCN3BehaviorException {
		if (T3Q.activeProfile.isCheckNamingConventions()) {
			namingConventionsChecker.checkSignatureTemplate(node);
		}

		return ContinueStatus.getInstance(true, true);
	}

	public ContinueStatus visitFormalValuePar(LocationAST node)
			throws TTCN3BehaviorException {
		if (T3Q.activeProfile.isCheckNamingConventions()) {
			namingConventionsChecker.checkFormalParameter(node);
		}
		if (T3Q.activeProfile.isCheckNoUnusedFormalParameters()) {
			checker.checkNoUnusedFormalParameters(node);
		}

		return ContinueStatus.getInstance(true, true);
	}

	public ContinueStatus visitFormalTemplatePar(LocationAST node)
			throws TTCN3BehaviorException {
		if (T3Q.activeProfile.isCheckNamingConventions()) {
			namingConventionsChecker.checkFormalParameter(node);
		}
		if (T3Q.activeProfile.isCheckNoUnusedFormalParameters()) {
			checker.checkNoUnusedFormalParameters(node);
		}

		return ContinueStatus.getInstance(true, true);
	}

	public ContinueStatus visitFormalTimerPar(LocationAST node)
			throws TTCN3BehaviorException {
		if (T3Q.activeProfile.isCheckNamingConventions()) {
			namingConventionsChecker.checkFormalParameter(node);
		}
		if (T3Q.activeProfile.isCheckNoUnusedFormalParameters()) {
			checker.checkNoUnusedFormalParameters(node);
		}

		return ContinueStatus.getInstance(true, true);
	}

	public ContinueStatus visitFormalPortPar(LocationAST node)
			throws TTCN3BehaviorException {
		if (T3Q.activeProfile.isCheckNoUnusedFormalParameters()) {
			checker.checkNoUnusedFormalParameters(node);
		}
		return ContinueStatus.getInstance(true, true);
	}

	public ContinueStatus visitPredefinedValue(LocationAST node)
			throws TTCN3BehaviorException {
		if (T3Q.activeProfile.isCheckNoLiterals()) {
			checker.checkNoLiterals(node);
		}
		return ContinueStatus.getInstance(true, true);
	}
	

	public ContinueStatus visitTypeDef(LocationAST node)
			throws TTCN3BehaviorException {
		if (T3Q.activeProfile.isCheckNamingConventions()) {
			namingConventionsChecker.checkDataType(node);
		}

		return ContinueStatus.getInstance(true, true);
	}

	public ContinueStatus visitEnumeration(LocationAST node)
			throws TTCN3BehaviorException {
		if (T3Q.activeProfile.isCheckNamingConventions()) {
			namingConventionsChecker.checkEnumeratedValue(node);
		}

		return ContinueStatus.getInstance(true, true);
	}
	
	public ContinueStatus visitStatementBlock(LocationAST node)
			throws TTCN3BehaviorException {
		functionStatementOrDefNodes.clear();
		return ContinueStatus.getInstance(true, true);
	}

	public ContinueStatus visitFunctionDef(LocationAST node)
			throws TTCN3BehaviorException {
		functionStatementOrDefNodes.clear();
		if (T3Q.activeProfile.isCheckNamingConventions()) {
			namingConventionsChecker.checkFunction(node);
		}
		return ContinueStatus.getInstance(true, true);
	}

	public ContinueStatus visitTestcaseDef(LocationAST node)
			throws TTCN3BehaviorException {
		functionStatementOrDefNodes.clear();
		if (T3Q.activeProfile.isCheckNamingConventions()) {
			namingConventionsChecker.checkTestcase(node);
		}
		return ContinueStatus.getInstance(true, true);
	}

	public ContinueStatus visitAltstepDef(LocationAST node)
			throws TTCN3BehaviorException {
		functionStatementOrDefNodes.clear();
		if (T3Q.activeProfile.isCheckNamingConventions()) {
			namingConventionsChecker.checkAltstep(node);
		}
		return ContinueStatus.getInstance(true, true);
	}

	public ContinueStatus visitModuleControlPart(LocationAST node)
			throws TTCN3BehaviorException {
		functionStatementOrDefNodes.clear();

		return ContinueStatus.getInstance(true, true);
	}

	public ContinueStatus visitModuleControlBody(LocationAST node)
			throws TTCN3BehaviorException {

		if (T3Q.activeProfile.isCheckLocalDefinitionsComeFirst()) {
			checker.checkLocalDefinitionsComeFirstWithinControlPart(node);
		}
		if (T3Q.activeProfile.isCheckNoUnusedLocalDefinitions()) {
			checker.checkNoUnusedLocalDefinitions(node);
		}

		return ContinueStatus.getInstance(true, true);
	}
	
	
	
	public ContinueStatus visitFunctionRef(LocationAST node)
			throws TTCN3BehaviorException {

		if (T3Q.activeProfile
				.isCheckExternalFunctionInvocationPrecededByLogStatement()) {

			checker.checkExternalFunctionInvocationPrecededByLogStatement(node);
		}

		return ContinueStatus.getInstance(true, true);
	}

	public ContinueStatus visitGotoStatement(LocationAST node)
			throws TTCN3BehaviorException {

		if (T3Q.activeProfile.isCheckNoLabelsOrGotoStatements()) {
			checker.checkNoGotoStatements(node);
		}

		return ContinueStatus.getInstance(true, true);
	}

	public ContinueStatus visitLabelStatement(LocationAST node)
			throws TTCN3BehaviorException {

		if (T3Q.activeProfile.isCheckNoLabelsOrGotoStatements()) {
			checker.checkNoLabelStatements(node);
		}

		return ContinueStatus.getInstance(true, true);
	}

	public ContinueStatus visitLogItem(LocationAST node)
			throws TTCN3BehaviorException {

		if (T3Q.activeProfile.isCheckLogItemFormat()) {
			checker.checkLogItemFormat(node);
		}
		return ContinueStatus.getInstance(true, true);
	}
	
	public ContinueStatus visitLogStatement(LocationAST node)
			throws TTCN3BehaviorException {
		//TODO: Temporary/TEMEA+Enhancements
		//may also be adopted instead of log item checking
		if (T3Q.activeProfile.isCheckLogStatementFormat()) {
			checker.checkLogStatementFormat(node);
		}
		return ContinueStatus.getInstance(true, true);
	}

	public ContinueStatus visitPermutationMatch(LocationAST node)
			throws TTCN3BehaviorException {

		if (T3Q.activeProfile.isCheckNoPermutationKeyword()) {
			checker.checkNoPermutationKeyword(node);
		}

		return ContinueStatus.getInstance(true, true);
	}

	public ContinueStatus visitSetLocalVerdict(LocationAST node)
			throws TTCN3BehaviorException {

		if (T3Q.activeProfile
				.isCheckInconcOrFailSetVerdictPrecededByLog()) {
			checker.checkInconcOrFailSetVerdictPrecededByLog(node);
		}

		return ContinueStatus.getInstance(true, true);
	}

	public ContinueStatus visitFunctionStatementOrDef(LocationAST node)
			throws TTCN3BehaviorException {
		//TODO: deprecated
		functionStatementOrDefNodes.add(node);
		return ContinueStatus.getInstance(true, true);
	}

	public ContinueStatus visitFunctionStatement(LocationAST node)
			throws TTCN3BehaviorException {

		functionStatementOrDefNodes.add(node);
		return ContinueStatus.getInstance(true, true);
	}	
	
	public ContinueStatus visitFunctionLocalInst(LocationAST node)
			throws TTCN3BehaviorException {

		functionStatementOrDefNodes.add(node);
		return ContinueStatus.getInstance(true, true);
	}	

	public ContinueStatus visitFunctionLocalDef(LocationAST node)
			throws TTCN3BehaviorException {

		functionStatementOrDefNodes.add(node);
		return ContinueStatus.getInstance(true, true);
	}
	
	
	public LinkedList<LocationAST> getFunctionStatementOrDefNodes() {
		return functionStatementOrDefNodes;
	}

	public void setFilename(String filename) {
		this.filename = filename;
	}

	public String getFilename() {
		return filename;
	}



}
