#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( unsigned int p ) : parameter( p ) { /* Empty. */ }
      public:
        virtual ~Condition() { /* Empty. */ }
        virtual bool poll() const = 0;
    };
  class LocalCondition : public Condition {
      protected:
        LocalCondition( unsigned int p ) : Condition( p ) { /* Empty. */ }
    };
  class GlobalCondition : public Condition {
      protected:
        GlobalCondition( unsigned int p ) : Condition( p ) { /* Empty. */ }
    };
  public:
  class LocalConditionFitness : public LocalCondition {
      private:
        const FloatType target;
        const SgEngine *engine;
      public:
        LocalConditionFitness( FloatType t, const SgEngine *e ) :
            LocalCondition( 0u ), target( t ), engine( e ) {
          assert( engine );
        }
        bool poll() const;
    };
  struct LocalConditionConvergedAlleles : public LocalCondition {
      LocalConditionConvergedAlleles( unsigned int p ) : LocalCondition( p ) { /* Empty. */ }
      bool poll() const;
    };
  struct LocalConditionGenerations : public LocalCondition {
      LocalConditionGenerations( unsigned int p ) : LocalCondition( p ) { /* Empty. */ }
      bool poll() const;
    };
  struct LocalConditionCpuTime : public LocalCondition {
      LocalConditionCpuTime( unsigned int p ) : LocalCondition( p ) { /* Empty. */ }
      bool poll() const;
    };
  struct LocalConditionEpochs : public LocalCondition {
      LocalConditionEpochs( unsigned int p ) : LocalCondition( p ) { /* Empty. */ }
      bool poll() const;
    };
  struct GlobalConditionStoppedDemes : public GlobalCondition {
      GlobalConditionStoppedDemes( unsigned int p ) : GlobalCondition( p ) { /* Empty. */ }
      bool poll() const;
    };
  struct GlobalConditionConvergedAlleles : public GlobalCondition {
      GlobalConditionConvergedAlleles( unsigned int p ) : GlobalCondition( p ) { /* Empty. */ }
      bool poll() const;
    };
  struct GlobalConditionGenerations : public GlobalCondition {
      GlobalConditionGenerations( unsigned int p ) : GlobalCondition( p ) { /* Empty. */ }
      bool poll() const;
    };
  struct GlobalConditionCpuTime : public GlobalCondition {
      GlobalConditionCpuTime( unsigned int p ) : GlobalCondition( p ) { /* Empty. */ }
      bool poll() const;
    };
  struct GlobalConditionEpochs : public GlobalCondition {
      GlobalConditionEpochs( unsigned int p ) : GlobalCondition( p ) { /* Empty. */ }
      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_ */
