// $Id: gc_locus_dialogs.cpp,v 1.30 2018/01/03 21:32:59 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_datastore.h"
#include "gc_errhandling.h"
#include "gc_event_ids.h"
#include "gc_data.h"
#include "gc_dialog.h"
#include "gc_layout.h"
#include "gc_locus.h"
#include "gc_locus_dialogs.h"
#include "gc_strings.h"
#include "gc_types.h"

#include "wx/checkbox.h"
#include "wx/log.h"
#include "wx/sizer.h"
#include "wx/statbox.h"
#include "wx/statline.h"
#include "wx/textctrl.h"

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

gcLocusDataTypeChoice::gcLocusDataTypeChoice(   size_t              locusId,
                                                gcSpecificDataType  type)
    :
    m_locusId(locusId),
    m_type(type),
    m_box(NULL)
{
}

gcLocusDataTypeChoice::~gcLocusDataTypeChoice()
{
}

void
gcLocusDataTypeChoice::UpdateDisplayInitial(GCDataStore & dataStore)
{
    m_box->SetLabel(ToWxString(m_type));
    UpdateDisplayInterim(dataStore);
}

void
gcLocusDataTypeChoice::UpdateDisplayInterim(GCDataStore & dataStore)
{
    // grab the locus
    gcLocus & locusRef = dataStore.GetStructures().GetLocus(m_locusId);

    // set selection
    bool isThisOne = (locusRef.GetDataType() == m_type );
    m_box->SetValue( isThisOne ? 1 : 0 );

    // enable all types possible for this locus

    // EWFIX.P3.BUG.539 -- later -- it would be great if we
    // could update the possible loci to merge with as
    // we click individual loci -- at the moment it just
    // sets the enable value at creation time
    gcGeneralDataType types = dataStore.GetLegalLocusTypes(m_locusId);
    assert(m_type != sdatatype_NONE_SET);
    m_box->Enable(types.find(m_type) != types.end());

}

void
gcLocusDataTypeChoice::UpdateDataInterim(GCDataStore & dataStore)
{
    if(m_box->GetValue() > 0 )
    {
        gcLocus & locusRef = dataStore.GetStructures().GetLocus(m_locusId);
        locusRef.SetDataType(m_type);
    }
}

void
gcLocusDataTypeChoice::UpdateDataFinal(GCDataStore & dataStore)
{
    UpdateDataInterim(dataStore);
}

wxWindow *
gcLocusDataTypeChoice::MakeWindow(wxWindow * parent)
{
    m_box = new wxCheckBox(parent,-1,wxEmptyString);
    return m_box;
}

wxWindow *
gcLocusDataTypeChoice::FetchWindow()
{
    assert(m_box != NULL);
    return m_box;
}

size_t
gcLocusDataTypeChoice::GetRelevantId()
{
    return m_locusId;
}

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

gcLocusLength::gcLocusLength(size_t locusId)
    :
    m_locusId(locusId)
{
}

gcLocusLength::~gcLocusLength()
{
}

wxString
gcLocusLength::FromDataStore(GCDataStore & dataStore)
{
    gcLocus & locusRef = dataStore.GetStructures().GetLocus(m_locusId);
    if(locusRef.HasLength())
    {
        return wxString::Format("%d",(int)(locusRef.GetLength()));
    }
    return InitialString();
}

void
gcLocusLength::ToDataStore(GCDataStore & dataStore, wxString text)
{
    gcLocus & locusRef = dataStore.GetStructures().GetLocus(m_locusId);

    long length;
    if(text.ToLong(&length))
    {
        locusRef.SetTotalLength(length);
    }
    else
    {
        wxLogVerbose(gcverbose::locusLengthNotLong,
                     text.c_str(),
                     locusRef.GetName().c_str());
    }
}

const wxValidator &
gcLocusLength::GetValidator()
{
    return m_validator;
}

wxString
gcLocusLength::InitialString()
{
    return gcstr::unsetValueLocusLength;
}

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

gcLocusFirstPosition::gcLocusFirstPosition(size_t locusId)
    :
    m_locusId(locusId)
{
}

gcLocusFirstPosition::~gcLocusFirstPosition()
{
}

wxString
gcLocusFirstPosition::FromDataStore(GCDataStore & dataStore)
{
    gcLocus & locusRef = dataStore.GetStructures().GetLocus(m_locusId);
    if(locusRef.HasOffset())
    {
        return wxString::Format("%d",(int)(locusRef.GetOffset()));
    }
    return InitialString();
}

void
gcLocusFirstPosition::ToDataStore(GCDataStore & dataStore, wxString text)
{
    gcLocus & locusRef = dataStore.GetStructures().GetLocus(m_locusId);

    long firstPosition;
    if(text.ToLong(&firstPosition))
    {
        locusRef.SetOffset(firstPosition);
    }
    else
    {
        wxLogVerbose(gcverbose::firstPositionNotLong,
                     text.c_str(),
                     locusRef.GetName().c_str());
    }
}

const wxValidator &
gcLocusFirstPosition::GetValidator()
{
    return m_validator;
}

wxString
gcLocusFirstPosition::InitialString()
{
    return gcstr::unsetValueOffset;
}

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

gcLocusLocations::gcLocusLocations(size_t locusId)
    :
    m_locusId(locusId)
{
}

gcLocusLocations::~gcLocusLocations()
{
}

wxString
gcLocusLocations::FromDataStore(GCDataStore & dataStore)
{
    gcLocus & locusRef = dataStore.GetStructures().GetLocus(m_locusId);
    if(locusRef.HasLocations())
    {
        return locusRef.GetLocationsAsString();
    }
    return InitialString();
}

void
gcLocusLocations::ToDataStore(GCDataStore & dataStore, wxString text)
{
    gcLocus & locusRef = dataStore.GetStructures().GetLocus(m_locusId);
    if(text != InitialString() && !text.IsEmpty())
    {
        locusRef.SetLocations(text);
    }
    else
    {
        wxLogVerbose(gcverbose::locationsNotIntegers,
                     text.c_str(),
                     locusRef.GetName().c_str());
    }

}

const wxValidator &
gcLocusLocations::GetValidator()
{
    return m_validator;
}

wxString
gcLocusLocations::InitialString()
{
    return gcstr::unsetValueLocations;
}

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

gcLocusLinkageChoice::gcLocusLinkageChoice(size_t locusId, bool linked)
    :
    m_locusId(locusId),
    m_linked(linked)
{
}

gcLocusLinkageChoice::~gcLocusLinkageChoice()
{
}

void
gcLocusLinkageChoice::UpdateDisplayInitial(GCDataStore & dataStore)
{
    // set labels
    if(m_linked)
    {
        m_box->SetLabel(gcstr::linkageYes);
    }
    else
    {
        m_box->SetLabel(gcstr::linkageNo);
    }

    UpdateDisplayInterim(dataStore);
}

void
gcLocusLinkageChoice::UpdateDisplayInterim(GCDataStore & dataStore)
{
    gcLocus & locusRef = dataStore.GetStructures().GetLocus(m_locusId);

    if(m_linked == locusRef.GetLinked())
    {
        m_box->SetValue(1);
    }
    else
    {
        m_box->SetValue(0);
    }

    gcGeneralDataType gtype = dataStore.GetLegalLocusTypes(m_locusId);
    m_box->Enable( m_linked ||  (gtype.HasAllelic() && !gtype.HasNucleic())) ;

}

void
gcLocusLinkageChoice::UpdateDataInterim(GCDataStore & dataStore)
{
    if(m_box->GetValue() > 0)
    {
        gcLocus & locusRef = dataStore.GetStructures().GetLocus(m_locusId);
        locusRef.SetLinkedUserValue(m_linked); // EWFIX.P3.BUG.551 -- not always a user value
    }
}

void
gcLocusLinkageChoice::UpdateDataFinal(GCDataStore & dataStore)
{
    UpdateDataInterim(dataStore);
}

wxWindow *
gcLocusLinkageChoice::MakeWindow(wxWindow * parent)
{
    m_box = new wxCheckBox(parent,-1,wxEmptyString);
    return m_box;
}

wxWindow *
gcLocusLinkageChoice::FetchWindow()
{
    assert(m_box != NULL);
    return m_box;
}

size_t
gcLocusLinkageChoice::GetRelevantId()
{
    return m_locusId;
}

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

gcLocusMergeChoice::gcLocusMergeChoice( size_t choiceLocusId,
                                        size_t dialogLocusId)
    :
    m_choiceLocusId(choiceLocusId),
    m_dialogLocusId(dialogLocusId),
    m_box(NULL)
{
}

gcLocusMergeChoice::~gcLocusMergeChoice()
{
}

void
gcLocusMergeChoice::UpdateDisplayInitial(GCDataStore & dataStore)
{
    gcLocus & locusRef = dataStore.GetStructures().GetLocus(m_choiceLocusId);

    m_box->SetLabel(locusRef.GetName());
    m_box->SetValue(0);

    UpdateDisplayInterim(dataStore);
}

void
gcLocusMergeChoice::UpdateDisplayInterim(GCDataStore & dataStore)
{
    gcLocus & choiceLocus = dataStore.GetStructures().GetLocus(m_choiceLocusId);
    gcLocus & dialogLocus = dataStore.GetStructures().GetLocus(m_dialogLocusId);
    m_box->Enable(choiceLocus.CanMergeWith(dialogLocus));
}

void
gcLocusMergeChoice::UpdateDataInterim(GCDataStore & dataStore)
// nothing to do until the end at the top level
{
}

void
gcLocusMergeChoice::UpdateDataFinal(GCDataStore & dataStore)
// nothing to do until the end at the top level
{
}

wxWindow *
gcLocusMergeChoice::MakeWindow(wxWindow * parent)
{
    m_box = new wxCheckBox(parent,-1,wxEmptyString);
    return m_box;
}

wxWindow *
gcLocusMergeChoice::FetchWindow()
{
    assert(m_box != NULL);
    return m_box;
}

size_t
gcLocusMergeChoice::GetRelevantId()
{
    return m_choiceLocusId;
}

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

gcLocusMerge::gcLocusMerge( wxWindow *                      parent,
                            size_t                          locusId,
                            std::vector<gcChoiceObject*>    choices)
    :
    gcUpdatingChooseMulti(parent,gcstr::mergeLociInstructions,choices),
    m_locusId(locusId)
{
}

gcLocusMerge::~gcLocusMerge()
{
}

void
gcLocusMerge::DoFinalForMulti(GCDataStore & dataStore, gcIdVec chosens)
{
    chosens.insert(chosens.begin(),m_locusId);
    dataStore.GetStructures().MergeLoci(chosens);
}

wxString
gcLocusMerge::NoChoicesText() const
{
    return gcstr::noChoiceLocus;
}

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

gcLocusPosition::gcLocusPosition(size_t locusId)
    :
    m_locusId(locusId)
{
}

gcLocusPosition::~gcLocusPosition()
{
}

wxString
gcLocusPosition::FromDataStore(GCDataStore & dataStore)
{
    gcLocus & locusRef = dataStore.GetStructures().GetLocus(m_locusId);
    if(locusRef.HasMapPosition())
    {
        long mapPosition = locusRef.GetMapPosition();
        return wxString::Format("%ld",mapPosition);
    }
    return InitialString();
}

void
gcLocusPosition::ToDataStore(GCDataStore & dataStore, wxString newPosition)
{
    gcLocus & locusRef = dataStore.GetStructures().GetLocus(m_locusId);

    long position;
    if(newPosition.ToLong(&position))
    {
        locusRef.SetMapPosition(position);
    }
    else
    {
        wxLogVerbose(gcverbose::locusPositionNotLong,
                     newPosition.c_str(),
                     locusRef.GetName().c_str());
    }
}

const wxValidator &
gcLocusPosition::GetValidator()
{
    return m_validator;
}

wxString
gcLocusPosition::InitialString()
{
    return gcstr::unsetValueLocusPosition;
}

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

gcLocusRegionChoice::gcLocusRegionChoice(size_t locusId, size_t regionId, bool isNewlyCreated)
    :
    m_locusId(locusId),
    m_regionId(regionId),
    m_newlyCreated(isNewlyCreated),
    m_box(NULL)
{
}

gcLocusRegionChoice::~gcLocusRegionChoice()
{
}

void
gcLocusRegionChoice::UpdateDisplayInitial(GCDataStore & dataStore)
{
    gcRegion & regionRef = dataStore.GetStructures().GetRegion(m_regionId);
    if(m_newlyCreated)
    {
        m_box->SetLabel(gcstr::createNewRegion);
    }
    else
    {
        m_box->SetLabel(regionRef.GetName());
    }

    UpdateDisplayInterim(dataStore);
}

void
gcLocusRegionChoice::UpdateDisplayInterim(GCDataStore & dataStore)
{
    gcLocus & locusRef = dataStore.GetStructures().GetLocus(m_locusId);

    if(locusRef.GetRegionId() == m_regionId)
    {
        m_box->SetValue(1);
    }
    else
    {
        m_box->SetValue(0);
    }

    size_t numRegions = dataStore.GetStructures().GetDisplayableRegionIds().size();

    // if there is only one region, we'd better be assigned to it
    assert( (numRegions > 1) || (locusRef.GetRegionId() == m_regionId) );

    bool doEnable = ( (numRegions > 1) || (locusRef.GetRegionId() != m_regionId) );
    m_box->Enable(doEnable);
}

void
gcLocusRegionChoice::UpdateDataInterim(GCDataStore & dataStore)
{
}

void
gcLocusRegionChoice::UpdateDataFinal(GCDataStore & dataStore)
{
    // EWFIX.BUG674
}

wxWindow *
gcLocusRegionChoice::MakeWindow(wxWindow * parent)
{
    m_box = new wxCheckBox(parent,-1,wxEmptyString);
    return m_box;
}

wxWindow *
gcLocusRegionChoice::FetchWindow()
{
    assert(m_box != NULL);
    return m_box;
}

size_t
gcLocusRegionChoice::GetRelevantId()
// this is the one you want if you're recording which item is checked
{
    return m_regionId;
}

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

gcLocusOwnRegion::gcLocusOwnRegion(size_t locusId, bool isNewlyCreated)
    :
    m_locusId(locusId),
    m_newlyCreated(isNewlyCreated),
    m_box(NULL)
{
}

gcLocusOwnRegion::~gcLocusOwnRegion()
{
}

void
gcLocusOwnRegion::UpdateDisplayInitial(GCDataStore & dataStore)
{
    UpdateDisplayInterim(dataStore);
}

void
gcLocusOwnRegion::UpdateDisplayInterim(GCDataStore & dataStore)
{
    m_box->SetValue(0);
    const gcLocus & locusRef = dataStore.GetStructures().GetLocus(m_locusId);
    size_t regionId = locusRef.GetRegionId();
    gcIdVec locusIds = dataStore.GetStructures().GetLocusIdsForRegionByMapPosition(regionId);
    m_box->Enable(locusIds.size() > 1);
}

void
gcLocusOwnRegion::UpdateDataInterim(GCDataStore & dataStore)
{
}

void
gcLocusOwnRegion::UpdateDataFinal(GCDataStore & dataStore)
{
    if(m_box->GetValue() > 0)
    {
        dataStore.GetStructures().LocusToOwnRegion(m_locusId);
    }
}

wxWindow *
gcLocusOwnRegion::MakeWindow(wxWindow * parent)
{
    m_box = new wxCheckBox(parent,-1,gcstr::locusOwnRegion);
    return m_box;
}

wxWindow *
gcLocusOwnRegion::FetchWindow()
{
    assert(m_box != NULL);
    return m_box;
}

size_t
gcLocusOwnRegion::GetRelevantId()
// this is the one you want if you're recording which item is checked
{
    return m_locusId;
}

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

gcLocusRename::gcLocusRename(size_t locusId)
    :
    m_locusId(locusId)
{
}

gcLocusRename::~gcLocusRename()
{
}

wxString
gcLocusRename::FromDataStore(GCDataStore & dataStore)
{
    gcLocus & locusRef = dataStore.GetStructures().GetLocus(m_locusId);
    return locusRef.GetName();
}

void
gcLocusRename::ToDataStore(GCDataStore & dataStore, wxString newName)
{
    gcLocus & locusRef = dataStore.GetStructures().GetLocus(m_locusId);
    dataStore.GetStructures().Rename(locusRef,newName);
}

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

gcLocusMarkerCount::gcLocusMarkerCount(size_t locusId)
    :
    m_locusId(locusId)
{
}

gcLocusMarkerCount::~gcLocusMarkerCount()
{
}

wxString
gcLocusMarkerCount::FromDataStore(GCDataStore & dataStore)
{
    gcLocus & locusRef = dataStore.GetStructures().GetLocus(m_locusId);
    if(locusRef.HasNumMarkers())
    {
        return locusRef.GetNumMarkersString();
    }
    return "";
}

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

gcLocusEditDialog::gcLocusEditDialog(   wxWindow *      parent,
                                        GCDataStore &   dataStore,
                                        size_t          locusId,
                                        bool            forJustCreatedObj)
    :
    gcUpdatingDialog(   parent,
                        dataStore,
                        forJustCreatedObj
                        ?
                        gcstr::addLocus
                        :
                        wxString::Format(gcstr::editLocus,
                                         dataStore.GetStructures().GetLocus(locusId).GetName().c_str()),
                        forJustCreatedObj),
    m_locusId(locusId)
{
}

gcLocusEditDialog::~gcLocusEditDialog()
{
}

void
gcLocusEditDialog::DoDelete()
{
    gcLocus & locusRef = m_dataStore.GetStructures().GetLocus(m_locusId);
    m_dataStore.GetStructures().RemoveLocus(locusRef);
}

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

bool
DoDialogEditLocus(wxWindow *      parentWindow,
                  GCDataStore &   dataStore,
                  size_t          locusId,
                  bool            forJustCreatedObj)
{
    gcLocusEditDialog dialog(parentWindow,dataStore,locusId,forJustCreatedObj);

    // build the dialog
    gcDialogCreator creator;
    wxBoxSizer * contentSizer = new wxBoxSizer(wxHORIZONTAL);
    wxBoxSizer * leftSizer = new wxBoxSizer(wxVERTICAL);

    /////////////////////////
    // rename this locus
    gcTextHelper * locusRenameHelp = new gcLocusRename(locusId);
    gcUpdatingComponent * rename = new gcUpdatingTextCtrl(&dialog,
                                                          forJustCreatedObj ? gcstr::locusNewName : gcstr::locusRename,
                                                          locusRenameHelp);

    /////////////////////////
    // data type choices
    std::vector<gcChoiceObject*> locusChoicesDT;
    // EWFIX.P3.BUG.525  -- should be automated elsewhere
    wxArrayString dataTypes = gcdata::specificDataTypeChoices();
    for(size_t i=0; i < dataTypes.Count(); i++)
    {
        wxString dataTypeString = dataTypes[i];
        gcSpecificDataType type = ProduceSpecificDataTypeOrBarf(dataTypeString);
        if(type != sdatatype_NONE_SET)
        {
            locusChoicesDT.push_back(new gcLocusDataTypeChoice(locusId,type));
        }
    }
    gcUpdatingComponent * dataType = new gcUpdatingChoose(&dialog,
                                                          gcstr::dataType,
                                                          locusChoicesDT);

    /////////////////////////
    // linked markers ?
    std::vector<gcChoiceObject*> linkageChoices;
    linkageChoices.push_back(new gcLocusLinkageChoice(locusId,true));
    linkageChoices.push_back(new gcLocusLinkageChoice(locusId,false));
    gcUpdatingComponent * linkage = new gcUpdatingChoose(&dialog,
                                                         gcstr::linkageCaption,
                                                         linkageChoices);

    leftSizer->Add(rename,
                   0,
                   wxALL | wxALIGN_CENTER | wxEXPAND,
                   gclayout::borderSizeSmall);
    leftSizer->Add(dataType,
                   0,
                   wxALL | wxALIGN_CENTER | wxEXPAND,
                   gclayout::borderSizeSmall);
    leftSizer->Add(linkage,
                   0,
                   wxALL | wxALIGN_CENTER | wxEXPAND,
                   gclayout::borderSizeSmall);

    contentSizer->Add(leftSizer,
                      1,
                      wxALL | wxALIGN_CENTER | wxEXPAND,
                      gclayout::borderSizeSmall);

    creator.AddComponent(dialog,rename);
    creator.AddComponent(dialog,dataType);
    creator.AddComponent(dialog,linkage);

    //////////////////////////////////////////////////////
    wxBoxSizer * lMiddleSizer = new wxBoxSizer(wxVERTICAL);

    /////////////////////////
    // display number of markers
    gcPlainTextHelper * locusMarkerCountHelp = new gcLocusMarkerCount(locusId);
    gcUpdatingComponent * markerCount = new gcUpdatingPlainText(&dialog,
                                                                gcstr::locusMarkerCount,
                                                                locusMarkerCountHelp);

    /////////////////////////
    // display total length
    gcTextHelper * locusLengthHelp = new gcLocusLength(locusId);
    gcUpdatingComponent * totalLength = new gcUpdatingTextCtrl(&dialog,
                                                               gcstr::locusLength,
                                                               locusLengthHelp);

    /////////////////////////
    // display first position
    gcTextHelper * firstPositionHelp = new gcLocusFirstPosition(locusId);
    gcUpdatingComponent * firstPosition = new gcUpdatingTextCtrl(&dialog,
                                                                 gcstr::firstPositionScanned,
                                                                 firstPositionHelp);

    /////////////////////////
    // display locations
    gcTextHelper * locationsHelp = new gcLocusLocations(locusId);
    gcUpdatingComponent * locations = new gcUpdatingTextCtrl(&dialog,
                                                             gcstr::locations,
                                                             locationsHelp);

    // order in sizer
    lMiddleSizer->Add(markerCount,
                      0,
                      wxALL | wxALIGN_CENTER | wxEXPAND,
                      gclayout::borderSizeSmall);
    lMiddleSizer->Add(totalLength,
                      0,
                      wxALL | wxALIGN_CENTER | wxEXPAND,
                      gclayout::borderSizeSmall);
    lMiddleSizer->Add(firstPosition,
                      0,
                      wxALL | wxALIGN_CENTER | wxEXPAND,
                      gclayout::borderSizeSmall);
    lMiddleSizer->Add(locations,
                      0,
                      wxALL | wxALIGN_CENTER | wxEXPAND,
                      gclayout::borderSizeSmall);

    contentSizer->Add(new wxStaticLine(&dialog,-1,wxDefaultPosition,wxDefaultSize,wxLI_VERTICAL),
                      0,
                      wxALL | wxALIGN_CENTER | wxEXPAND,
                      gclayout::borderSizeSmall);
    contentSizer->Add(lMiddleSizer,
                      1,
                      wxALL | wxALIGN_CENTER | wxEXPAND,
                      gclayout::borderSizeSmall);
    creator.AddComponent(dialog,markerCount);
    creator.AddComponent(dialog,totalLength);
    creator.AddComponent(dialog,firstPosition);
    creator.AddComponent(dialog,locations);

    //////////////////////////////////////////////////////
    wxBoxSizer * rMiddleSizer = new wxBoxSizer(wxVERTICAL);

    std::vector<gcChoiceObject*> regionChoices;
    gcDisplayOrder ids = dataStore.GetStructures().GetDisplayableRegionIds();
    for(gcDisplayOrder::iterator iter=ids.begin(); iter != ids.end(); iter++)
    {
        size_t id = *iter;
        bool isNewlyCreated = forJustCreatedObj
            && (id == dataStore.GetStructures().GetLocus(locusId).GetRegionId());
        gcLocusRegionChoice * choice = new gcLocusRegionChoice(locusId,id,isNewlyCreated);
        regionChoices.push_back(choice);
    }
    regionChoices.push_back(new gcLocusOwnRegion(locusId,forJustCreatedObj));
    gcUpdatingComponent * regions = new gcUpdatingChoose(   &dialog,
                                                            gcstr::regionChoice,
                                                            regionChoices);

    gcTextHelper * locusPositionHelp = new gcLocusPosition(locusId);
    gcUpdatingComponent * position = new gcUpdatingTextCtrl(&dialog,
                                                            gcstr::locusDialogMapPosition,
                                                            locusPositionHelp);
    rMiddleSizer->Add(regions,
                      1,
                      wxALL | wxALIGN_CENTER | wxEXPAND,
                      gclayout::borderSizeSmall);
    rMiddleSizer->Add(position,
                      0,
                      wxALL | wxALIGN_CENTER | wxEXPAND,
                      gclayout::borderSizeSmall);

    contentSizer->Add(new wxStaticLine(&dialog,-1,wxDefaultPosition,wxDefaultSize,wxLI_VERTICAL),
                      0,
                      wxALL | wxALIGN_CENTER | wxEXPAND,
                      gclayout::borderSizeSmall);
    contentSizer->Add(rMiddleSizer,
                      1,
                      wxALL | wxALIGN_CENTER | wxEXPAND,
                      gclayout::borderSizeSmall);
    creator.AddComponent(dialog,regions);
    creator.AddComponent(dialog,position);

    //////////////////////////////////////////////////////
    // merging loci only for existing loci
    if(!forJustCreatedObj)
    {
        std::vector<gcChoiceObject*> locusChoices;
        gcDisplayOrder ids = dataStore.GetStructures().GetDisplayableLocusIds();
        for(gcDisplayOrder::iterator iter=ids.begin(); iter != ids.end(); iter++)
        {
            size_t id = *iter;
            if(id != locusId)
            {
                gcLocusMergeChoice * choice = new gcLocusMergeChoice(id,locusId);
                locusChoices.push_back(choice);
            }
        }
        gcUpdatingComponent * right = new gcLocusMerge(&dialog,locusId,locusChoices);
        contentSizer->Add(new wxStaticLine(&dialog,-1,wxDefaultPosition,wxDefaultSize,wxLI_VERTICAL),
                          0,
                          wxALL | wxALIGN_CENTER | wxEXPAND,
                          gclayout::borderSizeSmall);
        contentSizer->Add(right,
                          1,
                          wxALL | wxALIGN_CENTER | wxEXPAND,
                          gclayout::borderSizeSmall);
        creator.AddComponent(dialog,right);
    }

    creator.PlaceContent(dialog,contentSizer);

    // invoke the dialog
    return dialog.Go();
}

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

bool
gcActor_LocusAdd::OperateOn(wxWindow * parent, GCDataStore & dataStore)
{
    gcRegion & regionRef = dataStore.GetStructures().MakeRegion();
    gcCreationInfo creationInfo = gcCreationInfo::MakeGuiCreationInfo();
    gcLocus & locusRef = dataStore.GetStructures().MakeLocus(regionRef,"",true,creationInfo);
    return DoDialogEditLocus(parent,dataStore,locusRef.GetId(),true);
}

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

bool
gcActor_LocusEdit::OperateOn(wxWindow * parent, GCDataStore & dataStore)
{
    return DoDialogEditLocus(parent,dataStore,m_locusId,false);
}

//____________________________________________________________________________________
