/*
 * 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 "simpleprinttool.h"
#include <export/contracts/iwidgetscontract.h>
#include <api/controllers/ieventscontroller.h>
#include <eventos/modificacionimagen.h>
#include <eventos/render.h>
#include <api/iwidgetsmanager.h>
#include <api/ivista.h>
#include <main/entorno.h>
#include <main/controllers/commandcontroller.h>
#include <main/controllers/controladorlog.h>
#include <main/gui/toolsystem/wxmenuitemtool.h>

#ifdef __DEPRECATED
#undef __DEPRECATED
#endif

#include <vtk/vtkginkgoimageviewer.h>

#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkSmartPointer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderer.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkPolyData.h>
#include <vtkSphereSource.h>
#include <vtkWindowToImageFilter.h>
#include <vtkJPEGWriter.h>

#include <resources/ginkgoresourcesmanager.h>

#include <wx/bitmap.h>
#include <wx/image.h>
#include <wx/dataobj.h>
#include <wx/filename.h>
#include <wx/textfile.h>
#include <wx/print.h>
#include <wx/printdlg.h>

#define SIMPLE_SETUP  1876
#define SIMPLE_PRINT  1877
#define SIMPLE_PRINT_PREVIEW  1878

namespace GNC
{
namespace GUI
{
class wxEventHandlerSimplePrint : public wxEvtHandler
{
public:
        wxEventHandlerSimplePrint(wxEvtHandler* pParent, GNC::SimplePrintTool* pHerramienta):wxEvtHandler()
        {
                m_pEvtParent = pParent;
                m_pHerramienta=pHerramienta;

                m_pEvtParent->Connect(SIMPLE_SETUP, wxEVT_UPDATE_UI, wxUpdateUIEventHandler(wxEventHandlerSimplePrint::OnUpdateUI),NULL,this);
                m_pEvtParent->Connect(SIMPLE_PRINT, wxEVT_UPDATE_UI, wxUpdateUIEventHandler(wxEventHandlerSimplePrint::OnUpdateUI),NULL,this);
                m_pEvtParent->Connect(SIMPLE_PRINT_PREVIEW, wxEVT_UPDATE_UI, wxUpdateUIEventHandler(wxEventHandlerSimplePrint::OnUpdateUI),NULL,this);

                m_pEvtParent->Connect(SIMPLE_SETUP, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( wxEventHandlerSimplePrint::OnSetup),NULL,this);
                m_pEvtParent->Connect(SIMPLE_PRINT, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(wxEventHandlerSimplePrint::OnPrint),NULL,this);
                m_pEvtParent->Connect(SIMPLE_PRINT_PREVIEW, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(wxEventHandlerSimplePrint::OnPrintPreview),NULL,this);
        }

        ~wxEventHandlerSimplePrint()
        {
                m_pEvtParent->Disconnect(SIMPLE_SETUP, wxEVT_UPDATE_UI, wxUpdateUIEventHandler(wxEventHandlerSimplePrint::OnUpdateUI),NULL,this);
                m_pEvtParent->Disconnect(SIMPLE_PRINT, wxEVT_UPDATE_UI, wxUpdateUIEventHandler(wxEventHandlerSimplePrint::OnUpdateUI),NULL,this);
                m_pEvtParent->Disconnect(SIMPLE_PRINT_PREVIEW, wxEVT_UPDATE_UI, wxUpdateUIEventHandler(wxEventHandlerSimplePrint::OnUpdateUI),NULL,this);

                m_pEvtParent->Disconnect(SIMPLE_SETUP, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( wxEventHandlerSimplePrint::OnSetup),NULL,this);
                m_pEvtParent->Disconnect(SIMPLE_PRINT, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(wxEventHandlerSimplePrint::OnPrint),NULL,this);
                m_pEvtParent->Disconnect(SIMPLE_PRINT_PREVIEW, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(wxEventHandlerSimplePrint::OnPrintPreview),NULL,this);
                m_pEvtParent = NULL;
                m_pHerramienta = NULL;
        }

        void OnPrint( wxCommandEvent& event )
        {
                m_pHerramienta->doPrint();
                event.Skip(false);
        }

        void OnSetup( wxCommandEvent& event )
        {
                m_pHerramienta->doSetup();
                event.Skip(false);
        }

        void OnPrintPreview(wxCommandEvent& event)
        {
                m_pHerramienta->doPrintPreview();
                event.Skip(false);
        }

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


        GNC::SimplePrintTool* m_pHerramienta;
        wxEvtHandler* m_pEvtParent;
};
}

///////printout helper
class ginkgoPrintOutImage: public wxPrintout
{
public:
        ginkgoPrintOutImage(const wxImage& im):wxPrintout(_("Image printing")),img(im)
        {
        }

        ~ginkgoPrintOutImage()
        {
        }

        virtual bool HasPage(int page)
        {
                return page == 1;
        }

        virtual void GetPageInfo(int *minPage, int *maxPage, int *pageFrom, int *pageTo)
        {
                *minPage = *maxPage = *pageFrom = *pageTo= 1;
        }

        virtual bool OnPrintPage(int /*page*/)
        {
                wxDC *dc = GetDC();
                if (dc) {
                        //limpioi
                        dc->SetBackground(*wxWHITE_BRUSH);
                        dc->Clear();
                        if (img.IsOk()) {
                                wxSize pageSize = this->GetLogicalPageRect().GetSize();
                                wxSize imgSize = img.GetSize();

                                bool resample = false;

                                if (imgSize.x > pageSize.x || imgSize.y > pageSize.y) {
                                        //downscale
                                        if (imgSize.x > pageSize.x) {
                                                imgSize.y = ((double)pageSize.x/imgSize.x)*imgSize.y;
                                                imgSize.x = pageSize.x;
                                                resample = true;
                                        }
                                        if (imgSize.y > pageSize.y) {
                                                imgSize.x = ((double)pageSize.y/imgSize.y)*imgSize.x;
                                                imgSize.y = pageSize.y;
                                                resample = true;
                                        }
                                } else {
                                        //upscale
                                        if (((float)imgSize.x/pageSize.x) > ((float)imgSize.y/pageSize.y)) {
                                                imgSize.y = ((double)pageSize.x/imgSize.x)*imgSize.y;
                                                imgSize.x = pageSize.x;
                                                resample = true;
                                        } else {
                                                imgSize.x = ((double)pageSize.y/imgSize.y)*imgSize.x;
                                                imgSize.y = pageSize.y;
                                                resample = true;
                                        }
                                }

                                if (resample) {
                                        img.Rescale(imgSize.x, imgSize.y, wxIMAGE_QUALITY_BILINEAR);
                                }
                                dc->DrawBitmap( img, 0, 0 );
                        }

                        return true;
                } else {
                        return false;
                }
        }


        wxImage img;
};
}


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

GNC::SimplePrintTool::SimplePrintTool()
{
        pData = new wxPrintData();
}
GNC::SimplePrintTool::~SimplePrintTool()
{
        delete pData;
}

bool GNC::SimplePrintTool::ExecuteAction()
{
        return false;
}

bool GNC::SimplePrintTool::HasDropDownMenu()
{
        return true;
}

void GNC::SimplePrintTool::AppendDropDownMenu(wxEvtHandler* pParent, wxMenu* pMenu)
{
        if (pMenu->GetMenuItemCount() > 0 && !pMenu->GetMenuItems().back()->IsSeparator()) {
                pMenu->AppendSeparator();
        }
        pMenu->Append(new GNC::GUI::wxMenuItemTool(pMenu, SIMPLE_SETUP, _("Page setup") + wxString(wxT("...")), wxNullBitmap, new GNC::GUI::wxEventHandlerSimplePrint( pParent, this)));
        pMenu->Append(new GNC::GUI::wxMenuItemTool(pMenu, SIMPLE_PRINT_PREVIEW, _("Print preview") + wxString(wxT("...")), wxNullBitmap, new GNC::GUI::wxEventHandlerSimplePrint( pParent, this)));
        pMenu->Append(new GNC::GUI::wxMenuItemTool(pMenu, SIMPLE_PRINT, _("Print") + wxString(wxT("...")), GinkgoResourcesManager::MenuIcons::GetIcoImpresora(), new GNC::GUI::wxEventHandlerSimplePrint( pParent, this)));
}

void GNC::SimplePrintTool::AppendToolIn(wxEvtHandler* pParent, wxMenu* pMenu)
{
        if (AppendsInMenu()) {
                AppendDropDownMenu(pParent, pMenu);
        }
}

wxImage getImage(const vtkSmartPointer<vtkRenderWindow>& rendWin)
{
        if (rendWin == NULL) {
                return wxNullImage;
        }
        vtkSmartPointer<vtkWindowToImageFilter> windowToImageFilter =
                vtkSmartPointer<vtkWindowToImageFilter>::New();
        windowToImageFilter->SetInput(rendWin);

        windowToImageFilter->SetInputBufferTypeToRGB(); //also record the alpha (transparency) channel
        windowToImageFilter->Update();
        //copy image to wx...
        // put the pixels into a wxImage ...
        vtkSmartPointer<vtkImageData> timg = windowToImageFilter->GetOutput();
        unsigned char *pVtkPix = (unsigned char *)timg->GetScalarPointer();

        unsigned long imgsize = timg->GetDimensions()[0] * timg->GetDimensions()[1] * sizeof(unsigned char) * 3;
        unsigned char* data = new unsigned char[imgsize];
        int linesize = timg->GetDimensions()[0] *3;
        for (int y = 0; y < timg->GetDimensions()[1]; ++y) {
                int offsetWx = imgsize - (linesize * (y +1));
                int offsetVtk = y*linesize;
                for (int x = 0; x < linesize; ++x) {
                        data[offsetWx+x] = pVtkPix[offsetVtk+x];
                }
        }

        return wxImage(timg->GetDimensions()[0], timg->GetDimensions()[1],data,false);
}

void GNC::SimplePrintTool::doPrintPreview()
{
        wxImage image = getImage(WidgetsContract->GetViewerActivo()->GetRenderWindow());
        if (image.IsOk()) {
                wxPrintPreview* myPrintPreview = new wxPrintPreview(new ginkgoPrintOutImage(image), new ginkgoPrintOutImage(image), pData);
                wxPreviewFrame *frame = new wxPreviewFrame(myPrintPreview, WidgetsContract->GetManager()->GetVista()->GetWindow(),
                                _("Print image"), wxDefaultPosition, wxSize(800, 600));
                frame->InitializeWithModality(wxPreviewFrame_WindowModal);
                frame->Show(true);
                frame->Show(true);
        }
}

void GNC::SimplePrintTool::doPrint()
{
        wxImage image = getImage(WidgetsContract->GetViewerActivo()->GetRenderWindow());
        if (image.IsOk()) {
                wxPrintDialogData dlgData(*pData);
                wxPrinter printer(&dlgData);
                ginkgoPrintOutImage prOut(image);
                printer.Print(WidgetsContract->GetManager()->GetVista()->GetWindow(), &prOut);
        }
}

void GNC::SimplePrintTool::doSetup()
{
        wxPageSetupDialogData dlgData(*pData);
        wxPageSetupDialog dlg(WidgetsContract->GetManager()->GetVista()->GetWindow(), &dlgData);
        dlg.ShowModal();
}

