// $Id: gc_region.cpp,v 1.19 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 "gc_errhandling.h"
#include "gc_locus.h"
#include "gc_region.h"
#include "gc_strings.h"
#include "gc_strings_region.h"
#include "wx/log.h"

GCMapPosition::GCMapPosition()
    :
    m_hasPosition(false),
    m_position(0)
{
}

GCMapPosition::~GCMapPosition()
{
}

long
GCMapPosition::GetPosition() const
{
    if(!m_hasPosition)
    {
        gc_implementation_error e(gcerr::regionNoPositionToGet.c_str());
        throw e;
    }
    return m_position;
}

bool
GCMapPosition::HasPosition() const
{
    return m_hasPosition;
}

void
GCMapPosition::SetPosition(long position)
{
    m_hasPosition = true;
    m_position = position;
}

void
GCMapPosition::UnsetPosition()
{
    m_hasPosition = false;
}

wxString
GCMapPosition::AsString() const
{
    if(HasPosition())
    {
        return wxString::Format(gcstr_region::mapPosition,GetPosition());
    }
    return gcstr::mapPositionUnset;
}

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

GCLocusInfoMap::GCLocusInfoMap()
{
}

GCLocusInfoMap::~GCLocusInfoMap()
{
}

wxString
GCLocusInfoMap::AsString() const
{
    wxString retString = "";
    for(const_iterator i = begin(); i != end(); i++)
    {
        size_t locusId = (*i).first;
        GCMapPosition mapPosition = (*i).second;
        retString += wxString::Format(gcstr_region::locusMapPosition,(int)locusId,mapPosition.AsString().c_str());
    }
    return retString;
}

GCTraitInfoSet::GCTraitInfoSet()
{
}

GCTraitInfoSet::~GCTraitInfoSet()
{
}

wxString
GCTraitInfoSet::AsString() const
{
    wxString retString = "";
    for(const_iterator i = begin(); i != end(); i++)
    {
        retString += wxString::Format(gcstr_region::traitIndexListMember,(int)(*i));
    }
    return retString;
}

gcRegion::gcRegion()
    :
    m_name(wxString::Format(gcstr_region::internalName,(long)m_objId)),
    m_blessed(false),
    m_hasEffectivePopulationSize(false),
    m_effectivePopulationSize(0.0)
{
}

gcRegion::~gcRegion()
{
}

void
gcRegion::AddLocus(gcLocus & locus)
{
    if(m_loci.find(locus.GetId()) != m_loci.end())
    {
        wxString msg = wxString::Format(gcerr::duplicateLocusInRegion,
                                        locus.GetName().c_str(),
                                        GetName().c_str());
        gc_implementation_error e(msg.c_str());
        throw e;
    }

    m_loci[locus.GetId()] = GCMapPosition();
}

void
gcRegion::AddLocus(gcLocus & locus, long mapPosition)
{
    AddLocus(locus);
    m_loci[locus.GetId()].SetPosition(mapPosition);
}

void
gcRegion::AddTraitId(size_t traitId)
{
    if(m_traits.find(traitId) != m_traits.end())
    {
        wxString msg = wxString::Format(gcerr::regionTraitAlreadyAdded,
                                        (int)traitId);
        gc_implementation_error e(msg.c_str());
        throw e;
    }
    m_traits.insert(traitId);
}

void
gcRegion::RemoveLocusId(size_t locusId)
{
    GCLocusInfoMap::iterator iter = m_loci.find(locusId);
    if(iter == m_loci.end())
    {
        wxString msg = wxString::Format(gcerr::regionNoSuchLocus,
                                        (int)locusId,
                                        (int)GetId());
        gc_implementation_error e(msg.c_str());
        throw e;
    }
    m_loci.erase(iter);
}

void
gcRegion::RemoveTraitId(size_t traitId)
{
    GCTraitInfoSet::iterator iter = m_traits.find(traitId);
    if(iter == m_traits.end())
    {
        wxString msg = wxString::Format(gcerr::regionNoSuchTrait,
                                        (int)traitId,
                                        (int)GetId());
        gc_implementation_error e(msg.c_str());
        throw e;
    }
    m_traits.erase(iter);
}

bool
gcRegion::GetBlessed() const
{
    return m_blessed;
}

void
gcRegion::SetBlessed(bool blessed)
{
    m_blessed = blessed;
}

wxString
gcRegion::GetName() const
{
    return m_name;
}

void
gcRegion::SetName(wxString newName)
{
    m_name = newName;
}

bool
gcRegion::HasEffectivePopulationSize() const
{
    return m_hasEffectivePopulationSize;
}

double
gcRegion::GetEffectivePopulationSize() const
{
    if(!(HasEffectivePopulationSize()))
    {
        wxString msg = wxString::Format(gcerr::regionNoEffectivePopSize,
                                        (int)GetId());
        gc_implementation_error e(msg.c_str());
        throw e;
    }
    return m_effectivePopulationSize;
}

void
gcRegion::SetEffectivePopulationSize(double effectivePopulationSize)
{
    if( ! (effectivePopulationSize > 0))
    {
        wxString msg = wxString::Format(gcerr::badEffectivePopSize,
                                        GetName().c_str(),
                                        effectivePopulationSize);
        gc_data_error e(msg.c_str());
        throw e;
    }

    m_hasEffectivePopulationSize = true;
    m_effectivePopulationSize = effectivePopulationSize;
}

const GCLocusInfoMap &
gcRegion::GetLocusInfoMap() const
{
    return m_loci;
}

size_t
gcRegion::GetLocusCount() const
{
    return m_loci.size();
}

const GCTraitInfoSet &
gcRegion::GetTraitInfoSet() const
{
    return m_traits;
}

void
gcRegion::DebugDump(wxString prefix) const
{
    wxLogDebug("%sregion \"%s\", (id %ld)",  // EWDUMPOK
               prefix.c_str(),
               GetName().c_str(),
               (long)GetId());

    if(HasEffectivePopulationSize())
    {
        wxLogDebug("%seffecive population size %f", // EWDUMPOK
                   (prefix+gcstr::indent).c_str(),
                   GetEffectivePopulationSize());
    }

    wxLogDebug("%sloci:%s", // EWDUMPOK
               (prefix+gcstr::indent).c_str(),
               m_loci.AsString().c_str());

    wxLogDebug("%straits:%s",   // EWDUMPOK
               (prefix+gcstr::indent).c_str(),
               m_traits.AsString().c_str());
}

bool
gcRegion::CanMergeWith(const gcRegion & regionRef) const
{
    if(HasEffectivePopulationSize() && regionRef.HasEffectivePopulationSize())
    {
        if(GetEffectivePopulationSize() != regionRef.GetEffectivePopulationSize())
        {
            return false;
        }
    }

    return true;
}

//____________________________________________________________________________________
