/*
** (c) 1996-2000 The Regents of the University of California (through
** E.O. Lawrence Berkeley National Laboratory), subject to approval by
** the U.S. Department of Energy.  Your use of this software is under
** license -- the license agreement is attached and included in the
** directory as license.txt or you may contact Berkeley Lab's Technology
** Transfer Department at TTD@lbl.gov.  NOTICE OF U.S. GOVERNMENT RIGHTS.
** The Software was developed under funding from the U.S. Government
** which consequently retains certain rights as follows: the
** U.S. Government has been granted for itself and others acting on its
** behalf a paid-up, nonexclusive, irrevocable, worldwide license in the
** Software to reproduce, prepare derivative works, and perform publicly
** and display publicly.  Beginning five (5) years after the date
** permission to assert copyright is obtained from the U.S. Department of
** Energy, and subject to any subsequent five (5) year renewals, the
** U.S. Government is granted for itself and others acting on its behalf
** a paid-up, nonexclusive, irrevocable, worldwide license in the
** Software to reproduce, prepare derivative works, distribute copies to
** the public, perform publicly and display publicly, and to permit
** others to do so.
*/

#ifndef _StateDescriptor_H_
#define _StateDescriptor_H_ 
//
// $Id: StateDescriptor.H,v 1.21 2003/02/06 18:14:29 lijewski Exp $
//
#include <utility>
#include <vector>

#include <Array.H>
#include <PArray.H>
#include <REAL.H>
#include <Box.H>
#include <BCRec.H>
#include <ArrayLim.H>

class Interpolater;

extern "C"
{
    typedef void (*BndryFuncDefault)(Real* data, ARLIM_P(lo), ARLIM_P(hi),
                                     const int* dom_lo, const int* dom_hi,
                                     const Real* dx, const Real* grd_lo,
                                     const Real* time, const int* bc);
}

//
//@Man:
//@Memo: Attributes of StateData.
/*@Doc:

  Attributes of StateData.
*/

class StateDescriptor
{
    friend class DescriptorList;

public:
    //
    //@ManDoc: Defines the temporal centeredness of data.
    //
    enum TimeCenter { Point = 0 , Interval };
    //
    //@ManDoc: Type of function called by BCRec for user-supplied boundary data.
    //
    // Class wrapper around BndryFuncDefault.
    //
    class BndryFunc
    {
    public:
        //
        // Bogus constructor.
        //
        BndryFunc ();
        //
        // A Constructor.
        //
        BndryFunc (BndryFuncDefault inFunc);
        //
        // Another Constructor.
        //
        BndryFunc (BndryFuncDefault inFunc,BndryFuncDefault gFunc);
        //
        // Return a ptr to a clone of this object.
        // It is the responsibility of the caller to delete the result.
        //
        virtual BndryFunc* clone () const;
        //
        // Destructor.
        //
        virtual ~BndryFunc ();
        //
        // Fill boundary cells using "regular" function.
        //
        virtual void operator () (Real* data, const int* lo, const int* hi,
                                  const int* dom_lo, const int* dom_hi,
                                  const Real* dx, const Real* grd_lo,
                                  const Real* time, const int* bc) const;
        //
        // Fill boundary cells using "group" function.
        //
        virtual void operator () (Real* data, const int* lo, const int* hi,
                                  const int* dom_lo, const int* dom_hi,
                                  const Real* dx, const Real* grd_lo,
                                  const Real* time, const int* bc, bool) const;
    private:

        BndryFuncDefault  m_func;
        BndryFuncDefault  m_gfunc;
    };
    //
    //@ManDoc: The default constructor.
    //
    StateDescriptor ();
    //
    //@ManDoc: Constructor that sets all data members.
    //
    StateDescriptor (IndexType     btyp,
                     TimeCenter    ttyp,
                     int           ident,
                     int           nextra,
                     int           num_comp,
                     Interpolater* interp,
                     bool          extrap = false);
    //
    //@ManDoc: The destructor.
    //
    ~StateDescriptor ();
    //
    //@ManDoc: Define the data members if constructed with default construtor.
    //
    void define (IndexType     btyp,
                 TimeCenter    ttyp,
                 int           ident,
                 int           nextra,
                 int           num_comp,
                 Interpolater* interp,
                 bool          extrap = false);
    //
    //@ManDoc: Sets details of `comp' component.
    //
    void setComponent (int                comp,
                       const std::string& nm,
                       const BCRec&       bc,
                       const BndryFunc&   func,
                       Interpolater*      interp = 0,
                       int                max_map_start_comp = -1,
                       int                min_map_end_comp   = -1);
    //
    //@ManDoc: Sets details of `comp' component.
    //
    void setComponent (int                comp,
                       const std::string& nm,
                       const BCRec&       bc,
                       const BndryFunc&   func,
                       Interpolater*      interp,
                       bool               master_or_slave,
                       int                groupsize);
    //
    //@ManDoc: Resets boundary condition data for `comp' component.
    //
    void resetComponentBCs (int              comp,
                            const BCRec&     bcr,
                            const BndryFunc& func);
    //
    //@ManDoc: Set interpolaters for a subset of the state vector components.
    //
    void setUpMaps (int&                use_default_map,
                    const Interpolater* default_map,
                    int                 start_comp,
                    int                 num_comp,
                    Interpolater**&     maps, 
                    int&                nmaps,
                    int*&               map_start_comp, 
                    int*&               map_num_comp,
                    int*&               max_start_comp,
                    int*&               min_end_comp) const;
    //
    //@ManDoc: Cleanup interpolaters for a subset of the state vector components.
    //
    void cleanUpMaps (Interpolater**& maps, 
                      int*&           map_start_comp,
                      int*&           map_num_comp,
                      int*&           max_start_comp,
                      int*&           min_end_comp) const;
    //
    //@ManDoc: Output names of components.
    //
    void dumpNames (std::ostream& os,
                    int           start_comp,
                    int           num_comp) const;
    //
    //@ManDoc: Returns the IndexType.
    //
    IndexType getType () const;
    //
    //@ManDoc: Returns StateDescriptor::TimeCenter.
    //
    StateDescriptor::TimeCenter timeType () const;
    //
    //@ManDoc: Returns number of components.
    //
    int nComp () const;
    //
    //@ManDoc: Returns the grow factor.
    //
    int nExtra () const;
    //
    //@ManDoc: Returns the interpolater.
    //
    Interpolater* interp () const;
    //
    //@ManDoc: Returns the interpolater of specified component.
    //
    Interpolater* interp (int i) const;
    //
    //@ManDoc: Returns the name of specified component.
    //
    const std::string& name (int i) const;
    //
    //@ManDoc: Returns the BCRec of specified component.
    //
    const BCRec& getBC (int i) const;
    //
    //@ManDoc: Returns all BCRecs.
    //
    const Array<BCRec>& getBCs () const;
    //
    //@ManDoc: Returns the BndryFunc of specified component.
    //
    const BndryFunc& bndryFill (int i) const;
    //
    //@ManDoc: Is sc>=0 \&\& sc+nc<=ncomp ?
    //
    int inRange (int sc, int nc) const;
    //
    //@ManDoc: Are the interpolaters in the specified range identical?
    //
    bool identicalInterps (int scomp, int ncomp) const;
    //
    //@ManDoc: Returns contiguous ranges of comps with identical interpolaters.
    //
    std::vector< std::pair<int,int> > sameInterps (int scomp, int ncomp) const;
    //
    //@ManDoc: Can extrapolate in time.
    //
    bool extrap () const;

    bool master (int i) const { return m_master[i]; }

    int groupsize (int i) const { return m_groupsize[i]; }

protected:

    IndexType          type;     // Cell centered, node centered ...
    TimeCenter         t_type;   // Temporal centering
    int                id;       // Unique id
    int                ncomp;    // Number of components
    int                ngrow;    // Grow factor
    Interpolater*      mapper;   // Default interpolator
    bool               m_extrap; // Can extrapolate in time?
    Array<std::string> names;    // Printable names of components
    Array<BCRec>       bc;       // Array of bndry types for entire level
    PArray<BndryFunc>  bc_func;  // PArray of pointers to bndry fill functions
    std::vector<bool>  m_master; // Are we a master or slave?
    Array<int>         m_groupsize; // Groupsize if we're a master
    //
    // If mapper_comp[icomp] != 0, that map is used instead of mapper
    // when interpolating icomp; otherwise, mapper is used.
    //
    Array<Interpolater*> mapper_comp;
    //
    // For component icomp, max_map_start_comp[icomp] and
    // min_map_end_comp[icomp] represent the maximum starting index and
    // minimum ending index with which to use mapper_comp[icomp] when
    // interpolating component icomp.  These are convenient for using
    // with "coupled" multiple component maps like CellConservativeLinear.
    //
    // If there is no need to "couple" a component, max_map_start_comp[icomp]
    // and min_map_end_comp[icomp] simply equal icomp.
    //
    Array<int> max_map_start_comp;
    Array<int> min_map_end_comp;
};

//
//@Man:
//@Memo: A List of StateDescriptors.
/*@Doc:

  A container class for StateDescriptors.
*/

class DescriptorList
{
public:
    //
    //@ManDoc: The constructor.
    //
    DescriptorList ();
    //
    //@ManDoc: Set the list to its default state.
    //
    void clear ();
    //
    //@ManDoc: Returns number of elements in the list.
    //
    int size () const;
    //
    //@ManDoc: Adds new StateDescriptor at index `indx' to list.
    //
    void addDescriptor (int                         indx,
                        IndexType                   typ,
                        StateDescriptor::TimeCenter ttyp,
                        int                         nextra,
                        int                         num_comp,
                        Interpolater*               interp,
                        bool                        extrap = false);
    //
    //@ManDoc: Calls resetComponentBCs() on StateDescriptor at index `indx'.
    //
    void resetComponentBCs (int                               indx,
                            int                               comp,
                            const BCRec&                      bc,
                            const StateDescriptor::BndryFunc& func);
    //
    //@ManDoc: Calls setComponent() on StateDescriptor at index `indx'.
    //
    void setComponent (int                               indx,
                       int                               comp,
                       const std::string&                nm,
                       const BCRec&                      bc,
                       const StateDescriptor::BndryFunc& func,
                       Interpolater*                     interp = 0,
                       int                               max_map_start_comp = -1,
                       int                               min_map_end_comp   = -1);
    //
    //@ManDoc: Calls setComponent() on StateDescriptor at index `indx' on group.
    //
    void setComponent (int                               indx,
                       int                               comp,
                       const Array<std::string>&         nm,
                       const Array<BCRec>&               bc,
                       const StateDescriptor::BndryFunc& func,
                       Interpolater*                     interp = 0);
    //
    //@ManDoc: Returns StateDescriptor at index `k'.
    //
    const StateDescriptor& operator[] (int k) const;

private:
    //
    // These are disallowed.
    //
    DescriptorList (const DescriptorList&);
    DescriptorList& operator= (const DescriptorList&);

    PArray<StateDescriptor> desc;
};

#endif /*_StateDescriptor_H_*/
