package de.ugoe.cs.swe.bnftools.analysis;

import java.util.ArrayList;
import java.util.List;

import org.eclipse.xtext.resource.IReferenceDescription;
import org.eclipse.xtext.resource.IResourceDescription;
import org.eclipse.xtext.resource.IResourceDescriptions;

import de.ugoe.cs.swe.bnftools.ebnf.Atom;
import de.ugoe.cs.swe.bnftools.ebnf.DefinitionList;
import de.ugoe.cs.swe.bnftools.ebnf.Rule;
import de.ugoe.cs.swe.bnftools.ebnf.RuleReference;
import de.ugoe.cs.swe.bnftools.ebnf.SingleDefinition;
import de.ugoe.cs.swe.bnftools.ebnf.StringRule;
import de.ugoe.cs.swe.bnftools.ebnf.Term;

public class EbnfAnalysisUtils {

	//----------------------------------------------------------------------------------------------------

	static public boolean isPassthroughRule(Rule rule) {
		DefinitionList definitionList = rule.getDefinitionList();
		if (definitionList == null)
			return false;
		
		if (rule.getDefinitionList().getSingleDefinition().size() == 1) {
			SingleDefinition element = rule.getDefinitionList().getSingleDefinition().get(0);
			if (element.getTerms().size() == 1) {
				Term first = element.getTerms().get(0);
				if (first.getTermAtom() != null) {
					Atom atom = (Atom) first.getTermAtom();
					if (atom.getAtomRuleReference() != null)
						return true;
				}
			}
		}

		return false;
	}

	//----------------------------------------------------------------------------------------------------

	static public RuleReference getPassthroughRuleReference(Rule rule) {
		DefinitionList definitionList = rule.getDefinitionList();
		if (definitionList == null)
			return null;
		
		if (rule.getDefinitionList().getSingleDefinition().size() == 1) {
			SingleDefinition element = rule.getDefinitionList().getSingleDefinition().get(0);
			if (element.getTerms().size() == 1) {
				Term first = element.getTerms().get(0);
				if (first.getTermAtom() != null) {
					Atom atom = (Atom) first.getTermAtom();
					if (atom.getAtomRuleReference() != null)
						return atom.getAtomRuleReference();
				}
			}
		}

		return null;
	}
	
	//----------------------------------------------------------------------------------------------------

	static public boolean isTokenRule(Rule rule) {
		DefinitionList definitionList = rule.getDefinitionList();
		if (definitionList == null)
			return false;
		
		if (rule.getDefinitionList().getSingleDefinition().size() == 1) {
			SingleDefinition element = rule.getDefinitionList().getSingleDefinition().get(0);
			if (element.getTerms().size() == 1) {
				Term first = element.getTerms().get(0);
				Atom atom = first.getTermAtom();
				if (atom != null && atom.getAtomStringRule() != null)  {
					return true;
				}
			}
		}

		return false;
	}

	//----------------------------------------------------------------------------------------------------

	static public StringRule getTokenRuleTerminal(Rule rule) {
		DefinitionList definitionList = rule.getDefinitionList();
		if (definitionList == null)
			return null;
		
		if (rule.getDefinitionList().getSingleDefinition().size() == 1) {
			SingleDefinition element = rule.getDefinitionList().getSingleDefinition().get(0);
			if (element.getTerms().size() == 1) {
				Term first = element.getTerms().get(0);
				if ((first.getTermAtom() != null) && (first.getTermAtom().getAtomStringRule() != null)) {
					StringRule stringRule = first.getTermAtom().getAtomStringRule();
					return stringRule;
				}
			}
		}

		return null;
	}

	//----------------------------------------------------------------------------------------------------

	static public List<Rule> findReferences(Rule rule, IResourceDescriptions resourceDescriptions) {
		List<Rule> ruleReferences = new ArrayList<Rule>();
		
		final String ruleURIF = rule.eResource().getURIFragment(rule);
		
		for (IResourceDescription resourceDescription : resourceDescriptions
				.getAllResourceDescriptions()) {
			if (!resourceDescription.getURI().equals(rule.eResource().getURI()))
				continue;
			
			for (IReferenceDescription referenceDescription : resourceDescription
					.getReferenceDescriptions()) {
				if (ruleURIF.equals(referenceDescription.getTargetEObjectUri()
						.fragment())) {
					ruleReferences.add((Rule) rule.eResource().getEObject(referenceDescription.getTargetEObjectUri().fragment()));
				}

			}
		}
		return ruleReferences;
	}

}
