/*******************************************************************************
 * 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
 *
 *******************************************************************************/

#ifndef ALTA_VALUE_H
#define ALTA_VALUE_H

#include "../domains/Domains.hh"
#include "../AltaricaException.hh"
#include <set>

namespace epoch {
  namespace altarica {

    class ValueInt;
    class ValueBool;
    class ValueSymbol;
    class ValueReal;

    class Value {

    protected:

      // bool singleton_;
      int owner_;
      bool constrained_;

    public:
      virtual ~Value() {}

      Value(): owner_(0), constrained_(false) {}
      void own() {owner_++;}
      void release() {owner_--;}
      bool ro() {return owner_ != 0;} // ro for readonly <=> owned by so else

      int getNown() const {return owner_;}

      static void release(Value * v) {
        if (v != NULL) {
          v->owner_--;
          if (v->owner_ <= 0)
            delete v;
        }
      }

      static void deleteIfPossible(Value*v) {
        if (v->owner_ <= 0)
          delete v;
      }


      // virtual bool isOpen() const {return !singleton_;}
      // virtual bool isFixed() const {return singleton_;}
      virtual void setDomain(const Domain *d) {}
      virtual bool isSymbol() const {return false;}
      virtual bool isInt() const {return false;}
      virtual bool isBool() const {return false;}
      virtual bool isReal() const {return false;}


      virtual void inverse() = 0;
      virtual Value * clone() const = 0;

      virtual std::vector<Value*> * getSingletons() const = 0;

      virtual bool equals(const Value*v) const;
      virtual bool equals(const ValueInt*v) const {return false;}
      virtual bool equals(const ValueBool*v) const {return false;}
      virtual bool equals(const ValueSymbol*v) const {return false;}
      virtual bool equals(const ValueReal*v) const {return false;}

      virtual void merge(const Value *v);
      virtual void merge(const ValueInt*v);
      virtual void merge(const ValueBool*v);
      virtual void merge(const ValueSymbol*v);
      virtual void merge(const ValueReal*v);

      virtual bool contains(const Value *v) const;
      virtual bool contains(const ValueInt*v)const;
      virtual bool contains(const ValueBool*v)const;
      virtual bool contains(const ValueSymbol*v)const;
      virtual bool contains(const ValueReal*v)const;

      virtual bool possible(bool b) const {return false;}

      virtual Value* getComplement() const = 0;


      virtual bool pDifferent(const Value *v) const;
      virtual bool pDifferent(const ValueInt *v) const {return true;}
      virtual bool pDifferent(const ValueBool *v) const {return true;}
      virtual bool pDifferent(const ValueSymbol *v) const {return true;}
      virtual bool pDifferent(const ValueReal *v) const {return true;}


      virtual bool hasIntersection(const Value *v) const;
      virtual bool hasIntersection(const ValueInt*v)const {return false;}
      virtual bool hasIntersection(const ValueBool*v)const {return false;}
      virtual bool hasIntersection(const ValueSymbol*v)const{return false;}
      virtual bool hasIntersection(const ValueReal*v)const{return false;}

      void removeValue(const Value *v);
      virtual void removeValue(const ValueInt *v)  {}
      virtual void removeValue(const ValueBool *v) {}
      virtual void removeValue(const ValueSymbol *v) {}
      virtual void removeValue(const ValueReal *v) {}

      // bool less(const Value*v) const;
      // virtual bool less(const ValueInt*v) const = 0;
      // virtual bool less(const ValueBool*v) const {return false;}
      // virtual bool less(const ValueSymbol*v) const {return true;}

      void intersectValue(const Value* v) ;
      virtual void intersectValue(const ValueInt* v) {return;}
      virtual void intersectValue(const ValueBool* v) {return;}
      virtual void intersectValue(const ValueSymbol* v) {return;}
      virtual void intersectValue(const ValueReal* v) {return;}
      virtual std::string toString() const = 0;
      bool constrained() const {return constrained_;}
      void constrain() {constrained_ = true;}
      void unConstrain() {constrained_ = false;}
      void setConstrained(bool c) {constrained_ = c;}

      virtual int toHash() const = 0;

      virtual int toInt() const {
        throw AltaricaException("bad conversion in openvalues");
      }
      virtual bool toBool() const {
        throw AltaricaException("bad conversion in openvalues");
      }
      virtual std::string toSymbol() const {
        throw AltaricaException("bad conversion in openvalues");
      }
      virtual double toDouble() const {
        throw AltaricaException("bad conversion in openvalues");
      }

      virtual int card() const = 0;

      virtual bool less(const Value *v) const;
      virtual bool less(const ValueInt *v) const {return true;}
      virtual bool less(const ValueBool *v) const {return false;}
      virtual bool less(const ValueSymbol *v) const = 0;
      virtual bool less(const ValueReal *v) const {return false;}


    };



  }
}


#endif
