//# FlagAgentSummary.cc: This file contains the implementation of the FlagAgentSummary 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: $

#include <flagging/Flagging/FlagAgentSummary.h>

#include <casacore/measures/TableMeasures/ScalarMeasColumn.h>

using namespace casacore;
namespace casa { //# NAMESPACE CASA - BEGIN

FlagAgentSummary::FlagAgentSummary(FlagDataHandler *dh, Record config):
		        FlagAgentBase(dh,config,ROWS_PREPROCESS_BUFFER,false)
{
    arrayId = 0;
    fieldId = 0;
    spw = 0;
    scan = 0;
    observationId = 0;

    arrayId_str = String("");
    fieldId_str = String("");
    spw_str = String("");
    observationId_str = String("");

    spwChannelCounts = false;
    spwPolarizationCounts = false;
    baselineCounts = false;
    fieldCounts = false;
    display_p = String("none");

    setAgentParameters(config);

    currentSummary = NULL;
    fieldSummaryMap.clear();
    if (fieldCounts)
    {
    	currentSummary = NULL;
    }
    else
    {
    	currentSummary = new summary();
    }

    // Request loading polarization map to FlagDataHandler
    flagDataHandler_p->setMapPolarizations(true);

    // Request pre-loading array,field,spw, scan, observation, antenna1, antenna2
    flagDataHandler_p->preLoadColumn(VisBufferComponent2::ArrayId);
    flagDataHandler_p->preLoadColumn(VisBufferComponent2::FieldId);
    flagDataHandler_p->preLoadColumn(VisBufferComponent2::Scan);
    flagDataHandler_p->preLoadColumn(VisBufferComponent2::ObservationId);
    flagDataHandler_p->preLoadColumn(VisBufferComponent2::SpectralWindows);
    flagDataHandler_p->preLoadColumn(VisBufferComponent2::Antenna1);
    flagDataHandler_p->preLoadColumn(VisBufferComponent2::Antenna2);
    //flagDataHandler_p->preLoadColumn(vi::Freq);
}

FlagAgentSummary::~FlagAgentSummary()
{
    if (fieldCounts)
    {
        for(const auto &iter : fieldSummaryMap)
        {
            delete iter.second;
        }
        fieldSummaryMap.clear();
    }
    else
    {
        delete currentSummary;
    }

    // Compiler automagically calls FlagAgentBase::~FlagAgentBase()
}

void
FlagAgentSummary::setAgentParameters(Record config)
{
    logger_p->origin(LogOrigin(agentName_p,__FUNCTION__,WHERE));

    int exists;

    exists = config.fieldNumber ("spwchan");
    if (exists >= 0)
    {
        if( config.type(exists) != TpBool )
        {
            throw( AipsError ( "Parameter 'spwchan' must be of type 'bool'" ) );
        }

        spwChannelCounts = config.asBool("spwchan");
    }
    else
    {
        spwChannelCounts = false;
    }

    if (spwChannelCounts)
    {
        *logger_p << LogIO::NORMAL << " Spw-Channel count activated " << LogIO::POST;
    }
/*
    else
    {
        *logger_p << LogIO::NORMAL << " Spw-Channel count deactivated " << LogIO::POST;
    }
*/

    exists = config.fieldNumber ("spwcorr");
    if (exists >= 0)
    {
        if( config.type(exists) != TpBool )
        {
            throw( AipsError ( "Parameter 'spwcorr' must be of type 'bool'" ) );
        }

        spwPolarizationCounts = config.asBool("spwcorr");
    }
    else
    {
        spwPolarizationCounts = false;
    }

    if (spwPolarizationCounts)
    {
        *logger_p << LogIO::NORMAL << " Spw-Correlation count activated " << LogIO::POST;
    }
/*
    else
    {
        *logger_p << LogIO::NORMAL << " Spw-Correlation count deactivated " << LogIO::POST;
    }
*/

    exists = config.fieldNumber ("basecnt");
    if (exists >= 0)
    {
        if( config.type(exists) != TpBool )
        {
            throw( AipsError ( "Parameter 'basecnt' must be of type 'bool'" ) );
        }

        baselineCounts = config.asBool("basecnt");
    }
    else
    {
        baselineCounts = false;
    }

    if (baselineCounts)
    {
        *logger_p << LogIO::NORMAL << " Baseline count activated " << LogIO::POST;
    }
/*
    else
    {
        *logger_p << LogIO::NORMAL << " Baseline count deactivated " << LogIO::POST;
    }
*/

    exists = config.fieldNumber ("fieldcnt");
    if (exists >= 0)
    {
        if( config.type(exists) != TpBool )
        {
            throw( AipsError ( "Parameter 'fieldcnt' must be of type 'bool'" ) );
        }

        fieldCounts = config.asBool("fieldcnt");
    }
    else
    {
    	fieldCounts = false;
    }

    if (fieldCounts)
    {
        *logger_p << LogIO::NORMAL << " Field breakdown activated " << LogIO::POST;
    }
/*
    else
    {
        *logger_p << LogIO::NORMAL << " Field breakdown deactivated " << LogIO::POST;
    }
*/

	exists = config.fieldNumber ("display");
	if (exists >= 0)
	{
		if( config.type(exists) != TpString )
		{
			throw( AipsError ( "Parameter 'display' must be of type 'string'" ) );
		}

		display_p = config.asString("display");
		*logger_p << LogIO::NORMAL << " display is: " << display_p << LogIO::POST;
	}


    return;
}

void
FlagAgentSummary::preProcessBuffer(const vi::VisBuffer2 &visBuffer)
{
    arrayId = visBuffer.arrayId()(0);
    arrayId_str = std::to_string(arrayId);

    fieldId = visBuffer.fieldId()(0);
    // Transform fieldId into field name using the corresponding subtable
    fieldId_str = flagDataHandler_p->fieldNames_p->operator()(fieldId);

    spw = visBuffer.spectralWindows()(0);
    spw_str = std::to_string(spw);

    observationId = visBuffer.observationId()[0];
    observationId_str = std::to_string(observationId);

    // Read in channel-frequencies.
    // RVU : I'm not sure if this should go here, or in the FlagDataHandler so that all agents get it.
    if (spwChannelCounts) {
        Vector<Double> flist(visBuffer.getFrequencies(0,MFrequency::TOPO));
        for(Int i=0;i<(Int) flist.nelements();i++)
            frequencyList[spw].push_back(flist[i]);
    }

    if (fieldCounts)
    {
        if (fieldSummaryMap.find(fieldId_str) != fieldSummaryMap.end())
        {
        	currentSummary = fieldSummaryMap[fieldId_str];
        }
        else
        {
        	summary *newsummary = new summary();
        	fieldSummaryMap.insert(std::pair<std::string, summary*>(fieldId_str,newsummary) );
        	currentSummary = fieldSummaryMap[fieldId_str];
        }
    }

    bufferTotal = 0;
    bufferFlags = 0;
}

bool
FlagAgentSummary::computeRowFlags(const vi::VisBuffer2 &visBuffer, FlagMapper &flags,
                                  uInt row)
{
    const Int antenna1 = visBuffer.antenna1()[row];
    const Int antenna2 = visBuffer.antenna2()[row];
    const auto antenna1Name = flagDataHandler_p->antennaNames_p->operator()(antenna1);
    const auto antenna2Name = flagDataHandler_p->antennaNames_p->operator()(antenna2);

    // Get scan for each particular row to cover for the "combine scans" case
    const auto scan = visBuffer.scan()[row];
    const auto scan_str = std::to_string(scan);

    // Compute totals
    Int nChannels, nRows;
    flags.shape(nChannels,nRows);
    const vector< vector<uInt> > polarizations = flags.getSelectedCorrelations();
    const Int nPolarizations = polarizations.size();
    const uInt64 rowTotal = nChannels*nPolarizations;

    // Initialize polarization counts
    Int pol_i = 0;;
    vector<uInt64> polarizationsBreakdownFlags(nPolarizations, 0);

    // Iterate through channels
    Bool flag;
    Int channel_i = 0;
    uInt64 rowFlags = 0;
    uInt64 channelFlags = 0;
    for (channel_i=0; channel_i<nChannels; ++channel_i)
    {
        channelFlags = 0;
        for (pol_i=0; pol_i < nPolarizations; ++pol_i)
        {
            flag = flags.getModifiedFlags(pol_i,channel_i,row);
            channelFlags += flag;
            polarizationsBreakdownFlags[pol_i] += flag;
        }
        rowFlags += channelFlags;

        if (spwChannelCounts)
        {
            currentSummary->accumChanneltotal[spw][channel_i] += nPolarizations;
            currentSummary->accumChannelflags[spw][channel_i] += channelFlags;
        }
    }

    // Update polarization counts
    const polarizationIndexMap *toPolarizationIndexMap =
        flagDataHandler_p->getPolarizationIndexMap();
    for (pol_i=0; pol_i < nPolarizations; ++pol_i)
    {
        const auto &polarization_str = (*toPolarizationIndexMap).at(polarizations[pol_i][0]);
        currentSummary->accumtotal["correlation"][polarization_str] += nChannels;
        currentSummary->accumflags["correlation"][polarization_str] += polarizationsBreakdownFlags[pol_i];

        if (spwPolarizationCounts)
        {
            currentSummary->accumPolarizationtotal[spw][polarization_str] += nChannels;
            currentSummary->accumPolarizationflags[spw][polarization_str] += polarizationsBreakdownFlags[pol_i];
        }
    }

    // Update row counts in fields that require row specific info (like scan, antenna and,
    // optionally, baseline)
    currentSummary->accumtotal["scan"][scan_str] += rowTotal;
    currentSummary->accumflags["scan"][scan_str] += rowFlags;

    currentSummary->accumtotal["antenna"][antenna1Name] += rowTotal;
    currentSummary->accumflags["antenna"][antenna1Name] += rowFlags;

    if (antenna1 != antenna2)
    {
    	currentSummary->accumtotal["antenna"][antenna2Name] += rowTotal;
        currentSummary->accumflags["antenna"][antenna2Name] += rowFlags;
    }

    if ( baselineCounts )
    {
        const auto baseline = antenna1Name + "&&" + antenna2Name;
    	currentSummary->accumtotal["baseline"][baseline] += rowTotal;
        currentSummary->accumflags["baseline"][baseline] += rowFlags;
        currentSummary->accumAntScantotal[antenna1][scan] += rowTotal;
        currentSummary->accumAntScanflags[antenna1][scan] += rowFlags;
        if (antenna1 != antenna2)
        {
            currentSummary->accumAntScantotal[antenna2][scan] += rowTotal;
            currentSummary->accumAntScanflags[antenna2][scan] += rowFlags;
        }
    }

    // keep updating buffer totals for postProcessBuffer()
    bufferTotal += rowTotal;
    bufferFlags += rowFlags;

    return false;
}

void
FlagAgentSummary::postProcessBuffer() {
    // Update here the summary fields that do not need to be updated on a row per row basis
    // (in computeRowFlags which would otherwise repeat all this many more times than needed)
    // The main reason to put these here is that this is much faster (CAS-12714)
    currentSummary->accumtotal["array"][arrayId_str] += bufferTotal;
    currentSummary->accumflags["array"][arrayId_str] += bufferFlags;

    currentSummary->accumtotal["field"][fieldId_str] += bufferTotal;
    currentSummary->accumflags["field"][fieldId_str] += bufferFlags;

    currentSummary->accumtotal["spw"][spw_str] += bufferTotal;
    currentSummary->accumflags["spw"][spw_str] += bufferFlags;

    currentSummary->accumtotal["observation"][observationId_str] += bufferTotal;
    currentSummary->accumflags["observation"][observationId_str] += bufferFlags;

    currentSummary->accumTotalCount += bufferTotal;
    currentSummary->accumTotalFlags += bufferFlags;
}

FlagReport
FlagAgentSummary::getReport()
{
    // Make the flagreport list
    FlagReport summarylist("list");

    // Add the standard summary dictionary as a report of type 'summary'
//    summarylist.addReport( FlagReport("summary", agentName_p, getResult())  );
    summarylist.addReport( FlagReport("summary", summaryName_p, getResult())  );

    //////// Note : Calculate extra views only if the user has asked for it.
    /////// If returning only summary report, do the following.
    ////////  return FlagReport("summary", agentName_p, getResult());

    // Add a list of reports from the flag-count dictionary
    if ( (display_p == String("report")) or (display_p == String("both")) )
    {
        summarylist.addReport ( buildFlagCountPlots() );
    }

    //         // Make a report (or a list of them )for a view, and add it to the list
    //         FlagReport viewrep("plotline",agentName_p,"title","xaxis","yaxis")
    //         viewrep.addData(xdata,ydata,"label");
    //         summarylist.addReport( viewRep );
    //
    return summarylist;
}

FlagReport
FlagAgentSummary::buildFlagCountPlots()
{
    logger_p->origin(LogOrigin(agentName_p,__FUNCTION__,WHERE));
    *logger_p << LogIO::NORMAL << "Generating flag count reports for display" << LogIO::POST;

    FlagReport countRepList("list");

    // (1) Plot of fraction flagged vs frequency (only if spwchan==true)
    if( spwChannelCounts )
    {
        std::pair<string, double> freqUnit("GHz",1e+9);

        FlagReport subRep1 = FlagReport("plotpoints",summaryName_p,"Percentage Flagged",
                "Frequency ("+freqUnit.first+")", "% Flagged");

        for (const auto  &key1 : currentSummary->accumChanneltotal)
        {
            Int nCh=currentSummary->accumChanneltotal[key1.first].size();

            Vector<Float> freqVals(nCh), flagPercent(nCh);
            uInt chCount=0;
            for (const auto &key2 : key1.second)
            {
                // read the frequency value for this channel.
                freqVals[chCount] = frequencyList[key1.first][key2.first] / freqUnit.second;

                // calculate the percentage flagged for this channel
                if( key2.second > 0 )
                {
                    flagPercent[chCount] = 100.0 *
                            (Double) currentSummary->accumChannelflags[key1.first][key2.first] /
                            (Double) key2.second;
                }
                else
                {
                    flagPercent[chCount] = 0.0;
                }

                // Increment channel counter
                chCount++;
            }

            subRep1.addData("line", freqVals,flagPercent,"",Vector<Float>(),
                    "spw"+String::toString(key1.first));

        }

        countRepList.addReport( subRep1 );
    }

    // (2) Plot of fraction flagged vs antenna-position
    Int nAnt=currentSummary->accumtotal["antenna"].size();
    if(nAnt>0) // Perhaps put a parameter to control this ?
    {
        Vector<Float> antPosX(nAnt), antPosY(nAnt), radius(nAnt);
        Int antCount=0;
        const Vector<double> xyzOrigin = (flagDataHandler_p->antennaPositions_p->operator()(0))
                                                                               .getValue().getValue();

        FlagReport subRep2 = FlagReport("plotpoints",summaryName_p,"Percentage Flagged",
                "X meters (ITRF)", "Y meters (ITRF)");

        for (const auto antkey : currentSummary->accumtotal["antenna"])
        {
            Int antId = 0; //antCount; // this needs to find the antenna-id for the antenna name.... aaaaah.
            for(antId=0; antId<(Int) flagDataHandler_p->antennaNames_p->nelements(); antId++)
            {
                if( flagDataHandler_p->antennaNames_p->operator()(antId)
                    == String(antkey.first) ) break;
            }

            const Vector<double> xyz = (flagDataHandler_p->antennaPositions_p->operator()(antId))
                                                                                .getValue().getValue();
            antPosX[antCount] = xyz[0]-xyzOrigin[0];
            antPosY[antCount] = xyz[1]-xyzOrigin[1];
            radius[antCount] = 200.0 *
                    (Double) currentSummary->accumflags["antenna"][antkey.first]/
                    (Double) antkey.second;
            antCount++;
        }
        subRep2.addData("scatter", antPosX,antPosY,"circle",radius,"");
        countRepList.addReport( subRep2 );
    }

    Int nBase= baselineCounts? 0:currentSummary->accumtotal["baseline"].size();

    // (3) Plot of fraction flagged vs baseline-length
    if(nBase>0) // Perhaps put a parameter to control this ?
    {
        Vector<Float> baselineLength(nBase), flagFraction(nBase);
        Int baseCount=0;
        FlagReport subRep3 = FlagReport("plotpoints",summaryName_p,"Percentage Flagged per baseline",
                "Baseline Length (m)", "% Flagged");

        for (const auto &basekey : currentSummary->accumtotal["baseline"])
        {
            Int antId1 = 0, antId2=0;
            String antName1,antName2;
            antName1 = antName2 = String(basekey.first);
            antName1 = antName1.before("&&");
            antName2 = antName2.after("&&");
            for(Int antId=0; antId<(Int) flagDataHandler_p->antennaNames_p->nelements(); antId++)
            {
                if( flagDataHandler_p->antennaNames_p->operator()(antId) == antName1 ) antId1 = antId;
                if( flagDataHandler_p->antennaNames_p->operator()(antId) == antName2 ) antId2 = antId;
            }

            const Vector<double> xyz1 = (flagDataHandler_p->antennaPositions_p->operator()(antId1))
                                                                                 .getValue().getValue();
            const Vector<double> xyz2 = (flagDataHandler_p->antennaPositions_p->operator()(antId2))
                                                                                 .getValue().getValue();
            baselineLength[baseCount] = sqrt( fabs( (xyz1[0]-xyz2[0])*(xyz1[0]-xyz2[0]) +
                    (xyz1[1]-xyz2[1])*(xyz1[1]-xyz2[1]) +
                    (xyz1[2]-xyz2[2])*(xyz1[2]-xyz2[2]) ) );
            flagFraction[baseCount] = 100.0 *
                    (Double) currentSummary->accumflags["baseline"][basekey.first]/
                    (Double) basekey.second;
            baseCount++;
        }
        subRep3.addData("scatter", baselineLength,flagFraction,"",Vector<Float>(),"");
        countRepList.addReport( subRep3 );
    }

    // jagonzal: CAS-3450
    if(nBase>0)
    {
        Int totalNAnt = flagDataHandler_p->antennaNames_p->size();
        // Add ant1xant2 summary views
        FlagReport subRep4 = FlagReport("plotraster",summaryName_p,"% Flagged per baseline", "Antenna 1", "Antenna 2");
        Array<Float> ant1ant2View( IPosition(2, totalNAnt, totalNAnt) , (Float)0);
        std::pair<Int,Int> ant1ant2;
        Float percentageFlagged;
        for (const auto &basekey : currentSummary->accumtotal["baseline"])
        {
            ant1ant2 = flagDataHandler_p->baselineToAnt1Ant2_p[basekey.first];
            percentageFlagged = (Float)100*((Double)currentSummary->accumflags["baseline"][basekey.first] /
                                            (Double)currentSummary->accumtotal["baseline"][basekey.first]);
            ant1ant2View(IPosition(2, ant1ant2.first, ant1ant2.second)) = percentageFlagged;
            ant1ant2View(IPosition(2, ant1ant2.second, ant1ant2.first)) = percentageFlagged;

        }

        subRep4.addData(ant1ant2View);
        countRepList.addReport( subRep4 );

        // Add ant1xscan summary views
        FlagReport subRep5 = FlagReport("plotraster",summaryName_p,"% Flagged per antenna and scan", "Scan relative index", "% Flagged per antenna");

        // NOTE: We need to handle directly the storage array, because it seems that the dimension steps are switched
        Array<Float> antScanView( IPosition(2, currentSummary->accumflags["scan"].size(),totalNAnt) , (Float)0);
        Bool deleteIt = false;
        Float* antScanViewPtr = antScanView.getStorage(deleteIt);


        uInt scanIdx,antennaIdx = 0;
        for (const auto &antkey : currentSummary->accumAntScantotal)
        {
            scanIdx = 0;
            for (const auto scankey : antkey.second)
            {
                percentageFlagged = (Float)100*((Double)currentSummary->accumAntScanflags[antkey.first][scankey.first] /
                                                (Double)currentSummary->accumAntScantotal[antkey.first][scankey.first]);
                antScanViewPtr[totalNAnt*scanIdx + antkey.first] = percentageFlagged;
                scanIdx += 1;
            }
            antennaIdx += 1;
        }

        subRep5.addData(antScanView);
        countRepList.addReport( subRep5 );
    }


    return countRepList;
}


Record
FlagAgentSummary::getResult()
{
    logger_p->origin(LogOrigin(agentName_p,__FUNCTION__,WHERE));

    Record result;

    if (fieldCounts)
    {
        for(const auto &iter : fieldSummaryMap)
    	{
            Record subresult;
            currentSummary = iter.second;
            getResultCore(subresult);
            result.defineRecord(iter.first, subresult);
    	}
    }
    else
    {
    	getResultCore(result);
    }

    return result;
}

void
FlagAgentSummary::getResultCore(Record &result)
{
	if (fieldCounts)
	{
		string field = currentSummary->accumtotal["field"].begin()->first;
		string spaces(field.size(),'=');
		*logger_p << LogIO::NORMAL << "======" << spaces << "==========" << LogIO::POST;
	    *logger_p << LogIO::NORMAL << "Field " << field << " breakdown" << LogIO::POST;
		*logger_p << LogIO::NORMAL << "======" << spaces << "==========" << LogIO::POST;
	}

    if (spwChannelCounts)
    {
        Record stats_key1;

        for (const auto &key1 : currentSummary->accumChanneltotal)
        {
            // Transform spw id into string
            stringstream spw_stringStream;
            spw_stringStream << key1.first;

            for (const auto &key2 : key1.second)
            {
                Record stats_key2;

                stats_key2.define("flagged", (Double) currentSummary->accumChannelflags[key1.first][key2.first]);
                stats_key2.define("total", (Double) key2.second);

                // Transform channel id into string
                stringstream channel_stringStream;
                channel_stringStream << key2.first;

                // Construct spw:channel string as first key
                stats_key1.defineRecord(spw_stringStream.str() + ":" + channel_stringStream.str(), stats_key2);
                // Calculate percentage flagged
                stringstream percentage;
                percentage.precision(3);
                //				percentage.fixed;
                if( key2.second > 0 )
                {
                    percentage << " (" << 100.0 *
                            (Double) currentSummary->accumChannelflags[key1.first][key2.first]/
                            (Double) key2.second << "%)";
                }

                *logger_p 	<< LogIO::NORMAL
                        << " Spw:" << key1.first << " Channel:" << key2.first
                        << " flagged: " <<  (Double) currentSummary->accumChannelflags[key1.first][key2.first]
                                         << " total: " <<  (Double) key2.second
                                         << percentage.str()
                                         << LogIO::POST;
            }

        }

        result.defineRecord("spw:channel", stats_key1);
    }

    if (spwPolarizationCounts)
    {
        Record stats_key1;

        for (const auto &key1 : currentSummary->accumPolarizationtotal)
        {
            // Transform spw id into string
            stringstream spw_stringStream;
            spw_stringStream << key1.first;

            for (const auto &key2 : key1.second)
            {
                Record stats_key2;

                stats_key2.define("flagged", (Double) currentSummary->accumPolarizationflags[key1.first][key2.first]);
                stats_key2.define("total", (Double) key2.second);

                // Construct spw:correlation string as first key (Polarization already comes as a string)
                stats_key1.defineRecord(spw_stringStream.str() + ":" + key2.first, stats_key2);

                // Calculate percentage flagged
                stringstream percentage;
                percentage.precision(3);
                //				percentage.fixed;
                if( key2.second > 0 )
                {
                    percentage << " (" << 100.0 *
                            (Double) currentSummary->accumPolarizationflags[key1.first][key2.first]/
                            (Double) key2.second << "%)";
                }

                *logger_p 	<< LogIO::NORMAL
                        << " Spw:" << key1.first << " Correlation:" << key2.first
                        << " flagged: " <<  (Double) currentSummary->accumPolarizationflags[key1.first][key2.first]
                                            << " total: " <<  (Double) key2.second
                                            << percentage.str()
                                            << LogIO::POST;
            }
        }

        result.defineRecord("spw:correlation", stats_key1);
    }

    if (baselineCounts)
    {
        Record stats_key1;

        for (const auto &key1 : currentSummary->accumAntScantotal)
        {
            // Construct antenna name
            stringstream antenna_stringStream;
            const auto antennaName = flagDataHandler_p->antennaNames_p->operator()(key1.first);
            antenna_stringStream << antennaName;

            for (const auto &key2 : key1.second)
            {
                // Construct scan name
                stringstream scan_stringStream;
                scan_stringStream << key2.first;

                Record stats_key2;

                stats_key2.define("flagged", (Double) currentSummary->accumAntScanflags[key1.first][key2.first]);
                stats_key2.define("total", (Double) key2.second);

                // Construct spw:correlation string as first key (Polarization already comes as a string)
                stats_key1.defineRecord(antenna_stringStream.str() + ":" + scan_stringStream.str(), stats_key2);

                // Calculate percentage flagged
                stringstream percentage;
                percentage.precision(3);
                //				percentage.fixed;
                if( key2.second > 0 )
                {
                    percentage << " (" << 100.0 *
                            (Double) currentSummary->accumAntScanflags[key1.first][key2.first]/
                            (Double) key2.second << "%)";
                }

                *logger_p 	<< LogIO::NORMAL
                        << " Antenna:" << antennaName << " Scan:" << key2.first
                        << " flagged: " <<  (Double) currentSummary->accumAntScanflags[key1.first][key2.first]
                                         << " total: " <<  (Double) key2.second
                                         << percentage.str()
                                         << LogIO::POST;
            }
        }

        result.defineRecord("antenna:scan", stats_key1);
    }

    for (const auto &key1 : currentSummary->accumtotal)
    {
        Record stats_key1;
        for (const auto &key2 : key1.second)
        {
            Record stats_key2;

            stats_key2.define("flagged", (Double) currentSummary->accumflags[key1.first][key2.first]);
            stats_key2.define("total", (Double) key2.second);
            stats_key1.defineRecord(key2.first, stats_key2);

            // Calculate percentage flagged
            stringstream percentage;
            percentage.precision(3);
            //			percentage.fixed;
            if( key2.second > 0 )
            {
                percentage << " (" << 100.0 *
                        (Double) currentSummary->accumflags[key1.first][key2.first] /
                        (Double) key2.second << "%)";
            }

            *logger_p 	<< LogIO::NORMAL
                    << " " << key1.first << " " << key2.first
                    << " flagged: " <<  (Double) currentSummary->accumflags[key1.first][key2.first]
                                     << " total: " <<  (Double) key2.second
                                     << percentage.str()
                                     << LogIO::POST;
        }

        result.defineRecord(key1.first, stats_key1);
    }

    result.define("flagged", (Double) currentSummary->accumTotalFlags);
    result.define("total"  , (Double) currentSummary->accumTotalCount);

    // Calculate percentage flagged
    stringstream percentage;
    percentage.precision(3);
    //	percentage.fixed;
    if( currentSummary->accumTotalCount > 0 )
    {
        percentage << " (" << 100.0 *
                (Double) currentSummary->accumTotalFlags /
                (Double) currentSummary->accumTotalCount << "%)";
    }
    *logger_p 	<< LogIO::NORMAL
            << " Total Flagged: " <<  (Double) currentSummary->accumTotalFlags
            << " Total Counts: " <<  (Double) currentSummary->accumTotalCount
            << percentage.str()
            << LogIO::POST;

    return;
}

} //# NAMESPACE CASA - END