// Copyright (c) 2014-2015, Pacific Biosciences of California, Inc.
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted (subject to the limitations in the
// disclaimer below) provided that the following conditions are met:
//
//  * Redistributions of source code must retain the above copyright
//    notice, this list of conditions and the following disclaimer.
//
//  * Redistributions in binary form must reproduce the above
//    copyright notice, this list of conditions and the following
//    disclaimer in the documentation and/or other materials provided
//    with the distribution.
//
//  * Neither the name of Pacific Biosciences nor the names of its
//    contributors may be used to endorse or promote products derived
//    from this software without specific prior written permission.
//
// NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE
// GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY PACIFIC
// BIOSCIENCES AND ITS CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL PACIFIC BIOSCIENCES OR ITS
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
// USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
// SUCH DAMAGE.

// Author: Yuan Li

#include "HDFZMWMetricsWriter.hpp"
#include "reads/ScanData.hpp"

HDFZMWMetricsWriter::HDFZMWMetricsWriter(const std::string & filename, 
        HDFGroup & parentGroup, const std::map<char, size_t> & baseMap)
    : HDFWriterBase(filename)
    , parentGroup_(parentGroup)
    , baseMap_(baseMap)
    , curRow_(0)
{
    if (not parentGroup.groupIsInitialized)
        PARENT_GROUP_NOT_INITIALIZED_ERROR(PacBio::GroupNames::zmwmetrics);
    else {
        parentGroup_.AddGroup(PacBio::GroupNames::zmwmetrics); 

        if (zmwMetricsGroup_.Initialize(parentGroup_, PacBio::GroupNames::zmwmetrics) == 0)
            FAILED_TO_CREATE_GROUP_ERROR(PacBio::GroupNames::zmwmetrics);

        InitializeChildHDFGroups();
    }

    // Sanity Check BaseMap
    assert(ScanData::IsValidBaseMap(baseMap));
}

HDFZMWMetricsWriter::~HDFZMWMetricsWriter() {
    Flush(); // Must flush in case group is empty.
    assert(WriteAttributes());
    Close();
}

bool HDFZMWMetricsWriter::WriteOneZmw(const SMRTSequence & read) {
    try {
        float snrs[4];
        for (char base: {'A', 'C', 'G', 'T'}) {
            snrs[baseMap_[base]] = read.HQRegionSnr(base);
        }
        hqRegionSNRArray_.WriteRow(snrs, SNRNCOLS);
        readScoreArray_.Write(&read.readScore, 1);
        productivityArray_.Write(&read.zmwData.holeStatus, 1);
    }
    catch (H5::Exception & e) {
        AddErrorMessage("Failed to write HQRegionSNR or ReadScore or Productivity.");
        return false;
    }
    ++curRow_;

    return true;
}

void HDFZMWMetricsWriter::Flush(void) {
    hqRegionSNRArray_.Flush();
    readScoreArray_.Flush();
    productivityArray_.Flush();
}

void HDFZMWMetricsWriter::Close(void) {
    hqRegionSNRArray_.Close();
    readScoreArray_.Close();
    productivityArray_.Close();

    zmwMetricsGroup_.Close();
}

bool HDFZMWMetricsWriter::InitializeChildHDFGroups(void) {
    bool OK = true;

    if (hqRegionSNRArray_.Initialize(zmwMetricsGroup_, PacBio::GroupNames::hqregionsnr, SNRNCOLS) == 0) { 
        FAILED_TO_CREATE_GROUP_ERROR(PacBio::GroupNames::hqregionsnr);
        OK = false;
    }

    if (readScoreArray_.Initialize(zmwMetricsGroup_, PacBio::GroupNames::readscore) == 0) {
        FAILED_TO_CREATE_GROUP_ERROR(PacBio::GroupNames::readscore);
        OK = false;
    }

    if (productivityArray_.Initialize(zmwMetricsGroup_, PacBio::GroupNames::productivity) == 0) {
        FAILED_TO_CREATE_GROUP_ERROR(PacBio::GroupNames::productivity);
        OK = false;
    }

    return OK;
}

bool HDFZMWMetricsWriter::WriteAttributes(void) {
    if (curRow_ > 0) {
        bool OK = 
        AddAttribute(hqRegionSNRArray_, 
                     PacBio::AttributeNames::Common::description,
                     PacBio::AttributeValues::ZMWMetrics::HQRegionSNR::description)
        and 
        AddAttribute(readScoreArray_,
                     PacBio::AttributeNames::Common::description, 
                     PacBio::AttributeValues::ZMWMetrics::ReadScore::description)
        and 
        AddAttribute(productivityArray_,
                     PacBio::AttributeNames::Common::description, 
                     PacBio::AttributeValues::ZMWMetrics::Productivity::description);
        return OK;
    } else {
        AddErrorMessage("Could not write attributes when ZMWMetrics group is empty.");
        return false;
    }
}
