// $Id: gc_sequential_data.cpp,v 1.26 2018/01/03 21:32:56 mkkuhner Exp $

/*
Copyright 2002-2005 Mary K. Kuhner, Peter Beerli, and Joseph Felsenstein

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

*/

/* Authors: Mary Kuhner, Jon Yamato, and Joseph Felsenstein */


#include <cassert>

#include "gc_errhandling.h" // EWFIX.P4 -- can this be taken out
#include "gc_data.h"
#include "gc_infile_err.h"
#include "gc_parse.h"
#include "gc_parse_block.h"
#include "gc_parse_locus.h"
#include "gc_sequential_data.h"
#include "gc_strings.h"

#include "wx/log.h"
#include "wx/regex.h"
#include "wx/tokenzr.h"

//------------------------------------------------------------------------------------

GCSequentialData::GCSequentialData(GCParseBlock & block)
    :
    m_block(block)
{
}

GCSequentialData::~GCSequentialData()
{
}

void
GCSequentialData::CheckMarkerCount()
{
    size_t currentMarkerCount = GetNumMarkers();
    size_t wantedMarkerCount = GetParseBlock().GetLocusRef().GetNumMarkers();
    if(currentMarkerCount > wantedMarkerCount)
    {
        throw gc_too_many_markers(currentMarkerCount,wantedMarkerCount);
    }
}

void
GCSequentialData::DebugDump(wxString prefix) const
{
    wxLogDebug("%sdata: %s",prefix.c_str(),GetData().c_str());  // EWDUMPOK
}

GCParseBlock &
GCSequentialData::GetParseBlock()
{
    return m_block;
}

const GCParseBlock &
GCSequentialData::GetParseBlock() const
{
    return m_block;
}

//------------------------------------------------------------------------------------

GCAllelicData::GCAllelicData(GCParseBlock& block)
    :
    GCSequentialData(block)
{
}

GCAllelicData::~GCAllelicData()
{
}

void
GCAllelicData::AddMarker(wxString data)
{
    const GCParseBlock & b = GetParseBlock();
    const GCParse & p = b.GetParse();
    assert(!(p.GetDataType().empty()));
    long longVal;
    wxString questionMark("?");
    if (data != questionMark)
    {
        if(!data.ToLong(&longVal))
        {
            GetParseBlock().SetCannotBeMsat();
        }
        else
        {
            if(longVal <= 0)
            {
                GetParseBlock().SetCannotBeMsat();
            }
        }
        if (p.GetDataType().empty())
        {
            throw gc_illegal_msat(data);
        }
    }

    m_data.Add(data);
    CheckMarkerCount();
}

size_t
GCAllelicData::GetNumMarkers() const
{
    return m_data.Count();
}

wxString
GCAllelicData::GetData() const
{
    wxString dataOut;
    for(size_t index=0; index < m_data.Count(); index++)
    {
        dataOut += wxString::Format(" %s",m_data[index].c_str());
    }
    return dataOut;
}

wxString
GCAllelicData::GetData(size_t markerIndex) const
{
    assert(markerIndex < m_data.Count());
    return wxString::Format(" %s ",m_data[markerIndex].c_str());
}

//------------------------------------------------------------------------------------

GCNucData::GCNucData(GCParseBlock& block)
    :
    GCSequentialData(block)
{
}

GCNucData::~GCNucData()
{
}

void
GCNucData::AddMarker(wxString data)
{
    // don't move the dash from its position just after the
    // caret -- otherwise the regex compiler will think it's
    // indicating a character range
    wxRegEx illegalData("[^-ACGTUMRWSYKVHDBNOX? \t]",wxRE_ICASE);
    if(illegalData.Matches(data))
    {
        size_t start;
        size_t length;
        illegalData.GetMatch(&start,&length);
        throw gc_illegal_dna_character(data[start],start+1,data);
    }

    wxString dataNoWhiteSpace = data;
    dataNoWhiteSpace.Replace(" ","",true);
    dataNoWhiteSpace.Replace("\t","",true);
    m_data+=dataNoWhiteSpace;
    CheckMarkerCount();
}

size_t
GCNucData::GetNumMarkers() const
{
    return m_data.Len();
}

wxString
GCNucData::GetData() const
{
    return m_data;
}

wxString
GCNucData::GetData(size_t markerIndex) const
{
    assert(markerIndex < m_data.Len());
    return wxString::Format(" %c ",m_data[markerIndex]);
}

//____________________________________________________________________________________
