// -*- mode: C++; c-file-style: "stroustrup"; c-basic-offset: 4; -*-
////////////////////////////////////////////////////////////////////
//
// $Id: assignment.h 816 2011-09-10 13:19:07Z Sebastian Kupferschmid $
//
////////////////////////////////////////////////////////////////////

#ifndef SYSTEM_ASSIGNMENT_H
#define SYSTEM_ASSIGNMENT_H

#include "expression.h"
#include "varset.h"

#include "common/flyweight.h"

class State;
class Integer;
class Clock;
class Constant;

class Assignment : public Expression {
protected:
    Assignment(int32_t id) : Expression(Expression::ASSIGNMENT), id(id) {}
public:
    int32_t id;
    
    virtual varset_t readVars() const = 0;
    virtual varset_t writeVars() const = 0;
    virtual void apply(State* state) const = 0;
};

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

class VarAssignment;
class ValueAssignment;

class IntAssignment : public Assignment {    
public:
    Integer* lhs;

    virtual bool operator==(const IntAssignment&) const = 0;
    virtual bool operator==(const VarAssignment&) const = 0;
    virtual bool operator==(const ValueAssignment&) const = 0;

    virtual varset_t writeVars() const;
    
protected:
    IntAssignment(Integer* lhs, int32_t id) : Assignment(id), lhs(lhs) {}  

    friend class AssignmentFactory;
};

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

class VarAssignment : public IntAssignment {
private:
    VarAssignment(Integer* lhs, Integer* rhs, int32_t id);
public:
    Integer* rhs;

    virtual varset_t readVars() const;
    
    virtual bool operator==(const IntAssignment& v) const { return v.operator==(*this); }
    virtual bool operator==(const VarAssignment& v) const; 
    virtual bool operator==(const ValueAssignment& v) const;

    virtual void apply(State* state) const;
    virtual std::ostream& display(std::ostream& o) const;

    friend class AssignmentFactory;
};

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

class ValueAssignment : public IntAssignment {
private:
    ValueAssignment(Integer* lhs, int32_t rhs, int32_t id);
    ValueAssignment(Integer* lhs, const Constant* rhs, int32_t id);

    void init() const;
public:
    int32_t rhs;
    
    virtual varset_t readVars() const { return varset_t(); }

    virtual bool operator==(const IntAssignment& v) const { return v.operator==(*this); }
    virtual bool operator==(const VarAssignment& v) const;
    virtual bool operator==(const ValueAssignment& v) const;

    virtual void apply(State* state) const;
    virtual std::ostream& display(std::ostream& o) const;

    friend class AssignmentFactory;
};

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

class ClockReset : public Assignment {
private:
    ClockReset(Clock* lhs, int32_t rhs, int32_t id);
    ClockReset(Clock* lhs, const Constant* rhs, int32_t id);    
public:
    Clock* lhs;
    int32_t rhs;
    
    virtual varset_t readVars() const { return varset_t(); }
    virtual varset_t writeVars() const;    
    virtual bool operator==(const ClockReset& cr) const;

    virtual void apply(State* state) const;
    virtual std::ostream& display(std::ostream& o) const;

    friend class AssignmentFactory;
};

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

class AssignmentFactory {
private:    
    Flyweight<IntAssignment> ints;
    Flyweight<ClockReset> clocks;
    AssignmentFactory() {}
    AssignmentFactory(const AssignmentFactory&);
public:
    static AssignmentFactory& getFactory() {
    	static AssignmentFactory theFactory;
    	return theFactory;
    }

    ClockReset* create(Clock* lhs, int32_t rhs);
    ClockReset* create(Clock* lhs, const Constant* rhs);    
    IntAssignment* create(Integer* lhs, Integer* rhs);    
    IntAssignment* create(Integer* lhs, int32_t rhs);
    IntAssignment* create(Integer* lhs, const Constant* rhs);

    uint32_t totalNrIntAssignments() const { return ints.size(); }
    uint32_t totalNrClockResets() const { return clocks.size(); }
};

#endif /* SYSTEM_ASSIGNMENT_H */
