#ifndef CONVERGENCEMASTER_H
#define CONVERGENCEMASTER_H
//_____________________________________________________________________________
///
/// \class ConvergenceMaster 
///
/// ConvergencMaster - class guiding the sequence in which fits are attemmpted.
/// During the initial iterations many of the track hits are "masked out" and 
/// ignored by the fitter. As the iterations progress ConvergenceMaster keeps 
/// unmasking the hits until the longest possible part of the track (starting
/// at the vertex) is fit using all hits. The "masks" are stored in vectors
/// and organized in "binary levels" where a "next" level mask is obtained by
/// removing every other hit from a "current" level mask.
///
/// \author Sergei avva@fnal.gov
///

#include <vector>
#include <list>

#include "Rtypes.h"

class DataFT;


class ConvergenceMaster {

public:
    typedef Int_t                           Count_t;
    
    typedef UShort_t                        Mask_t;
    typedef std::vector<Mask_t>             ViewMask_t;
    
private:    
    typedef ViewMask_t::iterator            ViewMaskItr;
    typedef ViewMask_t::reverse_iterator    ViewMaskRItr;
    typedef ViewMask_t::const_iterator      ViewMaskCItr;
    typedef ViewMask_t::const_reverse_iterator ViewMaskCRItr;
    typedef std::vector<ViewMask_t>         ViewMaskVec_t;
    typedef std::list<ViewMask_t>           ViewMaskList_t;
    typedef ViewMaskList_t::iterator        ViewMaskListItr;
    typedef ViewMaskList_t::const_iterator  ViewMaskListCItr;
    
    ///
    /// nested class MaskStep - holds U and V masks for one "level",
    /// minimum allowed plane count, maximum plane count, current
    /// plane count, last plane count 
    ///
    class MaskStep {
    
        public:
            MaskStep(   const ViewMask_t& umask, const ViewMask_t& vmask,
                        Int_t nhitsinviewmin                              
                    );
            ~MaskStep();
                
            Bool_t      IncrementPlaneCount();
            Bool_t      DecrementPlaneCount();
            
            Count_t     GetPlaneCountCur() const { return fPlaneCountCur; };
            void        SetPlaneCountCur(Count_t n) { fPlaneCountCur = n; };
            void        SetPlaneCountLast(Count_t n) { fPlaneCountLast = n; };
            
            Count_t     GetPlaneCountMax() const { return fPlaneCountMax; };
            Count_t     GetPlaneCountMin() const { return fPlaneCountMin; };
            Count_t     GetPlaneCountLast() const { return fPlaneCountLast; };
            Bool_t      GetConvergedCur() const { return fConvergedCur; };
            
            Count_t     GetNPlanesToFit() const { return GetPlaneCountCur(); };        
                        
            void        SetConverged() { fConvergedCur = kTRUE; };
            void        SetDiverged()  { fConvergedCur = kFALSE; };
        
            Count_t     FindPlaneCountMin( const ViewMask_t& mask, 
                                                 Count_t nhitsmin  );
            Count_t     FindPlaneCountMax( const ViewMask_t& mask  );
            
            const ViewMask_t& GetMaskU() const { return fMaskU; } ;
            const ViewMask_t& GetMaskV() const { return fMaskV; };
            
            void        Print() const;
            void        PrintMasks() const;
            
        private:
            ViewMask_t      fMaskU;
            ViewMask_t      fMaskV;
            
            ViewMask_t      fMaskUVSum;
            
            Count_t         fPlaneCountMin;
            Count_t         fPlaneCountMax;
            
            Count_t         fPlaneCountCur;
            Bool_t          fConvergedCur;
            
            Count_t         fPlaneCountLast;        
    };
                        
    typedef std::vector<MaskStep>           MaskList_t;
    typedef MaskList_t::iterator            MaskListItr;
    typedef MaskList_t::const_iterator      MaskListCItr;

public:
    ConvergenceMaster(Int_t nhitsinviewmin = 4);
    ~ConvergenceMaster();

    ///
    /// Create mask arrays
    ///
    void        BuildMasks(const DataFT& data);
        
    void        SetNHitsInViewMin(Int_t n) 
                    { fNHitsInViewMin = n; } ;
    
    Bool_t      NextStep();
    
    Bool_t      MaskIsValid() const { return fMaskIsValid; };
    void        SetMaskIsValid(Bool_t valid) { fMaskIsValid = valid; };
    
    void        SetConverged() { fMaskCur->SetConverged(); };    
    void        SetDiverged()  { fMaskCur->SetDiverged(); };
    
    Count_t     GetNPlanesCur() const;    
    Count_t     GetNPlanesMin() const;    
    Count_t     GetNPlanesMax() const;    
        
    const ViewMask_t& GetMaskUCur() const;
    const ViewMask_t& GetMaskVCur() const;    
    
private:
    void    PrintMasks() const;
    
    void    SetInitialMask();
    
    void    BuildMaskSteps( const ViewMaskList_t& maskU, 
                            const ViewMaskList_t& maskV  );
    
    void    BuildViewMasks(const ViewMask_t& maskIn, 
                            ViewMaskList_t& maskList);
    
    Bool_t  UnsetEverySecond(ViewMask_t& mask);        
    
    void    PadMaskLists(ViewMaskList_t& maskU, ViewMaskList_t& maskV);
    void    PadWithLastElement(ViewMaskList_t& maskList, UInt_t n);

    Bool_t      IncrementPlaneCount();
    Bool_t      DecrementPlaneCount();
    Bool_t      NextMask(Count_t planeCount);
    
    Int_t           fNHitsInViewMin;
    
    MaskList_t      fMaskList;    
    MaskListItr     fMaskCur;    
    
    Bool_t          fMaskIsValid;
};

#endif
