/*
*  
*  $Id: gwaveformview.cpp $
*  Ginkgo CADx Project
*
*  Copyright 2008-14 MetaEmotion S.L. All rights reserved.
*  http://ginkgo-cadx.com
*
*  This file is licensed under LGPL v3 license.
*  See License.txt for details
*
*
*/
#include "gwaveformview.h"
#include <main/controllers/configurationcontroller.h>
#include <main/entorno.h>
#include <eventos/modificacionimagen.h>
#include <eventos/modificacionwidget.h>
#include <eventos/render.h>
#include <wx/pen.h>
#include <wx/wxginkgotoolbar.h>
#include <api/iannotator.h>
#include <wx/ginkgostyle/ginkgostyle.h>

#include <visualizator/vistas/waveformview.h>
#include <visualizator/estudios/visualizatorstudy.h>
#include <main/controllers/commandcontroller.h>
#include <api/controllers/ieventscontroller.h>
#include <api/controllers/icontroladorvistas.h>
#include <api/iwidgetsrenderer.h>
#include <api/iwidgetsmanager.h>
#include <visualizator/widgets/wecg.h>
#include <vtk/widgets/widgetsactor.h>
#include <widgets/wanotacionesquina.h>

#include <resources/visualizatorresourcesmanager.h>
#include <export/tools/iherramientascore.h>
#include <export/contracts/iwidgetscontract.h>
#include <export/contracts/irulecontract.h>
#include <api/toolsystem/itoolcontroller.h>
#include <api/toolsystem/itool.h>

#define ANNOTATOR_TEXT_COLOR 0.1f, 0.1f, 0.1f, 1.0f

#define ID_BUTTON_METADATA 0
#define ID_BUTTON_CORNER_ANNOTATIONS 1

namespace GNKVisualizator 
{
	namespace GUI 
	{		
		class GWaveformViewDelegate: public GNC::GCS::IRuleContract
		{
		public:
			GWaveformViewDelegate(GWaveformView* gView):GView(gView)
			{
			}
			~GWaveformViewDelegate()
			{
			}

			//contrato widgets
			vtkGinkgoImageViewer* GetViewerActivo()
			{
				return GView->ViewImage2D;
			}


			GNC::GCS::IWidgetsManager* GetManager()
			{ 
				return GView->m_pManager; 
			}

			virtual bool SupportsCallibration()
			{
				return false;
			}
		protected:
			GWaveformView* GView;
		};
		////////////////////GWaveform annotator delegate
		class GWaveformAnnotatorDelegate: public GNC::GCS::IAnnotator
		{
		public:
			GWaveformAnnotatorDelegate(GWaveformView* gView, GNKVisualizator::WaveFormView* pView):GNC::GCS::IAnnotator(pView),
				GView(gView)
			{
			}
			~GWaveformAnnotatorDelegate()
			{
			}

			virtual std::string GetAnnotationValue(GNC::GCS::Contexto3D* c, const std::string& key)
			{
				if (key == "${SLICE.WL.FULLTEXT}") {
					return "";
				} else if (key == "${SLICE.IDX.FULLTEXT}") {
					return "";
				} else if (key == "${VIEW.COORDLABELS}") {
					std::ostringstream os;
					os << "25 mm/s, 10 mm/mV";
					return os.str();
				}
				return GNC::GCS::IAnnotator::GetAnnotationValue(c, key);
			}



		protected:
			GWaveformView* GView;
		};
				
		/* Constructor */
		GWaveformView::GWaveformView(GNKVisualizator::WaveFormView* pView) : GWaveformViewBase(pView->GetEstudio()->ParentWindow),
				Delegate(new GWaveformViewDelegate(this)),
				AnnotatorDelegate(new GWaveformAnnotatorDelegate(this, pView))
		{
			View = pView;
			WECG = NULL;

			ViewImage2D->SetBackgroundColor(0.0f,0.0f,0.0f);
			ViewInteractor2D->m_pImageViewer = ViewImage2D;
			View->GetEstudio()->SetViewer(ViewImage2D);
			ViewImage2D->SetInputConnection(View->GetEstudio()->renderConnection);
			ViewImage2D->SetShowAnnotations(false);
			ViewImage2D->SetInteractionStyle(vtkGinkgoImageViewer::ZOOM_INTERACTION);

			// Setup del manejador de widgets */
			m_pManager = GNC::GCS::IEntorno::Instance()->NewWidgetsManager(View);
			m_pManager->SetAnnotator(AnnotatorDelegate);
			ViewInteractor2D->SetManager(m_pManager);
			ViewInteractor2D->SetVID(0,false);
			m_pManager->SetRendererActivo(ViewInteractor2D);
			
			WidgetRepresentation* pWidgetsRepresentation = WidgetRepresentation::New();
			pWidgetsRepresentation->SetRenderer(ViewInteractor2D->FindPokedRenderer(0,0));
			ViewInteractor2D->FindPokedRenderer(0,0)->AddViewProp(pWidgetsRepresentation);
			ViewInteractor2D->SetRepresentation(pWidgetsRepresentation);
			pWidgetsRepresentation->SetWidgetsManager(m_pManager);
			pWidgetsRepresentation->SetWidgetsRenderer(ViewInteractor2D);
			pWidgetsRepresentation->Delete();
			
			//toolbar
			GNC::GCS::IToolController* pToolBar = View->GetToolController();
			//widgets...
			pToolBar->AddTool(HCore_Pointer, (GNC::GCS::IWidgetsContract*) Delegate);
			pToolBar->AddTool(HCore_Zoom, (GNC::GCS::IWidgetsContract*) Delegate);
			pToolBar->AddTool(HCore_Pan, (GNC::GCS::IWidgetsContract*) Delegate);
			pToolBar->AddTool(HCore_Angulo, (GNC::GCS::IWidgetsContract*) Delegate);
			pToolBar->AddTool(HCore_Rule, (GNC::GCS::IRuleContract*) Delegate);
			pToolBar->AddTool(HCore_Nota, (GNC::GCS::IWidgetsContract*) Delegate);
			pToolBar->AddTool(HCore_Marcado, (GNC::GCS::IWidgetsContract*) Delegate);
			//view menu...
			pToolBar->AddTool(HCore_CornerAnnotations, (GNC::GCS::IWidgetsContract*) Delegate);
			#if !defined(__WXGTK__)
			pToolBar->AddTool(HCore_DetachWindow, (GNC::GCS::IViewContract*) View);
			#endif
			pToolBar->AddTool(HCore_MetricGrid, (GNC::GCS::IWidgetsContract*) Delegate);
			pToolBar->AddTool(HCore_Reset, (GNC::GCS::IWidgetsContract*) Delegate);

			pToolBar->AddTool(HCore_SecondaryCapture, (GNC::GCS::IWidgetsContract*) Delegate);
			//tools
			pToolBar->AddTool(HCore_ShowDicomTags, (GNC::GCS::IViewContract*) View);
			pToolBar->AddTool(HCore_ShowHistory, (GNC::GCS::IViewContract*) View);
			pToolBar->AddTool(HCore_PACSUpload, (GNC::GCS::IViewContract*) View);
			pToolBar->AddTool(HCore_Deshacer, (GNC::GCS::IViewContract*) View);
			m_pSizerTools->Add(pToolBar->CreateNewToolBar(this, GNC::GCS::ITool::TFamiliaVisualizacion), 0, wxEXPAND);
			m_pSizerTools->Add(pToolBar->CreateNewToolBar(this, GNC::GCS::ITool::TFamiliaMedicion), 0, wxEXPAND);
			m_pSizerTools->Add(pToolBar->CreateNewToolBar(this, GNC::GCS::ITool::TFamiliaAnotacion), 0, wxEXPAND);

			{
				GNC::GCS::IToolController::TIdList listids;
				listids.push_back(HCore_ShowHistory);
				wxWindow* pwxToolBar = pToolBar->CreateNewToolBar(this, listids, false);
				m_pSizerTools->Add(pwxToolBar, 1, wxEXPAND);
			}

			//events
			GNC::GCS::Events::EventoModificacionImagen ev2(View);
			GNC::GCS::Events::EventoModificacionWidget ev3(View);
			GNC::GCS::Events::EventoRender ev4(View);

			m_pButtonBar = new wxGinkgoToolBar(m_pManipulationPanel, wxColour(0x40, 0x40, 0x40));
			m_pButtonBar->AddTool(ID_BUTTON_METADATA,_("Show/Hide metadata"),GNKVisualizator::ResourcesManager::ToolIcons::GetIcoECGMetadata(),_("Show/Hide metadata"));
			m_pButtonBar->Connect(ID_BUTTON_METADATA,wxEVT_COMMAND_TOOL_CLICKED, wxCommandEventHandler( GWaveformView::OnShowHideMetadata),NULL,this);

			{
				GNC::GCS::IToolController::TIdList toolsLeft;
				toolsLeft.push_back(HCore_CornerAnnotations);
				wxWindow* toolBarLeft = pToolBar->CreateNewToolBar(m_pManipulationPanel, toolsLeft);
				m_pSizerRight->Add(toolBarLeft,0, wxALIGN_CENTER_VERTICAL|wxEXPAND,0);	
			}

			m_pButtonBar->Realize();
			m_pSizerRight->Add(m_pButtonBar,0, wxALIGN_CENTER_VERTICAL|wxEXPAND,0);

			//connect key events..
			pToolBar->ConnectKeyEvents(this);
			
			GNC::GCS::IEntorno::Instance()->GetControladorEventos()->Registrar(this, ev2);
			GNC::GCS::IEntorno::Instance()->GetControladorEventos()->Registrar(this, ev3);
			GNC::GCS::IEntorno::Instance()->GetControladorEventos()->Registrar(this, ev4);

			bool showMetadata = false;
		// if metadata is shown at start, zoom will be broken
		//	GNC::GCS::ConfigurationController::Instance()->readBoolUser("/GNKVisualizator/ECGView", "ShowMetadata", showMetadata, true);
			ShowMetaData(showMetadata);
			
			this->Connect(wxEVT_CHILD_FOCUS, wxChildFocusEventHandler(GWaveformView::OnFocus),NULL,this);
			
			Layout();
		}

		GWaveformView::~GWaveformView()
		{
			this->Disconnect(wxEVT_CHILD_FOCUS, wxChildFocusEventHandler(GWaveformView::OnFocus),NULL,this);
			if (View != NULL) {
				GNC::GCS::IEntorno::Instance()->GetCommandController()->AbortarComandosDeOwner(View);
			}			
			View->GetToolController()->FinalizeToolController();
			m_pManager->EliminarTodosLosWidgets(false);
			
			ViewInteractor2D->SetRepresentation(NULL);

			GNC::GCS::IEntorno::Instance()->FreeWidgetsManager(m_pManager);
			m_pManager = NULL;
			
			ViewImage2D->Detach();
			ViewImage2D->Delete();
			ViewImage2D = NULL;

			ViewInteractor2D->Delete();
			ViewInteractor2D = NULL;

			View->Lock();
			delete View;
		}

		void GWaveformView::InitPipeline()
		{
			ViewImage2D->SetInputConnection(View->GetEstudio()->renderConnection);

			m_pComboGroups->Clear();

			std::list<std::string> listOfLabels = View->GetECGStudy()->GetLabelOfMultiplexGroups();
			for (std::list<std::string>::iterator it = listOfLabels.begin(); it != listOfLabels.end(); ++it) {
				m_pComboGroups->AppendString(wxString::FromUTF8((*it).c_str()));
			}
			m_pComboGroups->Select(0);

			if(ViewImage2D != NULL) {
				// FIXME: Comprobar si el pipeline esta conectado.
				ViewImage2D->SetupPipeline();
				
				WECG = new GNKVisualizator::Widgets::WECG(GetManager(), 0);
					GetManager()->InsertarWidget(WECG, false);
				
				if (!View->GetECGStudy()->Ok()) {
					wxMessageBox(_("Error loading study with ecg view"), _("Error"), wxOK, NULL);
				} else {
					WECG->Reload(View->GetECGStudy()->GetListOfChannels());
					WECG->AutoCallibrate();

					m_pTextDiagnosis->SetValue(wxString::FromUTF8(View->GetECGStudy()->GetDiagnosis().c_str()));
					m_pTextMeasurements->SetValue(wxString::FromUTF8(View->GetECGStudy()->GetGlobalMeasurement().c_str()));

					//change color to widget anotacionesesquina
					for( GNC::GCS::ListaWidgets::iterator it = m_pManager->GetListaWidgets().begin(); it != m_pManager->GetListaWidgets().end(); ++it) {
						GNC::GCS::Widgets::IWidget* w = *it;
						if (w->GetVID() == -1) {
							GNC::GCS::Widgets::WAnotador* wac = dynamic_cast<GNC::GCS::Widgets::WAnotador*> (w);
							if (wac != NULL) {
								wac->SetTextColor(GNC::GCS::GLHelper::TColor(ANNOTATOR_TEXT_COLOR));
							}
						}
					}
				}		
			}
		}

		void GWaveformView::StopPipeline()
		{
			m_pManager->OcultarTodosLosWidgets(true, 666);
			m_pManager->DisableAnimation();
			m_pManager->Render();
		}

		void GWaveformView::OnFinishLoad()
		{
			View->GetToolController()->InitializeToolController();
			m_pManager->OcultarTodosLosWidgets(true, 666);
			m_pManager->DisableAnimation();
			m_pManager->Render();
		}

		vtkGinkgoImageViewer* GWaveformView::GetViewerActivo()
		{
			return ViewImage2D;
		}
		
		GNC::GCS::IWidgetsManager* GWaveformView::GetManager()
		{ 
			return m_pManager; 
		}

		void GWaveformView::OnPaint(wxPaintEvent& event)
		{
			//std::cout << "GVistaCompleja::OnPaint()" << std::endl;
			GWaveformViewBase::OnPaint(event);
			if(GNC::GCS::IEntorno::Instance()->GetControladorVistas()->GetVistaActiva() == View)
			{
				wxPaintDC dc(this);
				wxColour colorLineaSeleccion(219, 219, 0, 255);
				dc.SetBrush(wxBrush(colorLineaSeleccion,wxTRANSPARENT));
				dc.SetPen(wxPen(colorLineaSeleccion, 3, wxSOLID));
				dc.DrawRectangle(wxRect(wxPoint(1, 1), wxPoint(dc.GetSize().x-1, dc.GetSize().y-1)));
			}
		}
	
		void GWaveformView::OnComboGroup(wxCommandEvent &)
		{
			View->GetECGStudy()->SetIndexOfActualMultiplexGroup(m_pComboGroups->GetSelection());
			WECG->Reload(View->GetECGStudy()->GetListOfChannels());
			WECG->AutoCallibrate();

			m_pTextDiagnosis->SetValue(wxString::FromUTF8(View->GetECGStudy()->GetDiagnosis().c_str()));
			m_pTextMeasurements->SetValue(wxString::FromUTF8(View->GetECGStudy()->GetGlobalMeasurement().c_str()));
		}

		void GWaveformView::OnShowHideMetadata(wxCommandEvent &)
		{
			ShowMetaData(!m_pPanelMetadata->IsShown());
			GNC::GCS::ConfigurationController::Instance()->writeBoolUser("/GNKVisualizator/ECGView", "ShowMetadata", m_pPanelMetadata->IsShown());
		}

		void GWaveformView::ShowMetaData(bool show)
		{
			if (show && ! m_pSplitterPanel->IsSplit()) {
				//show
				m_pSplitterPanel->SplitHorizontally(m_pPanelView, m_pPanelMetadata, -100);
			} else if (!show && m_pSplitterPanel->IsSplit()) {
				//hide
				m_pSplitterPanel->Unsplit(m_pPanelMetadata);
			}
		}

		void GWaveformView::OnShowHideCornerAnnotations(wxCommandEvent &)
		{
			m_pManager->ShowAnnotations(!m_pManager->IsShownAnnotations());			
			GNC::GCS::IEntorno::Instance()->GetControladorEventos()->ProcesarEvento(new GNC::GCS::Events::EventoRender(View));
		}


		void GWaveformView::OnFocus(wxChildFocusEvent &)
		{
			if (View != NULL) {
				View->OnFocus();
			}
		}

		void GWaveformView::PreProcesarEvento(GNC::GCS::Events::IEvent* evt, std::list<GNC::GCS::Events::IEvent*>& lista)
		{
			if (evt == NULL) {
				std::cerr << "Error: Evento nulo" << std::endl;
				return;
			}
			switch (evt->GetCodigoEvento()) {
				case ginkgoEVT_Core_ModificacionImagen:
					{
						GNC::GCS::Events::EventoModificacionImagen* pEvt = dynamic_cast<GNC::GCS::Events::EventoModificacionImagen*>(evt);
						if (pEvt == NULL) {
							std::cerr << "Error al interpretar evento como evento de modificación de imagen: Evento = " << evt << std::endl;
							return;
						}
						switch (pEvt->GetTipo()) {
							case GNC::GCS::Events::EventoModificacionImagen::ImagenRecalibrada:
								{
									lista.push_back(new GNC::GCS::Events::EventoModificacionImagen(View,GNC::GCS::Events::EventoModificacionImagen::ImagenCargada, -1));
								}
								break;
							default:
								break;
						}
						if (pEvt->GetApilarRender()) {
							lista.push_back(new GNC::GCS::Events::EventoRender(View,pEvt->GetSliceAfectado()));
						}
					}
					break;
				default:
					break;
			}
		}

		void GWaveformView::ProcesarEvento(GNC::GCS::Events::IEvent *evt) 
		{
			switch (evt->GetCodigoEvento()) {
				case ginkgoEVT_Core_ModificacionImagen:
				{
					GNC::GCS::Events::EventoModificacionImagen* pEvt = dynamic_cast<GNC::GCS::Events::EventoModificacionImagen*>(evt);
					if (pEvt == NULL) {
						std::cerr << "Error al interpretar evento como evento de modificación de imagen: Evento = " << evt << std::endl;
						return;
					}
					switch (pEvt->GetTipo()) {
						case GNC::GCS::Events::EventoModificacionImagen::ImagenModificada:
						case GNC::GCS::Events::EventoModificacionImagen::ImagenCargada:
						case GNC::GCS::Events::EventoModificacionImagen::SliceCambiado:
								{
									ViewImage2D->Modified();
									GNC::GCS::IEntorno::Instance()->GetControladorEventos()->ProcesarEvento(new GNC::GCS::Events::EventoModificacionImagen(View,GNC::GCS::Events::EventoModificacionImagen::AnotacionesEstaticasModificadas));
									if (View->GetECGStudy()->Ok()) {
										WECG->Reload(View->GetECGStudy()->GetListOfChannels());
									}
								}
								break;
						case GNC::GCS::Events::EventoModificacionImagen::ImagenRecalibrada:
							{
								View->GetEstudio()->RecalibrateActiveImage(pEvt->GetNewSpacing(), pEvt->GetNewOrigin());
							}
						break;
						case GNC::GCS::Events::EventoModificacionImagen::VisualizacionImagenModificada:
							{
								//para que pille bien el window/level
								if(pEvt->ResetZoom())
								{
									ViewImage2D->ResetZoom(false, pEvt->GetResetZoomMode());
								}
								GNC::GCS::IEntorno::Instance()->GetControladorEventos()->ProcesarEvento(new GNC::GCS::Events::EventoModificacionImagen(View,GNC::GCS::Events::EventoModificacionImagen::AnotacionesEstaticasModificadas));
							}
						break;
						case GNC::GCS::Events::EventoModificacionImagen::ImagenDescargada:
							{
							}
						break;
						
						case GNC::GCS::Events::EventoModificacionImagen::MapaModificado:
						case GNC::GCS::Events::EventoModificacionImagen::AnotacionesEstaticasModificadas:
						break;
					}
				}//fin modificacion
				break;

				case ginkgoEVT_Core_Render:
					{
						ViewInteractor2D->Refresh(false);
					}
					break;
				default:
					break;
			}			
		}
	}
}
