/*
 *  
 *  $Id: wxginkgotoolbar.cpp $
 *  Ginkgo CADx Project
 *
 *  Copyright 2008-12 MetaEmotion S.L. All rights reserved.
 *  http://ginkgo-cadx.com
 *
 *  This file is licensed under LGPL v3 license.
 *  See License.txt for details
 *
 */


#include "wxginkgotoolbar.h"
#include <api/toolsystem/itoolcontroller.h>
#include <api/toolsystem/iwidgettool.h>
#include <resources/ginkgoresourcesmanager.h>
#include <eventos/toolevents.h>
#include <api/controllers/ieventscontroller.h>

#include <wx/menu.h>

class GinkgoToolBarArt : public wxAuiDefaultToolBarArt 
{
public:

	GinkgoToolBarArt(GNC::GCS::IToolController* pControlador) {
		m_pToolBar = pControlador;
	}

	virtual ~GinkgoToolBarArt() {}

	void SetCustomBaseColor(const wxColor& color) {
		m_base_colour = color;
	}

	wxColor GetCustomBaseColor() {
		return m_base_colour;
	}


	////////////////////////////////////////////////////begin draw drowpdown////////////////////////////////////////
	//WXWIDGETS DOESN'T SUPPORT DRAW CHECKED + DROPDOWN
	// wxAuiBlendColour is used by wxAuiStepColour
	unsigned char wxAuiBlendColour(unsigned char fg, unsigned char bg, double alpha)
	{
		double result = bg + (alpha * (fg - bg));
		if (result < 0.0)
			result = 0.0;
		if (result > 255)
			result = 255;
		return (unsigned char)result;
	}

	// wxAuiStepColour() it a utility function that simply darkens
	// or lightens a color, based on the specified percentage
	// ialpha of 0 would be completely black, 100 completely white
	// an ialpha of 100 returns the same colour
	wxColor wxAuiStepColour(const wxColor& c, int ialpha)
	{
		if (ialpha == 100)
			return c;

		unsigned char r = c.Red(),
			g = c.Green(),
			b = c.Blue();
		unsigned char bg;

		// ialpha is 0..200 where 0 is completely black
		// and 200 is completely white and 100 is the same
		// convert that to normal alpha 0.0 - 1.0
		ialpha = wxMin(ialpha, 200);
		ialpha = wxMax(ialpha, 0);
		double alpha = ((double)(ialpha - 100.0))/100.0;

		if (ialpha > 100)
		{
			// blend with white
			bg = 255;
			alpha = 1.0 - alpha;  // 0 = transparent fg; 1 = opaque fg
		}
		else
		{
			// blend with black
			bg = 0;
			alpha += 1.0;         // 0 = transparent fg; 1 = opaque fg
		}

		r = wxAuiBlendColour(r, bg, alpha);
		g = wxAuiBlendColour(g, bg, alpha);
		b = wxAuiBlendColour(b, bg, alpha);

		return wxColour(r, g, b);
	}

	void DrawDropDownButton(
		wxDC& dc,
		wxWindow* WXUNUSED(wnd),
		const wxAuiToolBarItem& item,
		const wxRect& rect)
	{
		//
		const int BUTTON_DROPDOWN_WIDTH = 10;
		const unsigned char
			DISABLED_TEXT_GREY_HUE = wxAuiBlendColour(0, 255, 0.4);
		const wxColour DISABLED_TEXT_COLOR(DISABLED_TEXT_GREY_HUE,
			DISABLED_TEXT_GREY_HUE,
			DISABLED_TEXT_GREY_HUE);
		//

		int text_width = 0, text_height = 0, text_x = 0, text_y = 0;
		int bmp_x = 0, bmp_y = 0, dropbmp_x = 0, dropbmp_y = 0;

		wxRect button_rect = wxRect(rect.x,
			rect.y,
			rect.width-BUTTON_DROPDOWN_WIDTH,
			rect.height);
		wxRect dropdown_rect = wxRect(rect.x+rect.width-BUTTON_DROPDOWN_WIDTH-1,
			rect.y,
			BUTTON_DROPDOWN_WIDTH+1,
			rect.height);

		if (m_flags & wxAUI_TB_TEXT)
		{
			dc.SetFont(m_font);

			int tx, ty;
			if (m_flags & wxAUI_TB_TEXT)
			{
				dc.GetTextExtent(wxT("ABCDHgj"), &tx, &text_height);
				text_width = 0;
			}

			dc.GetTextExtent(item.GetLabel(), &text_width, &ty);
		}



		dropbmp_x = dropdown_rect.x +
			(dropdown_rect.width/2) -
			(m_button_dropdown_bmp.GetWidth()/2);
		dropbmp_y = dropdown_rect.y +
			(dropdown_rect.height/2) -
			(m_button_dropdown_bmp.GetHeight()/2);


		if (m_text_orientation == wxAUI_TBTOOL_TEXT_BOTTOM)
		{
			bmp_x = button_rect.x +
				(button_rect.width/2) -
				(item.GetBitmap().GetWidth()/2);
			bmp_y = button_rect.y +
				((button_rect.height-text_height)/2) -
				(item.GetBitmap().GetHeight()/2);

			text_x = rect.x + (rect.width/2) - (text_width/2) + 1;
			text_y = rect.y + rect.height - text_height - 1;
		}
		else if (m_text_orientation == wxAUI_TBTOOL_TEXT_RIGHT)
		{
			bmp_x = rect.x + 3;

			bmp_y = rect.y +
				(rect.height/2) -
				(item.GetBitmap().GetHeight()/2);

			text_x = bmp_x + 3 + item.GetBitmap().GetWidth();
			text_y = rect.y +
				(rect.height/2) -
				(text_height/2);
		}


		if (item.GetState() & wxAUI_BUTTON_STATE_PRESSED)
		{
			dc.SetPen(wxPen(m_highlight_colour));
			dc.SetBrush(wxBrush(wxAuiStepColour(m_highlight_colour, 140)));
			dc.DrawRectangle(button_rect);
			dc.DrawRectangle(dropdown_rect);
		}
		else if ( (item.GetState() & wxAUI_BUTTON_STATE_HOVER) || item.IsSticky())
		{
			dc.SetPen(wxPen(m_highlight_colour));
			dc.SetBrush(wxBrush(wxAuiStepColour(m_highlight_colour, 170)));
			dc.DrawRectangle(button_rect);
			dc.DrawRectangle(dropdown_rect);
		}
		//MODIFIED
		else if (item.GetState() & wxAUI_BUTTON_STATE_CHECKED)
		{
			// it's important to put this code in an else statment after the
			// hover, otherwise hovers won't draw properly for checked items
			dc.SetPen(wxPen(m_highlight_colour));
			dc.SetBrush(wxBrush(wxAuiStepColour(m_highlight_colour, 170)));
			dc.DrawRectangle(rect);
		}
		///END MODIFIED

		wxBitmap bmp;
		wxBitmap dropbmp;
		if (item.GetState() & wxAUI_BUTTON_STATE_DISABLED)
		{
			bmp = item.GetDisabledBitmap();
			dropbmp = m_disabled_button_dropdown_bmp;
		}
		else
		{
			bmp = item.GetBitmap();
			dropbmp = m_button_dropdown_bmp;
		}

		if (!bmp.IsOk())
			return;

		dc.DrawBitmap(bmp, bmp_x, bmp_y, true);
		dc.DrawBitmap(dropbmp, dropbmp_x, dropbmp_y, true);

		// set the item's text color based on if it is disabled
		dc.SetTextForeground(*wxBLACK);
		if (item.GetState() & wxAUI_BUTTON_STATE_DISABLED)
			dc.SetTextForeground(DISABLED_TEXT_COLOR);

		if ( (m_flags & wxAUI_TB_TEXT) && !item.GetLabel().empty() )
		{
			dc.DrawText(item.GetLabel(), text_x, text_y);
		}
	}
	////////////////////////////////////////////////////end draw drowpdown////////////////////////////////////////

	virtual void DrawButton(
		wxDC& dc,
		wxWindow* wnd,
		const wxAuiToolBarItem& item,
		const wxRect& rect)
	{
		if (item.HasDropDown()) {
			//we have modified default draw function to draw checked + drop down (not supported in wxWidgets)
			DrawDropDownButton(dc, wnd, item, rect);
		} else {
			AUI_NAMESPACE wxAuiDefaultToolBarArt::DrawButton(dc, wnd, item, rect);
		}
		if (item.IsActive() && ( (item.GetState() & wxAUI_BUTTON_STATE_CHECKED) != 0) ) 
		{
			GNC::GCS::IWidgetTool* pTool = NULL;
			if ((m_pToolBar->GetLeftTool() != NULL && m_pToolBar->GetLeftTool()->ID == (unsigned int)item.GetId())) {
				pTool = m_pToolBar->GetLeftTool();
			}
			if (m_pToolBar->GetRightTool() != NULL && m_pToolBar->GetRightTool()->ID == (unsigned int)item.GetId()) {
				pTool = m_pToolBar->GetRightTool();
			}

			if (pTool != NULL) {
				wxBitmap bmp;
				if ( pTool->GetTriggerButton().IsLeftEnabled() && pTool->GetTriggerButton().IsRightEnabled()) {
					//l+r
					bmp = GinkgoResourcesManager::ToolIcons::GetIcoMouseRL();
				} else if ( pTool->GetTriggerButton().IsLeftEnabled() ) {
					//l
					bmp = GinkgoResourcesManager::ToolIcons::GetIcoMouseL();
				} else {
					//r
					bmp = GinkgoResourcesManager::ToolIcons::GetIcoMouseR();
				}

				if ( pTool->GetTriggerButton().IsLeftEnabled() ||  pTool->GetTriggerButton().IsRightEnabled()) {
					wxPoint point(rect.x, rect.height - bmp.GetHeight()+7);
					dc.DrawBitmap(bmp, point);
				}
			}
		}
	}

private:
	GNC::GCS::IToolController* m_pToolBar;

};

GNC::GUI::wxGinkgoToolBar::wxGinkgoToolBar(wxWindow* pParent, GNC::GCS::IToolController* pToolBar, const GNC::GCS::ITool::TToolFamily& family):AUI_NAMESPACE wxAuiToolBar(pParent,wxID_ANY, wxDefaultPosition, wxDefaultSize,AUI_NAMESPACE wxAUI_TB_DEFAULT_STYLE )
{
	this->Connect(wxID_ANY,wxEVT_LEFT_UP, wxMouseEventHandler( wxGinkgoToolBar::OnLeftUp) , NULL, this);
	this->Connect(wxID_ANY,wxEVT_RIGHT_UP, wxMouseEventHandler( wxGinkgoToolBar::OnRightUp) , NULL, this);
	this->Connect(wxID_ANY, wxEVT_COMMAND_AUITOOLBAR_TOOL_DROPDOWN,  wxAuiToolBarEventHandler(wxGinkgoToolBar::OnDropDownTool) , NULL, this);
	pParent->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler( wxGinkgoToolBar::OnKeyEvent ), NULL, this);

	SetToolBitmapSize(wxSize(16,16));
	SetAutoLayout(true);
	m_pToolBar = pToolBar;
	GinkgoToolBarArt* pToolArt = new GinkgoToolBarArt(pToolBar);
#if !defined(__WXOSX__)
	wxColor color = pToolArt->GetCustomBaseColor();
	switch(family) {
		case GNC::GCS::ITool::TFamiliaGlobal:
			color = wxColor(67,67,67);
			break;
		case GNC::GCS::ITool::TFamiliaVisualizacion:
			color = wxColor(255,255,186);
			break;
		case GNC::GCS::ITool::TFamiliaAnotacion:
			color = wxColor(255,186,186);
			break;
		case GNC::GCS::ITool::TFamiliaMedicion:
			color = wxColor(217,255,186);
			break;
		case GNC::GCS::ITool::TFamiliaVision:
			color = wxColor(186,230,255);
			break;
		case GNC::GCS::ITool::TFamiliaChroma:
			color = wxColor(230,181,242);
			break;
		case GNC::GCS::ITool::TMenuVer:
			break;
		case GNC::GCS::ITool::TSeriesMenu:
			break;
		case GNC::GCS::ITool::TMenuHerramientas:
			break;
		case GNC::GCS::ITool::TMenuExport:
			break;
		case GNC::GCS::ITool::TMenuEdicion:
			break;
			}
	pToolArt->SetCustomBaseColor(color);
#endif

	SetArtProvider(pToolArt);

	GNC::GCS::IEventsController::Instance()->Registrar(this, GNC::GCS::Events::ToolConnectedEvent());
	GNC::GCS::IEventsController::Instance()->Registrar(this, GNC::GCS::Events::ToolEnabledEvent());
	GNC::GCS::IEventsController::Instance()->Registrar(this, GNC::GCS::Events::ChangeToolIconEvent());
}

GNC::GUI::wxGinkgoToolBar::~wxGinkgoToolBar()
{
	this->Disconnect(wxID_ANY,wxEVT_COMMAND_TOOL_CLICKED, wxMouseEventHandler( wxGinkgoToolBar::OnLeftUp), NULL, this);
	this->Disconnect(wxID_ANY,wxEVT_COMMAND_TOOL_CLICKED, wxMouseEventHandler( wxGinkgoToolBar::OnRightUp), NULL, this);
	this->Disconnect(wxID_ANY, wxEVT_COMMAND_AUITOOLBAR_TOOL_DROPDOWN,  wxAuiToolBarEventHandler(wxGinkgoToolBar::OnDropDownTool) , NULL, this);
	GetParent()->Disconnect(wxEVT_KEY_DOWN, wxKeyEventHandler( wxGinkgoToolBar::OnKeyEvent ), NULL, this);
	m_pToolBar=NULL;
}

wxRect GNC::GUI::wxGinkgoToolBar::GetToolRect(int tool_id) const
{
	wxRect rect = wxAuiToolBar::GetToolRect(tool_id);
	rect.x -= 5;
	rect.y -= 5;
	rect.width += 5;
	rect.height += 5;
	return rect;
}

void GNC::GUI::wxGinkgoToolBar::OnRightUp(wxMouseEvent& evt)
{
	wxAuiToolBarItem* hit_item;
	hit_item = FindToolByPosition(evt.GetX(), evt.GetY());
	if (hit_item != NULL && hit_item->IsActive()) {
		m_pToolBar->ActivateTool(hit_item->GetId(), GNC::GCS::TriggerButton().EnableRight(), this);
	}
	evt.Skip(false);
}

void GNC::GUI::wxGinkgoToolBar::OnLeftUp(wxMouseEvent& evt)
{
	wxAuiToolBarItem* hit_item;
	hit_item = FindToolByPosition(evt.GetX(), evt.GetY());
	if (hit_item != NULL && hit_item->IsActive()) {
		m_pToolBar->ActivateTool(hit_item->GetId(), GNC::GCS::TriggerButton().EnableLeft(), this);
	}
	evt.Skip(false);
}

void GNC::GUI::wxGinkgoToolBar::OnDropDownTool(wxAuiToolBarEvent& evt)
{
	if (evt.IsDropDownClicked()){
		wxAuiToolBarItem* hit_item;
		hit_item = FindToolByPosition(evt.GetClickPoint().x, evt.GetClickPoint().y);
		if (hit_item != NULL && hit_item->IsActive()) {
			//Activate...
			wxAuiToolBar* tb = static_cast<wxAuiToolBar*>(evt.GetEventObject());

			tb->SetToolSticky(evt.GetId(), true);
			// create the popup menu
			wxMenu menuPopup;

			m_pToolBar->AppendDropDownMenu(hit_item->GetId(), &menuPopup, &menuPopup);

			// line up our menu with the button
			wxRect rect = tb->GetToolRect(evt.GetId());
			wxPoint pt = tb->ClientToScreen(rect.GetBottomLeft());
			pt = ScreenToClient(pt);

			PopupMenu(&menuPopup, pt);

			// make sure the button is "un-stuck"
			tb->SetToolSticky(evt.GetId(), false);
		//	m_pToolBar->ActivateTool(hit_item->GetId(), GNC::GCS::TriggerButton().EnableLeft(), this);
		}
	}
	evt.Skip(true);
}

void GNC::GUI::wxGinkgoToolBar::OnKeyEvent(wxKeyEvent& event)
{
	GNC::GCS::Events::EventoTeclado evt(&event, NULL);
	evt.Skip(true);
	m_pToolBar->OnKeyAccelerator(evt, this);
		/*
#if defined(__WXGTK__)
		if (m_pParent != NULL) {
			m_pParent->SetFocus();
		}
#endif
		*/	
	event.Skip(evt.GetSkipped());
	event.ResumePropagation(3);
}

void GNC::GUI::wxGinkgoToolBar::ProcesarEvento(GNC::GCS::Events::IEvent* evt)
{
	switch (evt->GetCodigoEvento())
	{
		case ginkgoEVT_Core_ToolConnected:
			{
				GNC::GCS::Events::ToolConnectedEvent* pToolEvt = static_cast<GNC::GCS::Events::ToolConnectedEvent*>(evt);
				if (pToolEvt->GetToolBar() == m_pToolBar) {
					this->ToggleTool(pToolEvt->GetTool()->ID, pToolEvt->IsConnected());
					wxRect rect = GetToolRect(pToolEvt->GetTool()->ID);
					Refresh(true, &rect);
				}
			}
			break;
		case ginkgoEVT_Core_ToolEnabled:
			{
				GNC::GCS::Events::ToolEnabledEvent* pToolEvt = static_cast<GNC::GCS::Events::ToolEnabledEvent*>(evt);
				if (pToolEvt->GetToolBar() == m_pToolBar) {
					this->EnableTool(pToolEvt->GetTool()->ID, pToolEvt->IsEnabled());
					wxRect rect = GetToolRect(pToolEvt->GetTool()->ID);
					Refresh(true, &rect);
				}
			}
			break;
		case ginkgoEVT_Core_ToolIconChanged:
			{
				GNC::GCS::Events::ChangeToolIconEvent* pToolEvt = static_cast<GNC::GCS::Events::ChangeToolIconEvent*>(evt);
				if (pToolEvt->GetToolBar() == m_pToolBar) {
					this->SetToolBitmap(pToolEvt->GetTool()->ID, *pToolEvt->GetBitmap());
					wxRect rect = GetToolRect(pToolEvt->GetTool()->ID);
					Refresh(true, &rect);
				}
			}
			break;
	}
}
