/*

  xmunipack - FITS file popup box

  Copyright © 2018 F.Hroch (hroch@physics.muni.cz)

  This file is part of Munipack.

  Munipack is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.

  Munipack is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with Munipack.  If not, see <http://www.gnu.org/licenses/>.

*/

#include "structtree.h"
#include "event.h"
#include "icon.h"
#include <wx/wx.h>
#include <wx/combo.h>
#include <wx/treectrl.h>
#include <wx/imaglist.h>

using namespace std;


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

class xTreeItemData: public wxTreeItemData
{
public:
  xTreeItemData(const int n): index(n) {}

  int index;
};

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

void MuniStructtree::Init() {

  Bind(wxEVT_MOTION,&MuniStructtree::OnMouseMove,this);
  Bind(wxEVT_LEFT_DOWN,&MuniStructtree::OnMouseClick,this);

}

  // Create popup control
bool MuniStructtree::Create(wxWindow* parent) {

  return wxTreeCtrl::Create(parent,wxID_ANY,wxDefaultPosition,wxDefaultSize,
			    (wxTR_DEFAULT_STYLE | wxTR_HAS_BUTTONS |
			     wxTR_HIDE_ROOT | wxTR_FULL_ROW_HIGHLIGHT) &
			    ~wxTR_NO_LINES);
}

// Return pointer to the created control
//virtual wxWindow *MuniStructtree::GetControl() { return this; }

wxSize MuniStructtree::GetBestSize() const
{
  return wxSize(300,-1);
}

wxSize MuniStructtree::GetAdjustedSize( int minWidth,
						int WXUNUSED(prefHeight),
						int maxHeight )
{
  return wxSize(wxMax(300,minWidth),wxMin(250,maxHeight));
}

// Needed by SetStringValue
wxTreeItemId MuniStructtree::FindItemByText( wxTreeItemId parent,
					     const wxString& text )
{
  wxTreeItemIdValue cookie;
  wxTreeItemId child = GetFirstChild(parent,cookie);
  while ( child.IsOk() )
    {
      if ( GetItemText(child) == text )
	{
	  return child;
	}
      if ( ItemHasChildren(child) )
	{
	  wxTreeItemId found = FindItemByText(child,text);
	  if ( found.IsOk() )
	    return found;
	}
      child = GetNextChild(parent,cookie);
    }
  return wxTreeItemId();
}

void MuniStructtree::SetStringValue( const wxString& s )
{
  wxTreeItemId root = GetRootItem();
  if ( !root.IsOk() )
    return;

  wxTreeItemId found = FindItemByText(root,s);
  if ( found.IsOk() )
    {
      m_value = m_itemHere = found;
      wxTreeCtrl::SelectItem(found);
    }
}

wxString MuniStructtree::GetStringValue() const
{
  if ( m_value.IsOk() )
    return wxTreeCtrl::GetItemText(m_value);
  return wxEmptyString;
}

//
// Popup event handlers
//

// Mouse hot-tracking
void MuniStructtree::OnMouseMove(wxMouseEvent& event)
{
  int resFlags;
  wxTreeItemId itemHere = HitTest(event.GetPosition(),resFlags);
  if ( itemHere.IsOk() &&
       ((resFlags & wxTREE_HITTEST_ONITEMLABEL) ||
	(resFlags & wxTREE_HITTEST_ONITEMICON) ||
	(resFlags & wxTREE_HITTEST_ONITEMSTATEICON) ||
	(resFlags & wxTREE_HITTEST_ONITEMBUTTON) ||
	(resFlags & wxTREE_HITTEST_ONITEMINDENT) ||
	(resFlags & wxTREE_HITTEST_ONITEMRIGHT) ) )
    {
      wxTreeCtrl::SelectItem(itemHere,true);
      m_itemHere = itemHere;
    }
  event.Skip();
}

// On mouse left, set the value and close the popup
void MuniStructtree::OnMouseClick(wxMouseEvent& event)
{
  int resFlags;
  wxTreeItemId itemHere = HitTest(event.GetPosition(),resFlags);
  if ( itemHere.IsOk() &&
       ((resFlags & wxTREE_HITTEST_ONITEMLABEL) ||
	(resFlags & wxTREE_HITTEST_ONITEMICON) ||
	(resFlags & wxTREE_HITTEST_ONITEMSTATEICON) ||
	(resFlags & wxTREE_HITTEST_ONITEMBUTTON) ||
	(resFlags & wxTREE_HITTEST_ONITEMINDENT) ||
	(resFlags & wxTREE_HITTEST_ONITEMRIGHT) ) )
    {
      m_itemHere = itemHere;
      m_value = itemHere;
      Dismiss();

      wxTreeItemId item = GetFocusedItem();
      if( item.IsOk() ) {
	xTreeItemData *data = dynamic_cast<xTreeItemData *>(GetItemData(item));
	wxASSERT(data);

	MuniHduEvent ev(EVT_HDU);
	ev.hdu = data->index;
	wxQueueEvent(GetGrandParent(),ev.Clone());
      }

    }
  event.Skip();
}

void MuniStructtree::PaintComboControl(wxDC& dc, const wxRect& rect)
{
  wxTreeItemId item = GetFocusedItem();
  if( item.IsOk() ) {

    wxString label(GetItemText(item));

    wxImageList *ilist = GetImageList();
    int index = GetItemImage(item);
    if( index > -1 ) {
      wxBitmap icon(ilist->GetBitmap(index));
      dc.DrawLabel(label,icon,rect,wxALIGN_CENTER|wxALIGN_CENTER_VERTICAL);
    }
    else
      dc.DrawLabel(label,rect,wxALIGN_CENTER|wxALIGN_CENTER_VERTICAL);
  }
  else
    dc.DrawLabel("-",rect,wxALIGN_CENTER|wxALIGN_CENTER_VERTICAL);

}

void MuniStructtree::SetMeta(const FitsMeta& meta)
{

  DeleteAllItems();

  wxFont fn(*wxNORMAL_FONT);
  int ssize = 2*(fn.GetPointSize()+3);
  wxImageList *icons = new wxImageList(ssize, ssize, true);
  for(size_t n = 0; n < meta.HduCount(); n++ ) {
    const FitsMetaHdu hdu = meta.Hdu(n);
    icons->Add(wxBitmap(MuniIcon::ListIcon(hdu.GetIcon(),ssize)));
  }
  icons->Add(wxBitmap(MuniIcon::ListIcon(meta.GetIcon(),ssize)));
  AssignImageList(icons);

  wxTreeItemId root = AddRoot("<root>");

  wxTreeItemId hub = AppendItem(root,meta.GetName(),meta.HduCount(),-1,
				new xTreeItemData(-1));
  for(size_t n = 0; n < meta.HduCount(); n++ ) {
    const FitsMetaHdu hdu = meta.Hdu(n);
    wxString label = hdu.GetControlLabel();
    AppendItem(hub,label,n,-1,new xTreeItemData(n));
  }
  Expand(hub);
}

void MuniStructtree::SetHdu(int hdu)
{
  wxTreeItemId root = GetRootItem();

  wxTreeItemIdValue cookie;
  wxTreeItemId hub = GetFirstChild(root,cookie);
  while ( hub.IsOk() ) {

    xTreeItemData *data = dynamic_cast<xTreeItemData *>(GetItemData(hub));
    wxASSERT(data);
    if( data->index == hdu ) {
      SelectItem(hub);
      return;
    }
    else {

      wxTreeItemIdValue cookies;
      wxTreeItemId child = GetFirstChild(hub,cookies);
      while ( child.IsOk() ) {

	xTreeItemData *data = dynamic_cast<xTreeItemData *>(GetItemData(child));
	wxASSERT(data);
	if( data->index == hdu ) {
	  SelectItem(child);
	  return;
	}

	child = GetNextChild(hub,cookies);
      }
    }
      hub = GetNextChild(root,cookie);
  }
}
