// -*- mode: C++; c-file-style: "stroustrup"; c-basic-offset: 4; -*-
////////////////////////////////////////////////////////////////////
//
// $Id: causalGraph.h 823 2011-10-01 14:48:13Z Sebastian Kupferschmid $
//
////////////////////////////////////////////////////////////////////

#ifndef CAUSAL_GRAPH_H
#define CAUSAL_GRAPH_H

#include "causalgraph/idmapper.h"
#include <string>
#include <vector>
#include <map>
#include <iosfwd>

class Task;
class IntConstraint;

namespace cg {

    class CGVariable;
    class CGOperator;
    class DomainTransitionGraph;
    class DTG;
    
    class CausalGraph {
    public:
	typedef std::vector<std::vector<CGVariable*> > Partition;
	typedef std::vector<CGVariable*> Ordering;

	Ordering ordering;
	Partition sccs;
	std::vector<DTG*> g_transition_graphs;
	std::vector<std::pair<CGVariable*, int> > goals;
	IDMapper idmapper;
    private:
	
	typedef std::map<CGVariable*, int> WeightedSuccessors;
	typedef std::map<CGVariable*, WeightedSuccessors> WeightedGraph;
	WeightedGraph weighted_graph;
	typedef std::map<CGVariable*, int> Predecessors;
	typedef std::map<CGVariable*, Predecessors> PredecessorGraph;
	// predecessor_graph is weighted_graph with edges turned around
	PredecessorGraph predecessor_graph;	
	bool acyclic;
	
	std::vector<CGVariable*> independent_vars;	
	std::vector<CGVariable*> variables;
	std::vector<CGOperator*> operators;

	bool check_for_clocks(CGVariable* var) const;
	void computeDomainTransitionGraphs(std::vector<DomainTransitionGraph*>& transition_graphs);
	void initCGVariables(const Task* task);
	void initCGOperators(const Task* task);
	void initCGGoals(const Task* task);
	bool leftOf(const CGVariable* v1, const CGVariable* v2) const;
	void processValueAssignmentDTG(std::vector<DomainTransitionGraph*>& transition_graphs, 
				       int va_rhs,
				       const CGVariable* asvar_lhs,
				       const std::vector<const IntConstraint*>& integerconstraints,
				       const CGOperator* op, 
				       int op_index, 
				       const std::vector<std::pair<CGVariable*, int> >& additionalConstraints);
	void processLocationAssignmentDTG(std::vector<DomainTransitionGraph*>& transition_graphs, const CGOperator* op, int op_index);
	void constructGraph();
	void constructDTGs();
	const Partition& compute_sccs();
	const Ordering& compute_topological_pseudo_sort();

    public:
	CausalGraph(const Task* task);
	
	void get_root_variables(std::vector<CGVariable*>& root_variables) const;
	void get_successors(int var, std::vector<int>& successors) const;
	bool member(const std::vector<CGVariable*> scc, const std::string& varname) const;
	std::ostream& display(std::ostream& o) const;
	std::ostream& graphviz(std::ostream& o) const;
	void compute_safe_variables(std::vector<CGVariable*>& safe_variables);
    };    

    inline std::ostream& operator<<(std::ostream& o, const CausalGraph& cg) {
	return cg.display(o);
    }
}

#endif
