/*******************************************************************************
 * Copyright (c) 2015-2016 ONERA.
 * Ce logiciel est la propriété de l’ONERA (the French Aerospace Lab).
 * 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).
 * 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
 *
 *******************************************************************************/

#include "LandmarkDriver.hh"
#include "AltaricaModel.hh"
#include "AltaricaState.hh"
#include "LandmarkState.hh"
#include "LandmarkMetaEvent.hh"
#include "Values.hh"
#include "iostream"



using namespace epoch::altarica;

LandmarkDriver::LandmarkDriver(AltaricaModel * amodel) {
    amodel_ = amodel;
    finalState_ = NULL;
}


void LandmarkDriver::computeLandmarks() {
    AltaricaState *init = amodel_->initialState();
    // AltaricaState *initialMacroState  = init->getMacroState();
    std::cerr << "INIT STATE:" << init->toString(true,true,false,false);
    
    LandmarkState * is = new LandmarkState(init);
    is->addSelfAsLabel();
    //    std::cerr<<is->toString();

    LandmarkState * currentState = is;
    LandmarkState * previousState = NULL;
   
    int i = 0;
    while (!stablePlanningGraph(previousState,currentState)) {
	std::cout << "LEVEL IN PLANNINGGRAPH: " << i++ << "\n";
	previousState = currentState;
	currentState = new LandmarkState(previousState->getState()->clone());
	std::cout << "CURRENT STATE: " << currentState->getState()->toString(true,true,false,false) << "\n";
	
	std::vector<MetaEvent*> * mevs = amodel_->getEnabledMetaEventsAll(previousState->getState());
	int j=0;
	for (std::vector<MetaEvent*>::iterator mevi = mevs->begin(); mevi!= mevs->end(); ++mevi) {
	    std::cout << "EVALUATING MEV: " << j++ << "\n";
	    LandmarkMetaEvent * lmev = new LandmarkMetaEvent(*mevi, amodel_);
	    lmev->computeLabels((const AltaricaModel*)amodel_, previousState);
	    std::cout << "LANDMARK MEV\n" << lmev->toString();
	    AltaricaState * cs = amodel_->getNextState(previousState->getState(), *mevi);
	    //amodel_->evaluateFlowVars(cs);
	    LandmarkState * tempState = new LandmarkState(cs);
	    tempState->computeLabels((const AltaricaModel*) amodel_, previousState->getState(), lmev);
	    //tempState->computeFlowLabels(amodel_);
	    // std::cout << "TEMPSTATE\n" << tempState->toString();
	    currentState->mergeIntersectLabels(tempState);
	    cs->mergeToState(currentState->getState());
	    // std::cout << "CURRENTSTATE INC\n" << currentState->toString();
	}
	if (currentState == NULL)
	    currentState = previousState;
	else {
	    currentState->addNoopLabels(previousState);
	    // std::cout << "CURRENTSTATE AFTER NOOP\n" << currentState->toString();
	    currentState->addSelfAsLabel();
	    // std::cout << "CURRENTSTATE AFTER SELF\n" << currentState->toString();
	}
	std::cout << "CURRENTSTATE AT END\n" << currentState->toString();


    }
    finalState_ = currentState;
    // std::cout << "CURRENTSTATE AT END BEFORE REMOVESELF\n" << currentState->toString();
    // finalState_->removeSelfAsLabel();
    // std::cout << "CURRENTSTATE AT END AFTER REMOVESELF\n" << currentState->toString();
    finalState_->computeFlowLabels(amodel_);
}

bool LandmarkDriver::stablePlanningGraph(LandmarkState *ps, LandmarkState*cs) {
    if (ps == NULL)
	return false;
    for (unsigned int i = 0; i<amodel_->getNStateVars(); ++i) 
	if (!ps->getState()->getStateValue(i)->equals(cs->getState()->getStateValue(i)))
	    return false;	
    for (unsigned int i = 0; i<amodel_->getNFlowVars(); ++i)
	if (ps->getState()->getFlowValue(i) != NULL && cs->getState()->getFlowValue(i) != NULL)
	    if (!ps->getState()->getFlowValue(i)->equals(cs->getState()->getFlowValue(i)))
	    return false;
    return true;
}
