//# LayeredVi2Factory.h: Interface definition of the LayeredVi2Factory class.
//#
//#  CASA - Common Astronomy Software Applications (http://casa.nrao.edu/)
//#  Copyright (C) Associated Universities, Inc. Washington DC, USA 2011, All rights reserved.
//#  Copyright (C) European Southern Observatory, 2011, All rights reserved.
//#
//#  This library is free software; you can redistribute it and/or
//#  modify it under the terms of the GNU Lesser General Public
//#  License as published by the Free software Foundation; either
//#  version 2.1 of the License, or (at your option) any later version.
//#
//#  This library is distributed in the hope that it will be useful,
//#  but WITHOUT ANY WARRANTY, without even the implied warranty of
//#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//#  Lesser General Public License for more details.
//#
//#  You should have received a copy of the GNU Lesser General Public
//#  License along with this library; if not, write to the Free Software
//#  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
//#  MA 02111-1307  USA
//# $Id: $

#ifndef LayeredVi2Factory_H_
#define LayeredVi2Factory_H_

// Where ViFactory interface is defined
#include <msvis/MSVis/VisibilityIterator2.h>
#include <msvis/MSVis/IteratingParameters.h>

#include <casacore/casa/Containers/Record.h>

namespace casa { //# NAMESPACE CASA - BEGIN
namespace vi { //# NAMESPACE VI - BEGIN

class IteratingParameters;
class AveragingParameters;
class CalibratingVi2FactoryI;

// <summary>
// A factory for generating ViImplementation2 layers that optionally include calibration
//  (via CalibratingVi2) and time-averaging (via AveragingTvi2).
// </summary>
//
// <use visibility=export>
//
// <prerequisite>
//   <li> <linkto class="VisibilityIterator2:description">VisibilityIterator2</linkto>
//   <li> <linkto class="CalibratingVi2:description">CalibratingVi2</linkto>
//   <li> <linkto class="AveragingTvi2:description">AveraringTvi2</linkto>
// </prerequisite>
//
// <etymology>
// Factory for layered ViImplementation2 construction
// </etymology>
//
// <synopsis>
// LayeredVi2Factory generates a Visibility Iterator implementation (ViImplementation2)
// object that can be plugged into a Visibility Iterator (VisibilityIterator2) object,
// so that the user can access the data using the Visibility Iterator interface.
// The ViImplementation2 generated by this factory consists of an underlying 
// VisibilityIteratorImpl2, and (optionally) CalibratingVi2 and AveragingTvi2 ViImplementation2s, 
// thereby supporting these operations in sequence.  When both calibration and averaging
// are invoked, calibration is hard-wired to occur first.
// </synopsis>
//
// <motivation>
// This class makes the combination of OTF calibration application and time-averaging portable,
// and available to all VisibilityIterator2 users.
// </motivation>
//
// <example>
// External usage is quite simple, and compliant with the 'normal' VI/VB framework.
//
// The user first makes objects describing the data iteration, calibration parameters,
// and averaging parameters:
//
// <srcblock>
//      IteratingParameters iterpar(60.0);  // 60s chunk interval
//
//      casacore::Float calfactor(100.0);             // a simple factor with which to multiply the data
//      casacore::Record calrec;                      //   (in leiu of full VisEquation functionality (TBD)
//      calrec.define("calfactor",calfactor); // in a casacore::Record   
//                                            
//      AveragingParameters avepar(10.0);   // 10s averaging
//
//
// </srcblock>
//
// Then these parameter objects, along with a casacore::MeasurementSet pointer, are used to make
//  a factory suitable for the generic VisibilityIterator2 ctor, which is then invoked
//
// <srcblock>
//      casacore::MeasurementSet *ms(....);   // typically from elsewhere, e.g., selected
//      LayeredVi2Factory factory(ms,&iterpar,calrec,&avepar);
//      vi::VisibilityIterator2 *visIter = new vi::VisibilityIterator2 (factory);
//      vi::VisBuffer2 *visBuffer = visIter->getVisBuffer();
// </srcblock>
//
// Once this is done one can normally iterate and access OTF calibrated and averaged data:
//
// <srcblock>
//      while (visIter->moreChunks())
//      {
//              visIter->origin();
//
//              while (visIter->more())
//              {
//
//                      // the following will have been calibrated and averaged to 10s
//                      casacore::Vector<casacore::Int> ddi = visBuffer->dataDescriptionIds();
//                      casacore::Vector<casacore::Int> antenna1 = visBuffer->antenna1();
//                      casacore::Vector<casacore::Int> antenna2 = visBuffer->antenna2();
//                      casacore::Cube<casacore::Complex> cvis = visBuffer->visCubeCorrected();
//
//                      visIter->next();
//              }
//
//              visIter->nextChunk();
//      }
// </srcblock>
//
// casacore::Notice that it is the responsibility of the application layer to delete the VisibilityIterator2
// pointer returned by the factory method. However the life cycle of the VisBuffer2 object is
// responsibility of the VisibilityIterator2 object.
//
// <srcblock>
//      delete visIter;
// </srcblock>
//
// </example>



class LayeredVi2Factory : public vi::ViFactory
{

public:

  // Non-calibrating version
  LayeredVi2Factory(casacore::MeasurementSet* ms,
		    IteratingParameters* iterpar,
		    AveragingParameters* avepar=0);
  // Calibrating version, via CalLib Record
  LayeredVi2Factory(casacore::MeasurementSet* ms,
		    IteratingParameters* iterpar,
		    const casacore::Record& calrec,
		    AveragingParameters* avepar=0);
  // Calibrating version, vis CalLib casacore::String (filename or casacore::String)
  LayeredVi2Factory(casacore::MeasurementSet* ms,
		    IteratingParameters* iterpar,
		    const casacore::String& callib,
		    AveragingParameters* avepar=0);
  ~LayeredVi2Factory();

  vi::ViImplementation2 * createVi () const;
  vi::ViImplementation2 * createVi (vi::ViImplementation2 *) const {throw(casacore::AipsError("NYI!"));};  // NYI

private:

  casacore::MeasurementSet* ms_p;

  vi::IteratingParameters* iterpar_p;
  vi::AveragingParameters* avepar_p;
  casacore::Bool doCal_p;
  casacore::String callib_p;
  casacore::Record calrec_p;
  casacore::Int nlayer_p;
  CalibratingVi2FactoryI* calvi2factory_p;

};



//////////////////////////////////////////////////////////////////////
//
// Class VisIterImpl2LayerFactory
//
//  (Ideally, this should be in ViiLayerFactory.h, but it has include problems there)
//
class VisIterImpl2LayerFactory : public ViiLayerFactory {

 public:
  
    VisIterImpl2LayerFactory(casacore::MeasurementSet* ms,
                             const IteratingParameters& pars,
                             bool writable,
                             bool useMSIter2=false);

    VisIterImpl2LayerFactory(casacore::MeasurementSet * ms,
                             const SortColumns & chunkSortColumns,
                             const SortColumns & subchunkSortColumns,
                             bool writable);

  void setFrequencySelections(std::shared_ptr<FrequencySelections> selections);

  virtual ~VisIterImpl2LayerFactory () {}

 protected:

  // VisibilityIteratorImpl2-specific layer-creater
  //   
  virtual ViImplementation2 * createInstance (ViImplementation2* vii0) const;

 private:

  // Pointer to _external_ ms  (support only one, for now)
  casacore::MeasurementSet* ms_;

  // Store a copy of the parameters
  const vi::IteratingParameters pars_;

  // Should VisibilityIteratorImpl2 be generated w/ write-permission
  bool writable_;

  // Control use of ~experimental MSIter2, which has smarter time iteration
  bool useMSIter2_;

  // Whether full sorting specification has been configured
  bool fullSortingSpecification_p;

  //Frequency selections to be applied to the generated visibility iterator 
  std::shared_ptr<FrequencySelections> frequencySelections_p;

  // Sorting specification for chunks
  SortColumns chunkSortColumns_p;

  // Sorting specification for subchunks
  SortColumns subchunkSortColumns_p;

};



} //# NAMESPACE VI - END
} //# NAMESPACE CASA - END


#endif /* LayeredVi2Factory_H_ */