/*
 * VisibilityBufferAsync.cc
 *
 *  Created on: Nov 1, 2010
 *      Author: jjacobs
 */
#include <stdcasa/UtilJ.h>

using namespace casacore;
#include <regex>  // >>>----------------> no compile failure
using namespace casa::utilj;
// include <regex>   >>>----------------> causes compile failure
#include <casacore/casa/Containers/Record.h>

#include <msvis/MSVis/VisBufferAsync.h>
#include <msvis/MSVis/VisBufferAsyncWrapper.h>
#include <msvis/MSVis/VisibilityIterator.h>
#include <msvis/MSVis/AsynchronousInterface.h>
#include <msvis/MSVis/VLAT.h>

#include <algorithm>

using std::transform;

#include <casacore/ms/MeasurementSets/MSColumns.h>
#include <typeinfo>

#define Log(level, ...) \
    {if (casa::asyncio::AsynchronousInterface::logThis (level)) \
         casa::async::Logger::get()->log (__VA_ARGS__);};

using namespace casacore;
namespace casa {

namespace asyncio {

template <typename MeasureType, typename AsMeasure>
MeasureType
unsharedCopyMeasure (const MeasureType & measure, AsMeasure asMeasure)
{
    // MeasureType is a derived type of MeasBase<> (e.g., MDirection, MEpoch, etc.)
    // AsMeasure is the MeasureHolder converter for the desired type (e.g., asMDirection, asMEpoch, etc.)

    // Make a completely distinct copy of this measure.  The
    // methods provided by a Measure always result in the sharing
    // of the measurement reference object so this roundabout
    // approach is necessary.

    // Using a MeasureHolder object, transform the contents of the
    // measure into a generic record.

    MeasureHolder original (measure);
    Record record;
    String err;

    original.toRecord(err, record);

    // Now use the record to create another MMeasure object using
    // the record created to hold the original's information.

    MeasureHolder copy;
    copy.fromRecord (err, record);

    MeasureType result = (copy .* asMeasure) ();

    return result;
}

} // end namespace asyncio

VisBufferAsync::VisBufferAsync ()
  : VisBuffer ()
{
    construct();
}

VisBufferAsync::VisBufferAsync (const VisBufferAsync & vb)
: VisBuffer ()
{
//    const VisBufferAsync * vb = dynamic_cast<const VisBufferAsync *> (& vb0);
//    ThrowIf (vb == NULL, "Cannot copy VisBuffer into VisBufferAsync");

    construct ();

    * this = vb;
}

VisBufferAsync::VisBufferAsync (ROVisibilityIterator & iter)
  : VisBuffer ()
{
    construct ();

    Log (2, "VisBufferAsync::VisBufferAsync: attaching in constructor this=%08x\n", this);
    attachToVisIter (iter);
}


VisBufferAsync::~VisBufferAsync ()
{
    Log (2, "Destroying VisBufferAsync; addr=0x%016x\n", this);

    // Should never be attached at the synchronous level

    Assert (visIter_p == NULL || ! twoWayConnection_p);

    delete msColumns_p;
    delete msd_p;
}

VisBufferAsync &
VisBufferAsync::operator= (const VisBufferAsync & other)
{
    if (this != & other){

        assign (other, true);
    }

    return * this;
}

void
VisBufferAsync::allSelectedSpectralWindows(Vector<Int> & spectralWindows,
                                           Vector<Int>& nVisibilityChannels)
{
    spectralWindows.assign (selectedSpectralWindows_p);
    nVisibilityChannels.assign (selectedNVisibilityChannels_p);
}

VisBufferAsync &
VisBufferAsync::assign (const VisBuffer & other, Bool copy)
{
    if (this != & other){

        //    assert (copy); // The copy parameter is ignored since it makes no sense to
        //                   // assign a VBA without copying its values

        Log (2, "Assign from VisBufferAsync @ 0x%08x to VisBufferAsync @ 0x%08x\n", & other, this);

        Assert (dynamic_cast<const VisBufferAsync *> (& other) != NULL);
        Assert (visIter_p == NULL); // shouldn't be attached at sync level

        if (other.corrSorted_p)
            throw(AipsError("Cannot assign a VisBuffer that has had correlations sorted!"));

        azelCachedTime_p = 0; // flush this cached value
        feedpaCachedTime_p = 0; // flush this cached value
        parangCachedTime_p = 0; // flush this cached value

        if (copy){

            // Let the standard VisBuffer do the copying of values
            // from the old VisBuffer

            copyCache (other, false);

            // Copy over the async values

            copyAsyncValues (dynamic_cast<const VisBufferAsync &> (other));

        }
    }

    return * this;
}

void
VisBufferAsync::attachToVisIter(ROVisibilityIterator & iter)
{
    Assert (isFilling_p == true); // Only allowed while being filled
    Assert (visIter_p == NULL);   // Shouldn't already be attached

    VisBuffer::attachToVisIter(iter);
}

Vector<MDirection>
VisBufferAsync::azel(Double time) const
{
    if (time != azelCachedTime_p){

        azelCachedTime_p = time;

        ROVisibilityIterator::azelCalculate (time, * msd_p, azelCached_p, nAntennas_p, mEpoch_p);
    }

    return azelCached_p;
}

MDirection
VisBufferAsync::azel0(Double time) const
{
    MDirection azel0;
    //MSDerivedValues msd;
    //msd.setMeasurementSet (* measurementSet_p);


    ROVisibilityIterator::azel0Calculate (time, * msd_p, azel0, mEpoch_p);

    return azel0;
}

void
VisBufferAsync::checkVisIter (const char * func, const char * file, int line, const char * extra) const
{
    // This is called from a VisBuffer fill method.  Throw an error if the this is not
    // part of the VLAT filling operation or if there is not visibility iterator attached

    if (visIter_p == NULL){
        Log (1, "VisBufferAsync: request for column not in prefetched set (in call to %s (%s))\n)",
             func, extra);
        throw AipsErrorTrace ("VisBufferAsync: request for column not in prefetched set (in call to "
                              + String (func) + String (extra) + ")", file, line);
    }
}


void
VisBufferAsync::clear ()
{
    Log (2, "Clearing VisBufferAsync; addr=0x%016x\n", this);

    // Put scalars to deterministic values

    dataDescriptionId_p = -1;
    measurementSet_p = NULL;
    nAntennas_p = 0;

    invalidateAsync ();  // set all the flags to indicate caches are empty

    // Since VBA was created using a shallow copy of shared data
    // it is necessary to break the linkage with the shared data
    // while the shared data is locked.  Otherwise there could be
    // some interaction between the base and lookahead threads
    // because of the reference counted data structures, etc.

    // Wipe the fields that are part of VisBuffer proper

    if (antenna1OK_p)
        antenna1_p.resize();
    if (antenna2OK_p)
        antenna2_p.resize();
    chanAveBounds_p.resize();
    //chanFreqs_p = NULL;
    if (channelOK_p)
        channel_p.resize();
    if (cjonesOK_p)
        cjones_p.resize();
    if (corrTypeOK_p)
        corrType_p.resize();
    if (correctedVisCubeOK_p)
        correctedVisCube_p.resize();
    if (correctedVisibilityOK_p)
        correctedVisibility_p.resize();
    if (direction1OK_p)
        direction1_p.resize();
    if (direction2OK_p)
        direction2_p.resize();
    if (feed1OK_p)
        feed1_p.resize();
    if (feed1_paOK_p)
        feed1_pa_p.resize();
    if (feed2OK_p)
        feed2_p.resize();
    if (feed2_paOK_p)
        feed2_pa_p.resize();
    if (flagCubeOK_p)
        flagCube_p.resize();
    if (flagRowOK_p)
        flagRow_p.resize();
    if (flagOK_p)
        flag_p.resize();
    if (frequencyOK_p)
        frequency_p.resize();
    if (imagingWeightOK_p)
        imagingWeight_p.resize();
//    if (lsrFrequencyOK_p)
//        lsrFrequency_p.resize();
    measurementSet_p = NULL;
    if (modelVisCubeOK_p)
        modelVisCube_p.resize();
    if (modelVisibilityOK_p)
        modelVisibility_p.resize();
    delete msColumns_p;
    msColumns_p = NULL;
    nAntennas_p = -1;
    nCoh_p = -1;
    phaseCenter_p = MDirection ();
    if (rowIdsOK_p)
        rowIds_p.resize();
    if (scanOK_p)
        scan_p.resize();
    if (sigmaMatOK_p)
        sigmaMat_p.resize();
    if (sigmaOK_p)
        sigma_p.resize();
    if (timeIntervalOK_p)
        timeInterval_p.resize();
    if (timeOK_p)
        time_p.resize();
    if (uvwMatOK_p)
        uvwMat_p.resize();
    if (uvwOK_p)
        uvw_p.resize();
    if (visCubeOK_p)
        visCube_p.resize();
    if (visibilityOK_p)
        visibility_p.resize();
    weightCube_p.resize();
    if (weightMatOK_p)
        weightMat_p.resize();
    if (weightSpectrumOK_p)
        weightSpectrum_p.resize();
    if (weightOK_p)
        weight_p.resize();

    // Wipe fields that are part of VisBufferAsync only

    //delete msd_p;
    //msd_p = new MSDerivedValues();

    channelGroupNumber_p.resize (0);
    channelIncrement_p.resize (0);
    channelStart_p.resize (0);
    channelWidth_p.resize (0);
    lsrFrequency_p.resize (0);
    mEpoch_p = MEpoch();
    observatoryPosition_p = MPosition();
    phaseCenter_p = MDirection();
    receptor0Angle_p.resize (0);
    rowIds_p.resize (0);
    selFreq_p.resize (0);
    selectedNVisibilityChannels_p.resize (0);
    selectedSpectralWindows_p.resize (0);
    visibilityShape_p.resize (0, false);
}

VisBuffer *
VisBufferAsync::clone () const
{
    return new VisBufferAsync (* this);
}


void
VisBufferAsync::construct ()
{
    Log (2, "Constructing VisBufferAsync; addr=0x%016x\n", this);

    initializeScalars ();

    azelCachedTime_p = 0; // tag azel as currently uncached
    feedpaCachedTime_p = 0; // tag azel as currently uncached
    parangCachedTime_p = 0; // tag azel as currently uncached
    msColumns_p = NULL;
    visIter_p = NULL;
    isFilling_p = false;
    msd_p = new MSDerivedValues();

    clear ();
}

void
VisBufferAsync::copyCache (const VisBuffer & other, Bool force)
{
    assert (! force);
    UnusedVariable (force);

    VisBuffer::copyCache (other, false);
}


void
VisBufferAsync::copyAsyncValues (const VisBufferAsync & other)
{

    channelGroupNumber_p = other.channelGroupNumber_p;
    channelIncrement_p = other.channelIncrement_p;
    channelStart_p = other.channelStart_p;
    channelWidth_p = other.channelWidth_p;

    dataDescriptionId_p = other.dataDescriptionId_p;
    lsrFrequency_p = other.lsrFrequency_p;
    measurementSet_p = other.measurementSet_p;
    mEpoch_p = other.mEpoch_p;


    delete msColumns_p; // kill the current one
    msColumns_p = NULL;

    nAntennas_p = other.nAntennas_p;
    newArrayId_p = other.newArrayId_p;
    newFieldId_p = other.newFieldId_p;
    newSpectralWindow_p = other.newSpectralWindow_p;
    nRowChunk_p = other.nRowChunk_p;
//    obsMFreqTypes_p = other.obsMFreqTypes_p;
    observatoryPosition_p = other.observatoryPosition_p;
    phaseCenter_p = other.phaseCenter_p;
    receptor0Angle_p = other.receptor0Angle_p;
    rowIds_p = other.rowIds_p;
    selectedNVisibilityChannels_p = other.selectedNVisibilityChannels_p;
    selectedSpectralWindows_p = other.selectedSpectralWindows_p;
    selFreq_p = other.selFreq_p;
    velSelection_p = other.velSelection_p;
    visibilityShape_p = other.visibilityShape_p;

    setMSD (* other.msd_p);
}


//VisBuffer *
//VisBufferAsync::create (const VisBuffer & other)
//{
//
//    VisBuffer * result;
//
//    if (ROVisibilityIteratorAsync::isAsynchronousIoEnabled ()){
//
//        result = new VisBufferAsync (other);
//
//    }
//    else {
//
//
//        result = new VisBuffer (other);
//    }
//
//    return result;
//}


//VisBuffer *
//VisBufferAsync::create (ROVisibilityIterator & iter)
//{
//    return create (& iter);
//}
//
//VisBuffer *
//VisBufferAsync::create (ROVisibilityIterator * iter)
//{
//    VisBuffer * result = NULL;
//    ROVisibilityIteratorAsync * via = dynamic_cast<ROVisibilityIteratorAsync *> (iter);
//
//    bool createAsynchronous = ROVisibilityIteratorAsync::isAsynchronousIoEnabled () &&
//                              via != NULL;
//
//    if (createAsynchronous){
//
//        // Asynchronous I/O is enabled so return a
//        // VisBufferAsync
//
//        Assert (via != NULL); // mixing VB with other than a ROVIA is not good
//        result = new VisBufferAsync (* via);
//    }
//    else {
//
//        // By default return a normal VisBuffer
//
//        Assert (via == NULL); // mixing VB with a ROVIA is not good
//
//        result = new VisBuffer (* iter);
//    }
//
//    String reason;
//    if (ROVisibilityIteratorAsync::isAsynchronousIoEnabled ()){
//        if (via == NULL){
//            reason = format (" (synchronous iterator received: %s)", typeid (* iter).name());
//        }
//        else{
//            reason = format ("Async; addr=0x%016x", result);
//        }
//
//    }
//    else{
//        reason = " (async I/O disabled)";
//    }
//
//    Log (2, "Created VisBuffer%s\n", reason.c_str());
//    //printBacktrace (cerr, "VisBufferAsync creation");
//
//    return result;
//}


//Int
//VisBufferAsync::dataDescriptionId() const
//{
//    return dataDescriptionId_p;
//}

void
VisBufferAsync::detachFromVisIter ()
{

	if (isFilling_p){
	    VisBuffer::detachFromVisIter();
	}
}


Vector<Float>
VisBufferAsync::feed_pa(Double time) const
{
    if (time != feedpaCachedTime_p){

        feedpaCachedTime_p = time;

        if (visIter_p != NULL){

            // This method can be called during filling; if so then let it
            // work the original way (possible hole for detached VBAs).

            feedpaCached_p = VisBuffer::feed_pa (time);
        }
        else{

            //MSDerivedValues msd;
            //msd.setMeasurementSet (* measurementSet_p);

            feedpaCached_p.assign (ROVisibilityIterator::feed_paCalculate (time, * msd_p, nAntennas_p,
                                                                           mEpoch_p, receptor0Angle_p));
        }

    }

    return feedpaCached_p;
}

Bool
VisBufferAsync::fillAllBeamOffsetsZero ()
{
    allBeamOffsetsZero_p = visIter_p->allBeamOffsetsZero();

    return allBeamOffsetsZero_p;
}

Vector <String>
VisBufferAsync::fillAntennaMounts ()
{
    antennaMounts_p = visIter_p->antennaMounts();

    return antennaMounts_p;
}

Cube <RigidVector <Double, 2> >
VisBufferAsync::fillBeamOffsets ()
{
    beamOffsets_p = visIter_p->getBeamOffsets ();

    return beamOffsets_p;
}

Cube <Double>
VisBufferAsync::fillReceptorAngles ()
{
    receptorAngles_p = visIter_p->receptorAngles();

    return receptorAngles_p;
}


void
VisBufferAsync::fillFrom (const VisBufferAsync & other)
{
    // Almost like assignment except that the attachment to the
    // Visibility iterator is preserved.  Only used for copying
    // data from the buffer ring into the user's VB

    Log (2, "Fill from VisBufferAsync @ 0x%08x to VisBufferAsync @ 0x%08x\n", & other, this);

    copyCache (other, false);
    copyAsyncValues (other);

}

Vector<MDirection>&
VisBufferAsync::fillDirection1()
{
    // Perform filling in the normal way

    VisBuffer::fillDirection1();

    if (isFilling_p) {

        // Now install unshared copies of the direction objects

        unsharedCopyDirectionVector (direction1_p);

    }

    return direction1_p;
}



Vector<MDirection>&
VisBufferAsync::fillDirection2()
{
    // Perform filling in the normal way

    VisBuffer::fillDirection2();

    if (isFilling_p){

        // Now install unshared copies of the direction objects

        unsharedCopyDirectionVector (direction2_p);

    }

    return direction2_p;
}

MDirection &
VisBufferAsync::fillPhaseCenter()
{
    // Perform filling in the normal way

    VisBuffer::fillPhaseCenter();

    // Now convert the value to an unshared one.

    phaseCenter_p = unsharedCopyDirection (phaseCenter_p);
    phaseCenterOK_p = true;

    return phaseCenter_p;
}

Bool
VisBufferAsync::getAllBeamOffsetsZero () const
{
    return allBeamOffsetsZero_p;
}

const Vector <String> &
VisBufferAsync::getAntennaMounts () const
{
    return antennaMounts_p;
}

const Cube <RigidVector <Double, 2> > &
VisBufferAsync::getBeamOffsets () const
{
    return beamOffsets_p;
}


const MeasurementSet &
VisBufferAsync::getMs () const
{
    return * measurementSet_p;
}

Int
VisBufferAsync::getNSpw () const
{
    return nSpw_p;
}


MDirection
VisBufferAsync::getPhaseCenter () const
{
    return phaseCenter_p;
}


const Cube <Double> &
VisBufferAsync::getReceptorAngles () const
{
    return receptorAngles_p;
}

Double
VisBufferAsync::hourang(Double time) const
{
    //MSDerivedValues msd;
    //msd.setMeasurementSet (* measurementSet_p);

    Double hourang = ROVisibilityIterator::hourangCalculate (time, * msd_p, mEpoch_p);

    return hourang;
}

void
VisBufferAsync::initializeScalars ()
{
    // Set all VBA specific scalars to known values to prevent
    // nondeterminism.

    dataDescriptionId_p = -1;
    feedpaCachedTime_p = -1;
    isFilling_p = false;
    measurementSet_p = NULL;
    msColumns_p = NULL;
    msd_p = NULL;
    nAntennas_p = -1;
    nCoh_p = -1;
    newArrayId_p = false;
    newFieldId_p = false;
    newSpectralWindow_p = false;
    nRowChunk_p = -1;
    nSpw_p = -1;
    parangCachedTime_p = -1;
    polarizationId_p = -1;
    velSelection_p = false;
}

void
VisBufferAsync::invalidate ()
{
    // This is called by synchronous code.  Just ignore it since
    // the cache validity is being managed by async code.  To really
    // invalidate use invalidateAsync.
}

void
VisBufferAsync::invalidateAsync ()
{
    // A way for the new code to invalidate the buffer that
    // can be distinguished from the old way.

    VisBuffer::invalidate ();
}

void
VisBufferAsync::lsrFrequency (const Int& spw, Vector<Double>& freq, Bool& convert) const
{
    if (velSelection_p) {
        freq.assign (lsrFrequency_p);
        convert = false;
        return;
    }

    const ArrayColumn <Double> & chanFreqs = msColumns().spectralWindow().chanFreq();
    const ScalarColumn<Int> & obsMFreqTypes= msColumns().spectralWindow().measFreqRef();

    MPosition obsPos = observatoryPosition_p;
    MDirection dir = phaseCenter_p;

    ROVisibilityIterator::lsrFrequency (spw, freq, convert, channelStart_p, channelWidth_p, channelIncrement_p,
                                        channelGroupNumber_p, chanFreqs, obsMFreqTypes, mEpoch_p, obsPos, dir);
}

const MSColumns &
VisBufferAsync::msColumns() const
{
    if (isFilling_p){

        Assert (visIter_p != NULL);

        return visIter_p->msColumns ();
    }
    else {

        Assert (measurementSet_p != NULL);

        if (msColumns_p == NULL){
            msColumns_p = new MSColumns (* measurementSet_p);
        }

        return * msColumns_p;
    }
}

Int
VisBufferAsync::msId () const
{
    return oldMSId_p;
}

Bool
VisBufferAsync::newArrayId () const
{
    return newArrayId_p;
}

Bool
VisBufferAsync::newFieldId () const
{
    return newFieldId_p;
}

Bool
VisBufferAsync::newSpectralWindow () const
{
    return newSpectralWindow_p;
}


Bool
VisBufferAsync::newMS() const
{
    return newMS_p;
}


Int
VisBufferAsync::numberAnt () const
{
  return nAntennas_p;
}

Int
VisBufferAsync::numberCoh () const
{
    return nCoh_p;
}


Vector<Float>
VisBufferAsync::parang(Double time) const
{
    if (time != parangCachedTime_p){

        parangCachedTime_p = time;

        parangCached_p = ROVisibilityIterator::parangCalculate (time, * msd_p, nAntennas_p, mEpoch_p);
    }

    return parangCached_p;
}

Float
VisBufferAsync::parang0(Double time) const
{
    //MSDerivedValues msd;
    //msd.setMeasurementSet (* measurementSet_p);

    Float parang0 = ROVisibilityIterator::parang0Calculate (time, * msd_p, mEpoch_p);

    return parang0;
}

Int
VisBufferAsync::polarizationId() const
{
    return polarizationId_p;
}



//Vector<uInt>&
//VisBufferAsync::rowIds()
//{
//    return rowIds_p;
//}

//void
//VisBufferAsync::setDataDescriptionId (Int id)
//{
//    dataDescriptionId_p = id;
//}

void
VisBufferAsync::setCorrectedVisCube(Complex c)
{
    correctedVisCube_p.resize(visibilityShape_p);
    correctedVisCube_p.set(c);
    correctedVisCubeOK_p=true;
}

void
VisBufferAsync::setCorrectedVisCube (const Cube<Complex> & vis)
{
    VisBuffer::setCorrectedVisCube (vis);
}


void
VisBufferAsync::setModelVisCube (const Cube<Complex> & vis)
{
    VisBuffer::setModelVisCube (vis);
}

void
VisBufferAsync::setModelVisCube (const Vector<Float> & stokes)
{
    VisBuffer::setModelVisCube (stokes);
}

void
VisBufferAsync::setNRowChunk (Int nRowChunk)
{
    nRowChunk_p = nRowChunk;
}


void
VisBufferAsync::setFilling (Bool isFilling)
{
    isFilling_p = isFilling;
}

void
VisBufferAsync::setLsrInfo (const Block <Int> & channelGroupNumber,
                            const Block <Int> & channelIncrement,
                            const Block <Int> & channelStart,
                            const Block <Int> & channelWidth,
                            const MPosition & observatoryPosition,
                            const MDirection & phaseCenter,
                            Bool velocitySelection)
{
    channelGroupNumber_p = channelGroupNumber;
    channelIncrement_p = channelIncrement;
    channelStart_p = channelStart;
    channelWidth_p = channelWidth;
    observatoryPosition_p = unsharedCopyPosition (observatoryPosition);
    phaseCenter_p = unsharedCopyDirection (phaseCenter);
    velSelection_p = velocitySelection;
}


void
VisBufferAsync::setMeasurementSet (const MeasurementSet & ms)
{
    measurementSet_p = & ms;
    //msd_p->setMeasurementSet (ms);
}

void
VisBufferAsync::setMeasurementSetId (Int id, Bool isNew)
{
    oldMSId_p = id;
    msOK_p = true;
    newMS_p = isNew;
}


void
VisBufferAsync::setMEpoch (const MEpoch & mEpoch)
{
    mEpoch_p = unsharedCopyEpoch (mEpoch);
}

void
VisBufferAsync::setModelVisCube(Complex c)
{
    modelVisCube_p.resize(visibilityShape_p);
    modelVisCube_p.set(c);
    modelVisCubeOK_p=true;
}

void
VisBufferAsync::setMSD (const MSDerivedValues & msd)
{
    * msd_p = msd;

    msd_p->setEpoch (mEpoch_p);

    // set antennas

    const Vector<MPosition> & antennaPositions = msd.getAntennaPositions();
    Vector<MPosition> unsharedAntennaPositions (antennaPositions.nelements());

    for (Vector<MPosition>::const_iterator ap = antennaPositions.begin();
            ap != antennaPositions.end();
            ap ++){

        unsharedAntennaPositions = unsharedCopyPosition (* ap);
    }

    msd_p->setAntennaPositions (unsharedAntennaPositions);

    msd_p->setObservatoryPosition (observatoryPosition_p);

    msd_p->setFieldCenter (phaseCenter_p);

    msd_p->setVelocityFrame (msd.getRadialVelocityType ());
}


void
VisBufferAsync::setNAntennas (Int nAntennas)
{
    nAntennas_p = nAntennas;
}

void
VisBufferAsync::setNCoh (Int nCoh)
{
    nCoh_p = nCoh;
}

void
VisBufferAsync::setNewEntityFlags (bool newArrayId, bool newFieldId, bool newSpectralWindow)
{
    newArrayId_p = newArrayId;
    newFieldId_p = newFieldId;
    newSpectralWindow_p = newSpectralWindow;
}

void
VisBufferAsync::setNSpw (Int nSpw)
{
    nSpw_p = nSpw;
}


void
VisBufferAsync::setPolarizationId (Int pId)
{
    polarizationId_p = pId;
}

void
VisBufferAsync::setReceptor0Angle (const Vector<Float> & angles)
{
    receptor0Angle_p = angles;
}

void
VisBufferAsync::setRowIds (const Vector<rownr_t> & rowIds)
{
    rowIds_p = rowIds;
}

void
VisBufferAsync::setSelectedNVisibilityChannels (const Vector<Int> & nVisibilityChannels)
{
    selectedNVisibilityChannels_p.assign (nVisibilityChannels);
}

void
VisBufferAsync::setSelectedSpectralWindows (const Vector<Int> & spectralWindows)
{
    selectedSpectralWindows_p.assign (spectralWindows);
}


void
VisBufferAsync::setTopoFreqs (const Vector<Double> & lsrFreq, const Vector<Double> & selFreq)
{
    lsrFrequency_p.assign (lsrFreq);
    selFreq_p.assign (selFreq);
}

void
VisBufferAsync::setVisCube(Complex c)
{
    visCube_p.resize(visibilityShape_p);
    visCube_p.set(c);
    visCubeOK_p=true;
}

void
VisBufferAsync::setVisCube (const Cube<Complex>& vis)
{
    VisBuffer::setVisCube (vis);
}


void
VisBufferAsync::setVisibilityShape (const IPosition & visibilityShape)
{
    visibilityShape_p = visibilityShape;
}

MDirection
VisBufferAsync::unsharedCopyDirection (const MDirection & direction)
{
    return asyncio::unsharedCopyMeasure (direction, & MeasureHolder::asMDirection);
}

void
VisBufferAsync::unsharedCopyDirectionVector (Vector<MDirection> & direction)
{
    // The MDirection object consists of the actual direction a frame of reference
    // object.  The direction component follows copy semnatics while the frame of
    // reference uses a counter pointer and is shared across multiple MDirections.
    // This causes problems now that values are being shared across threads.  Modify
    // the direction vector so that the frame of reference object is only shared
    // within this vector.  N.B., this could cause a problem if there is comparison
    // between the reference frames of the two direction.  Each element doesn't get
    // its own copy because the unsharing operation is klugy and somewhat compute
    // intensive.

    int nElements = direction.shape () [0];

    if (nElements > 0){

        // Take the first reference frame object, make an unshared copy and provide it to
        // any of the other direction components which use the same reference.  If a
        // direction uses a different reference give it its own unshared copy.

        MeasRef<MDirection> uncleanRef = direction[0].getRef ();
        MDirection cleanDirection = unsharedCopyDirection (direction[0]);
        MeasRef<MDirection> cleanRef = cleanDirection.getRef ();
            // Since cleanRef uses a counted pointer to an underlying object
            // the above construction does not cause a dangling pointer problem.

        for (int i = 0; i < nElements; i++){

            // If this element of the direction uses the same reference as the
            // original, then just install a reference to our "clean" reference.
            // N.B., the == comparasion just compares the pointer to the underlying
            // reference frame object!

            if (uncleanRef == direction[i].getRef()){

                direction[i].set (cleanRef);
            }
            else {
                direction[i] = unsharedCopyDirection (direction[i]);
            }
        }
    }
}

MEpoch
VisBufferAsync::unsharedCopyEpoch (const MEpoch & epoch)
{
    return asyncio::unsharedCopyMeasure (epoch, & MeasureHolder::asMEpoch);
}

MPosition
VisBufferAsync::unsharedCopyPosition (const MPosition & position)
{
    return asyncio::unsharedCopyMeasure (position, & MeasureHolder::asMPosition);
}

void
VisBufferAsync::updateCoordInfo(const VisBuffer * other, const Bool dirDepend)
{
    clear ();
    copyVector (other->antenna1_p, antenna1_p);
    antenna1OK_p = true;
    copyVector (other->antenna2_p, antenna2_p);
    antenna2OK_p = true;
    copyVector (other->time_p, time_p);
    timeOK_p = true;
    copyVector (other->frequency_p, frequency_p);
    frequencyOK_p = true;
    copyVector (other->feed1_p, feed1_p);
    feed1OK_p = true;
    copyVector (other->feed2_p, feed2_p);
    feed2OK_p = true;
    if(dirDepend){
      copyVector (other->feed1_pa_p, feed1_pa_p);
      feed1_paOK_p = true;
      copyVector (other->feed2_pa_p, feed2_pa_p);
      feed2_paOK_p = true;
      //copyVector (direction1_p);
      //copyVector (direction2_p);
    }
    else{
      feed1_paOK_p=false; 
      feed2_paOK_p=false;
      direction1OK_p=false;
      direction2OK_p=false;
    }
}




using namespace casacore;
} // end namespace casa