// $Id: gc_gridpanel.cpp,v 1.31 2018/01/03 21:33:00 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 <stdio.h>

#include "wx/sizer.h"
#include "gc_color.h"
#include "gc_event_ids.h"
#include "gc_event_publisher.h"
#include "gc_gridpanel.h"
#include "gc_layout.h"
#include "gc_logic.h"
#include "gc_strings.h"
#include "gc_types.h"

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

gcGridPane::gcGridPane(wxWindow * parent, size_t cols, size_t growCol)
    :
    wxPanel(parent,-1,wxDefaultPosition,wxDefaultSize,wxTAB_TRAVERSAL),
    m_sizer(NULL),
    m_rows(0),
    m_cols(cols)
{
    //(void) new wxStaticText( this, wxID_ANY, wxT("In gcGridPane Create."), wxPoint(10, 10) );

    m_sizer = new wxFlexGridSizer(cols);
    m_sizer->AddGrowableCol(growCol);
    SetSizerAndFit(m_sizer);
}

gcGridPane::~gcGridPane()
{
}

void
gcGridPane::NotifyEntering(size_t row, size_t col)
{
    for(size_t c = 0; c < m_cols; c++)
    {
        cellIndices indices(row,c);
        cellMap::iterator iter = m_cells.find(indices);
        assert(iter != m_cells.end());
        wxWindow * obj = (*iter).second;
        obj->SetBackgroundColour(gccolor::enteredObject());
    }
}

void
gcGridPane::NotifyLeaving(size_t row, size_t col)
{
    for(size_t c = 0; c < m_cols; c++)
    {
        cellIndices indices(row,c);
        cellMap::iterator iter = m_cells.find(indices);
        assert(iter != m_cells.end());
        wxWindow * obj = (*iter).second;
        obj->SetBackgroundColour(wxNullColour);
    }
}

void
gcGridPane::NotifyLeftDClick(size_t row, size_t col)
{
    wxLogDebug("Implementation Error: override NotifyLeftDClick");
}

void
gcGridPane::NotifyLeftDown(size_t row, size_t col)
{
    for(size_t c = 0; c < m_cols; c++)
    {
        cellIndices indices(row,c);
        cellMap::iterator iter = m_cells.find(indices);
        assert(iter != m_cells.end());
        wxWindow * obj = (*iter).second;
        obj->SetBackgroundColour(gccolor::activeObject());
    }
}

void
gcGridPane::NotifyLeftUp(size_t row, size_t col)
{

    for(size_t c = 0; c < m_cols; c++)
    {
        cellIndices indices(row,c);
        cellMap::iterator iter = m_cells.find(indices);
        assert(iter != m_cells.end());
        wxWindow * obj = (*iter).second;
        obj->SetBackgroundColour(gccolor::enteredObject());
    }

}

void
gcGridPane::AddRow(size_t objId, wxArrayString labels)
{
    assert(labels.size() == m_cols);
    for(size_t i=0; i < labels.size(); i++)
    {
        wxWindow * cell = new gcGridCell(this,labels[i],m_rows,i);
        m_sizer->Add(cell,
                     1,
                     wxALL | wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL | wxEXPAND,
                     gclayout::borderSizeNone);

        m_cells[cellIndices(m_rows,i)] = cell;
    }
    m_objVec.push_back(objId);
    m_rows++;
}

void
gcGridPane::Finish()
// This is necesary to get the scrollbars to be created correctly
// EWFIX.P4 -- is there a better way to do this?
{
    SetSizerAndFit(m_sizer);
}

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

BEGIN_EVENT_TABLE(gcGridText,wxStaticText)
EVT_MOUSE_EVENTS(gcGridText::OnMouse)
END_EVENT_TABLE()

gcGridText::gcGridText(gcGridCell * parent, wxString label)
:
wxStaticText(parent,-1,label)
{
}

gcGridText::~gcGridText()
{
}

void
gcGridText::OnMouse(wxMouseEvent & event)
{
    // according to the wxWidgets documentation, calling event.Skip()
    // here might be necessary because it might be handling more basic
    // functionality (such as bringing the window to the front).
    event.Skip();

    // send this event on to the containing gcGridCell object. We do
    // this because which window (i.e. this gcGridText of the parent
    // gcGridCell) responds to the mouse events we're interested in
    // does not appear to be consistent across platforms.
    event.ResumePropagation(1);

}

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

BEGIN_EVENT_TABLE(gcGridCell,wxPanel)
EVT_MOUSE_EVENTS(gcGridCell::OnMouse)
END_EVENT_TABLE()

gcGridCell::gcGridCell( gcGridPane *    parent,
                        wxString        label,
                        size_t          rowIndex,
                        size_t          colIndex)
:
wxPanel(parent),
    m_rowIndex(rowIndex),
    m_colIndex(colIndex)
{
    wxBoxSizer * sizer = new wxBoxSizer(wxHORIZONTAL);
    sizer->Add(new gcGridText(this,label),
               1,
               wxALL | wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL | wxEXPAND,
               gclayout::borderSizeSmall);
    SetSizerAndFit(sizer);
}

gcGridCell::~gcGridCell()
{
}

void
gcGridCell::OnMouse(wxMouseEvent & event)
{
    gcGridPane * gridPane = dynamic_cast<gcGridPane*>(GetParent());
    assert(gridPane != NULL);

    event.Skip();
    if( !event.Moving())
    {
        if ( event.Entering() )
        {
            gridPane->NotifyEntering(m_rowIndex,m_colIndex);
        }
        if ( event.Leaving() )
        {
            gridPane->NotifyLeaving(m_rowIndex,m_colIndex);
        }
        if ( event.LeftDClick() )
        {
            gridPane->NotifyLeftDClick(m_rowIndex,m_colIndex);
        }
        if ( event.LeftDown() )
        {
            gridPane->NotifyLeftDown(m_rowIndex,m_colIndex);
        }
        if ( event.LeftUp() )
        {
            gridPane->NotifyLeftUp(m_rowIndex,m_colIndex);
        }
    }
}

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

gcInfoPane::gcInfoPane(wxWindow * parent, GCLogic & logic, wxString title)
    :
    wxPanel(parent,
            -1,
            wxDefaultPosition,
            wxDefaultSize,
            wxTAB_TRAVERSAL | wxSUNKEN_BORDER),
    m_scrolled(NULL),
    m_contentSizer(NULL),
    m_innerPanel(NULL),
    m_topSizer(NULL),
    m_panelLabelFmt(title),
    m_panelLabel(NULL),
    m_logic(logic)
{
    //(void) new wxStaticText( this, wxID_ANY, wxT("In gcInfoPane Create."), wxPoint(10, 10) );

    m_scrolled = new wxScrolledWindow(this, -1,
                                      wxDefaultPosition,
                                      wxDefaultSize,
                                      wxRAISED_BORDER | wxTAB_TRAVERSAL);

    m_innerPanel = new wxPanel(m_scrolled,-1);
    (void) new wxStaticText( m_innerPanel, wxID_ANY, wxT("In m_innerPanel Create."), wxPoint(10, 10) );

    m_contentSizer = new wxBoxSizer(wxVERTICAL);
    m_contentSizer->Add(m_innerPanel,
                        1,
                        wxALL | wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL | wxEXPAND,
                        gclayout::borderSizeSmall);

    m_scrolled->SetScrollRate(5,5); // if removed, scrolling doesn't work
    m_scrolled->SetSizerAndFit(m_contentSizer);

    m_topSizer = new wxBoxSizer(wxVERTICAL);
    m_panelLabel = new wxStaticText(this,-1,wxEmptyString);
    m_topSizer->Add(m_panelLabel,
                    0,
                    wxALL | wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL | wxEXPAND,
                    gclayout::borderSizeSmall);
    m_topSizer->Add( m_scrolled,
                     1,
                     wxALL | wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL | wxEXPAND,
                     gclayout::borderSizeSmall);
    SetSizerAndFit(m_topSizer);

    assert(m_contentSizer != NULL);

}

gcInfoPane::~gcInfoPane()
{
}

void
gcInfoPane::UpdateUserCues()
{
    wxPanel * newContent = MakeContent();
    m_contentSizer->Detach(m_innerPanel);
    m_panelLabel->SetLabel(MakeLabel());
    m_innerPanel->Destroy();
    m_innerPanel = newContent;
    m_contentSizer->Add(m_innerPanel,
                        1,
                        wxALL | wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL | wxEXPAND,
                        gclayout::borderSizeSmall);
    m_innerPanel->Layout();
    m_contentSizer->Layout();
    m_scrolled->FitInside();
    //m_scrolled->Layout();
    m_topSizer->Layout();
    Layout();
}

//____________________________________________________________________________________
