// -*- mode: C++; c-file-style: "stroustrup"; c-basic-offset: 4; -*-
////////////////////////////////////////////////////////////////////
//
// $Id: ffsystem.h 137 2008-02-21 17:38:32Z sebastian $
//
////////////////////////////////////////////////////////////////////

#ifndef FF_SYSTEM_H
#define FF_SYSTEM_H

#include "ff_heuristic/ffloc.h"
#include "ff_heuristic/ffset.h"
#include "ff_heuristic/ffgoal.h"

#include <vector>
#include <iosfwd>

class State;
class Integer;
class Edge;
class Location;
class IntAssignment;
class IntConstraint;
class Assignment;
class Variable;
class Task;

namespace ff {

    class Variable;
    class Edge;
    class Location;
    class IntegerConstraint;
    class IntegerAssignment;
    
    class System {
    private:
	std::vector<Variable*> variables;
	std::vector<Edge*> edges;
	std::vector<Location*> locations;
	std::vector<IntegerAssignment*> assignments;
	std::vector<IntegerConstraint*> constraints;
	PtrSet<Location> reachedLocations;
	std::vector<uint32_t> procOffsets;
	uint32_t nrChannels;
	Goal goal;
	int32_t level;
	
	// builder
	void buildSystem(const Task* system);	
	void buildVariable(const ::Integer* i);
	void buildEdge(const ::Edge* edge);
	void buildLocation(const ::Location* loc);
	
	// factory methods
	IntegerAssignment* newAssignment(const ::IntAssignment* assign);
	IntegerConstraint* newIntegerConstraint(const ::IntConstraint* ic);
	
	// classifiers
	bool isConstAssignment(const ::IntAssignment* assign) const;
	bool isVarAssignment(const ::IntAssignment* ass) const;
	bool isConstConstraint(const ::IntConstraint* constraint) const;
	
	// converter
	Edge*     convert(const ::Edge* edge) const;
	Location* convert(const ::Location* loc) const;
	Variable* convert(const ::Integer* var) const;

    public:

	System(const Task* task);
	~System();
	
	void init(const State* state);
	void incLevel();
	int32_t getLevel() const { return level; }
	
	uint32_t getNrChannels() const { return nrChannels; }
	uint32_t getNrEdges() const { return edges.size(); }
	uint32_t getNrLocations() const { return locations.size(); }
	uint32_t getNrConstraints() const { return constraints.size(); }
	uint32_t getNrAssignments() const { return assignments.size(); }

	const std::vector<Location*>& getLocations() const;
	const std::vector<Variable*>& getVariables() const;
	const std::vector<Edge*>& getEdges() const;
	const std::vector<IntegerConstraint*>& getConstraints() const;
	std::vector<IntegerConstraint*>& getConstraints();
	const std::vector<IntegerAssignment*>& getAssignments() const;
		
	PtrSet<Location>& getReachedLocations();
	bool locationReached(const Location* l) const;
	bool addToReachedLocations(Location* l);
	bool goalReached() const;
	const Goal& getGoal() const { return goal; }
	std::ostream& display(std::ostream& o) const;
    };

    ////////////////////////////////////////////////////////////////////
    
    inline std::ostream& operator<<(std::ostream& o, const System& sys) {
	return sys.display(o);
    }

    inline bool System::goalReached() const {
	return goal.isReached(getLevel());
    }

    inline bool System::locationReached(const Location* loc) const {
	return reachedLocations.isMember(loc);
    }

    inline PtrSet<Location>& System::getReachedLocations() {
	return reachedLocations;
    }

    inline bool System::addToReachedLocations(Location* l) {
	return reachedLocations.add(l);
    }

    inline const vector<Location*>& System::getLocations() const {
	return locations;
    }

    inline const vector<Variable*>& System::getVariables() const {
	return variables;
    }
    
    inline const vector<Edge*>& System::getEdges() const {
	return edges;
    }    

    inline const std::vector<IntegerConstraint*>& System::getConstraints() const {
	return constraints;
    }

    inline std::vector<IntegerConstraint*>& System::getConstraints() {
	return constraints;
    }

    inline const std::vector<IntegerAssignment*>& System::getAssignments() const {
	return assignments;
    }
}

#endif /* FF_SYSTEM_H */
