#ifndef FITFUNC_H
#define FITFUNC_H

// Filename: fitfunc.hh
// Author:   Michael P. Schubmehl
// Date(s):  July 2002
// Purpose:  This file contains the interface for the fittingFunction class,
//           which represents a real-valued function of one variable (and
//           severable real parameters, which can be changed). The fitting
//           function can be read from file and evaluated with the current
//           parameter values, and the parameter values can be inspected and
//           changed. The functions also support range checking, to ensure that
//           most of the area under the function falls within a particular
//           range. This is useful for checking the suitability of Mie tables.
//
// Notes:    Updated version uses class inheritance. The fittingFunction class
//           is purely virtual, meaning that it is impossible to create an
//           instance of a fittingFunction. (However, it is possible to have
//           an array of pointers to fitting functions, for example). The only
//           purpose of the class is to define the interface for the derived
//           classes representing specific functions. In the current version,
//           these classes are deltaFunction, gaussianFunction, and
//           logonormalFunction. Each is an extension of the fittingFunction
//           class, in that it realizes versions of all the functions that
//           fittingFunctions promise to deliver. Instances of these classes
//           can be created and manipulated, with the advantage that a pointer
//           to fittingFunction can actually point to any specific type of
//           fitting function. Then, calling (for example) evaluate() will
//           correspond to calling the appropriate evaluate() function for the
//           derived class. For more information on inheritance, look up C++
//           inheritance on the internet, and find a good tutorial.
//
//           Implemented in fitfunc.cpp.


#define R     0                               // Name indices for easy reference
#define ALPHA 1                               //   later. For example, the
#define SIGMA 2                               //   first parameter in each fit
                                              //   function is r, which can be
                                              //   accessed by
                                              //      _currentParams[R]    or
                                              //      _currentParams[0].

// Classes ********************************************************************
class fittingFunction;                        // The abstract fitting function

class deltaFunction;                          // Derived classes for several
class gaussianFunction;                       //   common types of functions.
class logonormalFunction;
// END Classes ****************************************************************

// class fittingFunction ******************************************************
class fittingFunction {
  public:
    ~fittingFunction();                       // Destructor


    virtual void readFromFile(ifstream& file) = 0;
                                              // Read parameter ranges in file
    virtual void toSizeParams(double n,       // Convert all parameters from
                              double lambda)  //   microns of radius into
                              = 0;            //   size parameters.
    virtual void toMicronsR(double n,         // Convert all parameters to
                              double lambda)  //   microns of radius from
                              = 0;            //   size parameters.

    virtual bool inRange(double& minX,        // Checks to be sure 95% of the
                         double& maxX) = 0;   //   size distribution is in the
                                              //   given parameter range.  
  
    virtual double evaluate(double x) = 0;    // Evaluate function with
                                              //   current parameters, at
                                              //   the size x.
    virtual double evaluateWith(double* params, double x) = 0;
                                              // Evaluate with specified list
                                              //   of parameters at size x.
    virtual void output(ostream& stream) = 0; // Print to stream

    const int numParams();                    // Accessor functions
    double&   minimumParams(int i);
    double&   maximumParams(int i);
    double&   currentParams(int i);
    bool&     fitting(int i);

  protected:
    int     _numParams;
    bool    _inMicronsOfRadius;               // Whether current units are um
    double* _minimumParams;                   // The actual parameter arrays
    double* _maximumParams;
    double* _currentParams;
    bool*   _fitting;
};

ostream& operator<<(ostream& stream,          // Operator to output function
                    fittingFunction& source);
// END class fittingFunction ***************************************************


// class deltaFunction *********************************************************
class deltaFunction : public fittingFunction {
  public:
    deltaFunction();                          // Constructors
    deltaFunction(double r, double alpha);    

    void   readFromFile(ifstream& file);
    void   toSizeParams(double n, double lambda);
    void   toMicronsR(double n, double lambda);
    bool   inRange(double& minX, double& maxX);
    double evaluate(double x);
    double evaluateWith(double* params, double x);
    void   output(ostream& stream); 
};
// END class deltaFunction *****************************************************

// class gaussianFunction ******************************************************
class gaussianFunction : public fittingFunction {
  public:
    gaussianFunction();
    gaussianFunction(double r, double alpha, double sigma);

    void   readFromFile(ifstream& file);
    void   toSizeParams(double n, double lambda);
    void   toMicronsR(double n, double lambda);
    bool   inRange(double& minX, double& maxX);
    double evaluate(double x);
    double evaluateWith(double* params, double x);
    void   output(ostream& stream);
};
// END class gaussianFunction **************************************************

// class logonormalFunction ****************************************************
class logonormalFunction : public fittingFunction {
  public:
    logonormalFunction();
    logonormalFunction(double r, double alpha, double sigma);

    void   readFromFile(ifstream& file);
    void   toSizeParams(double n, double lambda);
    void   toMicronsR(double n, double lambda);
    bool   inRange(double& minX, double& maxX);
    double evaluate(double x);
    double evaluateWith(double* params, double x);
    void   output(ostream& stream);
};
// END class logonormalFunction ************************************************
    

#endif // FITFUNC_H
