// -*- mode: C++; c-file-style: "stroustrup"; c-basic-offset: 4; -*-
////////////////////////////////////////////////////////////////////
//
// $Id: ffheur.h 810 2011-09-03 15:21:54Z Sebastian Kupferschmid $
//
////////////////////////////////////////////////////////////////////

#ifndef FF_HEUR_H
#define FF_HEUR_H

#include "search/heuristic.h"

#include "ff_heuristic/ffarray.h"
#include "ff_heuristic/ffastore.h"
#include "ff_heuristic/ffedge.h"
#include "ff_heuristic/ffsystem.h"

#include "common/utapfwd.h"
#include <inttypes.h>
#include <vector>

class State;
class Task;
class Options;

namespace ff {

    class IntegerAssignment;
    class Location;

    class FFHeuristic : public Heuristic {
    protected:
	System* system;
	std::vector<PtrArray<Edge> > enabledBangEdges;
	std::vector<PtrArray<Edge> > enabledQueEdges;
	std::vector<bool> activeChannels;
	AssignmentStore assigns;
	
	virtual bool isActiveChannel(uint32_t channelNr) const;
	virtual void initialiseAbstractSystem(const State* state);
	virtual bool processEdge(const Edge* edge) {
	    assigns.add(edge->getAssignments());
	    return system->addToReachedLocations(edge->to);
	}
	virtual bool processEdges(PtrArray<Edge>& edges);
	virtual void init() {}
	virtual void copyIntegerVars() {}
	virtual void updateWaitingEdges(const PtrSet<Location>& locs, std::vector<Edge*>& waitingEdges) const;

	// debugging helper functions 
	virtual void showReachedLocations();
	virtual void showVariables();
	virtual void showActiveChannels();
	virtual void show();	
    public:
	FFHeuristic(const Task* task, const Options* opts);
	virtual int32_t compute(const State* state);
    };

    ////////////////////////////////////////////////////////////////////

    inline bool FFHeuristic::processEdges(PtrArray<Edge>& edges) {
	bool result = false;
	for (PtrArray<Edge>::iterator it = edges.begin(); it != edges.end(); ++it) {
	    result |= processEdge(*it);
	}
	edges.clear();
	return result;
    }
    
    inline bool FFHeuristic::isActiveChannel(uint32_t channelNr) const {
	PtrArray<Edge>::const_iterator bend = enabledBangEdges[channelNr].end();
	PtrArray<Edge>::const_iterator qend = enabledQueEdges[channelNr].end();
	
	for (PtrArray<Edge>::const_iterator b = enabledBangEdges[channelNr].begin(); b != bend; ++b) {
	    for (PtrArray<Edge>::const_iterator q = enabledQueEdges[channelNr].begin(); q != qend; ++q) {
		if ((*b)->getProcID() != (*q)->getProcID()) {
		    return true;
		}
	    }
	}
	return false;
    }

    inline void FFHeuristic::updateWaitingEdges(const PtrSet<Location>& locs, std::vector<Edge*>& waitingEdges) const {
	for (PtrSet<Location>::const_iterator it = locs.begin(); it != locs.end(); ++it) {
	    assert(system->locationReached(*it));
	    for (uint32_t i = 0; i < (*it)->getOutgoingEdges().size(); i++) {
		waitingEdges.push_back((*it)->getOutgoingEdges()[i]);
	    }
	}
    }
}

#endif /* FF_HEUR_H */
