// $Id: gc_migtab.cpp,v 1.8 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 */


/* NOTE:  8/29/2014 Mary edited gc_migtab.cpp to reverse the sense
of "from" and "to" in the migration matrix, since it was producing
XML files that were backwards to what LAMARC assumes.  She did NOT
change variable names or anything else to match, so there are probably
misleading variable names in this part of the converter and in the
corresponding XML output routines.  Maintainers beware!  DEBUG */

#include <cassert>
#include <stdio.h>

#include "gc_matrix_display.h"
#include "gc_event_publisher.h"
#include "gc_logic.h"
#include "gc_migration_dialogs.h"
#include "gc_migtab.h"
#include "gc_strings.h"
#include "gc_default.h"
#include "gc_migration.h"
#include "gc_population.h"

#include "wx/log.h"

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

gcMigCell::gcMigCell(wxWindow * parent, GCStructures & st_var, const size_t cellId, matrix_cell_type cellType)
    :   gcClickCell(parent,""),
        m_cellId(gcdefault::badIndex),
        m_cellType(cellType)
{
    wxString dispstr;
    switch (cellType){
        case matrixcelltype_EMPTY:
            dispstr = "";
            AddText(dispstr);
            Disable();
            break;

        case matrixcelltype_INVALID:
            dispstr = "invalid";
            AddText(dispstr);
            Disable();
            break;

        case matrixcelltype_CORNER:
            dispstr = "From >";
            AddText(dispstr);
            dispstr = "";
            AddText(dispstr);
            dispstr = "To v";
            AddText(dispstr);
            Disable();
            break;

        case matrixcelltype_LABEL:
            dispstr = st_var.GetPop(cellId).GetName();
            AddText(dispstr);
            Disable();
            break;

        case matrixcelltype_VALUE:
            m_cellId = cellId;
            AddText(wxString::Format(gcstr::migRate, st_var.GetMigration(m_cellId).GetStartValueString().c_str()));
            AddText(wxString::Format(gcstr::migMethod, st_var.GetMigration(m_cellId).GetMethodString().c_str()));
            AddText(wxString::Format(gcstr::migProfile, st_var.GetMigration(m_cellId).GetProfileAsString().c_str()));
            AddText(wxString::Format(gcstr::migConstraint, st_var.GetMigration(m_cellId).GetConstraintString().c_str()));
            break;

        default:
            dispstr = "undefined";
    }
    FinishSizing();
}

gcMigCell::~gcMigCell()
{
}

void
gcMigCell::ToDataStore(GCStructures & st_var, wxString newValue)
{
    //gcLocus & locusRef = dataStore.GetStructures().GetLocus(m_locusId);
    //dataStore.GetStructures().Rename(locusRef,newName);
}

size_t
gcMigCell::GetCellId()
{
    return m_cellId;
}

matrix_cell_type
gcMigCell::GetCellType()
{
    return m_cellType;
}

void
gcMigCell::NotifyLeftDClick()
{
    wxLogVerbose(" Migration cell %i pushed", (int)m_cellId);  // JMDBG
    if (m_cellType == matrixcelltype_VALUE)
    {
        gcEventActor * migrationActor = new gcActor_MigrationEdit(m_cellId);
        PublishScreenEvent(GetEventHandler(),migrationActor);
    }
}

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

gcDivCell::gcDivCell(wxWindow * parent, GCStructures & st_var, const size_t cellId, bool isParent, matrix_cell_type cellType)
    :   gcClickCell(parent,""),
        m_cellId(gcdefault::badIndex),
        m_cellType(cellType)
{
    wxString dispstr;
    switch (cellType){
        case matrixcelltype_EMPTY:
            dispstr = "";
            AddText(dispstr);
            Disable();
            break;

        case matrixcelltype_INVALID:
            dispstr = "invalid";
            AddText(dispstr);
            Disable();
            break;

        case matrixcelltype_CORNER:
            dispstr = "From >";
            AddText(dispstr);
            dispstr = "";
            AddText(dispstr);
            dispstr = "To v";
            AddText(dispstr);
            Disable();
            break;

        case matrixcelltype_LABEL:
            if (!isParent)
            {
                dispstr = st_var.GetPop(cellId).GetName();
            }
            else
            {
                dispstr = st_var.GetParent(cellId).GetName();
            }
            AddText(dispstr);
            Disable();
            break;

        case matrixcelltype_VALUE:
            m_cellId = cellId;
            AddText(wxString::Format(gcstr::migRate, st_var.GetMigration(m_cellId).GetStartValueString().c_str()));
            AddText(wxString::Format(gcstr::migMethod, st_var.GetMigration(m_cellId).GetMethodString().c_str()));
            AddText(wxString::Format(gcstr::migProfile, st_var.GetMigration(m_cellId).GetProfileAsString().c_str()));
            AddText(wxString::Format(gcstr::migConstraint, st_var.GetMigration(m_cellId).GetConstraintString().c_str()));
            break;

        default:
            dispstr = "undefined";
    }
    FinishSizing();
}

gcDivCell::~gcDivCell()
{
}

void
gcDivCell::ToDataStore(GCStructures & st_var, wxString newValue)
{
    //gcLocus & locusRef = dataStore.GetStructures().GetLocus(m_locusId);
    //dataStore.GetStructures().Rename(locusRef,newName);
}

size_t
gcDivCell::GetCellId()
{
    return m_cellId;
}

matrix_cell_type
gcDivCell::GetCellType()
{
    return m_cellType;
}

void
gcDivCell::NotifyLeftDClick()
{
    wxLogVerbose(" Migration cell %i pushed", (int)m_cellId);  // JMDBG
    if (m_cellType == matrixcelltype_VALUE)
    {
        gcEventActor * migrationActor = new gcActor_MigrationEdit(m_cellId);
        PublishScreenEvent(GetEventHandler(),migrationActor);
    }
}

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

gcMigTab::gcMigTab( wxWindow * parent, GCLogic & logic)
    :
    gcInfoPane(parent, logic, gcstr::migrationMatrix)
    ,
    m_parent(parent)
{
}

gcMigTab::~gcMigTab()
{
}

wxPanel *
gcMigTab::MakeContent()
{
    wxPanel * newPanel = new wxPanel(   m_scrolled,
                                        -1,
                                        wxDefaultPosition,
                                        wxDefaultSize,
                                        wxTAB_TRAVERSAL);


    GCMatrixDisplaySizer * mds = new GCMatrixDisplaySizer();
    GCStructures & st_var = m_logic.GetStructures();

    // convenience to make the code easier to read
    gcDisplayOrder popids = st_var.GetDisplayablePopIds();
    gcDisplayOrder parids = st_var.GetParentIds();
    //objVector popsToDisplay    =  st_var.GetDisplayablePops();

    if (st_var.GetDivergenceState() &&
        (st_var.GetUnusedPopCount() + st_var.GetUnusedParentCount() < 2))
    {
        // make divergence migration matrix
        st_var.MakeMigrationMatrix();

        // Display Divergence Migration Matrix
        int matrixDim = st_var.GetPopCount();
        int ncell = 0; // for debug JRM

        // first the corner square
        mds->AddCell(new gcDivCell(newPanel, st_var, gcdefault::badIndex, false, matrixcelltype_CORNER),0,0);
        ncell++;

        // the left name column
        size_t nrow = 0;
        size_t ncol = 0;

        // population names
        for(gcDisplayOrder::iterator iter=popids.begin(); iter != popids.end(); iter++)
        {
            nrow++;
            mds->AddCell(new gcDivCell(newPanel, st_var, *iter, false, matrixcelltype_LABEL), ncol, nrow);
            ncell++;
        }

        // parent names
        for(gcDisplayOrder::iterator iter=parids.begin(); iter != parids.end(); iter++)
        {
            nrow++;
            mds->AddCell(new gcDivCell(newPanel, st_var, *iter, true, matrixcelltype_LABEL), ncol, nrow);
            ncell++;
        }

        // now the rest of the matrix

        // populatons columns
        for(gcDisplayOrder::iterator iter=popids.begin(); iter != popids.end(); iter++)
        {
            ncol++;
            nrow = 0;

            // label
            mds->AddCell(new gcDivCell(newPanel, st_var, *iter, false, matrixcelltype_LABEL), ncol, nrow);
            ncell++;

            // population data
            for(gcDisplayOrder::iterator jter=popids.begin(); jter != popids.end(); jter++)
            {
                nrow++;
                if (st_var.HasMigration(*iter,*jter))
                {
                    // hack to shut off FST if the user defined it because it will kill divergence
                    if(st_var.GetMigration(*iter,*jter).GetMethod() == migmethod_FST)
                    {
                        st_var.GetMigration(*iter,*jter).SetMethod(migmethod_USER);
                    }

                    mds->AddCell(new gcDivCell(newPanel, st_var, st_var.GetMigration(*iter,*jter).GetId(), false, matrixcelltype_VALUE), ncol, nrow);
                }
                else
                {
                    mds->AddCell(new gcDivCell(newPanel, st_var,  gcdefault::badIndex, false, matrixcelltype_INVALID), ncol, nrow);
                }
                ncell++;
            }

            // parent data
            for(gcDisplayOrder::iterator jter=parids.begin(); jter != parids.end(); jter++)
            {
                nrow++;
                if (st_var.HasMigration(*iter,*jter))
                {
                    // hack to shut off FST if the user defined it because it will kill divergence
                    // probably not necessary here, but better safe than dead
                    if(st_var.GetMigration(*iter,*jter).GetMethod() == migmethod_FST)
                    {
                        st_var.GetMigration(*iter,*jter).SetMethod(migmethod_USER);
                    }
                    mds->AddCell(new gcDivCell(newPanel, st_var, st_var.GetMigration(*iter,*jter).GetId(), true, matrixcelltype_VALUE), ncol, nrow);
                }
                else
                {
                    mds->AddCell(new gcDivCell(newPanel, st_var,  gcdefault::badIndex, true, matrixcelltype_INVALID), ncol, nrow);
                }
                ncell++;
            }

        }

        // parent columns
        for(gcDisplayOrder::iterator iter=parids.begin(); iter != parids.end(); iter++)
        {
            ncol++;
            nrow = 0;
            // label
            mds->AddCell(new gcDivCell(newPanel, st_var, *iter, true, matrixcelltype_LABEL), ncol, nrow);
            ncell++;

            // population data
            for(gcDisplayOrder::iterator jter=popids.begin(); jter != popids.end(); jter++)
            {
                nrow++;
                if (st_var.HasMigration(*iter,*jter))
                {
                    // hack to shut off FST if the user defined it because it will kill divergence
                    if(st_var.GetMigration(*iter,*jter).GetMethod() == migmethod_FST)
                    {
                        st_var.GetMigration(*iter,*jter).SetMethod(migmethod_USER);
                    }
                    mds->AddCell(new gcDivCell(newPanel, st_var, st_var.GetMigration(*iter,*jter).GetId(), false, matrixcelltype_VALUE), ncol, nrow);
                }
                else
                {
                    mds->AddCell(new gcDivCell(newPanel, st_var,  gcdefault::badIndex, false, matrixcelltype_INVALID), ncol, nrow);
                }
                ncell++;
            }

            // parent data
            for(gcDisplayOrder::iterator jter=parids.begin(); jter != parids.end(); jter++)
            {
                nrow++;
                if (st_var.HasMigration(*iter,*jter))
                {
                    // hack to shut off FST if the user defined it because it will kill divergence
                    // probably not necessary here, but better safe than dead
                    if(st_var.GetMigration(*iter,*jter).GetMethod() == migmethod_FST)
                    {
                        st_var.GetMigration(*iter,*jter).SetMethod(migmethod_USER);
                    }
                    mds->AddCell(new gcDivCell(newPanel, st_var, st_var.GetMigration(*iter,*jter).GetId(), true, matrixcelltype_VALUE), ncol, nrow);
                }
                else
                {
                    mds->AddCell(new gcDivCell(newPanel, st_var,  gcdefault::badIndex, true, matrixcelltype_INVALID), ncol, nrow);
                }
                ncell++;
            }

        }

        //        }
        st_var.SetMigMatrixDefined(false);
        st_var.SetDivMigMatrixDefined(true);
    }
    else
    {
        if (popids.size() > 0)
        {
            // make migration matrix
            st_var.MakeMigrationMatrix();

            // Display Migration Matrix
            int matrixDim = st_var.GetPopCount();
            int ncell = 0; // for debug JRM

            // first the corner square
            mds->AddCell(new gcMigCell(newPanel, st_var, gcdefault::badIndex, matrixcelltype_CORNER),0,0);
            ncell++;

            // the left name column
            popids = st_var.GetDisplayablePopIds();
            size_t nrow = 0;
            size_t ncol = 0;
            for(gcDisplayOrder::iterator iter=popids.begin(); iter != popids.end(); iter++)
            {
                nrow++;
                mds->AddCell(new gcMigCell(newPanel, st_var, *iter, matrixcelltype_LABEL), ncol, nrow);
                ncell++;
            }

            // now the rest of the matrix
            for(gcDisplayOrder::iterator iter=popids.begin(); iter != popids.end(); iter++)
            {
                ncol++;
                nrow = 0;

                // first the label
                mds->AddCell(new gcMigCell(newPanel, st_var, *iter, matrixcelltype_LABEL), ncol, nrow);
                ncell++;

                // now the data
                for(gcDisplayOrder::iterator jter=popids.begin(); jter != popids.end(); jter++)
                {
                    nrow++;
                    if (*iter == *jter)
                    {
                        mds->AddCell(new gcMigCell(newPanel, st_var,  gcdefault::badIndex, matrixcelltype_INVALID), ncol, nrow);
                        ncell++;
                    }
                    else
                    {
                        mds->AddCell(new gcMigCell(newPanel, st_var, st_var.GetMigration(*iter,*jter).GetId(), matrixcelltype_VALUE), ncol, nrow);
                        ncell++;
                    }
                }
            }
        }
        st_var.SetMigMatrixDefined(true);
        st_var.SetDivMigMatrixDefined(false);
    }
    newPanel->SetSizerAndFit(mds);
    return newPanel;

}

wxString
gcMigTab::MakeLabel()
{
    return m_panelLabelFmt;
}

//____________________________________________________________________________________
