/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package uce.parser;

import java.io.ByteArrayOutputStream;
import java.math.BigInteger;
import java.util.List;
import javax.xml.bind.JAXB;
import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.Duration;
import javax.xml.datatype.XMLGregorianCalendar;
import org.antlr.runtime.tree.CommonTree;
import usecase.Condition;
import usecase.ConditionSet;
import usecase.Extension;
import usecase.ObjectFactory;
import usecase.OntValueCondition;
import usecase.OntoPhrase;
import usecase.Quantifier;
import usecase.SpecificTime;
import usecase.Statement;
import usecase.StatementText;
import usecase.StatementText.ObjectPhrase;
import usecase.TimeType;
import usecase.UseCase;
import usecase.ValueRelation;

/**
 *
 * @author Chetan Pawgi
 */
public class UseCasePrinter {

	private ObjectFactory m_ObjFactory = new ObjectFactory();
	private DatatypeFactory m_DataFactory;

	{
		try {
			m_DataFactory = DatatypeFactory.newInstance();
		} catch (DatatypeConfigurationException ex) {
			ex.printStackTrace();
		}
	}

	public ObjectFactory getObjectFactory() {
		return m_ObjFactory;
	}

	public String getXmlFromUseCase(UseCase useCase) {
		ByteArrayOutputStream stream = new ByteArrayOutputStream();
		JAXB.marshal(useCase, stream);
		return stream.toString();
	}

	public void processStatement(CommonTree tree, List<Statement> lstStatements) {
		if (tree == null) {
			return;
		}
		Statement stmt = m_ObjFactory.createStatement();
		StatementText text = m_ObjFactory.createStatementText();
		internalprocessStatement(tree, text);
		stmt.setText(text);
		lstStatements.add(stmt);
	}

	private Condition createCondition(String condnText) {
		Condition cond = m_ObjFactory.createCondition();
		if (condnText.startsWith("AFTER")) {
			String aftTime = condnText.substring("AFTER".length()).trim();
			Duration duration = m_DataFactory.newDuration(aftTime);
			cond.setAfterTime(duration);
		} else if (condnText.startsWith("WHEN")) {
			String[] arrValue = condnText.substring("WHEN".length()).split("[=]");
			XMLGregorianCalendar cal = m_DataFactory.newXMLGregorianCalendar(arrValue[1]);
			if (arrValue[0].trim().equals("_TIME")) {
				cond.setWhenTime(cal);
			} else if (arrValue[0].trim().equals("_DATE_TIME")) {
				cond.setWhenDateTime(cal);
			}
		}
		return cond;
	}

	public void processCondition(CommonTree tree, String condnText, ConditionSet condnSet) {
		if (condnText.startsWith("WHEN") || condnText.startsWith("AFTER")) {
			condnSet.getCondition().add(createCondition(condnText));
		} else {
			condnSet.getCondition().add(createCondition(tree));
		}
	}

	private OntoPhrase createOntoPhrase(CommonTree tree) {
		OntoPhrase oPhrase = m_ObjFactory.createOntoPhrase();
		oPhrase.setQuantifier(Quantifier.SPECIFIC);
		if (tree.getText().equals("ALLOC") || tree.getText().equals("SPECOC")) {
			oPhrase.setConcept(tree.getChild(0).getChild(0).getText());
			if (tree.getText().equals("ALLOC")) {
				oPhrase.setQuantifier(Quantifier.EVERY);
			}
		} else if (tree.getText().equals("OC")) {
			oPhrase.setConcept(tree.getChild(0).getText());
		} else if (tree.getText().equals("OAP")) {
			OntoPhrase.AttribConcept attribConcept = m_ObjFactory.createOntoPhraseAttribConcept();
			attribConcept.setAttribute(tree.getChild(0).getText());
			attribConcept.setConcept(tree.getChild(1).getChild(0).getText());
			oPhrase.setAttribConcept(attribConcept);
		}
		return oPhrase;
	}

	private ObjectPhrase createObjectPhrase(CommonTree tree) {
		ObjectPhrase phrase = m_ObjFactory.createStatementTextObjectPhrase();
		if (tree.getChild(0).getText().equals("OAXP")) {
			OntoPhrase oPhrase = m_ObjFactory.createOntoPhrase();
			oPhrase.setQuantifier(Quantifier.EVERY);
			OntoPhrase.AttribConcept attribConcept = m_ObjFactory.createOntoPhraseAttribConcept();
			attribConcept.setAttribute(tree.getChild(0).getChild(0).getText());
			attribConcept.setConcept(tree.getChild(0).getChild(1).getChild(0).getChild(0).getText());
			oPhrase.setAttribConcept(attribConcept);
			phrase.setOntoPhrase(oPhrase);
		} else if (tree.getChild(0).getText().equals("ALLOC") || tree.getChild(0).getText().equals("SPECOC") || tree.getChild(0).getText().equals("OC") || tree.getChild(0).getText().equals("OAP")) {
			phrase.setOntoPhrase(createOntoPhrase((CommonTree) tree.getChild(0)));
		} else if (tree.getChild(0).getText().equals("OVP")) {
			CommonTree tOVP = (CommonTree) tree.getChild(0);
			OntValueCondition vCond = m_ObjFactory.createOntValueCondition();
			vCond.setLvalue(createOntoPhrase((CommonTree) tOVP.getChild(0).getChild(0)));
			vCond.setRvalue(tOVP.getChild(0).getChild(1).getText());
			String strRel = tOVP.getChild(0).getText();
			strRel = strRel.toLowerCase().contains("by") ? "BY" : "TO";
			vCond.setRelation(ValueRelation.fromValue(strRel));
			phrase.setOntValueCondition(vCond);
		}
		return phrase;
	}

	private Condition createCondition(CommonTree tree) {
		Condition cond = m_ObjFactory.createCondition();
		OntValueCondition vCond = m_ObjFactory.createOntValueCondition();
		vCond.setLvalue(createOntoPhrase((CommonTree) tree.getChild(0)));
		vCond.setRvalue(tree.getChild(1).getText());
		if (tree.getText().contains("IS_NOT")) {
			vCond.setRelation(ValueRelation.IS_NOT);
		} else if (tree.getText().contains("IS")) {
			vCond.setRelation(ValueRelation.IS);
		} else if (tree.getText().contains("NOTEQUALS")) {
			vCond.setRelation(ValueRelation.NOTEQUALS);
		} else if (tree.getText().contains("EQUAL_TO")) {
			vCond.setRelation(ValueRelation.EQUAL_TO);
		}
		cond.setOntValueCondition(vCond);
		return cond;
	}

	private Extension createExtension(CommonTree tree) {
		Extension extension = m_ObjFactory.createExtension();
		if (tree.getText().equals("TIME")) {
			SpecificTime time = m_ObjFactory.createSpecificTime();
			time.setQuantity(new BigInteger(tree.getChild(0).getText()));
			time.setUnitOftime(TimeType.fromValue(tree.getChild(1).getText().toUpperCase()));
			extension.setFor(time);
		} else if (tree.getText().equals("COND")) {
			ConditionSet condition_set = m_ObjFactory.createConditionSet();
			List<Condition> lstCond = condition_set.getCondition();
			for (Object c : ((CommonTree) tree.getChild(0)).getChildren()) {
				CommonTree child = (CommonTree) c;
				Condition cond = createCondition(child);
				lstCond.add(cond);
			}
			extension.setUntil(condition_set);
		}
		return extension;
	}

	private void internalprocessStatement(CommonTree tree, StatementText sentence) {
		if (tree == null) {
			return;
		}
		//JOptionPane.showMessageDialog(null, tree.getText());
		String text = tree.getText();
		if (text.equals("SIMPLEAP")) {
			sentence.setActor(tree.getChild(0).getChild(0).getText());
			sentence.setAction(tree.getChild(1).getText());
			if (tree.getChildCount() >= 3) {
				if (!tree.getChild(2).getText().equals("EXT")) {
					sentence.setObjectPhrase(createObjectPhrase((CommonTree) tree.getChild(2)));
				}
				Extension extension = createExtension((CommonTree) tree.getChild(tree.getChildCount() - 1).getChild(0));
				sentence.setExtension(extension);
			}
			return;
		}
	}
}
