/*******************************************************************************
 * 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 "ExpressionInfoVar.hh"
#include "Expressions.hh"
#include "../Node.hh"
#include "../Variable.hh"


using namespace epoch::altarica;

ExpressionInfoVar::ExpressionInfoVar(bool flow, bool computed, const AltaricaModel* am, AltaricaState *s, const Node*n) : EvaluationVisitor (am, s,n) {
    n_ = n;
    flow_ = flow;
    computed_ = computed;
    vars_ = new std::vector<Variable*>();
}


void ExpressionInfoVar::visitADD(const ExpressionADD *e) {
    e->getLeft()->accept(this);
    e->getRight()->accept(this);
}



void ExpressionInfoVar::visitAND(const ExpressionAND *e) {
    e->getLeft()->accept(this);
    e->getRight()->accept(this);
}

void ExpressionInfoVar::visitARITH(const ExpressionARITH *e) {  
    e->getLeft()->accept(this);
    e->getRight()->accept(this);
}



void ExpressionInfoVar::visitBOOLCONSTANT(const ExpressionBOOLCONSTANT *e) {
    // NOTHING TO BE DONE (nothing to add)
}

void ExpressionInfoVar::visitCARD(const ExpressionCARD *e) {
    if (computed_)
	return;
    const std::vector<Expression*> * exprs = e->getExprs();
    if (exprs->size() == 0)
	return;
    for (std::vector<Expression*>::const_iterator i = exprs->begin(); i!=exprs->end(); ++i)
	(*i)->accept(this);    
}

void ExpressionInfoVar::visitCONSTARRAY(const ExpressionCONSTARRAY *e) {
    // NOTHING TO ADD
}

void ExpressionInfoVar::visitCONSTSTRUCT(const ExpressionCONSTSTRUCT *e) {
    // NOTHING TO ADD
}

void ExpressionInfoVar::visitCASE(const ExpressionCASE *e) {
    const std::vector<Expression*> * conds = e->getConds();
    const std::vector<Expression*> * thens = e->getThens();
    const Expression * eelse = e->getElse();
    std::vector<Expression*>::const_iterator i;
    for ( i = conds->begin(); i!= conds->end(); ++i)
	(*i)->accept(this);
    for ( i = thens->begin(); i!= thens->end(); ++i)
	(*i)->accept(this);
    if (eelse != NULL)
    eelse->accept(this);        
}

void ExpressionInfoVar::visitFUNCTIONCALL(const ExpressionFUNCTIONCALL *e) {
    BOOST_THROW_EXCEPTION(std::runtime_error("function call info not implemented"));
}

void ExpressionInfoVar::visitIfThenElse(const ExpressionIfThenElse *e) {
    e->getIf()->accept(this);
    e->getThen()->accept(this);
    const Expression* eelse = e->getElse();
    if (eelse != NULL)
    eelse->accept(this);    
}

void ExpressionInfoVar::visitLOG(const ExpressionLOG *e) {
    ExpressionInfoVar eiv( flow_, false,  amodel_,state_, node_);    
    e->getLeft()->accept(&eiv);
    vars_->insert(vars_->end(), eiv.getVars()->begin(),eiv.getVars()->end());
    delete (eiv.getVars());
    if (computed_)
	return;    
    e->getRight()->accept(this);
}
void ExpressionInfoVar::visitMEMBER(const ExpressionMEMBER *e) {
    if (computed_)
	return ;    
    Variable *v = node_->findFlowVariableByName(e->getMA());
    if (flow_) {
	if (v != NULL) 
	    vars_->push_back(v);
    } else {
	if (v != NULL) {	    
	    std::vector<Variable*> * sv = v->infoVars(amodel_, node_,false, computed_);
	    vars_->insert(vars_->end(), sv->begin(), sv->end());
	    delete (sv);
	} else {
	    v = node_->findStateVariableByName(e->getMA());
	    if (v != NULL) 
		vars_->push_back(v);
	}
    }
}

void ExpressionInfoVar::visitMINMAX(const ExpressionMINMAX *e) {
    if (computed_)
	return;
    for (std::vector<Expression*>::const_iterator i = e->getExprs()->begin(); i!= e->getExprs()->end(); ++i)
	(*i)->accept(this);
}


void ExpressionInfoVar::visitMUL(const ExpressionMUL *e) {
    e->getLeft()->accept(this);
    e->getRight()->accept(this);
}

void ExpressionInfoVar::visitOR(const ExpressionOR *e) {
    e->getLeft()->accept(this);
    e->getRight()->accept(this);
}

void ExpressionInfoVar::visitPAREN(const ExpressionPAREN *e) {
    e->getExpr()->accept(this);
}

void ExpressionInfoVar::visitQUANTIFIED(const ExpressionQUANTIFIED *e) {
     BOOST_THROW_EXCEPTION(std::runtime_error("expression quantified info not implemented"));
}

void ExpressionInfoVar::visitUNSIGNEDINT(const ExpressionUNSIGNEDINT *e) {
    return;
}

void ExpressionInfoVar::visitREAL(const ExpressionREAL *e) {
    return;
}

void ExpressionInfoVar::visitUNARY(const ExpressionUNARY *e) {
    e->getBelow()->accept(this);
}

void ExpressionInfoVar::visitINTERVAL(const ExpressionINTERVAL *e) {
    return;
}
