// $Id: errhandling.h,v 1.25 2018/01/03 21:32:54 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: Peter Beerli, Mary Kuhner, Jon Yamato and Joseph Felsenstein */


/**************************************************************
 This file contains all exception classes defined for this
 program.  For all of these exceptions, the public function
 what() can be called to get a string describing the error.

 Please remember to catch exceptions by reference, not by value,
 lest you slice them.

 Mary Kuhner      March 18, 2001
**************************************************************/

#ifndef ERRHANDLING_H
#define ERRHANDLING_H

#include <stdexcept>
#include <string>

//------------------------------------------------------------------------------------
// Data reading exceptions
//------------------------------------------------------------------------------------

class data_error : public std::exception
{
  private:
    std::string _what;

  public:
    data_error(const std::string& wh);
    virtual ~data_error() throw();
    virtual const char* what () const throw();
    virtual const std::string& whatString() const;
};

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

class file_error : public data_error
{
    // failure to read a necessary file
  public:
    file_error(const std::string& wh);
    virtual ~file_error() throw();
};

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

class incorrect_data : public data_error
{
    // XML did not contain required information
  public:
    incorrect_data(const std::string& wh);
    virtual ~incorrect_data() throw();
};

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

class incorrect_xml : public data_error
{
    // XML was syntactically incorrect
  public:
    incorrect_xml(const std::string& wh);
    virtual ~incorrect_xml() throw();
};

class incorrect_xml_extra_tag : public incorrect_xml
{
    std::string _tag;

  public:
    incorrect_xml_extra_tag(const std::string& wh,const std::string& text);
    virtual ~incorrect_xml_extra_tag() throw();
    const std::string& tag();
};

class incorrect_xml_missing_tag : public incorrect_xml
{
    std::string _tag;

  public:
    incorrect_xml_missing_tag(const std::string& wh,const std::string& text);
    virtual ~incorrect_xml_missing_tag() throw();
    const std::string& tag();
};

class incorrect_xml_not_double : public incorrect_xml
{
    std::string _text;

  public:
    incorrect_xml_not_double(const std::string& wh,const std::string& text);
    virtual ~incorrect_xml_not_double() throw();
    const std::string& text();
};

class incorrect_xml_not_long : public incorrect_xml
{
    std::string _text;

  public:
    incorrect_xml_not_long(const std::string& wh,const std::string& text);
    virtual ~incorrect_xml_not_long() throw();
    const std::string& text();
};

class incorrect_xml_not_size_t : public incorrect_xml
{
    std::string _text;

  public:
    incorrect_xml_not_size_t(const std::string& wh,const std::string& text);
    virtual ~incorrect_xml_not_size_t() throw();
    const std::string& text();
};

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

class invalid_sequence : public data_error
{
    // invalid genetic data
  public:
    invalid_sequence(const std::string& wh);
    virtual ~invalid_sequence() throw();
};

class unrecognized_tag_error : public data_error
{
    // tag not in schema
  private:
    int     m_where;

  public:
    unrecognized_tag_error(const std::string& wh, int where);
    virtual ~unrecognized_tag_error() throw();
    int where() const;
};

//------------------------------------------------------------------------------------
// Reject newly generated tree events
//------------------------------------------------------------------------------------

enum reject_type{TINYPOP, OVERRUN, ZERODL, STRETCHED, EPOCHBOUNDARYCROSS};

class rejecttree_error : public std::exception
{
  private:
    std::string _what;

  public:
    virtual reject_type GetType() const = 0;
    rejecttree_error(const std::string& wh) : _what(wh) {};
    virtual ~rejecttree_error() throw() {};
    virtual const char* what () const throw() { return _what.c_str (); };
};

// Reject for improbable population size
class tinypopulation_error : public rejecttree_error
{
  public:
    tinypopulation_error(const std::string& wh) : rejecttree_error(wh) {};
    virtual ~tinypopulation_error() throw() {};
    virtual reject_type GetType() const {return TINYPOP;};
};

// Reject for too-many-events (the tree has gotten bloated)
class overrun_error : public rejecttree_error
{
  public:
    overrun_error(const std::string& wh) : rejecttree_error(wh) { };
    virtual ~overrun_error() throw() {};
    virtual reject_type GetType() const {return OVERRUN;};
};

// Reject for zero data likelihood (the tree doesn't fit the data at all)
class zero_dl_error : public rejecttree_error
{
  public:
    zero_dl_error(const std::string& wh) : rejecttree_error(wh) {};
    virtual ~zero_dl_error() throw() {};
    virtual reject_type GetType() const {return ZERODL;};
};

// Reject for improbably long branch lengths  (the tree has gotten stretched)
class stretched_error : public rejecttree_error
{
  public:
    stretched_error(const std::string& wh) : rejecttree_error(wh) { };
    virtual ~stretched_error() throw() {};
    virtual reject_type GetType() const {return STRETCHED;};
};

// Reject for improper crossing of epoch boundaries
class epoch_error : public rejecttree_error
{
  public:
    epoch_error(const std::string& wh) : rejecttree_error(wh) {};
    virtual ~epoch_error() throw() {};
    virtual reject_type GetType() const {return EPOCHBOUNDARYCROSS;};
};

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

//LS NOTE:  coal_overrun no longer used--we'll catch this error in
// rec_overrun instead, and the user can't set max coal events.

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

class rec_overrun : public overrun_error
{
  public:
    rec_overrun(const std::string& wh = "Too many recombinations") :
        overrun_error(wh) { };
    virtual ~rec_overrun() throw() {};
};

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

class mig_overrun : public overrun_error
{
  public:
    mig_overrun(const std::string& wh = "Too many migrations") :
        overrun_error(wh) { };
    virtual ~mig_overrun() throw() {};
};

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

class dis_overrun : public overrun_error
{
  public:
    dis_overrun(const std::string& wh = "Too many disease mutations") :
        overrun_error(wh) { };
    virtual ~dis_overrun() throw() {};
};

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

class epoch_overrun : public overrun_error
{
  public:
    epoch_overrun(const std::string& wh = "Too many epochs") :
        overrun_error(wh) { };
    virtual ~epoch_overrun() throw() {};
};

//------------------------------------------------------------------------------------
// The denovo tree cannot be constructed (probably due to deeply
// unreasonable parameter values)
//------------------------------------------------------------------------------------

class denovo_failure : public overrun_error
{
  private:
    std::string _what;

  public:
    denovo_failure(const std::string& wh = "Can't generate denovo tree") :
        overrun_error(wh) { };
    virtual ~denovo_failure() throw() {};
};

//------------------------------------------------------------------------------------
// Errors that should never happen
//------------------------------------------------------------------------------------

class impossible_error : public std::exception
{
  private:
    std::string _what;

  public:
    impossible_error(const std::string& wh): _what ("impossible error:"+wh) { };
    virtual ~impossible_error() throw() {};
    virtual const char* what () const throw() { return _what.c_str (); };
};

//------------------------------------------------------------------------------------
// Errors indicating code that needs to be written
//------------------------------------------------------------------------------------

class implementation_error : public std::exception
{
  private:
    std::string _what;

  public:
    implementation_error(const std::string& wh): _what ("implementation error:"+wh) { };
    virtual ~implementation_error() throw() {};
    virtual const char* what () const throw() { return _what.c_str (); };
};

//------------------------------------------------------------------------------------
// Errors showing that deprecation is not complete
//------------------------------------------------------------------------------------

class deprecation_error : public std::exception
{
  private:
    std::string _what;

  public:
    deprecation_error(const std::string& wh): _what (wh) { };
    virtual ~deprecation_error() throw() {};
    virtual const char* what () const throw() { return _what.c_str (); };
};

//------------------------------------------------------------------------------------
// Errors showing that a dynamic allocation request was not successful
//------------------------------------------------------------------------------------

class alloc_error : public std::exception
{
  private:
    std::string _what;

  public:
    alloc_error(const std::string& wh) : _what(wh) { };
    virtual ~alloc_error() throw() {};
    virtual const char* what () const throw() { return _what.c_str (); };
    virtual const std::string& whatString() { return _what;};
};

//------------------------------------------------------------------------------------
// Errors that indicate a probable failure in data-likelihood calculation
//------------------------------------------------------------------------------------

class datalike_error : public std::exception
{
  private:
    std::string _what;

  public:
    datalike_error(const std::string& wh) : _what(wh) { };
    virtual ~datalike_error() throw() {};
    virtual const char* what () const throw() { return _what.c_str (); };
    virtual const std::string& whatString() { return _what;};
};

//------------------------------------------------------------------------------------
// Use this datalike_error when the failure can be fixed by turning on
// normalization.
//------------------------------------------------------------------------------------

class datalikenorm_error : public datalike_error
{
  public:
    datalikenorm_error(const std::string& wh) : datalike_error(wh) { };
    virtual ~datalikenorm_error() throw() {};
    virtual const char* what () const throw() { return datalike_error::what(); };
    virtual const std::string& whatString() { return datalike_error::whatString(); };
};

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

class insufficient_variability_over_regions_error : public std::exception
{
  private:
    //std::string _what;
    double m_oldAlpha;
    double m_newAlpha;

  public:
    //insufficient_variability_over_regions_error(const std::string& wh): _what ("error:"+wh) { };
    insufficient_variability_over_regions_error(const double& oldAlpha, const double& newAlpha):
        m_oldAlpha(oldAlpha),m_newAlpha(newAlpha) {};
    virtual ~insufficient_variability_over_regions_error() throw() {};
    double GetOldAlpha() const { return m_oldAlpha; };
    double GetNewAlpha() const { return m_newAlpha; };
    //virtual const char* what () const throw() { return _what.c_str (); };
};

class tixml_error : public data_error
{
    // complaint from tixml parser
  public:
    tixml_error(const std::string& wh);
    virtual ~tixml_error() throw();
};

#endif // ERRHANDLING_H

//____________________________________________________________________________________
