/*
*
*  $Id: downloadelementcontainerpanel.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 "downloadelementcontainerpanel.h"

#include <wx/dcbuffer.h>
#include <wx/ginkgostyle/ginkgostyle.h>
#include <wx/image.h>
#include <wx/aui/auibar.h>
#include <wx/msgdlg.h>

#include <api/observers/ieventsobserver.h>

#include <resources/ginkgoresourcesmanager.h>
#include <main/entorno.h>
#include <main/controllers/controladorcomandos.h>
#include <main/controllers/historycontroller.h>
#include <main/controllers/controladorpermisos.h>
#include <main/controllers/controladorlog.h>
#include <main/controllers/controladoreventos.h>
#include <eventos/progresocomando.h>
#include <eventos/handledicom.h>

#include <commands/comandopacs.h>

#define ID_BUTTON_INIT_STOP 0

namespace GNC {
	namespace GUI {
		class DownloadElementPanelToolBar:public wxAuiToolBar{
		public:
			DownloadElementPanelToolBar(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);
			}

			~DownloadElementPanelToolBar()
			{
			}
		};

		class DownloadElementPanel: public DownloadElementPanelBase, public GNC::GCS::IEventsObserver
		{
		public:
			enum Estado
			{
				Parada,
				Iniciada,
				Terminada,
				Erronea
			};

			DownloadElementPanel(DownloadElementContainerPanel* pContainer, wxWindow* pParent, const std::string& s, const std::string& pd,const std::string& des, const std::string& mod, bool seriesMode, const std::string& studyInstanceUID, const std::string& seriesInstanceUID) :
					DownloadElementPanelBase(pParent),
					m_pContainer(pContainer),
					Server(s),
					PatientDescription(pd),
					Description(des),
					Modality(mod),
					SeriesInstanceUID(seriesInstanceUID),
					StudyInstanceUID(studyInstanceUID),
					SeriesMode(seriesMode),
					Progreso(0.0),
					Status(),
					StatusId(Parada),
					m_pToolBar(new DownloadElementPanelToolBar(this, GetBackgroundColour())),
					m_pComando(NULL),
					m_Abortar(false)
			{

				//button bar (play, stop retry)
				m_pToolBar->AddTool(ID_BUTTON_INIT_STOP,_("Start"),GinkgoResourcesManager::CineBar::GetIcoPlay(),_("Start"));
				m_pToolBar->Connect(ID_BUTTON_INIT_STOP,wxEVT_COMMAND_TOOL_CLICKED, wxCommandEventHandler( DownloadElementPanel::OnInitStopDownload),NULL,this);

				m_pToolBar->Realize();
				m_pSizerStatus->Insert(0, m_pToolBar,0, wxALIGN_CENTER_VERTICAL|wxEXPAND,0);

				//max width...
				wxClientDC dc(this);
				int width,height;

				dc.SetFont(m_pLabelPatient->GetFont());
				wxString strTmp = wxString::FromUTF8(PatientDescription.c_str());
				dc.GetTextExtent(strTmp, &width, &height, NULL, NULL, NULL);
				while (width > 375) {
					strTmp = strTmp.substr(0, strTmp.size() - 2);				
					dc.GetTextExtent(strTmp, &width, &height, NULL, NULL, NULL);
				}
				m_pLabelPatient->SetLabel(strTmp);

				dc.SetFont(m_pLabelStudy->GetFont());
				strTmp = wxString::FromUTF8(Description.c_str());
				dc.GetTextExtent(strTmp, &width, &height, NULL, NULL, NULL);
				while (width > 375) {
					strTmp = strTmp.substr(0, strTmp.size() - 2);				
					dc.GetTextExtent(strTmp, &width, &height, NULL, NULL, NULL);
				}
				m_pLabelStudy->SetLabel(strTmp);

				GNC::GCS::ControladorEventos::Instance()->Registrar(this, GNC::GCS::Events::EventoProgresoComando());

				Layout();
				m_pGinkgoProgress->SetMinSize(wxSize(-1, m_pToolBar->GetSize().y));
				Layout();
				DoStop();
			}

			~DownloadElementPanel()
			{
				DoStop();
				GNC::Entorno::Instance()->GetControladorComandos()->AbortarComandosDeOwner(this);
			}

			void DoStop() {
				if (StatusId == Parada || StatusId == Terminada || StatusId == Erronea) {
					return;
				}
				Progreso = 0.0f;
				m_Abortar = true;

				UpdateStatus(_Std("Stopped"));
				StatusId = Parada;
				if (m_pComando != NULL) {
					GNC::GCS::IControladorComandos::Instance()->AbortarComando(m_pComando, false);
					m_pComando = NULL;
					m_Abortar = true;
				}
				UpdateButtons();
			}

			void DoRun()
			{
				if (StatusId == Iniciada) {
					return;
				}
				if (m_pComando != NULL) {
					GNC::GCS::IControladorComandos::Instance()->AbortarComando(m_pComando, false);
					m_pComando = NULL;
				}

				GADAPI::ComandoPACSParams * pParams;
				{
					GIL::DICOM::DicomDataset base;
					base.tags["0020|000d"] = StudyInstanceUID; //study instance uid
					if (SeriesMode) {
						base.tags["0008|0052"] = "SERIES";
						base.tags["0020|000e"] = SeriesInstanceUID; //series instance uid
						if (!Modality.empty()) {
							base.tags["0008|0060"] = Modality; //modalitiy
						}
					} else {
						base.tags["0008|0052"] = "STUDY";
					}
					pParams = new GADAPI::ComandoPACSParams(Server, base);
				}

				m_pComando = new GADAPI::ComandoPACS(pParams);
				GNC::Entorno::Instance()->GetControladorComandos()->ProcessAsync(_Std("Downloading from PACS..."), m_pComando, this);

				UpdateStatus(_Std("Starting..."));
				StatusId = Iniciada;
				UpdateButtons();
			}

			virtual void OnDeleteDownload(wxCommandEvent&) 
			{
				m_pContainer->RemoveDownload(this);
			}

			virtual void OnOpenDownload(wxCommandEvent&  ) 
			{							
				if ( ! GNC::GCS::HistoryController::Instance()->ExistsSeriesWithUID(SeriesInstanceUID) ) {
					DialogoNotFoundBase dlg(this);
					std::ostringstream ostr;
					if (Description != "") {
						ostr << Description;
					} else {
						ostr << Modality << " (" << SeriesInstanceUID << ")";
					}

					dlg.m_pListaSeries->Append( wxString::FromUTF8(ostr.str().c_str()) );
					
					dlg.m_pPanelOkCancel->Show(false);

					int answer = dlg.ShowModal();
					if (answer == wxID_CANCEL) {
						return;
					}
				} else if ( Modality == "SR" ) {
					wxMessageBox(_("Diagnostic files can't be opened, you have to open the diagnosed series"), _("Info"),
						wxOK | wxICON_INFORMATION, this);					
				} else {
					GNC::GCS::Events::EvtHandleDicom::ListaUIDs listaUIdsAbrir;
					listaUIdsAbrir.push_back(SeriesInstanceUID);
					GNC::GCS::ControladorEventos::Instance()->ProcesarEvento(new GNC::GCS::Events::EvtHandleDicom(listaUIdsAbrir, GNC::GCS::Events::EvtHandleDicom::OpenSeries));
				}
			}

			void OnInitStopDownload(wxCommandEvent&)
			{
				switch (StatusId) {
					case Iniciada:
						DoStop();
					break;
					case Parada:
						DoRun();
					break;
					case Terminada:
					break;
					case Erronea:
						DoRun();
					break;
				}
			}

			void ProcesarEvento(GNC::GCS::Events::IEvent *evt)
			{
				GNC::GCS::Events::EventoProgresoComando* pEvt = dynamic_cast<GNC::GCS::Events::EventoProgresoComando*> (evt);
				if (pEvt == NULL  || pEvt->GetComando() == NULL || pEvt->GetComando() != m_pComando) {
					return;
				}
				switch (pEvt->GetTipo()) {
				case GNC::GCS::Events::EventoProgresoComando::TEP_Iniciado:
					OnProgresoInicio();
					break;
				case GNC::GCS::Events::EventoProgresoComando::TEP_Progreso:
					OnProgresoProgreso(pEvt->GetProgresoNormalizado(), pEvt->GetTexto());
					break;
				case GNC::GCS::Events::EventoProgresoComando::TEP_Finalizado:
					OnProgresoFinalizacion();
					break;
				case GNC::GCS::Events::EventoProgresoComando::TEP_Unknown:
					break;
				}
			}

			void OnProgresoInicio()
			{
				UpdateButtons();
			}

			void OnProgresoProgreso(float progresoNormalizado, const std::string& texto)
			{
				//on progreso...
				UpdateStatus(texto);
				m_pGinkgoProgress->SetProgress(progresoNormalizado);
				m_pGinkgoProgress->SetStatus(wxString::FromUTF8(texto.c_str()));
			}

			void OnProgresoFinalizacion()
			{
				m_pGinkgoProgress->SetProgress(1.0f);

				if (m_pComando->m_pPACSParams->m_error.size() > 0) {
					UpdateStatus(_Std("Error: ") + m_pComando->m_pPACSParams->m_error);
					StatusId = Erronea;
				} else if (!m_pComando->m_pPACSParams->m_pModelo->TieneImagenes()) {
					UpdateStatus(_Std("Error: No images were downloaded"));
					StatusId = Erronea;
				} else {
					UpdateStatus(_Std("Finished"));
					StatusId = Terminada;
				}
				m_pComando = NULL;
				UpdateButtons();
			}

			void UpdateStatus(const std::string& status)
			{
				Status = status;
				m_pGinkgoProgress->SetStatus(wxString::FromUTF8(Status.c_str()));
			}

			void UpdateButtons()
			{
				switch (StatusId) {
					case Iniciada:
						{
							m_pButtonDelete->Enable(false);
							m_pButtonOpen->Enable(false);
							m_pGinkgoProgress->SetColorSchema(GinkgoGauge::TCS_BLUE);
							m_pToolBar->SetToolBitmap(ID_BUTTON_INIT_STOP, GinkgoResourcesManager::CineBar::GetIcoStop());
							m_pToolBar->SetToolLabel(ID_BUTTON_INIT_STOP, _("Stop"));
							m_pToolBar->Enable(true);
							m_pToolBar->Refresh(true);
						}
						break;
					case Parada:
						{
							m_pButtonDelete->Enable(true);
							m_pButtonOpen->Enable(false);
							m_pGinkgoProgress->SetColorSchema(GinkgoGauge::TCS_GREY);
							m_pToolBar->SetToolBitmap(ID_BUTTON_INIT_STOP, GinkgoResourcesManager::CineBar::GetIcoPlay());
							m_pToolBar->SetToolLabel(ID_BUTTON_INIT_STOP, _("Play"));
							m_pToolBar->Enable(true);
							m_pToolBar->Refresh(true);
						}
						break;
					case Terminada:
						{
							m_pButtonDelete->Enable(true);
							m_pButtonOpen->Enable(true);
							m_pGinkgoProgress->SetColorSchema(GinkgoGauge::TCS_GREEN);
							m_pToolBar->Hide();
							m_pToolBar->Enable(false);
							m_pToolBar->Refresh(true);
							Layout();
						}
						break;
					case Erronea:
						{
							m_pButtonDelete->Enable(true);
							m_pButtonOpen->Enable(false);
							m_pGinkgoProgress->SetColorSchema(GinkgoGauge::TCS_RED);
							m_pToolBar->SetToolBitmap(ID_BUTTON_INIT_STOP, GinkgoResourcesManager::MenuIcons::GetIcoReset());
							m_pToolBar->SetToolLabel(ID_BUTTON_INIT_STOP, _("Retry"));
							m_pToolBar->Enable(true);
							m_pToolBar->Refresh(true);
						}
						break;
				}
			}

			Estado GetStatus() 
			{
				return StatusId;
			}

			const std::string GetUID() 
			{
				return SeriesInstanceUID + "@" + StudyInstanceUID;
			}

		protected:

			DownloadElementContainerPanel* m_pContainer;

			std::string Server;

			std::string PatientDescription;
			std::string Description;
			std::string Modality;
			std::string SeriesInstanceUID;
			std::string StudyInstanceUID;
			bool SeriesMode;

			float       Progreso;
			std::string Status;
			Estado      StatusId;

			DownloadElementPanelToolBar* m_pToolBar;


			GADAPI::ComandoPACS* m_pComando;
			bool                 m_Abortar;

		};
	}
}

////////////////////////////////////////////////////////////////////////////
GNC::GUI::DownloadElementContainerPanel::DownloadElementContainerPanel(wxWindow* pParent) : DownloadElementContainerPanelBase(pParent)
{
}

GNC::GUI::DownloadElementContainerPanel::~DownloadElementContainerPanel()
{
}

bool GNC::GUI::DownloadElementContainerPanel::FindDownload(const std::string& uid)
{
	return m_mapDownloads.find(uid) != m_mapDownloads.end();
}

bool GNC::GUI::DownloadElementContainerPanel::AddDownload(const std::string& s, const std::string& pd,const std::string& sd, const std::string& sm, bool initIfStopped, bool seriesMode, const std::string& studyUID, const std::string& seriesUID)
{
	if (s.empty() || (studyUID.empty()&&seriesUID.empty())) {
		LOG_ERROR("GUI/Adquisition", "Empty mandatory values (serverId | serieInstanceUID) while adding serie to download queue");
		return false;
	}
	std::string uid;
	uid = seriesUID + "@" + studyUID;
	if (FindDownload(uid)) {
		DownloadElementPanel* p = m_mapDownloads[uid];
		if (p->GetStatus() != DownloadElementPanel::Iniciada && initIfStopped) {
			p->DoRun();

			return true;
		} else {
			return false;
		}
	}

	DownloadElementPanel* p = new DownloadElementPanel(this, m_pScrolledWindow ,s, pd, sd, sm, seriesMode, studyUID, seriesUID);
	m_mapDownloads[p->GetUID()] = p;
	Freeze();
	m_pScrolledWindow->GetSizer()->Add(p, 0, wxEXPAND);

	m_pScrolledWindow->Layout();
	int ySize = p->GetSize().y;
	m_pScrolledWindow->SetVirtualSize(-1, ySize * m_mapDownloads.size());
	m_pScrolledWindow->AdjustScrollbars();

	Thaw();
	p->DoRun();
	return true;
}

void GNC::GUI::DownloadElementContainerPanel::RemoveDownload(DownloadElementPanel* de)
{
	if (!FindDownload(de->GetUID())) {
		return;
	}

	Freeze();
	m_mapDownloads.erase(m_mapDownloads.find(de->GetUID()));
	int ySize = de->GetSize().y;
	de->Destroy();

	m_pScrolledWindow->Layout();
	m_pScrolledWindow->SetVirtualSize(-1, ySize * m_mapDownloads.size());
	m_pScrolledWindow->AdjustScrollbars();

	Thaw();

}

void GNC::GUI::DownloadElementContainerPanel::OnRemoveFinished(wxCommandEvent &)
{
	Freeze();
	std::list<std::string> uidsRemove;
	for (TMapElements::iterator it = m_mapDownloads.begin(); it != m_mapDownloads.end(); ++it) {
		if (it->second->GetStatus() == DownloadElementPanel::Terminada || it->second->GetStatus() == DownloadElementPanel::Erronea || it->second->GetStatus() == DownloadElementPanel::Parada) {
			uidsRemove.push_back((*it).second->GetUID());
		}
	}
	int ySize = 100;
	for (std::list<std::string>::iterator it = uidsRemove.begin(); it != uidsRemove.end(); ++it) {
		TMapElements::iterator it2 = m_mapDownloads.find((*it));
		if (it2 == m_mapDownloads.end())
			continue;
		DownloadElementPanel* de = (*it2).second;
		ySize = de->GetSize().y;
		
		m_mapDownloads.erase(it2);
		de->Destroy();
	}

	m_pScrolledWindow->Layout();

	m_pScrolledWindow->SetVirtualSize(-1, ySize * m_mapDownloads.size());
	m_pScrolledWindow->AdjustScrollbars();
	Thaw();
}

