/*******************************************************************************
 * 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 <algorithm>
#include <sstream>
#include <iostream>

#include "AltaricaInitInfo.hh"
#include "AltaricaException.hh"
#include "AltaricaModel.hh"
#include "EventLaw.hh"
#include "Event.hh"
#include "Variable.hh"
#include "values/Value.hh"
#include "MemberAccess.hh"
#include "domains/Domains.hh"
#include "Values.hh"


using namespace epoch::altarica;

void AltaricaInitInfo::overrideLaws() {
  for (auto  i : initLaws)
    (i.first)->setLaw(i.second);
}

Value * AltaricaInitInfo::getInitValue(unsigned int i) const {
  std::map<unsigned int, Value*>::const_iterator j = initValues.find(i);
  if (j!=initValues.end())
    return j->second;
  return NULL;
}


std::string AltaricaInitInfo::toString() const {
  std::ostringstream oss;
  oss <<  std::endl
      << "INIT VALUES:" << std::endl;
  for (auto i: initValues) {
    oss << amodel->getStateVar(i.first)->toString()
        << " = " << i.second->toString()
        << std::endl;
  }
  oss << "INIT LAWS:" << std::endl;
  for (auto  i: initLaws) {
    oss << i.first->toString() << " : "
        << i.second->toString() << std::endl;
  }
  return oss.str();
}

Value * AltaricaInitInfo::getValue(Variable *var, std::string valName) {

  Value * v;
  Domain *d = var->getDomain();
  if (d != NULL) {
    PredefinedDomain *pd = dynamic_cast<PredefinedDomain*>(d);
    EnumDomain *ed = dynamic_cast<EnumDomain*>(d);
    RangeDomain *rd = dynamic_cast<RangeDomain*>(d);
    ArrayDomain *ad = dynamic_cast<ArrayDomain*>(d);
    StructuredDomain *sd = dynamic_cast<StructuredDomain*>(d);
    RealDomain *reald = dynamic_cast<RealDomain*>(d);

    if (pd) {
      if (pd->isBooleanDomain()) {
        // scan true of false from valName
        std::transform(valName.begin(),
                       valName.end(),
                       valName.begin(),
                       ::toupper);
        if (valName.compare("TRUE") == 0)
          v = new ValueBool(true, false);
        else
          v = new ValueBool(false, true);
      } else {
        //scan int from valName
        std::istringstream stm;
        int i;
        stm.str(valName);
        stm >>i;
        v = new ValueInt(i);
      }
    } else if (ed) {
      v = new ValueSymbol(valName);
    } else if (rd) {
      //scan int from valName
      std::istringstream stm;
      int i;
      stm.str(valName);
      stm >>i;
      v = new ValueInt(i);
    } else if (reald) {
      std::istringstream stm;
      double i;
      stm.str(valName);
      stm >>i;
      v = new ValueReal(i);
    } else if (ad) {
      throw AltaricaException("initing array domains not yet implemented");
    } else if (sd) {
      throw AltaricaException("initing structured domains not yet implemented");
    }
  } else {
    //identifiers starting with digit are forbidden...
    std::istringstream stm;
    int i = INT_MIN;
    stm.str(valName);
    stm >>i;
    if (i != INT_MIN) {
      v = new ValueInt(i);
    } else {
      std::string temp(valName);
      std::transform(temp.begin(), temp.end(),temp.begin(), ::toupper);
      if (temp.compare("TRUE") == 0)
        v = new ValueBool(true, false);
      else if (temp.compare("FALSE") == 0)
        v = new ValueBool(false, true);
      else
        v = new ValueSymbol(valName);
    }
  }
  return v;
}


std::vector<Node*> * AltaricaInitInfo::getNodes(std::string node_name) {
  std::vector<Node*> *altNodeVector = amodel->findNodesByType(node_name);
  if (altNodeVector == NULL) {
    altNodeVector = new std::vector<Node*>();
    Node * n =  amodel->findNodeByFullName(node_name);
    if (n==NULL)
      std::cout << "cannot find node: " << node_name << std::endl;
    else {
      altNodeVector->push_back(n);
    }
  }
  return altNodeVector;

}
