/*
 *  
 *  $Id$
 *  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 "ventanacontrolhl7.h"
#include <api/imodelohl7.h>

#include <main/controllers/controladorenviohl7.h>
#include <main/controllers/controladorbbddhl7.h>
#include <main/controllers/configurationcontroller.h>

#include <resources/ginkgoresourcesmanager.h>
#define LOGGER "VentanaControlHL7"
#include <main/controllers/controladorlog.h>

#include <main/entorno.h>
#include <wx/log.h>
#include <wx/msgdlg.h>
#include <set>

#define COL_FECHA           0
#define COL_DESTINO         1
#define COL_ESTADO          2
#define COL_MENSAJE_ERROR   3
#define COL_MENSAJE         4
#define COL_ID              5

namespace GNC {
	namespace GUI {
		/////////////////
		class DialogoMostrarMensaje: public GNC::GUI::DialogoMostrarMensajeBase
		{
		public:
			DialogoMostrarMensaje(wxWindow* pParent, const wxString& fecha, const wxString& url, const wxString& estado, const wxString& mensaje, const bool editar):DialogoMostrarMensajeBase(pParent)
			{
				m_pFecha->SetValue(fecha);
				m_pDestino->SetValue(url);
				m_pEstado->SetValue(estado);
				m_pContenido->SetValue(mensaje);
				if(editar) {
					m_pDestino->SetEditable(true);
					m_pContenido->SetEditable(true);
					m_pFecha->Disable();
					m_pEstado->Show(false);
					m_pChoiceEstado->Show(true);
					m_pChoiceEstado->Select(m_pChoiceEstado->FindString(estado));
				} else {
					m_CancelButton->Hide();
				}
			}
			~DialogoMostrarMensaje()
			{
			}

			std::string GetMensaje()
			{
				std::string mensaje(m_pContenido->GetValue().ToUTF8());
				return mensaje;
			}

			std::string GetDestino()
			{
				std::string destino(m_pDestino->GetValue().ToUTF8());
				return destino;
			}

			GIL::HL7::MensajeHL7::TEstado GetEstado()
			{
				switch(m_pChoiceEstado->GetSelection())
				{
					case 0:
						return GIL::HL7::MensajeHL7::TE_Enviado;
					case 1:
						return GIL::HL7::MensajeHL7::TE_Pendiente;
					case 2:
						return GIL::HL7::MensajeHL7::TE_Error;
					case 3:
						return GIL::HL7::MensajeHL7::TE_Warning;
				}
				return GIL::HL7::MensajeHL7::TE_Error;
			}

			virtual void OnKeyDown( wxKeyEvent& event )
			{
				if (event.GetKeyCode() == WXK_ESCAPE) {
					Close();
				}
				event.Skip();
			}

		};
		///////////////////
		class TimerControlHL7: public wxTimer {
		public:
			TimerControlHL7(VentanaControlHL7* pVentana)
			{
				m_pVentana = pVentana;
			}
			~TimerControlHL7()
			{
				m_pVentana = NULL;
			}
			virtual void Notify()
			{
				m_pVentana->Refrescar();
			}
			VentanaControlHL7* m_pVentana;
		};
		///////////////////

		VentanaControlHL7* VentanaControlHL7::m_pInstance = NULL;

		VentanaControlHL7* VentanaControlHL7::Instance()
		{
			if(m_pInstance == NULL) {
				m_pInstance = new VentanaControlHL7();
			}
			return m_pInstance;
		}

		void VentanaControlHL7::CerrarSiAbierta()
		{
			if(m_pInstance != NULL)
			{
				m_pInstance->Close(true);
			}
		}

		void VentanaControlHL7::Refrescar()
		{
			ActualizarEstadoControlador();
			RefrescarMensajes();
		}


		VentanaControlHL7::VentanaControlHL7():VentanaControlHL7Base(NULL)
		{
			Freeze();
			wxIcon icono;
			icono.CopyFromBitmap(GinkgoResourcesManager::Logos::GetLogoGinkgo32x32());
			this->SetIcon(icono);

			m_pLabelEnvio->SetLabel(wxString::FromUTF8("Proceso de envío:"));

			m_pTimerRefresh = new TimerControlHL7(this);

			ActualizarEstadoControlador();
			RefrescarMensajes();

			m_treeListCtrlMensajes->Connect(wxEVT_COMMAND_TREE_ITEM_MENU, wxTreeEventHandler( VentanaControlHL7::OnMensajeMenu ), NULL, this );
			m_treeListCtrlMensajes->Connect(wxEVT_COMMAND_TREE_ITEM_ACTIVATED, wxTreeEventHandler( VentanaControlHL7::OnMensajeDClick ), NULL, this );
			m_treeListCtrlMensajes->Connect(wxEVT_COMMAND_TREE_KEY_DOWN, wxTreeEventHandler( VentanaControlHL7::OnListaKey ), NULL, this );

			this->Connect( m_menuItemPurgarMensajes->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( VentanaControlHL7::OnPurgarMensajes ) );
			this->Connect( m_menuItemSalir->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( VentanaControlHL7::OnMenuSalir ) );
            this->Connect( m_menuItemActualizar->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( VentanaControlHL7::OnActualizar ) );

			Show();
			Layout();
			SetFocus();
			Thaw();
		}

		VentanaControlHL7::~VentanaControlHL7()
		{
			m_pInstance = NULL;
			if(m_pTimerRefresh != NULL) {
				delete m_pTimerRefresh;
				m_pTimerRefresh = NULL;
			}
		}

		void VentanaControlHL7::OnActivate(wxActivateEvent &event)
		{
			if(event.GetActive()){
				m_pTimerRefresh->Start(5000);
			} else {
					m_pTimerRefresh->Stop();
			}
		}

		void VentanaControlHL7::OnMensajeMenu(wxTreeEvent& )
		{
			//si hay un mensaje seleccionado..
			wxArrayTreeItemIds seleccionados;
			m_treeListCtrlMensajes->GetSelections(seleccionados);
			if(seleccionados.size() > 0) {
				wxMenu* popup = new wxMenu();
				wxMenuItem* pMenuMostrarVentana = new wxMenuItem(popup,wxID_ANY,_("Show Message"));
				wxMenuItem* pMenuEditarVentana = new wxMenuItem(popup,wxID_ANY,_("Edit Message"));
				wxMenuItem* pMenuEliminarMensaje = new wxMenuItem(popup,wxID_ANY,_("Delete message"));
				#ifdef __WXMSW__
				pMenuMostrarVentana->SetBitmaps( GinkgoResourcesManager::MenuIcons::GetIcoEditor());
				pMenuEliminarMensaje->SetBitmaps(GinkgoResourcesManager::MenuIcons::GetIcoEliminarWidget());
				#else
				pMenuMostrarVentana->SetBitmap(GinkgoResourcesManager::MenuIcons::GetIcoEditor());
				pMenuEliminarMensaje->SetBitmap(GinkgoResourcesManager::MenuIcons::GetIcoEliminarWidget());
				#endif
				popup->Append(pMenuMostrarVentana);
				popup->Append(pMenuEditarVentana);
				popup->Append(pMenuEliminarMensaje);
				popup->Connect(pMenuMostrarVentana->GetId(),wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( VentanaControlHL7::OnMostrarMensaje ), NULL, this  );
				popup->Connect(pMenuEditarVentana->GetId(),wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( VentanaControlHL7::OnEditarMensaje ), NULL, this  );
				popup->Connect(pMenuEliminarMensaje->GetId(),wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( VentanaControlHL7::OnEliminarMensaje ), NULL, this  );
				this->PopupMenu(popup);
				delete popup;
			} 
		}
		void VentanaControlHL7::OnMensajeDClick(wxTreeEvent& )
		{
			MostrarVentanaMensaje();
		}

		void VentanaControlHL7::OnMostrarMensaje(wxCommandEvent &)
		{
			MostrarVentanaMensaje();
		}

		void VentanaControlHL7::OnEditarMensaje(wxCommandEvent &)
		{
			wxTreeItemId id = m_treeListCtrlMensajes->GetSelection();
			if(id.IsOk()) {
				wxString fecha = m_treeListCtrlMensajes->GetItemText(id,COL_FECHA);
				wxString destino = m_treeListCtrlMensajes->GetItemText(id,COL_DESTINO);
				wxString estado = m_treeListCtrlMensajes->GetItemText(id,COL_ESTADO);
				wxString mensaje = m_treeListCtrlMensajes->GetItemText(id,COL_MENSAJE);
				wxString str = m_treeListCtrlMensajes->GetItemText(id,COL_ID);
				long idMensaje;
				if(str.ToLong(&idMensaje)){
					DialogoMostrarMensaje mostrar(this,fecha,destino,estado,mensaje, true);
					if(mostrar.ShowModal() == wxID_OK)
					{	
						try {
							GIL::HL7::ControladorBBDDHl7::Instance()->ActualizarMensaje(idMensaje, mostrar.GetDestino(), mostrar.GetMensaje(), mostrar.GetEstado());
							RefrescarMensajes();
						}
						catch (GIL::HL7::HL7Exception& ex) {
							wxMessageBox(wxString::FromUTF8(ex.GetCause().c_str()), _("Error editing message"), wxICON_ERROR, this);
						}
					}
				}
			}
		}

		void VentanaControlHL7::OnListaKey(wxTreeEvent &event)
		{
			int keycode = event.GetKeyEvent().GetKeyCode();
			switch (keycode) {
				case WXK_DELETE:
				case WXK_CLEAR:
				case WXK_BACK:
					EliminarMensaje();
					event.Skip(false);
					break;
				case WXK_RETURN:
					MostrarVentanaMensaje();
					event.Skip(false);
					break;
				case WXK_ESCAPE:
					Close();
					event.Skip(false);
					break;
				case WXK_TAB:
					SetFocus();
					event.Skip(false);
					break;
				default:
					event.Skip(true);
			}
		}

		void VentanaControlHL7::OnEliminarMensaje(wxCommandEvent &)
		{
			EliminarMensaje();
		}


		void VentanaControlHL7::OnPurgarMensajes(wxCommandEvent& )
		{
			try {
				GIL::HL7::ControladorBBDDHl7::Instance()->PurgarMensajesEnviados();
			}
			catch (GIL::HL7::HL7Exception& ex) {
				wxMessageBox(wxString::FromUTF8(ex.GetCause().c_str()), _("Error purguing messages"), wxICON_ERROR, this);
			}
			RefrescarMensajes();
		}

		void VentanaControlHL7::OnActualizar(wxCommandEvent &)
		{
			ActualizarEstadoControlador();
			RefrescarMensajes();
		}

		void VentanaControlHL7::OnArrancarPararClick(wxCommandEvent &)
		{
			m_pBArrancarParar->Disable();
			if (m_pBArrancarParar->GetLabel() == _("Stop") ) {
				GNC::GCS::ConfigurationController::Instance()->writeBoolGeneral("/GinkgoCore/HCE", "HL7MonitorEnabled", false);
				GIL::HL7::ControladorEnvioHl7::FreeInstance();
			}
			else {
				GNC::GCS::ConfigurationController::Instance()->writeBoolGeneral("/GinkgoCore/HCE", "HL7MonitorEnabled", true);
				GIL::HL7::ControladorEnvioHl7::Arrancar();
			}
			ActualizarEstadoControlador();
			m_pBArrancarParar->Enable();
		}

		void VentanaControlHL7::RefrescarMensajes() {
			m_pTimerRefresh->Start(5000);
			wxWindowDisabler disabler;
			Freeze();
			try {
				//conservamos los ids seleccionados
				wxArrayTreeItemIds seleccionados;
				m_treeListCtrlMensajes->GetSelections(seleccionados);
				std::set<int> listaIds;

				for(wxArrayTreeItemIds::iterator it =seleccionados.begin(); it!= seleccionados.end(); ++it) {
					wxString str = m_treeListCtrlMensajes->GetItemText((*it),COL_ID);
					long id;
					if(str.ToLong(&id)){
						listaIds.insert((int)id);
					}
				}
				//

				typedef std::list<GIL::HL7::MensajeHL7> TListaMensajes;
				TListaMensajes listaMensajes;
				GIL::HL7::ControladorBBDDHl7::Instance()->GetMensajesHL7(listaMensajes);
				//primero vaciamos el arbol
				m_treeListCtrlMensajes->DeleteRoot();
				m_treeListCtrlMensajes->AddRoot(wxT("raiz"));
				bool primero=true;
				for(TListaMensajes::iterator it = listaMensajes.begin(); it != listaMensajes.end(); ++it)
				{
					wxTreeItemId item = m_treeListCtrlMensajes->AppendItem(m_treeListCtrlMensajes->GetRootItem(),wxString::FromUTF8((*it).m_fecha.c_str()));
					m_treeListCtrlMensajes->SetItemText(item,COL_MENSAJE,wxString::FromUTF8((*it).m_mensaje.c_str()));
					m_treeListCtrlMensajes->SetItemText(item,COL_DESTINO,wxString::FromUTF8((*it).m_destino.c_str()));
					switch((*it).m_estado) {
						case GIL::HL7::MensajeHL7::TE_Enviado:
							m_treeListCtrlMensajes->SetItemText(item,COL_ESTADO,_("Sent"));
							break;
						case GIL::HL7::MensajeHL7::TE_Pendiente:
							m_treeListCtrlMensajes->SetItemText(item,COL_ESTADO,_("Pending"));
							break;
						case GIL::HL7::MensajeHL7::TE_Warning:
							m_treeListCtrlMensajes->SetItemText(item,COL_ESTADO,_("Warning"));
							m_treeListCtrlMensajes->SetItemText(item,COL_MENSAJE_ERROR,wxString::FromUTF8((*it).m_mensajeError.c_str()));
							break;
						case GIL::HL7::MensajeHL7::TE_Error:
							m_treeListCtrlMensajes->SetItemText(item,COL_ESTADO,_("Error"));
							m_treeListCtrlMensajes->SetItemText(item,COL_MENSAJE_ERROR,wxString::FromUTF8((*it).m_mensajeError.c_str()));
							break;
					}
					std::ostringstream ostr;
					ostr << (*it).m_id;
					m_treeListCtrlMensajes->SetItemText(item,COL_ID,wxString::FromUTF8(ostr.str().c_str()));
					if(listaIds.find((*it).m_id) != listaIds.end()) {
						m_treeListCtrlMensajes->SelectItem(item,NULL,primero);
						primero = false;
					}
				}
			}catch (GIL::HL7::HL7Exception& ex) {
				Thaw();
				wxMessageBox(wxString::FromUTF8(ex.GetCause().c_str()), _("Error getting message"), wxICON_ERROR, this);
				return;
			}
			Thaw();
		}

		void VentanaControlHL7::ActualizarEstadoControlador() {
			m_pTimerRefresh->Start(5000);
			if(GIL::HL7::ControladorEnvioHl7::EstaArrancado()) {
				m_pEstado->SetLabel(_("Running"));
				m_pEstado->SetToolTip(_("The submission process is started and ready to send"));
				m_pEstado->SetForegroundColour(wxColour(0,174,0));
				m_pBArrancarParar->SetLabel(_("Stop"));
			} else {
				m_pEstado->SetLabel(_("Stopped"));
				m_pEstado->SetToolTip(_("Usually due to an error in sending a message"));
				m_pEstado->SetForegroundColour(wxColour(174,0,0));
				m_pBArrancarParar->SetLabel(_("Start"));
			}
			m_panelEstado->Layout();
		}

		void VentanaControlHL7::MostrarVentanaMensaje()
		{
			wxTreeItemId id = m_treeListCtrlMensajes->GetSelection();
			if(id.IsOk()) {
				wxString fecha = m_treeListCtrlMensajes->GetItemText(id,COL_FECHA);
				wxString destino = m_treeListCtrlMensajes->GetItemText(id,COL_DESTINO);
				wxString estado = m_treeListCtrlMensajes->GetItemText(id,COL_ESTADO);
				wxString mensaje = m_treeListCtrlMensajes->GetItemText(id,COL_MENSAJE);
				DialogoMostrarMensaje* mostrar = new DialogoMostrarMensaje(this,fecha,destino,estado,mensaje, false);
				mostrar->Show();
			}
		}

		void VentanaControlHL7::EliminarMensaje()
		{
			//pillamos los elementos seleccionados
			wxArrayTreeItemIds seleccionados;
			m_treeListCtrlMensajes->GetSelections(seleccionados);
			std::list<int> listaIds;

			for(wxArrayTreeItemIds::iterator it =seleccionados.begin(); it!= seleccionados.end(); ++it) {
				wxString str = m_treeListCtrlMensajes->GetItemText((*it),COL_ID);
				long id;
				if(str.ToLong(&id)){
					listaIds.push_back((int)id);
				}
			}

			if(listaIds.empty())
			{
				return;
			}

			int answer = wxMessageBox(_("Would you like to remove these messages?"), _("Delete"), wxYES_NO, this);
			if (answer == wxYES) {
				for(std::list<int>::iterator it = listaIds.begin(); it != listaIds.end(); ++it) {
					try {
						GIL::HL7::ControladorBBDDHl7::Instance()->EliminarMensaje((*it));
					}catch (GIL::HL7::HL7Exception& ex) {
						wxMessageBox(wxString::FromUTF8(ex.GetCause().c_str()), _("Error deleting messages"), wxICON_ERROR, this);
					}
				}
				RefrescarMensajes();
			}
		}

		void VentanaControlHL7::OnMenuSalir( wxCommandEvent& /*event*/ )
		{
			Close();
		}

		void VentanaControlHL7::OnKeyDown( wxKeyEvent& event )
		{
			switch (event.GetKeyCode()) {
				case WXK_DELETE:
				case WXK_CLEAR:
				case WXK_BACK:
					EliminarMensaje();
					event.Skip(false);
					break;
				case WXK_RETURN:
					{
						wxCommandEvent evt;
						OnArrancarPararClick(evt);
						event.Skip(false);
					}
					break;
				case WXK_ESCAPE:
					Close();
					event.Skip(false);
					break;
				case WXK_TAB:
					m_treeListCtrlMensajes->SetFocus();
					event.Skip(false);
					break;
				default:
					event.Skip(true);
			}
		}
	}
}
