/*
 * This file is part of Ginkgo CADx
 *
 * Copyright (c) 2015-2016 Gert Wollny
 * Copyright (c) 2008-2014 MetaEmotion S.L. All rights reserved.
 *
 * Ginkgo CADx is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; version 3.
 *
 * This program 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 Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser Public License
 * along with Ginkgo CADx; if not, see <http://www.gnu.org/licenses/>.
 *
 */


#include "metricgridtool.h"
#if defined(ENABLE_METRICGRIDTOOL)
#include <widgets/wrejilla.h>
#include <wx/aui/aui.h>
#include <wx/spinctrl.h>
#include <wx/dialog.h>
#include <wx/statbox.h>
#include <wx/stattext.h>
#include <wx/button.h>
#include <wx/menu.h>
#include <wx/choice.h>


#include <api/ievento.h>
#include <eventos/render.h>
#include <api/controllers/ieventscontroller.h>
#include <export/contracts/iwidgetscontract.h>

#ifdef __DEPRECATED
#undef __DEPRECATED
#endif
#include <vtk/vtkginkgoimageviewer.h>

#include <api/iwidgetsmanager.h>
#include <resources/ginkgoresourcesmanager.h>


#define ACTIVAR_REJILLA  1241
#define ESCALA_REJILLA 1242

namespace GNC
{
namespace GUI
{
class DialogoRejilla: public wxDialog
{
public:
        typedef enum TMetrica {
                TM_UM = 0,
                TM_MM,
                TM_CM,
                TM_M
        } TMetrica;

        DialogoRejilla(wxWindow* pParent, GNC::MetricGridTool* pHerramienta):
                wxDialog(pParent,wxID_ANY,_("Grid"),wxDefaultPosition,wxDefaultSize,wxDEFAULT_DIALOG_STYLE)
        {
                m_pHerramienta=pHerramienta;

                this->SetSizeHints( wxDefaultSize, wxDefaultSize );

                wxBoxSizer* bSizer5;
                bSizer5 = new wxBoxSizer( wxVERTICAL );

                wxStaticBoxSizer* sbSizer2;
                sbSizer2 = new wxStaticBoxSizer( new wxStaticBox( this, wxID_ANY, _("Grid Scale") ), wxVERTICAL );

                wxFlexGridSizer* fgSizer1;
                fgSizer1 = new wxFlexGridSizer( 2, 3, 0, 0 );
                fgSizer1->SetFlexibleDirection( wxBOTH );
                fgSizer1->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );

                wxStaticText* m_staticText4 = new wxStaticText( this, wxID_ANY, _("Scale X"), wxDefaultPosition, wxDefaultSize, 0 );
                fgSizer1->Add(m_staticText4,0,wxALL|wxEXPAND|wxALIGN_CENTER_VERTICAL,5);

                m_pSpinEscalaX = new wxSpinCtrl( this, wxID_ANY, wxT("50"), wxDefaultPosition, wxSize(60,-1), wxSP_ARROW_KEYS, 1, 10000, 50 );
                m_pSpinEscalaX->SetToolTip(_("X axis scale"));
                fgSizer1->Add(m_pSpinEscalaX,0,wxALL|wxEXPAND|wxALIGN_CENTER_VERTICAL,5);

                std::string micrometros("µm.");
                wxString choices[] = {wxString::FromUTF8(micrometros.c_str()),wxT("mm."),wxT("cm."),wxT("m.")};
                int choice2NChoices = sizeof( choices ) / sizeof( wxString );
                m_pChoiceX = new wxChoice(this,wxID_ANY, wxDefaultPosition, wxDefaultSize, choice2NChoices, choices);
                fgSizer1->Add(m_pChoiceX,0,wxALL|wxALIGN_CENTER_VERTICAL,5);

                wxStaticText* m_staticText5 = new wxStaticText( this, wxID_ANY, _("Scale Y"), wxDefaultPosition, wxDefaultSize, 0 );
                fgSizer1->Add(m_staticText5,0,wxALL|wxEXPAND,5);

                m_pSpinEscalaY = new wxSpinCtrl( this, wxID_ANY, wxT("50"), wxDefaultPosition, wxSize(60,-1), wxSP_ARROW_KEYS, 1, 10000, 50 );
                m_pSpinEscalaY->SetToolTip(_("Y axis scale"));
                fgSizer1->Add(m_pSpinEscalaY,0,wxALL|wxEXPAND|wxALIGN_CENTER_VERTICAL,5);

                m_pChoiceY = new wxChoice(this,wxID_ANY, wxDefaultPosition, wxDefaultSize, choice2NChoices, choices);
                fgSizer1->Add(m_pChoiceY,0,wxALL|wxALIGN_CENTER_VERTICAL,5);

                sbSizer2->Add( fgSizer1, 1, wxEXPAND|wxALL, 5 );

                bSizer5->Add( sbSizer2, 1,wxALL|wxEXPAND, 5 );

                wxButton* m_button3 = new wxButton( this, wxID_OK, _("Ok"), wxDefaultPosition, wxDefaultSize, 0 );
                m_button3->SetDefault();
                bSizer5->Add( m_button3, 0, wxALL|wxALIGN_RIGHT, 5 );

                this->SetSizer( bSizer5 );
                this->Layout();
                bSizer5->Fit( this );

                this->Centre( wxBOTH );


                double escalaX = m_pHerramienta->GetScaleX();
                m_pChoiceX->Select((int)AjustaAMetricaApropiada(escalaX));
                m_pSpinEscalaX->SetValue(escalaX);
                double escalaY = m_pHerramienta->GetScaleY();
                m_pChoiceY->Select((int)AjustaAMetricaApropiada(escalaY));
                m_pSpinEscalaY->SetValue(escalaY);

                m_pSpinEscalaX->Connect( wxEVT_COMMAND_SPINCTRL_UPDATED, wxSpinEventHandler( DialogoRejilla::OnSpinCtrlX ), NULL, this );
                m_pSpinEscalaY->Connect( wxEVT_COMMAND_SPINCTRL_UPDATED, wxSpinEventHandler( DialogoRejilla::OnSpinCtrlY ), NULL, this );
                m_pChoiceX->Connect( wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( DialogoRejilla::OnEscalaX), NULL, this);
                m_pChoiceY->Connect( wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( DialogoRejilla::OnEscalaY), NULL, this);
        }

        ~DialogoRejilla()
        {
                m_pSpinEscalaX->Disconnect( wxEVT_COMMAND_SPINCTRL_UPDATED, wxSpinEventHandler( DialogoRejilla::OnSpinCtrlX ), NULL, this );
                m_pSpinEscalaX->Disconnect( wxEVT_COMMAND_SPINCTRL_UPDATED, wxSpinEventHandler( DialogoRejilla::OnSpinCtrlY ), NULL, this );
                m_pChoiceX->Disconnect( wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( DialogoRejilla::OnEscalaX), NULL, this);
                m_pChoiceY->Disconnect( wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( DialogoRejilla::OnEscalaY), NULL, this);
                m_pHerramienta = NULL;
        }

        TMetrica AjustaAMetricaApropiada(double &escala)
        {
                if (escala > 10000.0f) {
                        escala = (int)(escala / 1000.0f);
                        return TM_M;
                } else if (escala > 100.0f) {
                        escala = (int)(escala / 10.0f);
                        return TM_CM;
                } else if (escala < 10.0f) {
                        escala = (int)(escala * 1000.0f);
                        return TM_UM;
                } else {
                        escala = (int)(escala);
                        return TM_MM;
                }
        }

        double TransformToMM(double valor, TMetrica escala)
        {
                switch (escala) {
                case TM_M:
                        return valor * 1000.0;
                case TM_CM:
                        return valor*10.0;
                case TM_UM:
                        return valor / 1000.0;
                case TM_MM:
                        return valor;
                }
                return valor;
        }

        void OnSpinCtrlX( wxSpinEvent&  )
        {
                const double valor = TransformToMM(m_pSpinEscalaX->GetValue(), (TMetrica)m_pChoiceX->GetSelection());
                m_pHerramienta->SetScaleX(valor);
        }

        void OnEscalaX( wxCommandEvent &)
        {
                const double valor = TransformToMM(m_pSpinEscalaX->GetValue(), (TMetrica)m_pChoiceX->GetSelection());
                m_pHerramienta->SetScaleX(valor);
        }

        void OnSpinCtrlY( wxSpinEvent&  )
        {
                const double valor = TransformToMM(m_pSpinEscalaY->GetValue(), (TMetrica)m_pChoiceY->GetSelection());
                m_pHerramienta->SetScaleY(valor);
        }

        void OnEscalaY( wxCommandEvent &)
        {
                const double valor = TransformToMM(m_pSpinEscalaY->GetValue(), (TMetrica)m_pChoiceY->GetSelection());
                m_pHerramienta->SetScaleY(valor);
        }

        wxSpinCtrl* m_pSpinEscalaX;
        wxSpinCtrl* m_pSpinEscalaY;
        wxChoice* m_pChoiceX;
        wxChoice* m_pChoiceY;
        GNC::MetricGridTool* m_pHerramienta;
};


class MenuMetricGridTool : public wxMenu
{
public:
        MenuMetricGridTool(wxEvtHandler* pParent, GNC::MetricGridTool* pHerramienta):wxMenu()
        {
                m_pParent = pParent;
                m_pHerramienta=pHerramienta;
                wxMenuItem* pItemVer = new wxMenuItem(this,ACTIVAR_REJILLA,_("Show grid"),_("Show grid"),wxITEM_NORMAL);
                wxMenuItem* pItemEscala = new wxMenuItem(this,ESCALA_REJILLA,_("Configure Grid ..."),_("Configure Grid"),wxITEM_NORMAL);
#ifdef __WXMSW__
                pItemVer->SetBitmaps(GinkgoResourcesManager::GridBar::GetIcoVerRejilla());
#else
                pItemVer->SetBitmap(GinkgoResourcesManager::GridBar::GetIcoVerRejilla());
#endif
                m_pParent->Connect(pItemVer->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MenuMetricGridTool::OnActivarRejillaClick),NULL,this);
                m_pParent->Connect(pItemVer->GetId(), wxEVT_UPDATE_UI, wxUpdateUIEventHandler(MenuMetricGridTool::OnUpdateUIMostrar),NULL,this);
                m_pParent->Connect(pItemEscala->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MenuMetricGridTool::OnEscalaClick),NULL,this);
                m_pParent->Connect(pItemEscala->GetId(), wxEVT_UPDATE_UI, wxUpdateUIEventHandler(MenuMetricGridTool::OnUpdateUIHerramienta),NULL,this);
                Append(pItemVer);
                Append(pItemEscala);

                m_pParent->Connect(m_pHerramienta->ID, wxEVT_UPDATE_UI, wxUpdateUIEventHandler(MenuMetricGridTool::OnUpdateUIHerramienta),NULL,this);
        }

        ~MenuMetricGridTool()
        {
                m_pParent->Disconnect(ACTIVAR_REJILLA, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MenuMetricGridTool::OnActivarRejillaClick),NULL,this);
                m_pParent->Disconnect(ESCALA_REJILLA, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MenuMetricGridTool::OnEscalaClick),NULL,this);
                m_pParent->Disconnect(ACTIVAR_REJILLA, wxEVT_UPDATE_UI, wxUpdateUIEventHandler(MenuMetricGridTool::OnUpdateUIMostrar),NULL,this);
                m_pParent->Disconnect(ESCALA_REJILLA, wxEVT_UPDATE_UI, wxUpdateUIEventHandler(MenuMetricGridTool::OnUpdateUIHerramienta),NULL,this);

                m_pParent->Disconnect(m_pHerramienta->ID, wxEVT_UPDATE_UI, wxUpdateUIEventHandler(MenuMetricGridTool::OnUpdateUIHerramienta),NULL,this);

                m_pParent = NULL;
                m_pHerramienta = NULL;
        }

        void OnActivarRejillaClick( wxCommandEvent& event )
        {
                m_pHerramienta->ToggleGrid();
                event.Skip(false);
        }

        void OnEscalaClick( wxCommandEvent& event )
        {
                DialogoRejilla dlg(NULL,m_pHerramienta);
                dlg.ShowModal();
                event.Skip(false);
        }

        void OnUpdateUIMostrar(wxUpdateUIEvent& event)
        {
                if(m_pHerramienta->IsVisible()) {
                        event.SetText(_("Hide Grid"));
                } else {
                        event.SetText(_("Show Grid"));
                }
        }

        void OnUpdateUIHerramienta(wxUpdateUIEvent& event)
        {
                event.Enable(m_pHerramienta->IsEnabled());
        }

        GNC::MetricGridTool* m_pHerramienta;
        wxEvtHandler* m_pParent;
};
}
}





GNC::GCS::ITool* GNC::MetricGridTool::NewTool()
{
        return new GNC::MetricGridTool();
}

GNC::MetricGridTool::MetricGridTool()
{
}
GNC::MetricGridTool::~MetricGridTool()
{
}

bool GNC::MetricGridTool::ExecuteAction()
{
        ToggleGrid();
        return true;
}

void GNC::MetricGridTool::AppendToolIn(wxEvtHandler* pParent, wxMenu* pMenu)
{
        if (AppendsInMenu()) {
                wxMenu* pGridMenu = new GNC::GUI::MenuMetricGridTool(pParent,this);
                pMenu->Append(ID,wxString::FromUTF8(Name.c_str()),pGridMenu);
                pMenu->Enable(ID,Enabled);
        }
}

bool GNC::MetricGridTool::IsVisible()
{
        GNC::GCS::Widgets::WRejillaBuilder* pRejillaBuilder = new GNC::GCS::Widgets::WRejillaBuilder(WidgetsContract->GetManager(), (unsigned long)this);
        bool visible = pRejillaBuilder->IsRejillaVisible();
        delete pRejillaBuilder;
        return visible;
}

void GNC::MetricGridTool::ToggleGrid()
{
        double spacing[3] = {1.0,1.0,1.0};
        int dimensions[3] = {0,0,0};
        WidgetsContract->GetViewerActivo()->GetSpacing(spacing);
        WidgetsContract->GetViewerActivo()->GetDimensions(dimensions);

        double escalaXDefecto = spacing[0] * dimensions [0] / 10;
        double escalaYDefecto = spacing[1] * dimensions [1] / 10;

        GNC::GCS::Widgets::WRejillaBuilder* pRejillaBuilder = new GNC::GCS::Widgets::WRejillaBuilder(WidgetsContract->GetManager(), (unsigned long)this, escalaXDefecto, escalaYDefecto);
        pRejillaBuilder->ActivarRejilla(!pRejillaBuilder->IsRejillaVisible());
        delete pRejillaBuilder;
        GNC::GCS::IEventsController::Instance()->ProcesarEvento(new GNC::GCS::Events::EventoRender(WidgetsContract->GetManager()->GetVista()));
}

void GNC::MetricGridTool::SetScaleX(double escala)
{
        GNC::GCS::Widgets::WRejillaBuilder* pRejillaBuilder = new GNC::GCS::Widgets::WRejillaBuilder(WidgetsContract->GetManager(), (unsigned long)this);
        pRejillaBuilder->ActivarRejilla(true);
        pRejillaBuilder->SetEscalaX(escala);
        delete pRejillaBuilder;
        GNC::GCS::IEventsController::Instance()->ProcesarEvento(new GNC::GCS::Events::EventoRender(WidgetsContract->GetManager()->GetVista()));
}

void GNC::MetricGridTool::SetScaleY(double escala)
{
        GNC::GCS::Widgets::WRejillaBuilder* pRejillaBuilder = new GNC::GCS::Widgets::WRejillaBuilder(WidgetsContract->GetManager(), (unsigned long)this);
        pRejillaBuilder->ActivarRejilla(true);
        pRejillaBuilder->SetEscalaY(escala);
        delete pRejillaBuilder;
        GNC::GCS::IEventsController::Instance()->ProcesarEvento(new GNC::GCS::Events::EventoRender(WidgetsContract->GetManager()->GetVista()));
}

double GNC::MetricGridTool::GetScaleX()
{
        double scale = 50.0;
        GNC::GCS::Widgets::WRejillaBuilder* pRejillaBuilder = new GNC::GCS::Widgets::WRejillaBuilder(WidgetsContract->GetManager(), (unsigned long)this);
        scale = pRejillaBuilder->GetEscalaX();
        delete pRejillaBuilder;
        return scale;
}

double GNC::MetricGridTool::GetScaleY()
{
        double scale = 50.0;
        GNC::GCS::Widgets::WRejillaBuilder* pRejillaBuilder = new GNC::GCS::Widgets::WRejillaBuilder(WidgetsContract->GetManager(), (unsigned long)this);
        scale = pRejillaBuilder->GetEscalaY();
        delete pRejillaBuilder;
        return scale;
}


#endif
