#ifndef __STOPPINGCONDITIONS_H_
#define __STOPPINGCONDITIONS_H_

#include "SgEngine.h"
#include <boost/ptr_container/ptr_vector.hpp>
#include <boost/noncopyable.hpp>

class StoppingConditions : boost::noncopyable {
  protected:
  class Condition : boost::noncopyable {
      protected:
        unsigned int parameter;
        Condition( int p ) : parameter( p ) { /* Empty. */ }
      public:
        virtual ~Condition() { /* Empty. */ }
        virtual bool poll() const = 0;
    };
  class LocalCondition : public Condition {
      protected:
        LocalCondition( int p ) : Condition( p ) { /* Empty. */ }
    };
  class GlobalCondition : public Condition {
      protected:
        GlobalCondition( int p ) : Condition( p ) { /* Empty. */ }
    };
  public:
  struct LocalConditionConvergedAlleles : public LocalCondition {
      LocalConditionConvergedAlleles( int p ) : LocalCondition( p ) { /* Empty. */ }
      virtual bool poll() const;
    };
  struct LocalConditionGenerations : public LocalCondition {
      LocalConditionGenerations( int p ) : LocalCondition( p ) { /* Empty. */ }
      virtual bool poll() const;
    };
  struct LocalConditionCpuTime : public LocalCondition {
      LocalConditionCpuTime( int p ) : LocalCondition( p ) { /* Empty. */ }
      virtual bool poll() const;
    };
  struct LocalConditionEpochs : public LocalCondition {
      LocalConditionEpochs( int p ) : LocalCondition( p ) { /* Empty. */ }
      virtual bool poll() const;
    };
  struct GlobalConditionStoppedDemes : public GlobalCondition {
      GlobalConditionStoppedDemes( int p ) : GlobalCondition( p ) { /* Empty. */ }
      virtual bool poll() const;
    };
  struct GlobalConditionConvergedAlleles : public GlobalCondition {
      GlobalConditionConvergedAlleles( int p ) : GlobalCondition( p ) { /* Empty. */ }
      virtual bool poll() const;
    };
  struct GlobalConditionGenerations : public GlobalCondition {
      GlobalConditionGenerations( int p ) : GlobalCondition( p ) { /* Empty. */ }
      virtual bool poll() const;
    };
  struct GlobalConditionCpuTime : public GlobalCondition {
      GlobalConditionCpuTime( int p ) : GlobalCondition( p ) { /* Empty. */ }
      virtual bool poll() const;
    };
  struct GlobalConditionEpochs : public GlobalCondition {
      GlobalConditionEpochs( int p ) : GlobalCondition( p ) { /* Empty. */ }
      virtual bool poll() const;
    };

  public:
    enum ConditionContext { LOCAL, GLOBAL };

  protected:
    enum PollingMethod { DISJUNCTIVE, CONJUNCTIVE };

    PollingMethod localPollingMethod, globalPollingMethod;
    boost::ptr_vector<Condition> localConditions, globalConditions;

  public:
    StoppingConditions() : localPollingMethod( DISJUNCTIVE ), globalPollingMethod( DISJUNCTIVE ) { /* Empty. */ }
    void setPollingMethod( ConditionContext context, PollingMethod value );
    PollingMethod getPollingMethod( ConditionContext context ) const;
    void addLocal( LocalCondition *condition );
    void addGlobal( GlobalCondition *condition );
    void reset( ConditionContext context );
    void reset();
    bool poll( ConditionContext context ) const;
    bool checkEpoch() const;
};

#endif /* __STOPPINGCONDITIONS_H_ */
