// $Id: gc_structures.cpp,v 1.68 2018/01/03 21:32:55 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_creation_info.h"
#include "gc_default.h"
#include "gc_datastore.h"
#include "gc_errhandling.h"
#include "gc_file.h"
#include "gc_genotype_resolution.h"
#include "gc_loci_match.h"
#include "gc_locus_err.h"
#include "gc_parse.h"
#include "gc_parse_block.h"
#include "gc_pop_match.h"
#include "gc_strings.h"
#include "gc_strings_infile.h"
#include "gc_strings_structures.h"
#include "gc_structures.h"
#include "gc_structures_err.h"
#include "gc_trait_err.h"
#include "wx/log.h"

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

const wxString &
gcNameSet::infoString() const
{
    return gcstr_structures::objDict;
}

gcNameSet::gcNameSet()
{
}

gcNameSet::~gcNameSet()
{
}

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

const wxString &
gcTraitNameSet::infoString() const
{
    return gcstr_structures::traitDict;
}

gcTraitNameSet::gcTraitNameSet()
{
}

gcTraitNameSet::~gcTraitNameSet()
{
}

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

GCStructures::GCStructures(const GCDataStore * dsp)
    :
    m_dataStoreP(dsp),
    m_divergenceState(false),
    //m_divMigMatrixDefined(false),
    //m_migMatrixDefined(false)
    m_panelsState(false)
{
}

GCStructures::~GCStructures()
{
}

gcIdSet
GCStructures::GetBlockIds(size_t popId, size_t locusId) const
{
    gcIdSet outSet;
    gcPopLocusIdPair p(popId,locusId);
    gcBlockSetMap::const_iterator iter = m_blocks.find(p);
    if(iter != m_blocks.end())
    {
        outSet = (*iter).second;
    }
    return outSet;
}

gcIdSet
GCStructures::GetBlocksForLocus(size_t locusId) const
{
    gcIdSet blockIds;

    for(gcPopMap::const_iterator i=m_pops.begin();
        i != m_pops.end(); i++)
    {
        size_t popId = (*i).first;
        gcPopLocusIdPair p(popId,locusId);
        gcBlockSetMap::const_iterator biter = m_blocks.find(p);
        if(biter != m_blocks.end())
        {
            const gcIdSet & blocks = (*biter).second;
            if(!blocks.empty())
            {
                blockIds.insert(blocks.begin(),blocks.end());
            }
        }
    }
    return blockIds;
}

bool
GCStructures::HaveBlocksForRegion(size_t regionId) const
{
    gcIdVec locusIds = GetLocusIdsForRegionByCreation(regionId);

    if(locusIds.size() == 0)
    {
        return false;
    }
    else
    {
        for(gcIdVec::const_iterator liter=locusIds.begin(); liter != locusIds.end(); liter++)
        {
            size_t locusId = (*liter);
            if(HaveBlocksForLocus(locusId))
            {
                return true;
            }
        }
    }
    return false;
}

bool
GCStructures::HaveBlocksForLocus(size_t locusId) const
{
    for(gcPopMap::const_iterator i=m_pops.begin();
        i != m_pops.end(); i++)
    {
        size_t popId = (*i).first;
        gcPopLocusIdPair p(popId,locusId);
        gcBlockSetMap::const_iterator biter = m_blocks.find(p);
        if(biter != m_blocks.end())
        {
            const gcIdSet & blocks = (*biter).second;
            if(!blocks.empty())
            {
                return true;
            }
        }
    }
    return false;
}

bool
GCStructures::HaveBlocksForPop(size_t popId) const
{
    // EWFIX.P5 SPEED -- could make faster with additional structures
    for(gcLocusMap::const_iterator i = m_loci.begin(); i != m_loci.end(); i++)
    {
        size_t locusId = (*i).first;
        gcPopLocusIdPair p(popId,locusId);
        gcBlockSetMap::const_iterator biter = m_blocks.find(p);
        if(biter != m_blocks.end())
        {
            const gcIdSet & blocks = (*biter).second;
            if(!blocks.empty())
            {
                return true;
            }
        }
    }
    return false;
}

bool
GCStructures::IsBlessedRegion(size_t regionId) const
{
    const gcRegion & region = GetRegion(regionId);
    if(region.GetBlessed()) return true;
    gcIdVec loci = GetLocusIdsForRegionByCreation(regionId);
    for(gcIdVec::const_iterator iter=loci.begin(); iter!=loci.end();iter++)
    {
        const gcLocus & locus = GetLocus(*iter);
        if(locus.GetBlessed()) return true;
    }
    return false;
}

bool
GCStructures::IsBlessedLocus(size_t locusId) const
{
    return GetLocus(locusId).GetBlessed();
}

bool
GCStructures::IsBlessedPop(size_t popId) const
{
    return GetPop(popId).GetBlessed();
}

bool
GCStructures::GetDivergenceState() const
{
    return  m_divergenceState;
}

bool
GCStructures::GetDivergenceState()
{
    return  m_divergenceState;
}

void
GCStructures::SetDivergenceState(bool state)
{
    m_divergenceState = state;
}

bool
GCStructures::GetPanelsState() const
{
    return  m_panelsState;
}

bool
GCStructures::GetPanelsState()
{
    return  m_panelsState;
}

void
GCStructures::SetPanelsState(bool state)
{
    m_panelsState = state;
}


bool
GCStructures::GetDivMigMatrixDefined() const
{
    return  m_divMigMatrixDefined;
}

bool
GCStructures::GetDivMigMatrixDefined()
{
    return  m_divMigMatrixDefined;
}

void
GCStructures::SetDivMigMatrixDefined(bool state)
{
    m_divMigMatrixDefined = state;
}

bool
GCStructures::GetMigMatrixDefined() const
{
    return  m_migMatrixDefined;
}

bool
GCStructures::GetMigMatrixDefined()
{
    return  m_migMatrixDefined;
}

void
GCStructures::SetMigMatrixDefined(bool state)
{
    m_migMatrixDefined = state;
}

constObjVector
GCStructures::GetConstDisplayableRegions() const
{
    constObjVector toReturn;
    for(gcDisplayOrder::const_iterator i=m_regionDisplay.begin();
        i != m_regionDisplay.end();
        i++)
    {
        size_t regionId = *i;
        if(HaveBlocksForRegion(regionId) || IsBlessedRegion(regionId))
        {
            toReturn.push_back(&(GetRegion(regionId)));
        }
    }
    return toReturn;
}

objVector
GCStructures::GetDisplayableRegions()
{
    objVector toReturn;
    for(gcDisplayOrder::const_iterator i=m_regionDisplay.begin();
        i != m_regionDisplay.end();
        i++)
    {
        size_t regionId = *i;
        if(HaveBlocksForRegion(regionId) || IsBlessedRegion(regionId))
        {
            toReturn.push_back(&(GetRegion(regionId)));
        }
    }
    return toReturn;
}

gcDisplayOrder
GCStructures::GetDisplayableRegionIds() const
{
    gcDisplayOrder toReturn;
    for(gcDisplayOrder::const_iterator i=m_regionDisplay.begin();
        i != m_regionDisplay.end();
        i++)
    {
        size_t regionId = *i;
        if(HaveBlocksForRegion(regionId) || IsBlessedRegion(regionId))
        {
            toReturn.push_back(regionId);
        }
    }
    return toReturn;
}

constObjVector
GCStructures::GetConstDisplayableLoci() const
{
    constObjVector regionsInOrder = GetConstDisplayableRegions();

    constObjVector toReturn;
    for(gcRegionMap::const_iterator giter=m_regions.begin(); giter != m_regions.end(); giter++)
    {
        const gcRegion & region = (*giter).second;
        gcIdVec loci = GetLocusIdsForRegionByMapPosition(region.GetId());
        for(gcIdVec::const_iterator liter=loci.begin(); liter != loci.end(); liter++)
        {
            size_t locusId = *liter;
            if(HaveBlocksForLocus(locusId) || IsBlessedLocus(locusId))
            {
                toReturn.push_back(&(GetLocus(locusId)));
            }
        }
    }
    return toReturn;
}

objVector
GCStructures::GetDisplayableLoci()
{
    objVector regionsInOrder = GetDisplayableRegions();

    objVector toReturn;
    for(gcRegionMap::const_iterator giter=m_regions.begin(); giter != m_regions.end(); giter++)
    {
        const gcRegion & region = (*giter).second;
        gcIdVec loci = GetLocusIdsForRegionByMapPosition(region.GetId());
        for(gcIdVec::const_iterator liter=loci.begin(); liter != loci.end(); liter++)
        {
            size_t locusId = *liter;
            if(HaveBlocksForLocus(locusId) || IsBlessedLocus(locusId))
            {
                toReturn.push_back(&(GetLocus(locusId)));
            }
        }
    }
    return toReturn;
}

gcDisplayOrder
GCStructures::GetDisplayableLocusIds() const
{
    gcDisplayOrder toReturn;

    for(gcRegionMap::const_iterator giter=m_regions.begin(); giter != m_regions.end(); giter++)
    {
        const gcRegion & region = (*giter).second;
        gcIdVec loci = GetLocusIdsForRegionByMapPosition(region.GetId());
        for(gcIdVec::const_iterator liter=loci.begin(); liter != loci.end(); liter++)
        {
            size_t locusId = *liter;
            if(HaveBlocksForLocus(locusId) || IsBlessedLocus(locusId))
            {
                toReturn.push_back(locusId);
            }
        }
    }
    return toReturn;
}

#if 0
constObjVector
GCStructures::GetConstDisplayableLociFor(size_t regionId) const
{
    constObjVector toReturn;
    const gcRegion & region = GetRegion(regionId);
    gcIdVec loci = GetLocusIdsdForRegionByMapPosition(region.GetId());
    for(gcIdVec::const_iterator liter=loci.begin(); liter != loci.end(); liter++)
    {
        size_t locusId = *liter;
        if(HaveBlocksForLocus(locusId) || IsBlessedLocus(locusId))
        {
            toReturn.push_back(&(GetLocus(locusId)));
        }
    }
    return toReturn;
}
#endif

constObjVector
GCStructures::GetConstDisplayableLociInMapOrderFor(size_t regionId) const
{
    constObjVector toReturn;
    const gcRegion & region = GetRegion(regionId);
    gcIdVec loci = GetLocusIdsForRegionByMapPosition(region.GetId());
    for(gcIdVec::const_iterator liter=loci.begin(); liter != loci.end(); liter++)
    {
        size_t locusId = *liter;
        if(HaveBlocksForLocus(locusId) || IsBlessedLocus(locusId))
        {
            toReturn.push_back(&(GetLocus(locusId)));
        }
    }
    return toReturn;
}

constObjVector
GCStructures::GetConstDisplayableLinkedLociInMapOrderFor(size_t regionId) const
{
    constObjVector toReturn;
    const gcRegion & region = GetRegion(regionId);
    gcIdVec loci = GetLocusIdsForRegionByMapPosition(region.GetId());
    for(gcIdVec::const_iterator liter=loci.begin(); liter != loci.end(); liter++)
    {
        size_t locusId = *liter;
        if(HaveBlocksForLocus(locusId) || IsBlessedLocus(locusId))
        {
            const gcLocus & locusRef = GetLocus(locusId);
            if(locusRef.GetLinked())
            {
                toReturn.push_back(&locusRef);
            }
        }
    }
    return toReturn;
}

objVector
GCStructures::GetDisplayableLociFor(size_t regionId)
{

    objVector toReturn;
    const gcRegion & region = GetRegion(regionId);
    const GCLocusInfoMap & loci = region.GetLocusInfoMap();
    for(GCLocusInfoMap::const_iterator liter=loci.begin(); liter != loci.end(); liter++)
    {
        size_t locusId = (*liter).first;
        if(HaveBlocksForLocus(locusId) || IsBlessedLocus(locusId))
        {
            toReturn.push_back(&(GetLocus(locusId)));
        }
    }
    return toReturn;
}

constObjVector
GCStructures::GetConstDisplayablePops()  const
{
    constObjVector toReturn;
    for(gcDisplayOrder::const_iterator i=m_popDisplay.begin();
        i != m_popDisplay.end();
        i++)
    {
        size_t popId = *i;
        if(HaveBlocksForPop(popId) || IsBlessedPop(popId))
        {
            toReturn.push_back(&(GetPop(popId)));
        }
    }
    return toReturn;
}

gcDisplayOrder
GCStructures::GetDisplayablePopIds() const
{
    gcDisplayOrder toReturn;
    for(gcDisplayOrder::const_iterator i=m_popDisplay.begin();
        i != m_popDisplay.end();
        i++)
    {
        size_t popId = *i;
        if(HaveBlocksForPop(popId) || IsBlessedPop(popId))
        {
            toReturn.push_back(popId);
        }
    }
    return toReturn;
}

objVector
GCStructures::GetDisplayablePops()
{
    objVector toReturn;
    for(gcDisplayOrder::const_iterator i=m_popDisplay.begin();
        i != m_popDisplay.end();
        i++)
    {
        size_t popId = *i;
        if(HaveBlocksForPop(popId) || IsBlessedPop(popId))
        {
            toReturn.push_back(&(GetPop(popId)));
        }
    }
    return toReturn;
}

gcDisplayOrder
GCStructures::GetParentIds() const
{
    gcDisplayOrder toReturn;
    for(gcParentMap::const_iterator i=m_parents.begin();
        i != m_parents.end();
        i++)
    {
        size_t parentId = (*i).first;
        toReturn.push_back(parentId);
    }
    return toReturn;
}

objVector
GCStructures::GetParents()
{
    objVector toReturn;
    for(gcParentMap::const_iterator i=m_parents.begin();
        i != m_parents.end();
        i++)
    {
        size_t parentId = (*i).first;
        toReturn.push_back(&(GetParent(parentId)));
    }
    return toReturn;
}

constObjVector
GCStructures::GetConstParents() const
{
    constObjVector toReturn;
    for(gcParentMap::const_iterator i=m_parents.begin();
        i != m_parents.end();
        i++)
    {
        size_t parentId = (*i).first;
        toReturn.push_back(&(GetParent(parentId)));
    }
    return toReturn;
}

constObjVector
GCStructures::GetConstTraits() const
{
    constObjVector toReturn;
    for(gcTraitMap::const_iterator i=m_traitClasses.begin();
        i != m_traitClasses.end();
        i++)
    {
        const gcTraitInfo & trait = (*i).second;
        toReturn.push_back(&trait);
    }
    return toReturn;
}

gcTraitAllele &
GCStructures::GetAllele(size_t id)
{
    gcAlleleMap::iterator iter = m_alleles.find(id);
    assert(iter != m_alleles.end());
    return (*iter).second;
}

const gcTraitAllele &
GCStructures::GetAllele(size_t id) const
{
    gcAlleleMap::const_iterator iter = m_alleles.find(id);
    assert(iter != m_alleles.end());
    return (*iter).second;
}

gcRegion &
GCStructures::GetRegion(size_t id)
{
    gcRegionMap::iterator iter = m_regions.find(id);
    assert(iter != m_regions.end());
    return (*iter).second;
}

const gcRegion &
GCStructures::GetRegion(size_t id) const
{
    gcRegionMap::const_iterator iter = m_regions.find(id);
    assert(iter != m_regions.end());
    return (*iter).second;
}

gcLocus &
GCStructures::GetLocus(size_t id)
{
    gcLocusMap::iterator iter = m_loci.find(id);
    assert(iter != m_loci.end());
    return (*iter).second;
}

const gcLocus &
GCStructures::GetLocus(size_t id) const
{
    gcLocusMap::const_iterator iter = m_loci.find(id);
    assert(iter != m_loci.end());
    return (*iter).second;
}

gcPanel &
GCStructures::GetPanel(size_t id)
{
    for (gcPanelMap::iterator i=m_panels.begin();i != m_panels.end();i++)
    {
        if((*i).second.GetId() == id)
        {
            return (*i).second;
        }
    }
    wxString badId = wxString::Format("%i",(int)id);
    throw missing_panel_id(badId);
}

const gcPanel &
GCStructures::GetPanel(size_t id) const
{
    for (gcPanelMap::const_iterator i=m_panels.begin();i != m_panels.end();i++)
    {
        if((*i).second.GetId() == id)
        {
            return (*i).second;
        }
    }
    wxString badId = wxString::Format("%i",(int)id);
    throw missing_panel_id(badId);
}

gcParent &
GCStructures::GetParent(size_t id)
{
    for (gcParentMap::iterator i=m_parents.begin();i != m_parents.end();i++)
    {
        if((*i).second.GetId() == id)
        {
            return (*i).second;
        }
    }
    wxString badId = wxString::Format("%i",(int)id);
    throw missing_parent_id(badId);
}

const gcParent &
GCStructures::GetParent(size_t id) const
{
    for (gcParentMap::const_iterator i=m_parents.begin();i != m_parents.end();i++)
    {
        if((*i).second.GetId() == id)
        {
            return (*i).second;
        }
    }
    wxString badId = wxString::Format("%i",(int)id);
    throw missing_parent_id(badId);
}

gcPhenotype &
GCStructures::GetPhenotype(size_t id)
{
    gcPhenoMap::iterator iter = m_phenotypes.find(id);
    assert(iter != m_phenotypes.end());
    return (*iter).second;
}

const gcPhenotype &
GCStructures::GetPhenotype(size_t id) const
{
    gcPhenoMap::const_iterator iter = m_phenotypes.find(id);
    assert(iter != m_phenotypes.end());
    return (*iter).second;
}

gcPopulation &
GCStructures::GetPop(size_t id)
{
    gcPopMap::iterator iter = m_pops.find(id);
    assert(iter != m_pops.end());
    return (*iter).second;
}

const gcPopulation &
GCStructures::GetPop(size_t id) const
{
    gcPopMap::const_iterator iter = m_pops.find(id);
    assert(iter != m_pops.end());
    return (*iter).second;
}

gcTraitInfo &
GCStructures::GetTrait(size_t id)
{
    assert(m_traitClasses.find(id) != m_traitClasses.end());
    return m_traitClasses[id];
}

const gcTraitInfo &
GCStructures::GetTrait(size_t id) const
{
    gcTraitMap::const_iterator iter = m_traitClasses.find(id);
    assert(iter != m_traitClasses.end());
    return (*iter).second;
}

void
GCStructures::AssignAllele(gcTraitAllele & allele, gcTraitInfo & trait)
{
    if(allele.HasTraitId())
    {
        size_t oldTraitId = allele.GetTraitId();
        gcTraitInfo & oldTrait = GetTrait(oldTraitId);
        oldTrait.RemoveAllele(allele);
    }
    allele.SetTraitId(trait.GetId());
    trait.AddAllele(allele);
}

void
GCStructures::AssignLocus(size_t locusId, size_t regionId)
{
    gcLocus & locus = GetLocus(locusId);
    gcRegion & newRegion = GetRegion(regionId);
    return AssignLocus(locus,newRegion);
}

void
GCStructures::AssignLocus(gcLocus & locus, gcRegion & newRegion)
{
    if(locus.HasRegion())
    {
        size_t regionId = locus.GetRegionId();
        gcRegion & regionRef = GetRegion(regionId);
        regionRef.RemoveLocusId(locus.GetId());
    }

    locus.SetRegionId(newRegion.GetId());
    newRegion.AddLocus(locus);
}

void
GCStructures::AssignPhenotype(gcPhenotype & phenotype, gcTraitInfo & trait)
{
    if(phenotype.HasTraitId())
    {
        size_t oldTraitId = phenotype.GetTraitId();
        gcTraitInfo & oldTrait = GetTrait(oldTraitId);
        oldTrait.RemovePhenotype(phenotype);
    }
    phenotype.SetTraitId(trait.GetId());
    trait.AddPhenotype(phenotype);
}

void
GCStructures::AssignTrait(size_t traitId, size_t regionId)
{
    gcTraitInfo & trait = GetTrait(traitId);
    gcRegion & newRegion = GetRegion(regionId);
    AssignTrait(trait,newRegion);
}

void
GCStructures::AssignTrait(gcTraitInfo & trait, gcRegion & newRegion)
{
    if(trait.HasRegionId())
    {
        size_t oldRegionId = trait.GetRegionId();
        gcRegion & oldRegion = GetRegion(oldRegionId);
        oldRegion.RemoveTraitId(trait.GetId());
    }
    newRegion.AddTraitId(trait.GetId());
}

size_t
GCStructures::GetPopForBlock(size_t blockId) const
{
    for(gcBlockSetMap::const_iterator i=m_blocks.begin(); i != m_blocks.end(); i++)
    {
        gcPopLocusIdPair popLoc = (*i).first;
        const gcIdSet & blocks = (*i).second;
        if(blocks.find(blockId) != blocks.end())
        {
            return popLoc.first;
        }
    }
    assert(false);
    return gcdefault::badIndex;
}

size_t
GCStructures::GetLocusForBlock(size_t blockId) const
{
    for(gcBlockSetMap::const_iterator i=m_blocks.begin(); i != m_blocks.end(); i++)
    {
        gcPopLocusIdPair popLoc = (*i).first;
        const gcIdSet & blocks = (*i).second;
        if(blocks.find(blockId) != blocks.end())
        {
            return popLoc.second;
        }
    }
    assert(false);
    return gcdefault::badIndex;
}

void
GCStructures::AssignBlockToPop(size_t blockId, size_t popId)
{
    size_t oldLocus = GetLocusForBlock(blockId);
    AssignBlock(blockId,popId,oldLocus);
}

void
GCStructures::AssignBlockToLocus(size_t blockId, size_t locusId)
{
    size_t oldPop = GetPopForBlock(blockId);
    AssignBlock(blockId,oldPop,locusId);
}

void
GCStructures::AssignBlock(size_t blockId, size_t popId, size_t locusId)
{
    RemoveBlockAssignment(blockId);

    gcPopLocusIdPair plPair(popId,locusId);
    gcBlockSetMap::iterator iter = m_blocks.find(plPair);
    if(iter == m_blocks.end())
        // we need to insert a new, empty set
    {
        m_blocks[plPair] = gcIdSet();
        iter = m_blocks.find(plPair);
    }
    gcIdSet & blockSet = (*iter).second;
    blockSet.insert(blockId);
}

void
GCStructures::RemoveBlockAssignment(size_t blockId)
{
    size_t foundCount = 0;
    for(gcBlockSetMap::iterator i=m_blocks.begin(); i != m_blocks.end(); i++)
    {
        gcIdSet & blockSetRef = (*i).second;
        gcIdSet::iterator j = blockSetRef.find(blockId);
        if(j != blockSetRef.end())
        {
            foundCount++;
            blockSetRef.erase(j);
        }
    }
    assert(foundCount < 2);
}

gcTraitAllele &
GCStructures::FetchOrMakeAllele(gcTraitInfo& trait,wxString name)
{
    if(HasAllele(name))
    {
        return GetAllele(trait,name);
    }
    return MakeAllele(name);
}

gcLocus &
GCStructures::FetchOrMakeLocus(gcRegion & region, wxString name, const gcCreationInfo & createInfo)
{
    if(HasLocus(name))
    {
        return GetLocus(region,name);
    }
    return MakeLocus(region,name,true, createInfo); // true == blessed
}

gcPopulation &
GCStructures::FetchOrMakePop(wxString name)
{
    if(HasPop(name))
    {
        return GetPop(name);
    }
    return MakePop(name,true);  // true == blessed
}

gcRegion &
GCStructures::FetchOrMakeRegion(wxString name)
{
    wxLogVerbose("****FetchOrMakeRegion name: %s", name.c_str());  // JMDBG
    if(HasRegion(name))
    {
        return GetRegion(name);
    }
    return MakeRegion(name,true);   // true == blessed
}

gcTraitInfo &
GCStructures::FetchOrMakeTrait(wxString name)
{
    if(HasTrait(name))
    {
        return GetTrait(name);
    }
    return MakeTrait(name);
}

gcTraitAllele &
GCStructures::MakeAllele(wxString name)
{
    wxString nameToUse = m_traitNames.ReserveOrMakeName(name,gcstr::allele);
    gcTraitAllele newAllele;
    newAllele.SetName(nameToUse);
    size_t newId = newAllele.GetId();
    // don't do any setting after this step --
    // it won't propagate
    m_alleles[newId] = newAllele;
    return m_alleles[newId];
}

gcLocus &
GCStructures::MakeLocus(size_t regionId, wxString name, bool blessed, const gcCreationInfo & createInfo)
{
    gcRegion & region = GetRegion(regionId);
    return MakeLocus(region,name,blessed,createInfo);
}

gcLocus &
GCStructures::MakeLocus(gcRegion & region, wxString name, bool blessed, const gcCreationInfo & creationInfo)
{
    wxString nameToUse = m_names.ReserveOrMakeName(name,gcstr::locus);
    gcLocus newLocus;
    newLocus.SetName(nameToUse);
    newLocus.SetBlessed(blessed);
    newLocus.SetCreationInfo(creationInfo);
    size_t newId = newLocus.GetId();
    // don't make any direct changes to newLocus after
    // this step -- it won't propagate
    m_loci[newId] = newLocus;
    AssignLocus(m_loci[newId],region);
    return m_loci[newId];
}

gcPopulation &
GCStructures::MakePop(wxString name,bool blessed)
{
    wxString nameToUse = m_names.ReserveOrMakeName(name,gcstr::population);
    gcPopulation newPop;
    newPop.SetName(nameToUse);
    newPop.SetBlessed(blessed);
    size_t newId = newPop.GetId();
    // don't do any setting after this step --
    // it won't propagate
    m_pops[newId] = newPop;
    m_popDisplay.push_back(newId);
    return m_pops[newId];
}

gcPhenotype &
GCStructures::MakePhenotype(wxString name)
{
    wxString nameToUse = m_traitNames.ReserveOrMakeName(name,gcstr::phenotype);
    gcPhenotype newPhenotype;
    newPhenotype.SetName(nameToUse);
    size_t newId = newPhenotype.GetId();
    // don't do any setting after this step --
    // it won't propagate
    m_phenotypes[newId] = newPhenotype;
    return m_phenotypes[newId];
}

gcRegion &
GCStructures::MakeRegion(wxString name,bool blessed)
{
    wxLogVerbose("****MakeRegion name: %s", name.c_str());  // JMDBG
    wxString nameToUse = m_names.ReserveOrMakeName(name,gcstr::region);
    gcRegion newRegion;
    newRegion.SetName(nameToUse);
    newRegion.SetBlessed(blessed);
    wxLogVerbose("****MakeRegion nameToUse: %s blessed: %i", nameToUse.c_str(), (int)blessed);  // JMDBG
    size_t newId = newRegion.GetId();

    // create panels for each region / population pair
    for(gcPopMap::const_iterator i=m_pops.begin(); i != m_pops.end(); i++)
    {
        size_t popId = (*i).first;
        wxString popname =  (*i).second.GetName();
        wxString pname;
        pname.Printf(wxT("panel:%s:%s"), newRegion.GetName().c_str(), (*i).second.GetName().c_str());
        wxString panelNameToUse = m_names.ReserveOrMakeName(pname,gcstr::panel);
        wxLogVerbose("***MakeRegion create Panel name: %s", panelNameToUse.c_str());  // JMDBG
        gcPanel newPanel = MakePanel(panelNameToUse, blessed, newId, popId);
    }

    // don't do any setting after this step --
    // it won't propagate
    m_regions[newId] = newRegion;
    m_regionDisplay.push_back(newId);
    return m_regions[newId];
}

gcPanel &
GCStructures::CreatePanel(size_t regionId, size_t popId )
{
    wxString pname;
    pname.Printf(wxT("panel:%s:%s"), GetRegion(regionId).GetName().c_str(), GetPop(popId).GetName().c_str());
    wxString panelNameToUse = m_names.ReserveOrMakeName(pname,gcstr::panel);
    wxLogVerbose("***CreatePanel name: %s", panelNameToUse.c_str());  // JMDBG
    return MakePanel(panelNameToUse, false, regionId, popId);
}

gcPanel &
GCStructures::MakePanel(wxString name, bool blessed, size_t regionId, size_t popId )
{
    gcPanel newPanel;
    newPanel.SetName(name);
    newPanel.SetBlessed(blessed);
    newPanel.SetRegionId(regionId);
    newPanel.SetPopId(popId);
    wxLogVerbose("****MakePanel name: %s", name.c_str());  // JMDBG
    size_t newId = newPanel.GetId();

    gcRegionPopIdPair regPopPair = gcRegionPopIdPair(regionId, popId);

    // don't do any setting after this step --
    // it won't propagate
    m_panels[regPopPair] = newPanel;
    ////m_panelDisplay.push_back(newId);
    return m_panels[regPopPair];
}

gcParent &
GCStructures::MakeParent(wxString name)
{
    wxString nameToUse = m_names.ReserveOrMakeName(name,gcstr::parent);
    gcParent newParent;
    newParent.SetName(nameToUse);
    newParent.SetDispLevel(0);
    wxLogVerbose("****MakeParent name: %s", name.c_str());  // JMDBG
    size_t newId = newParent.GetId();
    // don't do any setting after this step --
    // it won't propagate
    m_parents[newId] = newParent;
    return m_parents[newParent.GetId()];
}

gcMigration &
GCStructures::MakeMigration(bool blessed, size_t toId, size_t fromId )
{
    gcMigration newMigration;

    newMigration.m_blessed = true;
    newMigration.SetToId(toId);
    newMigration.SetFromId(fromId);
    newMigration.m_startValue = 50.0;
    newMigration.m_method = migmethod_USER;
    newMigration.m_profile = migprofile_NONE;
    newMigration.m_constraint = migconstraint_UNCONSTRAINED;

    newMigration.SetName(wxString::Format(_T("cell%i:%i "), (int)toId, (int)fromId)); //JMDBG

    wxLogVerbose("****MakeMigration into: %i from: %i", (int)toId, (int)fromId );  // JMDBG
    size_t newId = newMigration.GetId();

    gcMigrationPair toFromPair = gcMigrationPair(toId, fromId);

    // don't do any setting after this step --
    // it won't propagate
    m_migrations[toFromPair] = newMigration;
    return m_migrations[toFromPair];
}

gcTraitInfo &
GCStructures::MakeTrait(wxString name)
{
    wxString nameToUse = m_traitNames.ReserveOrMakeName(name,gcstr::trait);
    gcTraitInfo newTrait;
    newTrait.SetName(nameToUse);
    // don't do any setting after this step --
    // it won't propagate
    assert(m_traitClasses.find(newTrait.GetId()) == m_traitClasses.end());
    m_traitClasses[newTrait.GetId()] = newTrait;
    return m_traitClasses[newTrait.GetId()];
}

void
GCStructures::Rename(GCQuantum & object, wxString newName)
{
    wxString oldName = object.GetName();
    wxLogVerbose("old name: %s \nnew name: %s", oldName.c_str(), newName.c_str());  // JMDBG
    if(newName.Cmp(oldName) == 0) return;

    assert(m_names.HasName(oldName) || m_traitNames.HasName(oldName));
    assert(! (m_names.HasName(oldName) && m_traitNames.HasName(oldName)));

    wxLogVerbose("checking m_names");  // JMDBG
    if(m_names.HasName(oldName))
    {
        wxLogVerbose("in m_names");  // JMDBG
        m_names.ReserveName(newName);
        object.SetName(newName);
        m_names.FreeName(oldName);
    }

    wxLogVerbose("checking m_traitNames");  // JMDBG
    if(m_traitNames.HasName(oldName))
    {
        wxLogVerbose("in m_traitNames");  // JMDBG
        m_traitNames.ReserveName(newName);
        object.SetName(newName);
        m_traitNames.FreeName(oldName);
    }
}

void
GCStructures::DebugDump(wxString prefix) const
{
    wxLogDebug(gcstr::structureDump,prefix.c_str());    // EWDUMPOK
    m_pops.DebugDump((prefix+gcstr::indent).c_str());
    m_regions.DebugDump((prefix+gcstr::indent).c_str());
    m_loci.DebugDump((prefix+gcstr::indent).c_str());
    m_traitClasses.DebugDump((prefix+gcstr::indent).c_str());
    m_blocks.DebugDump((prefix+gcstr::indent).c_str());
    m_files.DebugDump((prefix+gcstr::indent).c_str());
}

gcRegion &
GCStructures::GetRegion(wxString name)
{
    for(gcRegionMap::iterator i=m_regions.begin();
        i != m_regions.end();
        i++)
    {
        if((*i).second.GetName().CmpNoCase(name) == 0)
        {
            return (*i).second;
        }
    }
    missing_region e(wxString::Format(gcerr::missingRegion,name.c_str()).c_str());
    throw e;
}

const gcRegion &
GCStructures::GetRegion(wxString name) const
{
    for(gcRegionMap::const_iterator i=m_regions.begin();
        i != m_regions.end();
        i++)
    {
        if((*i).second.GetName().CmpNoCase(name) == 0)
        {
            return (*i).second;
        }
    }
    missing_region e(wxString::Format(gcerr::missingRegion,name.c_str()).c_str());
    throw e;
}

bool
GCStructures::HasRegion(wxString name) const
{
    for(gcRegionMap::const_iterator i=m_regions.begin();
        i != m_regions.end();
        i++)
    {
        if((*i).second.GetName().CmpNoCase(name) == 0)
        {
            return true;
        }
    }
    return false;
}

gcTraitAllele &
GCStructures::GetAllele(wxString name)
{
    for(gcAlleleMap::iterator i=m_alleles.begin();
        i != m_alleles.end();
        i++)
    {
        if((*i).second.GetName().Cmp(name) == 0)    // alleles case sensitive
        {
            return (*i).second;
        }
    }
    throw gc_missing_allele(name);
}

const gcTraitAllele &
GCStructures::GetAllele(wxString name) const
{
    for(gcAlleleMap::const_iterator i=m_alleles.begin();
        i != m_alleles.end();
        i++)
    {
        if((*i).second.GetName().Cmp(name) == 0)  // alleles case sensitive
        {
            return (*i).second;
        }
    }
    throw gc_missing_allele(name);
}

gcTraitAllele &
GCStructures::GetAllele(gcTraitInfo& trait, wxString alleleName)
{
    gcTraitAllele & allele = GetAllele(alleleName);
    assert(allele.HasTraitId());
    if(allele.GetTraitId() != trait.GetId())
    {
        const gcTraitInfo & oldTrait = GetTrait(allele.GetTraitId());
        throw gc_allele_trait_mismatch(alleleName,trait.GetName(),oldTrait.GetName());
    }
    return allele;
}

bool
GCStructures::HasAllele(wxString name) const
{
    for(gcAlleleMap::const_iterator i=m_alleles.begin();
        i != m_alleles.end();
        i++)
    {
        if((*i).second.GetName().Cmp(name) == 0)    // alleles case sensitive
        {
            return true;
        }
    }
    return false;
}

gcLocus &
GCStructures::GetLocus(wxString name)
{
    for(gcLocusMap::iterator i=m_loci.begin();
        i != m_loci.end();
        i++)
    {
        if((*i).second.GetName().CmpNoCase(name) == 0)
        {
            return (*i).second;
        }
    }
    throw gc_missing_locus(name);
}

const gcLocus &
GCStructures::GetLocus(wxString name) const
{
    for(gcLocusMap::const_iterator i=m_loci.begin();
        i != m_loci.end();
        i++)
    {
        if((*i).second.GetName().CmpNoCase(name) == 0)
        {
            return (*i).second;
        }
    }
    throw gc_missing_locus(name);
}

gcLocus &
GCStructures::GetLocus(gcRegion& region, wxString locusName)
{
    gcLocus & locus = GetLocus(locusName);
    assert(locus.HasRegion());
    if(locus.GetRegionId() != region.GetId())
    {
        const gcRegion & oldRegion = GetRegion(locus.GetRegionId());
        throw gc_locus_region_mismatch(locusName,region.GetName(),oldRegion.GetName());
    }
    return locus;
}

gcPanel &
GCStructures::GetPanel(wxString name)
{
    for(gcPanelMap::iterator i=m_panels.begin();i != m_panels.end();i++)
    {
        if((*i).second.GetName().CmpNoCase(name) == 0)
        {
            return (*i).second;
        }
    }
    throw missing_panel(name);
}

gcMigration &
GCStructures::GetMigration(size_t id)
{
    for (gcMigrationMap::iterator i=m_migrations.begin();i != m_migrations.end();i++)
    {
        if((*i).second.GetId() == id)
        {
            return (*i).second;
        }
    }
    wxString badId = wxString::Format("%i",(int)id);
    throw missing_migration_id(badId);
}

const gcMigration &
GCStructures::GetMigration(size_t id) const
{
    for (gcMigrationMap::const_iterator i=m_migrations.begin();i != m_migrations.end();i++)
    {
        if((*i).second.GetId() == id)
        {
            return (*i).second;
        }
    }
    wxString badId = wxString::Format("%i",(int)id);
    throw missing_migration_id(badId);
}

bool
GCStructures::HasMigration(size_t toId, size_t fromId) const
{
    gcMigrationPair p(toId, fromId);
    gcMigrationMap::const_iterator iter = m_migrations.find(p);
    if(iter != m_migrations.end())
    {
        return true;
    }
    return false;
}

gcMigration &
GCStructures::GetMigration(size_t toId, size_t fromId)
{
    gcMigrationPair p(toId, fromId);
    gcMigrationMap::iterator iter = m_migrations.find(p);
    if(iter != m_migrations.end())
    {
        return (*iter).second;
    }

    wxString fromName;
    if (IsPop(fromId))
    {
        fromName = GetPop(fromId).GetName();
    }
    else
    {
        if(IsParent(fromId))
        {
            fromName = GetParent(fromId).GetName();
        }
        else
        {
            fromName = wxString("Bad from ID:%s", fromId);
        }
    }

    wxString toName;
    if (IsPop(toId))
    {
        toName = GetPop(toId).GetName();
    }
    else
    {
        if(IsParent(toId))
        {
            toName = GetParent(toId).GetName();
        }
        else
        {
            toName = wxString("Bad to ID:%s", toId);
        }
    }
    throw missing_migration(toName, fromName);
}

const gcMigration &
GCStructures::GetMigration(size_t toId, size_t fromId) const
{
    gcMigrationPair p(toId, fromId);
    gcMigrationMap::const_iterator iter = m_migrations.find(p);
    if(iter != m_migrations.end())
    {
        return (*iter).second;
    }

    wxString fromName;
    if (IsPop(fromId))
    {
        fromName = GetPop(fromId).GetName();
    }
    else
    {
        if(IsParent(fromId))
        {
            fromName = GetParent(fromId).GetName();
        }
        else
        {
            fromName = wxString("Bad from ID:%s", fromId);
        }
    }

    wxString toName;
    if (IsPop(toId))
    {
        toName = GetPop(toId).GetName();
    }
    else
    {
        if(IsParent(toId))
        {
            toName = GetParent(toId).GetName();
        }
        else
        {
            toName = wxString("Bad to ID:%s", toId);
        }
    }
    throw missing_migration(fromName, toName);
}

const gcPanel &
GCStructures::GetPanel(wxString name) const
{
    for(gcPanelMap::const_iterator i=m_panels.begin();i != m_panels.end();i++)
    {
        if((*i).second.GetName().CmpNoCase(name) == 0)
        {
            return (*i).second;
        }
    }
    throw missing_panel(name);
}

bool
GCStructures::HasPanel(size_t regionId, size_t popId) const
{
    gcRegionPopIdPair p(regionId, popId);
    gcPanelMap::const_iterator iter = m_panels.find(p);
    if(iter == m_panels.end())
    {
        return false;
    }
    return true;
}

gcPanel &
GCStructures::GetPanel(size_t regionId, size_t popId)
{
    gcRegionPopIdPair p(regionId, popId);
    gcPanelMap::iterator iter = m_panels.find(p);
    if(iter != m_panels.end())
    {
        return (*iter).second;
    }
    wxString regionName = GetRegion(regionId).GetName();
    wxString popName = GetPop(popId).GetName();
    throw missing_panel(regionName, popName);
}

const gcPanel &
GCStructures::GetPanel(size_t regionId, size_t popId) const
{
    gcRegionPopIdPair p(regionId, popId);
    gcPanelMap::const_iterator iter = m_panels.find(p);
    if(iter != m_panels.end())
    {
        return (*iter).second;
    }
    wxString regionName = GetRegion(regionId).GetName();
    wxString popName = GetPop(popId).GetName();
    throw missing_panel(regionName, popName);
}

gcParent &
GCStructures::GetParent(wxString name)
{
    for(gcParentMap::iterator i=m_parents.begin();i != m_parents.end();i++)
    {
        if((*i).second.GetName().CmpNoCase(name) == 0)
        {
            return (*i).second;
        }
    }
    throw missing_parent(name);
}

const gcParent &
GCStructures::GetParent(wxString name) const
{
    for(gcParentMap::const_iterator i=m_parents.begin();i != m_parents.end();i++)
    {
        if((*i).second.GetName().CmpNoCase(name) == 0)
        {
            return (*i).second;
        }
    }
    throw missing_parent(name);
}

gcPhenotype &
GCStructures::GetPhenotype(wxString name)
{
    for(gcPhenoMap::iterator i=m_phenotypes.begin();
        i != m_phenotypes.end();
        i++)
    {
        if((*i).second.GetName().Cmp(name) == 0)  // phenotypes case sensitive
        {
            return (*i).second;
        }
    }
    throw gc_missing_phenotype(name);
}

const gcPhenotype &
GCStructures::GetPhenotype(wxString name) const
{
    for(gcPhenoMap::const_iterator i=m_phenotypes.begin();
        i != m_phenotypes.end();
        i++)
    {
        if((*i).second.GetName().Cmp(name) == 0)  // phenotypes case sensitive
        {
            return (*i).second;
        }
    }
    throw gc_missing_phenotype(name);
}

bool
GCStructures::HasLocus(wxString name) const
{
    for(gcLocusMap::const_iterator i=m_loci.begin();
        i != m_loci.end();
        i++)
    {
        if((*i).second.GetName().CmpNoCase(name) == 0)
        {
            return true;
        }
    }
    return false;
}

gcPopulation &
GCStructures::GetPop(wxString name)
{
    for(gcPopMap::iterator i=m_pops.begin();
        i != m_pops.end();
        i++)
    {
        if((*i).second.GetName().CmpNoCase(name) == 0)
        {
            return (*i).second;
        }
    }
    throw gc_missing_population(name);
}

const gcPopulation &
GCStructures::GetPop(wxString name) const
{
    for(gcPopMap::const_iterator i=m_pops.begin();
        i != m_pops.end();
        i++)
    {
        if((*i).second.GetName().CmpNoCase(name) == 0)
        {
            return (*i).second;
        }
    }
    throw gc_missing_population(name);
}

bool
GCStructures::HasPop(wxString name) const
{
    for(gcPopMap::const_iterator i=m_pops.begin();
        i != m_pops.end();
        i++)
    {
        if((*i).second.GetName().CmpNoCase(name) == 0)
        {
            return true;
        }
    }
    return false;
}

gcTraitInfo &
GCStructures::GetTrait(wxString name)
{
    for(gcTraitMap::iterator i=m_traitClasses.begin();
        i != m_traitClasses.end();
        i++)
    {
        if((*i).second.GetName().CmpNoCase(name) == 0)
        {
            return (*i).second;
        }
    }
    missing_trait e(wxString::Format(gcerr::missingTrait,name.c_str()).c_str());
    throw e;
}

const gcTraitInfo &
GCStructures::GetTrait(wxString name) const
{
    for(gcTraitMap::const_iterator i=m_traitClasses.begin();
        i != m_traitClasses.end();
        i++)
    {
        if((*i).second.GetName().CmpNoCase(name) == 0)
        {
            return (*i).second;
        }
    }
    missing_trait e(wxString::Format(gcerr::missingTrait,name.c_str()).c_str());
    throw e;
}

bool
GCStructures::HasTrait(wxString name) const
{
    for(gcTraitMap::const_iterator i=m_traitClasses.begin();
        i != m_traitClasses.end();
        i++)
    {
        if((*i).second.GetName().CmpNoCase(name) == 0)
        {
            return true;
        }
    }
    return false;
}

long
GCStructures::GetPopDisplayIndexOf(size_t popId) const
{
    long popIndex = 0;
    for(    gcDisplayOrder::const_iterator i = m_popDisplay.begin();
            i != m_popDisplay.end();
            i++, popIndex++)
    {
        if((*i) == popId) return popIndex;
    }
    return gcdefault::badDisplayIndex;
}

long
GCStructures::GetLocusDisplayIndexOf(size_t locusId) const
{
    long locusIndex = 0;
    for(    gcDisplayOrder::const_iterator i = m_regionDisplay.begin();
            i != m_regionDisplay.end();
            i++)
    {
        size_t regionId = (*i);
        const gcRegion & region = GetRegion(regionId);

        const GCLocusInfoMap & loci = region.GetLocusInfoMap();

        if(loci.size() == 0)
        {
            locusIndex++;
        }
        else
        {

            for(GCLocusInfoMap::const_iterator liter=loci.begin();
                liter != loci.end(); liter++)
            {
                if(locusId == ((*liter).first))
                {
                    return locusIndex;
                }
                locusIndex++;
            }
        }

    }
    return gcdefault::badDisplayIndex;
}

bool
GCStructures::RegionHasAnyLinkedLoci(size_t regionId) const
{
    const gcRegion & region = GetRegion(regionId);
    const GCLocusInfoMap & loci = region.GetLocusInfoMap();
    for(GCLocusInfoMap::const_iterator i=loci.begin(); i != loci.end(); i++)
    {
        size_t locusId = (*i).first;
        const gcLocus & locus = GetLocus(locusId);
        if(locus.GetLinked())
        {
            return true;
        }
    }
    return false;
}

bool
GCStructures::RegionHasAnyUnLinkedLoci(size_t regionId) const
{
    const gcRegion & region = GetRegion(regionId);
    const GCLocusInfoMap & loci = region.GetLocusInfoMap();
    for(GCLocusInfoMap::const_iterator i=loci.begin(); i != loci.end(); i++)
    {
        size_t locusId = (*i).first;
        const gcLocus & locus = GetLocus(locusId);
        if(!(locus.GetLinked()))
        {
            return true;
        }
    }
    return false;
}

void
GCStructures::FragmentRegion(size_t regionId)
{
    gcRegion & regionRef = GetRegion(regionId);
    gcIdVec loci = GetLocusIdsForRegionByCreation(regionId);
    for(gcIdVec::const_iterator i=loci.begin(); i != loci.end(); i++)
    {
        size_t locusId = *i;
        gcLocus & locusRef = GetLocus(locusId);

        wxLogVerbose("****FragmentRegion ");  // JMDBG
        gcRegion & newRegion = MakeRegion("",false); // false == not blessed
        if(regionRef.HasEffectivePopulationSize())
        {
            newRegion.SetEffectivePopulationSize(regionRef.GetEffectivePopulationSize());
        }

        // propogate panel size out to all the new panels
        for(gcPopMap::const_iterator i=m_pops.begin(); i != m_pops.end(); i++)
        {
            size_t popId = (*i).first;
            if (HasBlock(locusId, popId))
            {
                GetPanel(newRegion.GetId(),popId).SetNumPanels(GetPanel(regionId,popId).GetNumPanels());
                GetPanel(newRegion.GetId(),popId).SetBlessed(true);
            }
        }

        AssignLocus(locusRef,newRegion);
    }

    // unbless old region
    regionRef.SetBlessed(false);
}

void
GCStructures::LocusToOwnRegion(size_t locusId)
{
    gcLocus & locusRef = GetLocus(locusId);

    wxLogVerbose("****LocusToOwnRegion ");  // JMDBG
    gcRegion & newRegion = MakeRegion("",false); // false == not blessed
    if(locusRef.HasRegion())
    {
        gcRegion & regionRef = GetRegion(locusRef.GetRegionId());
        if(regionRef.HasEffectivePopulationSize())
        {
            newRegion.SetEffectivePopulationSize(regionRef.GetEffectivePopulationSize());
        }
    }
    AssignLocus(locusRef,newRegion);
}

void
GCStructures::MergeRegions(gcIdVec regions)
{
    if(regions.size() < 2) return;

    // testing mergeability

    // population size set
    bool haveEffPopSize = false;
    double effPopSize = 1;

    for(gcIdVec::iterator iter=regions.begin(); iter != regions.end(); iter++)
    {
        size_t regionId = *iter;
        gcRegion * regionP = &GetRegion(regionId);

        // effective population size
        if(regionP->HasEffectivePopulationSize())
        {
            double pSize = regionP->GetEffectivePopulationSize();
            if(haveEffPopSize)
            {
                if(effPopSize != pSize)
                {
                    throw effective_pop_size_clash(effPopSize,pSize);
                }
            }
            else
            {
                haveEffPopSize = true;
                effPopSize = pSize;
            }
        }
    }

    // test panel size and blessed state
    gcDisplayOrder popIds =  GetDisplayablePopIds();

    for(gcDisplayOrder::iterator piter=popIds.begin(); piter !=popIds.end(); piter++)
    {
        size_t popId = *piter;
        gcPopulation * curPop = &GetPop(popId);
        gcRegion * region1;
        gcRegion * region2;

        bool isBlessed = false;
        long panelSize = 0;
        //size_t lastId = 0;

        for(gcIdVec::iterator iter=regions.begin(); iter != regions.end(); iter++)
        {
            size_t regionId = *iter;
            wxLogVerbose("In MergeRegions testing region: %i pop: %i", regionId, popId);
            if (HasPanel(regionId, popId))
            {
                const gcPanel &panelId =  GetPanel(regionId, popId);
                long numP = panelId.GetNumPanels();
                wxLogVerbose("In MergeRegions region: %i pop: %i HasPanel numP: %i", regionId, popId, numP);
                if (panelId.GetBlessed())
                {
                    if(!isBlessed)
                    {
                        // blessed overides unblessed, no matter what the value
                        panelSize = numP;
                        isBlessed = true;
                        region1 = &GetRegion(regionId);
                    }
                    else
                    {
                        if (panelSize != numP)
                        {
                            wxLogVerbose("In MergeRegions panelSize: %i numP: %i", panelSize, numP);
                            // can't merge panels that are both blessed and have different number of members
                            region2 = &GetRegion(regionId);
                            throw panel_size_clash(curPop->GetName(),region1->GetName(), region2->GetName());
                        }
                    }
                }
                else
                {
                    if (numP > 0)
                    {
                        // this is a bug - you can't have >0 panel size that isn't blessed
                        region1 = &GetRegion(regionId);
                        throw panel_blessed_error(region1->GetName(), curPop->GetName());
                    }
                }
            }
        }
    }

    // everything worked so combine panels
    for(gcDisplayOrder::iterator piter=popIds.begin(); piter !=popIds.end(); piter++)
    {
        size_t popId = *piter;

        bool isFirstRegion = true;
        gcPanel * firstPanel;
        gcPanel * curPanel;
        for(gcIdVec::iterator iter=regions.begin(); iter != regions.end(); iter++)
        {
            size_t regionId = *iter;
            wxLogVerbose("In MergeRegions - regionId: %i popId: %i", regionId, popId);
            if (isFirstRegion)
            {
                // everything propogates to the first region selected
                isFirstRegion = false;
                if (HasPanel(regionId, popId))
                {
                    firstPanel = &GetPanel(regionId, popId);
                    wxLogVerbose(" first panel regionId: %i popId: %i", regionId, popId);
                    firstPanel->SetBlessed(true);
                }
                else
                {
                    // corner case - first region did not contain this pop so create it
                    CreatePanel(regionId, popId);
                }
            }
            else
            {
                // largest panel size wins
                if (HasPanel(regionId, popId))
                {
                    curPanel =  &GetPanel(regionId, popId);
                }
                if (curPanel->GetNumPanels() > firstPanel->GetNumPanels())
                {
                    firstPanel->SetNumPanels(curPanel->GetNumPanels());
                }
            }
        }
    }

    // combine regions
    bool firstItem = true;
    gcRegion * firstRegionPointer = NULL;
    for(gcIdVec::iterator iter=regions.begin(); iter != regions.end(); iter++)
    {
        size_t regionId = *iter;
        gcRegion * regionP = &GetRegion(regionId);
        assert(regionP != NULL);
        if(firstItem)
        {
            firstRegionPointer = regionP;
        }
        else
        {
            gcRegion & regionRef = *regionP;
            const GCLocusInfoMap & lmap = regionRef.GetLocusInfoMap();
            gcIdSet locusIds;
            for(GCLocusInfoMap::const_iterator miter=lmap.begin(); miter != lmap.end(); miter++)
            {
                locusIds.insert((*miter).first);
            }
            for(gcIdSet::const_iterator liter=locusIds.begin(); liter != locusIds.end(); liter++)
            {
                size_t locusId = *liter;
                AssignLocus(locusId,firstRegionPointer->GetId());    // EWFIX.P5 SPEED
            }

            // unbless region that's now empty
            regionRef.SetBlessed(false);
        }
        firstItem = false;
    }
    if(haveEffPopSize)
    {
        firstRegionPointer->SetEffectivePopulationSize(effPopSize);
    }
}

void
GCStructures::MergeLoci(gcIdVec locusIds)
// this operation can fail part way through. If that happens
// in the batch converter, the thrown error will result in
// aborting the program (cleanly, one would hope). If we're
// in the gui, the thrown error should be caught in
// gcUpdatingDialog::OnButton 's call to DoUpdateData
{
    // find all blocks that are assigned to one of these loci and
    // assign them all to the first
    if(locusIds.size() < 2) return;

    bool firstItem = true;
    gcLocus * firstLocusPointer = NULL;
    for(gcIdVec::iterator iter = locusIds.begin(); iter != locusIds.end(); iter++)
    {
        size_t locusId = *iter;
        gcLocus * locusP = &(GetLocus(locusId));
        assert(locusP != NULL);
        if(firstItem)
        {
            firstLocusPointer = locusP;
        }
        else
        {

            firstLocusPointer->MergeWith(*locusP);

            for(gcPopMap::const_iterator piter=m_pops.begin(); piter != m_pops.end(); piter++)
            {
                size_t popId = (*piter).first;
                gcPopLocusIdPair oldPair(popId,locusP->GetId());
                gcBlockSetMap::iterator biter = m_blocks.find(oldPair);
                if(biter != m_blocks.end())
                {
                    gcIdSet blocks = (*biter).second;
                    for(gcIdSet::iterator bsetIter=blocks.begin(); bsetIter != blocks.end(); bsetIter++)
                    {
                        size_t blockId = *bsetIter;
                        AssignBlock(blockId,popId,firstLocusPointer->GetId());  // EWFIX.P5 SPEED
                    }
                }
            }
            // unbless locus that's now empty
            locusP->SetBlessed(false);
        }
        firstItem = false;
    }

}

void
GCStructures::MergePops(gcIdVec popIds)
{
    // find all blocks that are assigned to one of these pops and
    // assign them all to the first
    if(popIds.size() < 2) return;

    bool firstItem = true;
    gcPopulation * firstPopP = NULL;
    for(gcIdVec::iterator iter = popIds.begin(); iter != popIds.end(); iter++)
    {
        size_t popId = *iter;
        gcPopulation * popP = &(GetPop(popId));
        assert(popP != NULL);
        if (popP->GetBlessed())
        {
            wxLogVerbose("****in GCStructures::MergePops popP: %i Blessed: true before merge", popId);  // JMDBG
        }
        else
        {
            wxLogVerbose("****in GCStructures::MergePops popP: %i Blessed: false before merge", popId);  // JMDBG
        }

        if(firstItem)
        {
            firstPopP = popP;
        }
        else
        {
            for(gcLocusMap::const_iterator liter=m_loci.begin(); liter != m_loci.end(); liter++)
            {
                size_t locusId = (*liter).first;
                gcPopLocusIdPair oldPair(popP->GetId(),locusId);
                gcBlockSetMap::iterator biter = m_blocks.find(oldPair);
                if(biter != m_blocks.end())
                {
                    gcIdSet blocks = (*biter).second;
                    for(gcIdSet::iterator bsetIter=blocks.begin(); bsetIter != blocks.end(); bsetIter++)
                    {
                        size_t blockId = *bsetIter;
                        AssignBlock(blockId,firstPopP->GetId(),locusId);
                    }
                }
            }
            // unbless pop that's now empty
            popP->SetBlessed(false);
        }
        firstItem = false;
        if (popP->GetBlessed())
        {
            wxLogVerbose("****in GCStructures::MergePops popP: %i Blessed: true after merge", popId);  // JMDBG
        }
        else
        {
            wxLogVerbose("****in GCStructures::MergePops popP: %i Blessed: false after merge", popId);  // JMDBG
        }
    }

}

bool
GCStructures::HasBlock(size_t locusId, size_t popId) const
{
    gcPopLocusIdPair p(popId,locusId);
    gcBlockSetMap::const_iterator iter = m_blocks.find(p);
    if(iter != m_blocks.end())
    {
        return true;
    }
    return false;
}

void
GCStructures::RemoveBlocks(gcIdSet blocksInFile)
{

    // check in structures
    for(gcBlockSetMap::iterator iter=m_blocks.begin(); iter != m_blocks.end(); )
    {
        gcIdSet & bSet = (*iter).second;
        for(gcIdSet::iterator biter=bSet.begin(); biter != bSet.end(); )
        {
            size_t blockId = *biter;
            if(blocksInFile.find(blockId) != blocksInFile.end())
            {
                bSet.erase(biter++);
            }
            else
            {
                biter++;
            }
        }
        if(bSet.empty())
        {
            m_blocks.erase(iter++);
        }
        else
        {
            iter++;
        }
    }
}

void
GCStructures::RemoveBlocksForLocus(size_t locusId)
{
    for(gcBlockSetMap::iterator iter=m_blocks.begin(); iter != m_blocks.end(); )
    {
        gcPopLocusIdPair p = (*iter).first;
        if(p.second == locusId)
        {
            m_blocks.erase(iter++);
        }
        else
        {
            iter++;
        }
    }
}

void
GCStructures::RemoveBlocksForPop(size_t popId)
{
    for(gcBlockSetMap::iterator iter=m_blocks.begin(); iter != m_blocks.end(); )
    {
        gcPopLocusIdPair p = (*iter).first;
        if(p.first == popId)
        {
            m_blocks.erase(iter++);
        }
        else
        {
            iter++;
        }
    }
}

gcIdVec
GCStructures::GetLocusIdsForRegionByCreation(size_t regionId) const
{
    const gcRegion & region = GetRegion(regionId);
    const GCLocusInfoMap & loci = region.GetLocusInfoMap();
    gcIdVec vec;
    for(GCLocusInfoMap::const_iterator iter=loci.begin(); iter != loci.end(); iter++)
    {
        size_t locusId = (*iter).first;
        if(iter != loci.begin())
        {
            assert(locusId > vec.back());
        }
        vec.push_back(locusId);
    }
    return vec;
}

gcIdVec
GCStructures::GetLocusIdsForRegionByMapPosition(size_t regionId) const
{
    const gcRegion & region = GetRegion(regionId);
    const GCLocusInfoMap & loci = region.GetLocusInfoMap();

    std::multimap<long,size_t> mapByPos;

    for(GCLocusInfoMap::const_iterator iter=loci.begin(); iter != loci.end(); iter++)
    {
        size_t locusId = (*iter).first;

        const gcLocus & locus = GetLocus(locusId);
        long pos = gcdefault::badMapPosition;
        if(locus.HasMapPosition())
        {
            pos = locus.GetMapPosition();
        }
        mapByPos.insert(std::pair<long, size_t>(pos,locusId));
    }

    gcIdVec vec;
    for(std::multimap<long,size_t>::iterator i=mapByPos.begin(); i!=mapByPos.end(); i++)
    {
        size_t id = (*i).second;
        vec.push_back(id);
    }
    return vec;
}

void
GCStructures::RemoveRegion(gcRegion & region)
{

    // remove all blocks for this region
    gcIdVec locusIds = GetLocusIdsForRegionByCreation(region.GetId());
    for(gcIdVec::const_iterator iter=locusIds.begin(); iter != locusIds.end(); iter++)
    {
        size_t locusId = (*iter);
        RemoveLocus(GetLocus(locusId));
    }

    // remove from display and master map
    // no need to delete, it lives there
    gcDisplayOrder::iterator displayIter =
        find(m_regionDisplay.begin(),m_regionDisplay.end(),region.GetId());
    m_regionDisplay.erase(displayIter);
    gcRegionMap::iterator masterIter = m_regions.find(region.GetId());
    m_regions.erase(masterIter);

}

void
GCStructures::RemoveLocus(gcLocus & locus)
{
    // we do everything by id in this class
    size_t locId = locus.GetId();

    // remove all blocks for this locus
    RemoveBlocksForLocus(locId);

    // remove this locus from its region
    if(locus.HasRegion())
    {
        size_t oldRegionId = locus.GetRegionId();
        gcRegion & oldRegion = GetRegion(oldRegionId);
        oldRegion.RemoveLocusId(locId);
    }

    // remove from master map -- no need to delete, it
    // lives there
    gcLocusMap::iterator masterIter = m_loci.find(locId);
    m_loci.erase(masterIter);

}

void
GCStructures::RemoveMigration(size_t toId, size_t fromId)
{
    gcMigrationPair p(toId, fromId);
    gcMigrationMap::iterator masterIter = m_migrations.find(p);
    m_migrations.erase(masterIter);
}

void
GCStructures::RemovePop(gcPopulation & pop)
{
    // we do everything by id in this class
    size_t popId = pop.GetId();

    // remove all blocks for this pop
    RemoveBlocksForPop(popId);

    // remove from display and master map
    gcDisplayOrder::iterator displayIter =
        find(m_popDisplay.begin(),m_popDisplay.end(),popId);
    m_popDisplay.erase(displayIter);
    gcPopMap::iterator masterIter = m_pops.find(popId);
    m_pops.erase(masterIter);

}

void
GCStructures::RemovePanel(size_t regionId, size_t popId)
{
    gcRegionPopIdPair p(regionId, popId);
    // remove from master map
    gcPanelMap::iterator masterIter = m_panels.find(p);
    m_panels.erase(masterIter);
}

void
GCStructures::RemoveParent(size_t parentId)
{
    const gcParent & parRef = GetParent(parentId);
    m_names.FreeName(parRef.GetName());
    gcParentMap::iterator masterIter = m_parents.find(parentId);
    m_parents.erase(masterIter);
}


void
GCStructures::RemoveRegions(objVector regions)
{
    for(objVector::iterator i=regions.begin(); i != regions.end(); i++)
    {
        GCQuantum * object = *i;
        gcRegion * regionP = dynamic_cast<gcRegion *>(object);
        assert(regionP != NULL);
        RemoveRegion(*regionP);
    }
}

void
GCStructures::RemoveLoci(objVector loci)
{
    for(objVector::iterator iter = loci.begin(); iter != loci.end(); iter++)
    {
        GCQuantum * object = *iter;
        gcLocus * locP = dynamic_cast<gcLocus *>(object);
        assert(locP != NULL);
        RemoveLocus(*locP);
    }
}

void
GCStructures::RemovePops(objVector pops)
{
    for(objVector::iterator iter = pops.begin(); iter != pops.end(); iter++)
    {
        GCQuantum * object = *iter;
        gcPopulation * popP = dynamic_cast<gcPopulation *>(object);
        assert(popP != NULL);
        RemovePop(*popP);
    }
}

void
GCStructures::RemoveParents()
{
    for (gcParentMap::iterator i=m_parents.begin();i != m_parents.end();i++)
    {
        RemoveParent((*i).second.GetId());
    }

    // clean up the populations
    for (gcPopMap::const_iterator i=m_pops.begin();i != m_pops.end();i++)
    {
        GetPop((*i).second.GetId()).ClearParent();
    }
}

bool
GCStructures::GetFileSelection(size_t fileId) const
{
    gcFileMap::const_iterator iter = m_files.find(fileId);
    assert(iter != m_files.end());
    const gcFileInfo & fileInfo = (*iter).second;
    return fileInfo.GetSelected();
}

void
GCStructures::SetFileSelection(size_t fileId, bool value)
{
    gcFileMap::iterator iter = m_files.find(fileId);
    assert(iter != m_files.end());
    gcFileInfo & fileInfo = (*iter).second;
    return fileInfo.SetSelected(value);
}

size_t
GCStructures::SelectedFileCount() const
{
    size_t count = 0;
    for(gcFileMap::const_iterator iter=m_files.begin(); iter != m_files.end(); iter++)
    {
        const gcFileInfo & fileInfo = (*iter).second;
        if(fileInfo.GetSelected())
        {
            count++;
        }
    }
    return count;
}

void
GCStructures::AllFileSelectionsTo(bool value)
{
    for(gcFileMap::iterator iter=m_files.begin(); iter != m_files.end(); iter++)
    {
        gcFileInfo & fileInfo = (*iter).second;
        fileInfo.SetSelected(value);
    }
}

const GCLocusMatcher &
GCStructures::GetLocusMatcher(const GCFile & fileRef) const
{
    gcFileMap::const_iterator iter = m_files.find(fileRef.GetId());
    assert(iter != m_files.end());
    const gcFileInfo & fileInfo = (*iter).second;
    return fileInfo.GetLocMatcher();
}

const GCPopMatcher &
GCStructures::GetPopMatcher(const GCFile & fileRef) const
{
    gcFileMap::const_iterator iter = m_files.find(fileRef.GetId());
    assert(iter != m_files.end());
    const gcFileInfo & fileInfo = (*iter).second;
    return fileInfo.GetPopMatcher();
}

void
GCStructures::SetLocusMatcher(const GCFile & fileRef, const GCLocusMatcher & l)
{
    gcFileMap::iterator iter = m_files.find(fileRef.GetId());
    assert(iter != m_files.end());
    gcFileInfo & fileInfo = (*iter).second;
    fileInfo.SetLocMatcher(l);
}

void
GCStructures::SetPopMatcher(const GCFile & fileRef, const GCPopMatcher & p)
{
    gcFileMap::iterator iter = m_files.find(fileRef.GetId());
    assert(iter != m_files.end());
    gcFileInfo & fileInfo = (*iter).second;
    fileInfo.SetPopMatcher(p);
}

const gcPhenoMap &
GCStructures::GetPhenotypeMap() const
{
    return m_phenotypes;
}

// EWFIX.P3 -- this should share code with ::GetParse(const GCFile&) const
const GCParse &
GCStructures::GetParse(size_t fileId) const
{
    gcFileMap::const_iterator iter = m_files.find(fileId);
    assert(iter != m_files.end());
    const gcFileInfo & fileInfo = (*iter).second;
    size_t parseId = fileInfo.GetParse();
    for(size_t i=0; i < m_dataStoreP->GetDataFile(fileId).GetParseCount(); i++)
    {
        const GCParse & parse = m_dataStoreP->GetDataFile(fileId).GetParse(i);
        if(parse.GetId() == parseId)
        {
            return parse;
        }
    }
    wxString msg = wxString::Format(gcerr::missingParse,m_dataStoreP->GetDataFile(fileId).GetName().c_str());
    gc_implementation_error e(msg.c_str());
    // implementation error -- you should have checked HasParse first!
    throw e;
}

const GCParse &
GCStructures::GetParse(const GCFile & file) const
{
    gcFileMap::const_iterator iter = m_files.find(file.GetId());
    assert(iter != m_files.end());
    const gcFileInfo & fileInfo = (*iter).second;
    size_t parseId = fileInfo.GetParse();
    for(size_t i=0; i < file.GetParseCount(); i++)
    {
        const GCParse & parse = file.GetParse(i);
        if(parse.GetId() == parseId)
        {
            return parse;
        }
    }
    wxString msg = wxString::Format(gcerr::missingParse,file.GetName().c_str());
    gc_implementation_error e(msg.c_str());
    // implementation error -- you should have checked HasParse first!
    throw e;
}

bool
GCStructures::HasParse(const GCFile & file) const
{
    gcFileMap::const_iterator iter = m_files.find(file.GetId());
    assert(iter != m_files.end());
    const gcFileInfo & fileInfo = (*iter).second;
    return fileInfo.HasParse();
}

bool
GCStructures::HasUnparsedFiles() const
{
    for(gcFileMap::const_iterator iter=m_files.begin(); iter != m_files.end(); iter++)
    {
        const gcFileInfo & fileInfo = (*iter).second;
        if(!(fileInfo.HasParse())) return true;
    }
    return false;
}

void
GCStructures::SetParse(const GCParse & parse)
{
    const GCFile & fileRef = parse.GetFileRef();
    gcFileMap::iterator iter = m_files.find(fileRef.GetId());
    assert(iter != m_files.end());
    gcFileInfo & fileInfo = (*iter).second;
    fileInfo.SetParse(parse.GetId());

    // EWFIX.BUG.588
    if(parse.GetHasSpacesInNames())
    {
        m_dataStoreP->GCWarning(wxString::Format(gcerr_infile::shortSampleName,fileRef.GetShortName().c_str()));
    }
}

void
GCStructures::UnsetParse(const GCParse & parse)
{
    const GCFile & fileRef = parse.GetFileRef();
    gcFileMap::iterator iter = m_files.find(fileRef.GetId());
    assert(iter != m_files.end());
    gcFileInfo & fileInfo = (*iter).second;
    if(fileInfo.HasParse())
    {
        if(fileInfo.GetParse() == parse.GetId())
        {
            fileInfo.UnsetParse();
        }
    }

    for(size_t popIndex = 0; popIndex < parse.GetPopCount(); popIndex++)
    {
        for(size_t locIndex = 0; locIndex < parse.GetLociCount(); locIndex++)
        {
            const GCParseBlock & block = parse.GetBlock(popIndex,locIndex);
            RemoveBlockAssignment(block.GetId());
        }
    }
}

void
GCStructures::AddFile(const GCFile & file)
{
    gcFileInfo g;
    g.UnsetParse();
    g.SetSelected(false);
    m_files[file.GetId()] = g;
}

void
GCStructures::RemoveFile(size_t fileId)
{
    gcFileMap::iterator iter = m_files.find(fileId);
    assert(iter != m_files.end());
    m_files.erase(iter);
}

size_t
GCStructures::GetHapFileAdjacent(size_t fileId) const
{
    assert(HasHapFileAdjacent(fileId));

    gcFileMap::const_iterator iter = m_files.find(fileId);
    assert(iter != m_files.end());
    const gcFileInfo & fileInfo = (*iter).second;

    return fileInfo.GetAdjacentHapAssignment();
}

void
GCStructures::SetHapFileAdjacent(size_t fileId, size_t numHaps)
{
    gcFileMap::iterator iter = m_files.find(fileId);
    assert(iter != m_files.end());
    gcFileInfo & fileInfo = (*iter).second;

    // EWFIX.P4
    // this part is here to throw an error if this would cause
    // a problem
    const GCParse & parse = GetParse(fileId);
    gcPhaseInfo * info = parse.GetPhaseRecordsForAdjacency(numHaps);
    delete info;

    fileInfo.SetAdjacentHapAssignment(numHaps);
}

void
GCStructures::UnsetHapFileAdjacent(size_t fileId)
{
    gcFileMap::iterator iter = m_files.find(fileId);
    assert(iter != m_files.end());
    gcFileInfo & fileInfo = (*iter).second;

    fileInfo.UnsetAdjacentHapAssignment();
}

bool
GCStructures::HasHapFileAdjacent(size_t fileId) const
{
    gcFileMap::const_iterator iter = m_files.find(fileId);
    assert(iter != m_files.end());
    const gcFileInfo & fileInfo = (*iter).second;
    return fileInfo.HasAdjacentHapAssignment();
}

void
GCStructures::UnsetGenoFile(size_t fileId)
{
    gcFileMap::iterator iter = m_files.find(fileId);
    assert(iter != m_files.end());
    gcFileInfo & fileInfo = (*iter).second;

    fileInfo.UnsetGenoFile();
}

bool
GCStructures::HasGenoFile(size_t fileId) const
{
    gcFileMap::const_iterator iter = m_files.find(fileId);
    assert(iter != m_files.end());
    const gcFileInfo & fileInfo = (*iter).second;
    return fileInfo.HasGenoFile();
}

void
GCStructures::VerifyLocusSeparations(const gcRegion& regionRef) const
{
    constObjVector loci =
        GetConstDisplayableLociInMapOrderFor(regionRef.GetId());

    bool havePrevious = false;
    long lastExtent = 0;
    size_t lastLocusId = 0;

    for(constObjVector::const_iterator i=loci.begin(); i != loci.end(); i++)
    {
        const gcLocus * locusP = dynamic_cast<const gcLocus *>(*i);
        assert(locusP != NULL);

        if(locusP->GetLinked())
            // no need to check unlinked loci, they are their own region
        {
            long start = 0;
            long stop = 0;
            if(locusP->HasMapPosition())
                // EWFIX.P3 -- should we insist ?
            {
                start += locusP->GetMapPosition();
                stop  += locusP->GetMapPosition();
            }
            if(locusP->HasOffset())
                // EWFIX.P3 -- should we insist ?
            {
                start += locusP->GetOffset();
                stop  += locusP->GetOffset();
            }
            stop   += locusP->GetLength();
            stop -= 1;    // EWFIX explain why

            if(havePrevious)
            {
                if(start <= lastExtent)
                {
                    long end = locusP->GetMapPosition()+locusP->GetLength()-1;
                    long lastStart = GetLocus(lastLocusId).GetMapPosition();
                    throw gc_locus_overlap(locusP->GetName(),start,end,
                                           GetLocus(lastLocusId).GetName(),lastStart,lastExtent);
                }
            }

            havePrevious = true;
            lastExtent = stop;
            lastLocusId = locusP->GetId();
        }
    }
}

bool
GCStructures::AnyZeroes() const
{
    constObjVector loci = GetConstDisplayableLoci();

    for(constObjVector::const_iterator i = loci.begin(); i != loci.end(); i++)
    {
        const GCQuantum * q = *i;
        const gcLocus * locusP = dynamic_cast<const gcLocus*>(q);
        assert(locusP != NULL);

        if(locusP->HasMapPosition())
        {
            if (locusP->GetMapPosition() == 0) return true;
        }

        if(locusP->HasOffset())
        {
            if (locusP->GetOffset() == 0) return true;
        }

        if(locusP->HasLocationZero()) return true;

        if (locusP->HasUnphasedMarkers())
        {
            const gcUnphasedMarkers * phaseInfo = locusP->GetUnphasedMarkers();
            if(phaseInfo != NULL)
            {
                if(phaseInfo->HasZero()) return true;
            }
        }

    }

    assert(m_dataStoreP != NULL);
    return m_dataStoreP->PhaseInfoHasAnyZeroes();
}

int
GCStructures::GetPopCount()
{
    return m_pops.size();
}

int
GCStructures::GetPopCount() const
{
    return m_pops.size();
}

int
GCStructures::GetParentCount()
{
    return m_parents.size();
}

int
GCStructures::GetParentCount() const
{
    return m_parents.size();
}

bool
GCStructures::IsPop(size_t id)
{
    gcPopMap::iterator iter = m_pops.find(id);
    if (iter == m_pops.end())
    {
        return false;
    }
    return true;
}

bool
GCStructures::IsPop(size_t id) const
{
    gcPopMap::const_iterator iter = m_pops.find(id);
    if (iter == m_pops.end())
    {
        return false;
    }
    return true;
}
bool
GCStructures::IsPop(wxString name)
{
    for(gcPopMap::iterator i=m_pops.begin();
        i != m_pops.end();
        i++)
    {
        if((*i).second.GetName().CmpNoCase(name) == 0)
        {
            return true;
        }
    }
    return false;
}

bool
GCStructures::IsPop(wxString name) const
{
    for(gcPopMap::const_iterator i=m_pops.begin();
        i != m_pops.end();
        i++)
    {
        if((*i).second.GetName().CmpNoCase(name) == 0)
        {
            return true;
        }
    }
    return false;
}

bool
GCStructures::IsParent(size_t id)
{
    gcParentMap::iterator iter = m_parents.find(id);
    if (iter == m_parents.end())
    {
        return false;
    }
    return true;
}

bool
GCStructures::IsParent(size_t id) const
{
    gcParentMap::const_iterator iter = m_parents.find(id);
    if (iter == m_parents.end())
    {
        return false;
    }
    return true;
}

int
GCStructures::GetUnusedPopCount()
{
    int count = 0;
    gcDisplayOrder ids = GetDisplayablePopIds();
    for(gcDisplayOrder::iterator iter=ids.begin(); iter != ids.end(); iter++)
    {
        size_t id = *iter;
        wxLogVerbose("GCStructures::GetUnusedPopCount pop id:%i name:%s", id, GetPop(id).GetName().c_str());  // JMDBG
        if (!GetPop(id).HasParent())
        {
            count++;
            wxLogVerbose("     has no parent");
        }
        else
        {
            wxLogVerbose("     has parent: %i", (int)GetPop(id).GetParentId());
        }
    }
    wxLogVerbose("GCStructures::GetUnusedPopCount count: %i", count);
    return count;
}

int
GCStructures::GetUnusedPopCount() const
{
    int count = 0;
    gcDisplayOrder ids = GetDisplayablePopIds();
    for(gcDisplayOrder::iterator iter=ids.begin(); iter != ids.end(); iter++)
    {
        size_t id = *iter;
        if (!GetPop(id).HasParent())
        {
            count++;
            wxLogVerbose("GCStructures::GetUnusedPopCount const pop id:%i name:%s has no parent", id, GetPop(id).GetName().c_str());  // JMDBG
        }
        else
        {
            wxLogVerbose("GCStructures::GetUnusedPopCount const pop id:%i name:%s has parent: %i", id, GetPop(id).GetName().c_str(), (int)GetPop(id).GetParentId());// JMDBG
        }
    }
    wxLogVerbose("GCStructures::GetUnusedPopCount count: %i", count);
    return count;
}

int
GCStructures::GetUnusedParentCount()
{
    int count = 0;
    gcDisplayOrder ids = GetParentIds();
    for(gcDisplayOrder::iterator iter=ids.begin(); iter != ids.end(); iter++)
    {
        size_t id = *iter;
        if (!GetParent(id).HasParent())
        {
            count++;
            wxLogVerbose("GCStructures::GetUnusedParentCount par id: %i name:%s has no parent", id, GetParent(id).GetName().c_str());  // JMDBG
        }
        else
        {
            wxLogVerbose("GCStructures::GetUnusedParentCount par id: %i name:%s has parent: %s", id, GetParent(id).GetName().c_str(), (int)GetParent(id).GetParentId());  // JMDBG
        }
    }
    wxLogVerbose("GCStructures::GetUnusedParentCount count: %i", count);
    return count;
}

int
GCStructures::GetUnusedParentCount() const
{
    int count = 0;
    gcDisplayOrder ids = GetParentIds();
    for(gcDisplayOrder::iterator iter=ids.begin(); iter != ids.end(); iter++)
    {
        size_t id = *iter;
        wxLogVerbose("GCStructures::GetUnusedParentCount const par id: %i name:%s", id, GetParent(id).GetName().c_str());  // JMDBG
        if (!GetParent(id).HasParent())
        {
            count++;
            wxLogVerbose("     has no parent");
        }
        else
        {
            wxLogVerbose("     has parent: &s", (int)GetParent(id).GetParentId());
        }
    }
    wxLogVerbose("GCStructures::GetUnusedParentCount count: %i", count);
    return count;
}

void
GCStructures::ClearPopDisplayOrder()
{
    gcDisplayOrder ids = GetDisplayablePopIds() ;
    for(gcDisplayOrder::iterator iter=ids.begin(); iter != ids.end(); iter++)
    {
        GetPop(*iter).SetDispOrder(0);
    }
}

size_t
GCStructures::FindTopParent()
{
    size_t retid = gcdefault::badIndex;
    gcDisplayOrder ids = GetParentIds();
    for(gcDisplayOrder::iterator iter=ids.begin(); iter != ids.end(); iter++)
    {
        if (!GetParent(*iter).HasParent())
        {
            retid = *iter;
        }
    }
    assert(retid != gcdefault::badIndex);
    return retid;
}

bool
GCStructures::HasParents() const
{
    if (m_parents.size() > 0)
    {
        return true;
    }
    else
    {
        return false;
    }
}

void
GCStructures::MakeMigrationMatrix()
{
    // convenience to make the code easier to read
    gcDisplayOrder popids = GetDisplayablePopIds();
    gcDisplayOrder parids = GetParentIds();

    int matrixDim = popids.size() + parids.size();

    assert(matrixDim > 0);

    size_t idex;
    size_t jdex;

    // build whole matrix
    for (int i=0; i<matrixDim; i++)
    {
        for (int j=0; j<matrixDim; j++)
        {
            if (j!=i)
            {
                if (i < (int)popids.size())
                {
                    int count = 0;
                    for(gcDisplayOrder::const_iterator iter = popids.begin(); iter != popids.end(); iter++)
                    {
                        if (count == i)
                        {
                            idex = *iter;
                        }
                        count ++;
                    }
                }
                else
                {
                    int ioff = i - popids.size();
                    int count = 0;
                    for(gcDisplayOrder::const_iterator iter = parids.begin(); iter != parids.end(); iter++)
                    {
                        if (count == ioff)
                        {
                            idex = *iter;
                        }
                        count ++;
                    }
                }

                if (j < (int) popids.size())
                {
                    int count = 0;
                    for(gcDisplayOrder::const_iterator jter = popids.begin(); jter != popids.end(); jter++)
                    {
                        if (count == j)
                        {
                            jdex = *jter;
                        }
                        count ++;
                    }
                }
                else
                {
                    int joff = j - popids.size();
                    int count = 0;
                    for(gcDisplayOrder::const_iterator jter = parids.begin(); jter != parids.end(); jter++)
                    {
                        if (count == joff)
                        {
                            jdex = *jter;
                        }
                        count ++;
                    }
                }
                if (!HasMigration(idex, jdex))
                {
                    gcMigration Mig1 = MakeMigration(true, idex, jdex );
                }
                if (!HasMigration(jdex, idex))
                {
                    gcMigration Mig2 = MakeMigration(true, jdex, idex );
                }
            }
        }
    }

    if (GetUnusedParentCount() < 2)
    {
        // divergence linkages finished so need to remove some of the matrix members

        // creation order list - used to decide which children have been used
        // and are thus no longer available for migration
        size_t* orderids = new size_t[matrixDim];
        for (int i=0; i<matrixDim; i++)
        {
            orderids[i] = gcdefault::badIndex;
        }

        // populations can always migrate between each other before parents are declared
        int mdx = 0;
        for(gcDisplayOrder::const_iterator iter = popids.begin(); iter != popids.end(); iter++)
        {
            orderids[mdx] = *iter;
            mdx++;
        }

        // now remove those that disappear as parents are declared
        for(gcDisplayOrder::const_iterator iter = parids.begin(); iter != parids.end(); iter++)
        {
            orderids[mdx] = *iter;
            const gcParent & parent = GetParent(*iter);

            if (!parent.HasParent())
            {
                // no migrations possible at top
                for(gcDisplayOrder::const_iterator jter = popids.begin(); jter != popids.end(); jter++)
                {
                    RemoveMigration(*iter, *jter );
                    RemoveMigration(*jter, *iter );
                }

                for(gcDisplayOrder::const_iterator jter = parids.begin(); jter != parids.end(); jter++)
                {
                    if (*jter != *iter)
                    {
                        RemoveMigration(*iter, *jter );
                        RemoveMigration(*jter, *iter );
                    }
                }
            }
            else
            {
                size_t child1Id = parent.GetChild1Id();
                size_t child2Id = parent.GetChild2Id();
                for (int i=0; i<matrixDim; i++)
                {
                    if (child1Id == orderids[i])
                    {
                        RemoveMigration(*iter, child1Id );
                        RemoveMigration(child1Id, *iter );
                    }
                    if (child2Id == orderids[i])
                    {
                        RemoveMigration(*iter, child2Id );
                        RemoveMigration(child2Id, *iter );
                    }
                }
            }
            mdx ++;
        }
    }
}

//____________________________________________________________________________________
