/*******************************************************************************
 * Copyright (c) 2015-2017 ONERA and IRT AESE (IRT Saint Exupéry).
 * Ce logiciel est la propriété de l’ONERA (the French Aerospace Lab) et de
 * l'IRT AESE (IRT Saint Exupéry).
 * Tous droits réservés.
 *
 * Ce programme et les éléments qui l'accompagnent sont mis à disposition
 * aux conditions définies par le contrat de licence logiciel CeCILL-C soumise
 * au droit français et respectant les principes de diffusion des logiciels libres.
 * Vous pouvez utiliser, modifier et/ou redistribuer ce programme
 * sous les conditions de la licence CeCILL-C (http://www.cecill.info).

 * This software is property of ONERA (the French Aerospace Lab) and of
 * the IRT AESE (IRT Saint Exupéry).
 * All rights reserved.
 *
 * This program and the accompanying materials are made available under
 * the terms of the CeCILL-C license under French law and
 * abiding by the rules of distribution of free software.
 * You can  use, modify and/ or redistribute the software under the terms of
 * the CeCILL-C license (http://www.cecill.info).
 *
 * Contributeurs/contributors:
 *     Guillaume Infantes (ONERA - Centre de Toulouse) - initial API and implementation
 *     Alexandre Albore (IRT Saint-Exupéry) - Altarica/Fiacre translation
 *
 *******************************************************************************/

#include "Transition.hh"
#include "Node.hh"
#include "AltaricaState.hh"
#include "Values.hh"
#include "Event.hh"
#include "Assignment.hh"
#include "expressions/Expression.hh"
#include "AltaricaException.hh"


namespace epoch {
    namespace altarica {
    
	Transition::Transition(Expression *precond) {
	    precond_ = precond;
	    node_ = NULL;
	    //	    stateVarsInPrecond = NULL;
	}

	Transition::Transition() {
	    node_ = NULL;
	    //	    stateVarsInPrecond = NULL;
	}

	void Transition::setPrecond(Expression *precond) {
	    precond_ = precond;
	}
	
	void Transition::addEvent(Event* e) {
	    eventList_.push_back(e);
	    e->addTrans(this);
	}

	void Transition::addEvents(std::vector<Event*>* ve) {
	    for (std::vector<Event*>::iterator i = ve->begin();	 i != ve->end(); ++i) 
	    eventList_.push_back(*i);
	}

	void Transition::addAssignment(Assignment  *a) {
	    assignmentList_.push_back(a);
	    a->setNode(node_);
	}

	void Transition::addAssignments(std::vector<Assignment*>  *va) {
	    for (std::vector<Assignment*>::iterator i = va->begin();
		 i != va->end(); ++i)
	    assignmentList_.push_back(*i);
	}


	Transition * Transition::clone() {
	    Transition * n = new Transition(precond_);
	    for (std::vector<Event*>::iterator it = eventList_.begin();
		 it != eventList_.end(); ++it)
		n->addEvent(*it);

	    for (std::vector<Assignment*>::iterator it = assignmentList_.begin();
		 it != assignmentList_.end(); ++it)
		n->addAssignment((*it)->clone());

	    for (std::vector<MemberAccess*>::iterator it = eventNames_.begin();
		 it != eventNames_.end(); ++it)
		n->addEventName((*it)->clone());
	    
	    return n;
	}

	void Transition::addEventName(MemberAccess*ma) {
	    eventNames_.push_back(ma);
	}

	void Transition::addEventNames(std::vector<MemberAccess *> *mav) {
	    for (std::vector<MemberAccess*>::iterator i = mav->begin(); i!= mav->end(); ++i)
	 	eventNames_.push_back(*i);
	}

	void Transition::setNode(Node*n) {
	    node_ = n;
	    for (std::vector<Assignment*>::iterator i = assignmentList_.begin(); i!=assignmentList_.end(); ++i)
		(*i)->setNode(n);
	    for (std::vector<Event*>::iterator i = eventList_.begin(); i!=eventList_.end(); ++i)
		(*i)->setNode(n);
	    
	}

	void Transition::matchEvents() {
//	  if (eventList_.size() != 0)
//      eventList_.clear();    
	    // we have only events names for now, we need to add corresponding events in node
	    for (std::vector<MemberAccess*>::const_iterator i = eventNames_.begin(); 
		 i!=eventNames_.end(); ++i) {
		Event *e = node_->findEventByName(*i);
    if (e == NULL) {
      std::string s = "cannot find event: ";
      s+= (*i)->toString();      
      throw AltaricaException(s, "epoch::altarica::Transition::matchEvents()");
      
    }
		addEvent(e);
		//		e->addTrans(this);		
	    }	    
	}

	// void Transition::cachePrecond() {
	//     stateVarsInPrecond = precond_->infoVars(node_,false,false);
	// }

	bool Transition::precondOK(const AltaricaModel *am, AltaricaState *s) const {
	    ValueBool * fv = (ValueBool*) precond_->evaluate(am, s,node_);
	    bool res = fv->allowedTop();
	    Value::deleteIfPossible(fv);
	    return res;
	}


	void Transition::doTransition(const AltaricaModel *am, AltaricaState *ps, AltaricaState *ns) {
	    // if (!ps->isMacro()) {
		for (std::vector<Assignment*>::iterator ai = assignmentList_.begin();
		     ai != assignmentList_.end(); ++ai) 		
		    ns->setValue((*ai)->getVar(), (*ai)->evaluate(am, ps));
	    // } else {	
	    // 	for (std::vector<Assignment*>::iterator ai = assignmentList_.begin();
	    // 	     ai != assignmentList_.end(); ++ai) 		
	    // 	    ns->addValue((*ai)->getVar(), (*ai)->evaluate(ps));
	    // }
	}



	void Transition::deleteExprs() {
	    delete precond_ ;
	    for (std::vector<Assignment*>::iterator i = assignmentList_.begin(); i != assignmentList_.end(); ++i) 
		(*i)->deleteExprs();	    	    
	}

	Transition::~Transition() {
	    for (std::vector<MemberAccess*>::iterator i = eventNames_.begin();
		 i!= eventNames_.end(); ++i)
		delete *i;
	    for (std::vector<Assignment*>::iterator i = assignmentList_.begin(); i != assignmentList_.end(); ++i) {
		delete (*i);
	    }
	}

	std::string Transition::toString() const {
	    std::string s;
	    s += "NODE "+ node_->toString() + "\n";
	    for (std::vector<MemberAccess*>::const_iterator i = eventNames_.begin(); i!=eventNames_.end(); ++i) {
		s+= (*i)->toString() + "; ";
	    }
	    return s;
	}

	std::string Transition::toFiacre() const {
	    std::string s;
	    s += "NODE "+ node_->toString() + "\n";
	    for (std::vector<MemberAccess*>::const_iterator i = eventNames_.begin(); i!=eventNames_.end(); ++i) {
	    	s+= (*i)->toString() + "; "; //node_
	    }
	    return s;
	}

    }
}


