// $Id: paramstat.h,v 1.11 2018/01/03 21:32:58 mkkuhner Exp $

/*
Copyright 2002-2005 Mary K. Kuhner, Peter Beerli, and Joseph Felsenstein

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

*/

/* Authors: Mary Kuhner, Jon Yamato, and Joseph Felsenstein */


#ifndef PARAMSTAT_H
#define PARAMSTAT_H

#include <cassert>
#include <string>
#include <vector>

#include "constants.h"
#include "stringx.h"

//-------------------------------------------------------------------------------------

// We want this class to be polymorphic, because it has a lot of subtypes with
// different behavior.  But, we want it not to be polymorphic because it has to
// go in vectors, and pointers/smart pointers are a pain.  So, it is a non-
// poly class which holds a poly one inside; no one else need care about that.
// ParamStatusImpl is the inside, hidden class.

class ParamStatus;
class ParamStatusImpl;
typedef std::pair<ParamStatus, std::vector<long> > ParamGroup;

class ParamStatus
{
  private:
    // owning pointer!
    ParamStatusImpl* m_impl;

    ParamStatusImpl* CreateParamStatus(pstatus mytype);

  public:
    // construction etc.
    ParamStatus(pstatus mytype);
    ParamStatus(const ParamStatus& src);
    ParamStatus& operator=(const ParamStatus& src);
    ~ParamStatus();

    // queries
    pstatus Status() const;
    bool Valid() const;
    bool Inferred() const;
    std::string ConstraintDescription(long groupindex) const;
    bool Varies() const;
    bool Grouped() const;

    // setters
    void SetWithConstraints(long pindex, double newval,
                            std::vector<double>& pvecnums, const std::vector<unsigned long>& groupmembers,
                            double multiplier) const;
    std::string ToggleIndividualStatus(force_type ftype) const;
    std::string ToggleGroupStatus(force_type ftype) const;
};

//-------------------------------------------------------------------------------------

class ParamStatusImpl
{
  public:
    virtual ~ParamStatusImpl() {};
    virtual pstatus Status() const = 0;
    virtual bool Valid() const = 0;
    virtual bool Inferred() const = 0;
    virtual std::string ConstraintDescription(long groupindex) const = 0;
    virtual bool Varies() const = 0;
    virtual bool Grouped() const = 0;
    virtual void SetWithConstraints(long pindex, double newval,
                                    std::vector<double>& pvecnums, const std::vector<unsigned long>& groupmembers,
                                    double multiplier) const = 0;
    virtual std::string ToggleIndividualStatus(force_type ftype) const = 0;
    virtual std::string ToggleGroupStatus(force_type ftype) const = 0;
};

//-------------------------------------------------------------------------------------

class InvalidStatus: public ParamStatusImpl
{
  public:
    virtual ~InvalidStatus() {};
    virtual pstatus Status() const { return pstat_invalid; };
    virtual bool Valid() const { return false; };
    virtual bool Inferred() const { return false; };
    virtual std::string ConstraintDescription(long groupindex) const;
    virtual bool Varies() const { return false; };
    virtual bool Grouped() const { return false; };

    virtual void SetWithConstraints(long, double, std::vector<double>&, const std::vector<unsigned long>&, double) const
    { assert(false); };

    virtual std::string ToggleIndividualStatus(force_type) const { return ToString(pstat_unconstrained); };
    virtual std::string ToggleGroupStatus(force_type) const { return ToString(pstat_identical); };
};

//-------------------------------------------------------------------------------------

class UnconstrainedStatus: public ParamStatusImpl
{
  public:
    virtual ~UnconstrainedStatus() {};
    virtual pstatus Status() const { return pstat_unconstrained; };
    virtual bool Valid() const { return true; };
    virtual bool Inferred() const { return true; };
    virtual std::string ConstraintDescription(long groupindex) const;
    virtual bool Varies() const { return true; };
    virtual bool Grouped() const { return false; };

    virtual void SetWithConstraints(long pindex, double newval,
                                    std::vector<double>& pvecnums,
                                    const std::vector<unsigned long>&, double) const
    { pvecnums[pindex] = newval; };

    virtual std::string ToggleIndividualStatus(force_type) const { return ToString(pstat_constant); };
    virtual std::string ToggleGroupStatus(force_type) const { return ToString(pstat_constant); };
};

//-------------------------------------------------------------------------------------

class ConstantStatus: public ParamStatusImpl
{
  public:
    virtual ~ConstantStatus() {};
    virtual pstatus Status() const { return pstat_constant; };
    virtual bool Valid() const { return true; };
    virtual bool Inferred() const { return false; };
    virtual std::string ConstraintDescription(long groupindex) const;
    virtual bool Varies() const { return false; };
    virtual bool Grouped() const { return false; };

    virtual void SetWithConstraints(long, double, std::vector<double>&,
                                    const std::vector<unsigned long>&, double) const
    { assert(false); };

    virtual std::string ToggleIndividualStatus(force_type ftype) const;
    virtual std::string ToggleGroupStatus(force_type ftype) const;
};

//-------------------------------------------------------------------------------------

class IdenticalStatus: public ParamStatusImpl
{
  public:
    virtual ~IdenticalStatus() {};
    virtual pstatus Status() const { return pstat_identical; };
    virtual bool Valid() const { return true; };
    virtual bool Inferred() const { return false; };
    virtual std::string ConstraintDescription(long groupindex) const;
    virtual bool Varies() const { return true; };
    virtual bool Grouped() const { return true; };

    virtual void SetWithConstraints(long, double, std::vector<double>&,
                                    const std::vector<unsigned long>&, double) const
    { assert(false); };

    virtual std::string ToggleIndividualStatus(force_type) const { return ToString(pstat_unconstrained); };
    virtual std::string ToggleGroupStatus(force_type) const { return ToString(pstat_constant); };
};

//-------------------------------------------------------------------------------------

class IdenticalHeadStatus: public ParamStatusImpl
{
  public:
    virtual ~IdenticalHeadStatus() {};
    virtual pstatus Status() const { return pstat_identical_head; };
    virtual bool Valid() const { return true; };
    virtual bool Inferred() const { return true; };
    virtual std::string ConstraintDescription(long groupindex) const;
    virtual bool Varies() const { return true; };
    virtual bool Grouped() const { return true; };
    virtual void SetWithConstraints(long pindex, double newval, std::vector<double>& pvecnums,
                                    const std::vector<unsigned long>& groupmembers, double) const;
    virtual std::string ToggleIndividualStatus(force_type) const { return ToString(pstat_unconstrained); };
    virtual std::string ToggleGroupStatus(force_type) const { return ToString(pstat_constant); };
};

//-------------------------------------------------------------------------------------

class MultiplicativeStatus: public ParamStatusImpl
{
  public:
    virtual ~MultiplicativeStatus() {};
    virtual pstatus Status() const { return pstat_multiplicative; };
    virtual bool Valid() const { return true; };
    virtual bool Inferred() const { return false; };
    virtual std::string ConstraintDescription(long groupindex) const;
    virtual bool Varies() const { return true; };
    virtual bool Grouped() const { return true; };

    virtual void SetWithConstraints(long, double, std::vector<double>&, const std::vector<unsigned long>&, double) const
    { assert(false); };

    virtual std::string ToggleIndividualStatus(force_type) const { return ToString(pstat_unconstrained); };
    virtual std::string ToggleGroupStatus(force_type) const { return ToString(pstat_constant); };
};

//-------------------------------------------------------------------------------------

class MultiplicativeHeadStatus: public ParamStatusImpl
{
  public:
    virtual ~MultiplicativeHeadStatus() {};
    virtual pstatus Status() const { return pstat_multiplicative_head; };
    virtual bool Valid() const { return true; };
    virtual bool Inferred() const { return true; };
    virtual std::string ConstraintDescription(long groupindex) const;
    virtual bool Varies() const { return true; };
    virtual bool Grouped() const { return true; };
    virtual void SetWithConstraints(long pindex, double newval, std::vector<double>& pvecnums,
                                    const std::vector<unsigned long>& groupmembers, double multiplier) const;
    virtual std::string ToggleIndividualStatus(force_type) const { return ToString(pstat_unconstrained); };
    virtual std::string ToggleGroupStatus(force_type) const { return ToString(pstat_constant); };
};

//-------------------------------------------------------------------------------------

# if 0
class EpochTimeStatus: public ParamStatusImpl
{
  public:
    virtual ~EpochTimeStatus() {};
    virtual pstatus Status() const { return pstat_epochtime; };
    virtual bool Valid() const { return true; };
    virtual bool Inferred() const { return true; };
    virtual std::string ConstraintDescription(long groupindex) const;
    virtual bool Varies() const { return true; };
    virtual bool Grouped() const { return false; };

    virtual void SetWithConstraints(long pindex, double newval, std::vector<double>& pvecnums,
                                    const std::vector<unsigned long>&, double) const
    { pvecnums[pindex] = newval; };

    // currently no toggles possible for epoch times
    virtual std::string ToggleIndividualStatus(force_type ftype) const
    {   assert(false);
        return ToString(pstat_invalid); };

    virtual std::string ToggleGroupStatus(force_type ftype) const
    {   assert(false);
        return ToString(pstat_invalid); };
};
#endif

//-------------------------------------------------------------------------------------

#endif // PARAMSTAT_H

//_____________________________________________________________________________________
