/*
*  
*  $Id: gwaveformview.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 "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/aui/auibar.h>
#include <wx/ginkgostyle/ginkgostyle.h>

#include <visualizator/vistas/waveformview.h>
#include <visualizator/estudios/visualizatorstudy.h>
#include <api/controllers/icommandscontroller.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;
		};
		//esta clase sirve para las barras de herramientas de abajo
		class GWaveformViewButtonBar:public wxAuiToolBar{
		public:
			GWaveformViewButtonBar(wxWindow* pParent, const wxColor& color = wxColor(0x40, 0x40, 0x40)): wxAuiToolBar(pParent,wxID_ANY, wxDefaultPosition, wxDefaultSize, wxAUI_TB_DEFAULT_STYLE)
			{
				SetToolBitmapSize(wxSize(16,16));
				AUI_NAMESPACE wxAuiDefaultToolBarArt* pToolArt= new AUI_NAMESPACE wxAuiDefaultToolBarArt();
		#if defined(USE_PATCHED_LIBS) && !defined(__WXOSX__)
				pToolArt->SetBaseColor(color);
		#endif
				SetArtProvider(pToolArt);
			}

			~GWaveformViewButtonBar()
			{
			}
		};
		
		/* Constructor */
		GWaveformView::GWaveformView(GNKVisualizator::WaveFormView* pView) : GWaveformViewBase(pView->GetEstudio()->ParentWindow),
				Delegate(new GWaveformViewDelegate(this))
		{
			Freeze();
			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);
			ViewInteractor2D->SetManager(m_pManager);
			ViewInteractor2D->SetVID(0,false);
			m_pManager->SetRendererActivo(ViewInteractor2D);

			m_pManager->CrearWidgetAnotador(this);

			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);
			pToolBar->AddTool(HCore_DetachWindow, (GNC::GCS::IViewContract*) View);
			pToolBar->AddTool(HCore_MetricGrid, (GNC::GCS::IWidgetsContract*) Delegate);
			pToolBar->AddTool(HCore_Reset, (GNC::GCS::IWidgetsContract*) Delegate);
			//tools
			pToolBar->AddTool(HCore_ShowDicomTags, (GNC::GCS::IViewContract*) View);
			pToolBar->AddTool(HCore_ShowHistory, (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 GWaveformViewButtonBar(m_pManipulationPanel);
			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);
			
			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();
			Thaw();
		}


		GWaveformView::~GWaveformView()
		{
			this->Disconnect(wxEVT_CHILD_FOCUS, wxChildFocusEventHandler(GWaveformView::OnFocus),NULL,this);
			if (View != NULL) {
				GNC::GCS::IEntorno::Instance()->GetControladorComandos()->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);
				
				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 &event)
		{
			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 &event)
		{
			m_pManager->MostrarOcultarAnotador();			
			GNC::GCS::IEntorno::Instance()->GetControladorEventos()->ProcesarEvento(new GNC::GCS::Events::EventoRender(View));
		}


		//IAnotador
		std::string GWaveformView::GetDICOMTag(std::string tagId)
		{
			std::string str("");
			View->GetEstudio()->GetTagActiveImage(tagId,str);

			return str;
		}

		std::string GWaveformView::GetTopLeftAnnotation(GNC::GCS::Contexto3D* c)
		{
			if (!this->ViewImage2D->IsInstalledAndInitialized() || View == NULL)
				return "";

			std::ostringstream os;
			std::string tag;

			tag = "0010|0010"; // Patient's Name

			os << _Std("Patient: ") << GetDICOMTag(tag).c_str() << std::endl;

			tag = "0010|0020"; // Patient's ID

			os << _Std("Patient Id: ") << GetDICOMTag(tag).c_str();

			return os.str();
		}

		std::string GWaveformView::GetTopRightAnnotation(GNC::GCS::Contexto3D* c)
		{
			if (!this->ViewImage2D->IsInstalledAndInitialized() || View == NULL)
				return "";

			std::ostringstream os;
			std::string tag;
			std::string str;

			tag = "0010|0040"; // Patient's Sex

			os << GetDICOMTag(tag).c_str() << " ";

			tag = "0010|0030"; // Patient's BirthDate
			str = GetDICOMTag(tag);
			if (str.size() == 8) {
				os << str.substr(6, 2).c_str() << "-";
				os << str.substr(4, 2).c_str() << "-";
				os << str.substr(0, 4).c_str() << " ";
			}

			tag = "0010|1010"; // Patient's Age
			str = GetDICOMTag(tag);
			if(str.size() > 0) {
				os << str.c_str() << "Y" << std::endl;
			}

			tag = "0008|0060"; // Modalidad
			os << _Std("Modality: ") << GetDICOMTag(tag).c_str() << std::endl;

			tag = "0008|0021"; // Series Date
			str = GetDICOMTag(tag);
			if (str.size() == 8) {
				os << str.substr(6, 2).c_str() << "-";
				os << str.substr(4, 2).c_str() << "-";
				os << str.substr(0, 4).c_str() << " ";
			}
			os<<std::endl;

			tag = "0008|103e"; // Series Description
			str = GetDICOMTag(tag);
			if (!str.empty()) {
				if(str.size()<18){
					os << str.c_str();
				}else {
					os << str.substr(0,18).c_str()<<"...";
				}
			}

			return os.str();
		}

		std::string GWaveformView::GetBottomLeftAnnotation(GNC::GCS::Contexto3D* c)
		{
			
			if (!this->ViewImage2D->IsInstalledAndInitialized() || View == NULL)
				return "";

			std::ostringstream os;
			std::string tag;
			std::string str;

			tag = "0008|0020"; // study Date
			str = GetDICOMTag(tag);
			if (str.size() == 8) {
				os << str.substr(6, 2).c_str() << "-";
				os << str.substr(4, 2).c_str() << "-";
				os << str.substr(0, 4).c_str() << " ";
			}
			os<<std::endl;

			tag = "0008|1030"; // Study Description
			str = GetDICOMTag(tag);
			if (!str.empty()) {
				if(str.size()<18){
					os << str.c_str()<<std::endl;
				}else {
					os << str.substr(0,18).c_str()<<"..."<<std::endl;
				}
			}

			tag = "0008|0080"; // Nombre del centro, si viene el centro en el estudio se pone si no el d los tags estaticos
			str = GetDICOMTag(tag);
			if (str.size() == 6) {
				os << str.substr(0, 2).c_str() << ":";
			} else {
				std::string tag;
				GNC::GCS::ConfigurationController::Instance()->readStringGeneral("/GinkgoCore/Estacion", "CentroNombre", tag);

				if (!tag.empty()) {
					os << tag.c_str() << std::endl;
				}
			}
			
			
			wxString appName ( wxString::FromUTF8(GNC::GCS::IEntorno::Instance()->GetApplicationName().c_str()));
			wxString madewith( wxString::Format(_("Made with %s"), appName.c_str()));
			
			os << std::string(madewith.ToUTF8());
			return os.str();
		}

		std::string GWaveformView::GetBottomRightAnnotation(GNC::GCS::Contexto3D* c)
		{
			if (!this->ViewImage2D->IsInstalledAndInitialized() || View == NULL)
				return "";
			std::ostringstream os;
			os << "25 mm/s, 10 mm/mV";
			return os.str();
		}
		std::string GWaveformView::GetAnotacionPosicion(GNC::GCS::Vector* pPosicionRaton)
		{
			return "";
		}
		//end ianotador

		void GWaveformView::OnFocus(wxChildFocusEvent &event)
		{
			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));
									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;
			}			
		}
	}
}
