// $Id: gc_block_dialogs.cpp,v 1.9 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_block_dialogs.h"
#include "gc_data.h"
#include "gc_datastore.h"
#include "gc_layout.h"
#include "gc_parse_block.h"
#include "gc_parse_locus.h"
#include "gc_parse_pop.h"
#include "gc_parse_pop.h"
#include "gc_parse_sample.h"
#include "gc_strings.h"

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

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

gcBlockPopChoice::gcBlockPopChoice(size_t blockId, size_t popId)
    :
    m_blockId(blockId),
    m_popId(popId),
    m_box(NULL)
{
}

gcBlockPopChoice::~gcBlockPopChoice()
{
}

void
gcBlockPopChoice::UpdateDisplayInitial(GCDataStore & dataStore)
{
    gcPopulation & popRef = dataStore.GetStructures().GetPop(m_popId);
    m_box->SetLabel(popRef.GetName());

    UpdateDisplayInterim(dataStore);
}

void
gcBlockPopChoice::UpdateDisplayInterim(GCDataStore & dataStore)
{
    size_t popIdFromStructures = dataStore.GetStructures().GetPopForBlock(m_blockId);
    if(popIdFromStructures ==  m_popId)
    {
        m_box->SetValue(1);
    }
    else
    {
        m_box->SetValue(0);
    }

    // if there is only one region, we'd better be assigned to it
    assert( (dataStore.GetStructures().GetDisplayablePopIds().size() > 1) || (popIdFromStructures == m_popId));

    m_box->Enable(true);
}

void
gcBlockPopChoice::UpdateDataInterim(GCDataStore & dataStore)
{
    if(m_box->GetValue() > 0 )
    {
        dataStore.GetStructures().AssignBlockToPop(m_blockId,m_popId);
    }
}

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

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

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

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

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

gcBlockLocusChoice::gcBlockLocusChoice(size_t blockId, size_t locusId)
    :
    m_blockId(blockId),
    m_locusId(locusId),
    m_box(NULL)
{
}

gcBlockLocusChoice::~gcBlockLocusChoice()
{
}

void
gcBlockLocusChoice::UpdateDisplayInitial(GCDataStore & dataStore)
{
    gcLocus & locusRef = dataStore.GetStructures().GetLocus(m_locusId);
    m_box->SetLabel(locusRef.GetName());

    UpdateDisplayInterim(dataStore);
}

void
gcBlockLocusChoice::UpdateDisplayInterim(GCDataStore & dataStore)
{
    size_t locusIdFromStructures = dataStore.GetStructures().GetLocusForBlock(m_blockId);
    if(locusIdFromStructures ==  m_locusId)
    {
        m_box->SetValue(1);
    }
    else
    {
        m_box->SetValue(0);
    }

    // if there is only one locus, we'd better be assigned to it
    assert( (dataStore.GetStructures().GetDisplayableLocusIds().size() > 1) || (locusIdFromStructures == m_locusId));

    const GCParseBlock * blockP = dataStore.GetParseBlock(m_blockId);
    assert(blockP != NULL);
    const GCParseLocus & pLocus = blockP->GetLocusRef();

    const gcLocus & locusRef = dataStore.GetStructures().GetLocus(m_locusId);
    bool canAssign = dataStore.CanAssignParseLocus(pLocus,locusRef);
    m_box->Enable(canAssign);
}

void
gcBlockLocusChoice::UpdateDataInterim(GCDataStore & dataStore)
{
    if(m_box->GetValue() > 0 )
    {
        dataStore.GetStructures().AssignBlockToLocus(m_blockId,m_locusId);
    }
}

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

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

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

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

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

gcBlockFileInfo::gcBlockFileInfo(size_t blockId)
    :
    m_blockId(blockId)
{
}

gcBlockFileInfo::~gcBlockFileInfo()
{
}

wxString
gcBlockFileInfo::FromDataStore(GCDataStore & dataStore)
{
    const GCParseBlock * pb = dataStore.GetParseBlock(m_blockId);
    assert(pb != NULL);
    const GCFile & fileRef = pb->GetParse().GetFileRef();
    return fileRef.GetShortName();
}

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

gcBlockPopIndex::gcBlockPopIndex(size_t blockId)
    :
    m_blockId(blockId)
{
}

gcBlockPopIndex::~gcBlockPopIndex()
{
}

wxString
gcBlockPopIndex::FromDataStore(GCDataStore & dataStore)
{
    const GCParseBlock * pb = dataStore.GetParseBlock(m_blockId);
    assert(pb != NULL);
    size_t index =  pb->GetPopRef().GetIndexInParse();
    return wxString::Format("%ld",(long)index);
}

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

gcBlockLocusIndex::gcBlockLocusIndex(size_t blockId)
    :
    m_blockId(blockId)
{
}

gcBlockLocusIndex::~gcBlockLocusIndex()
{
}

wxString
gcBlockLocusIndex::FromDataStore(GCDataStore & dataStore)
{
    const GCParseBlock * pb = dataStore.GetParseBlock(m_blockId);
    assert(pb != NULL);
    size_t index =  pb->GetLocusRef().GetIndexInParse();
    return wxString::Format("%ld",(long)index);
}

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

gcBlockPloidyInfo::gcBlockPloidyInfo(size_t blockId)
    :
    m_blockId(blockId)
{
}

gcBlockPloidyInfo::~gcBlockPloidyInfo()
{
}

wxString
gcBlockPloidyInfo::FromDataStore(GCDataStore & dataStore)
{
    const GCParseBlock * pb = dataStore.GetParseBlock(m_blockId);
    assert(pb != NULL);
    size_t sampleCount = pb->GetSamples().size();
    size_t hapCount = pb->FindSample(0).GetSequencesPerLabel();
    wxString hapString = gcdata::getPloidyString(hapCount);
    return wxString::Format(gcstr::blockPloidyInfo,(long)sampleCount,hapString.c_str());
}

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

gcBlockEditDialog::gcBlockEditDialog(   wxWindow *      parent,
                                        GCDataStore &   dataStore,
                                        size_t          blockId)
    :
    gcUpdatingDialog(   parent,
                        dataStore,
                        gcstr::editParseBlock,
                        false),
    m_blockId(blockId)
{
}

gcBlockEditDialog::~gcBlockEditDialog()
{
}

void
gcBlockEditDialog::DoDelete()
{
    m_dataStore.GetStructures().RemoveBlockAssignment(m_blockId);
}

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

bool
DoDialogEditBlock(wxWindow *    parentWindow,
                  GCDataStore &   dataStore,
                  size_t          blockId)
{
    gcBlockEditDialog dialog(parentWindow,dataStore,blockId);

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

    wxBoxSizer * leftSizer = new wxBoxSizer(wxVERTICAL);

    /////////////////////////
    // file data came from
    gcPlainTextHelper * blockFileInfo = new gcBlockFileInfo(blockId);
    gcUpdatingComponent * fileInfo = new gcUpdatingPlainText(&dialog,
                                                             gcstr::blockFileInfo,
                                                             blockFileInfo);

    /////////////////////////
    // pop index within file
    gcPlainTextHelper * blockPopInfo = new gcBlockPopIndex(blockId);
    gcUpdatingComponent * popInfo = new gcUpdatingPlainText(&dialog,
                                                            gcstr::blockPopIndexInFile,
                                                            blockPopInfo);

    /////////////////////////
    // locus index within file
    gcPlainTextHelper * blockLocusInfo = new gcBlockLocusIndex(blockId);
    gcUpdatingComponent * locusInfo = new gcUpdatingPlainText(&dialog,
                                                              gcstr::blockLocusIndexInFile,
                                                              blockLocusInfo);

    /////////////////////////
    // sample ploidy
    gcPlainTextHelper * blockPloidyInfo = new gcBlockPloidyInfo(blockId);
    gcUpdatingComponent * ploidyInfo = new gcUpdatingPlainText(&dialog,
                                                               gcstr::blockPloidyTitle,
                                                               blockPloidyInfo);

    leftSizer->Add(fileInfo,
                   0,
                   wxALL | wxALIGN_CENTER | wxEXPAND,
                   gclayout::borderSizeSmall);
    leftSizer->Add(popInfo,
                   0,
                   wxALL | wxALIGN_CENTER | wxEXPAND,
                   gclayout::borderSizeSmall);
    leftSizer->Add(locusInfo,
                   0,
                   wxALL | wxALIGN_CENTER | wxEXPAND,
                   gclayout::borderSizeSmall);
    leftSizer->Add(ploidyInfo,
                   0,
                   wxALL | wxALIGN_CENTER | wxEXPAND,
                   gclayout::borderSizeSmall);
    contentSizer->Add(leftSizer,
                      1,
                      wxALL | wxALIGN_CENTER | wxEXPAND,
                      gclayout::borderSizeSmall);

    creator.AddComponent(dialog,fileInfo);
    creator.AddComponent(dialog,popInfo);
    creator.AddComponent(dialog,locusInfo);
    creator.AddComponent(dialog,ploidyInfo);

    //////////////////////////////////////////////////////
    // re-assigning to a different population
    wxBoxSizer * middleSizer = new wxBoxSizer(wxVERTICAL);

    std::vector<gcChoiceObject*> popChoices;
    gcDisplayOrder ids = dataStore.GetStructures().GetDisplayablePopIds();
    for(gcDisplayOrder::iterator iter=ids.begin(); iter != ids.end(); iter++)
    {
        size_t id = *iter;
        gcBlockPopChoice * choice = new gcBlockPopChoice(blockId,id);
        popChoices.push_back(choice);
    }
    gcUpdatingComponent * pops = new gcUpdatingChoose(&dialog,
                                                      gcstr::blockPopChoice,
                                                      popChoices);

    middleSizer->Add(pops,
                     1,
                     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(middleSizer,
                      1,
                      wxALL | wxALIGN_CENTER | wxEXPAND,
                      gclayout::borderSizeSmall);
    creator.AddComponent(dialog,pops);

    //////////////////////////////////////////////////////
    // re-assigning to a different population
    wxBoxSizer * rightSizer = new wxBoxSizer(wxVERTICAL);
    std::vector<gcChoiceObject*> locusChoices;
    gcDisplayOrder locusIds = dataStore.GetStructures().GetDisplayableLocusIds();
    for(gcDisplayOrder::iterator iter=locusIds.begin(); iter != locusIds.end(); iter++)
    {
        size_t id = *iter;
        gcBlockLocusChoice * choice = new gcBlockLocusChoice(blockId,id);
        locusChoices.push_back(choice);
    }
    gcUpdatingComponent * loci = new gcUpdatingChoose(&dialog,
                                                      gcstr::blockLocusChoice,
                                                      locusChoices);
    rightSizer->Add(loci,
                    1,
                    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(rightSizer,
                      1,
                      wxALL | wxALIGN_CENTER | wxEXPAND,
                      gclayout::borderSizeSmall);
    creator.AddComponent(dialog,loci);

    creator.PlaceContent(dialog,contentSizer);

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

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

bool
gcActor_BlockEdit::OperateOn(wxWindow * parent, GCDataStore & dataStore)
{
    return DoDialogEditBlock(parent,dataStore,m_blockId);
}

//____________________________________________________________________________________
