/*
*  
*  $Id: comandoexportacion.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
*
*/
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable: 4996)
#endif

#include <sstream>

#include <wx/filename.h>
#include <wx/file.h>
#include <wx/dir.h>
#include <main/controllers/configurationcontroller.h>

#include <api/globals.h>
#include <api/ientorno.h>
#include <api/dicom/idicommanager.h>
#include <api/internationalization/internationalization.h>

#include <api/controllers/ipacscontroller.h>

#include <main/entorno.h>
#include <main/controllers/controladoreventos.h>
#include <main/controllers/historycontroller.h>
#include <main/controllers/controladorcomandos.h>
#include <main/gui/history3/historypanel3.h>

#include <eventos/mensajes.h>

#include "comandoexportacion.h"

#include <itkExceptionObject.h>
#include <itkImage.h>
#include <itkOrientedImage.h>
#include <itkRGBPixel.h>
#include <itkGDCMImageIO.h>
#include <itkJPEGImageIO.h>
#include <itkPNGImageIO.h>
#include <itkVectorResampleImageFilter.h>
#include <itkLinearInterpolateImageFunction.h>
#include <itkImageFileWriter.h>
#include <api/istudycontext.h>

#include <api/dicom/dcmdictionary.h>
#include <commands/comandoincluirhistorial.h>



namespace GADAPI {

	ComandoExportacionParams::ComandoExportacionParams(GNC::GCS::Ptr<GNC::GUI::TipoWizardExportacion>& pDatosPersistentes)
	{
		m_pDatosPersistentes = pDatosPersistentes;
		m_hasError = false;
		if (pDatosPersistentes->m_target != GNC::GUI::TipoWizardExportacion::EXTERNAL_FOLDER) {
			m_tempDir = GNC::Entorno::Instance()->CreateGinkgoTempDir();
		}
	}

	ComandoExportacionParams::~ComandoExportacionParams()
	{
	/*	if (m_pDatosPersistentes->m_target != GNC::GUI::TipoWizardExportacion::EXTERNAL_FOLDER) {
			GNC::Entorno::Instance()->RemoveDirRecursive(m_tempDir);
		}*/
	}

	ComandoExportacion::ComandoExportacion(ComandoExportacionParams* pParams): GNC::GCS::IComando(pParams,"Exportacion")
	{
		m_pExportacionParams = pParams;
	}

	void ComandoExportacion::Execute()
	{
		if (!NotificarProgreso(0.0, _Std("Exporting files...")) )
			return;
		if(m_pExportacionParams->m_pDatosPersistentes->m_formatoDestino == GNC::GUI::DICOM){
			ExportarDICOM();
		}
		else{
			ExportarImagenes();
		}

		if (m_pExportacionParams->m_pDatosPersistentes->m_target == GNC::GUI::TipoWizardExportacion::OVERWRITE) {
			GNC::GCS::HistoryController::FileModelList fileModelList;
			for (std::list<long>::iterator it = m_pExportacionParams->m_pDatosPersistentes->ListOfSeriesPks.begin(); it != m_pExportacionParams->m_pDatosPersistentes->ListOfSeriesPks.end(); ++it)
			{
				GNC::GCS::HistoryController::Instance()->GetSeriesSortedFileModels((*it), fileModelList);
			}
			GNC::GCS::HistoryController::Instance()->UpdateFiles(fileModelList);
		}
	}

	void ComandoExportacion::Update()
	{
		switch (m_pExportacionParams->m_pDatosPersistentes->m_target) {
			case GNC::GUI::TipoWizardExportacion::EXTERNAL_FOLDER:
			{
				if (m_pExportacionParams->m_hasError)
				{
					GNC::GCS::ControladorEventos::Instance()->ProcesarEvento(new GNC::GCS::Events::EventoMensajes(NULL,m_pExportacionParams->m_Error, GNC::GCS::Events::EventoMensajes::StatusMessage,true, GNC::GCS::Events::EventoMensajes::Error));
				} else {
					GNC::GCS::ControladorEventos::Instance()->ProcesarEvento(new GNC::GCS::Events::EventoMensajes(NULL, _Std("Export has been finished successfully"), GNC::GCS::Events::EventoMensajes::StatusMessage,true, GNC::GCS::Events::EventoMensajes::Informacion));
				}
			}
			break;
			case GNC::GUI::TipoWizardExportacion::OVERWRITE:
			{
				GNC::GUI::HistoryPanel3::Instance()->ReloadHistory();
			}
			break;
			case GNC::GUI::TipoWizardExportacion::NEW_STUDY:
			{
				//add to history...
				GADAPI::ComandoIncluirHistorial::ComandoIncluirHistorialParams* pParams = new GADAPI::ComandoIncluirHistorial::ComandoIncluirHistorialParams(m_pExportacionParams->m_outputPaths, false, GNC::GCS::HistoryController::TAA_MOVE);
				GADAPI::ComandoIncluirHistorial::ComandoIncluirHistorial* pCmd = new GADAPI::ComandoIncluirHistorial::ComandoIncluirHistorial(pParams);
				GNC::GCS::IControladorComandos::Instance()->ProcessAsync("Including...", pCmd, NULL);
			} 
			break;
		}
	}

	//endregion

	void ComandoExportacion::ExportarDICOM()
	{
		GNC::GCS::Ptr<GNC::GUI::TipoWizardExportacion> pDatosPersistentes = m_pExportacionParams->m_pDatosPersistentes;
		bool correcto = true;

		std::list<std::string> resultado;
		std::list<std::string> listaPaths;

		if (pDatosPersistentes->m_pExportDelegate.IsValid()) {
			if (pDatosPersistentes->m_ficheroActual) {
				listaPaths.push_back(pDatosPersistentes->m_pExportDelegate->GetPathActiveDICOM());
			}
			else
			{
				listaPaths = pDatosPersistentes->m_pExportDelegate->GetPathAllDICOMs();
			}
		} else if (!pDatosPersistentes->ListOfSeriesPks.empty()) {
			for (std::list<long>::iterator itUIDs = pDatosPersistentes->ListOfSeriesPks.begin(); itUIDs != pDatosPersistentes->ListOfSeriesPks.end(); ++itUIDs)
			{
				GNC::GCS::HistoryController::StringList pathsSerie = GNC::GCS::HistoryController::Instance()->GetSeriesSortedPaths((*itUIDs));
				listaPaths.insert(listaPaths.begin(), pathsSerie.begin(), pathsSerie.end());
			}
		}

		GIL::DICOM::IDICOMManager*	pDICOMManager;

		
		wxString destino;

		//update ids to get new study...
		std::map<std::string, std::string> mapOfUIDs;
		std::string stringTmp;
		GIL::DICOM::DicomDataset baseUIDs;
		//

		int contador = 1;
		for(std::list<std::string>::iterator it = listaPaths.begin(); it!= listaPaths.end(); ++it,++contador) {
			wxString cadena = wxString::Format(_("Exporting file %d of %d"), contador, listaPaths.size());
			if (!NotificarProgreso((float)contador/listaPaths.size(), std::string(cadena.ToUTF8())))
				return;

			GIL::DICOM::DicomDataset base;

			pDICOMManager = GNC::GCS::IEntorno::Instance()->GetPACSController()->CrearInstanciaDeDICOMManager();
			pDICOMManager->CargarFichero((*it), base);
			
			pDICOMManager->ActualizarJerarquia(pDatosPersistentes->m_base);

			if (pDatosPersistentes->m_target == GNC::GUI::TipoWizardExportacion::NEW_STUDY) {
				baseUIDs.tags.clear();
				//study instance uid
				base.getTag(GKDCM_StudyInstanceUID, stringTmp);
				if (mapOfUIDs.find(stringTmp) == mapOfUIDs.end()) {
					mapOfUIDs[stringTmp] = pDICOMManager->GetNewUID();
				}
				baseUIDs.tags[GKDCM_StudyInstanceUID] = mapOfUIDs[stringTmp];
				//series instance uid
				base.getTag(GKDCM_SeriesInstanceUID, stringTmp);
				if (mapOfUIDs.find(stringTmp) == mapOfUIDs.end()) {
					mapOfUIDs[stringTmp] = pDICOMManager->GetNewUID();
				}
				baseUIDs.tags[GKDCM_SeriesInstanceUID] = mapOfUIDs[stringTmp];
				//sop instance
				base.getTag(GKDCM_SOPInstanceUID, stringTmp);
				if (mapOfUIDs.find(stringTmp) == mapOfUIDs.end()) {
					mapOfUIDs[stringTmp] = pDICOMManager->GetNewUID();
				}
				baseUIDs.tags[GKDCM_SOPInstanceUID] = mapOfUIDs[stringTmp];
				//update uids
				pDICOMManager->ActualizarJerarquia(baseUIDs);
			}

			//anonimizar tags Ginkgo
			if(!pDatosPersistentes->m_incluirTagsGinkgo){
				pDICOMManager->AnonimizarTagsPrivados();
			}


			if (pDatosPersistentes->m_target == GNC::GUI::TipoWizardExportacion::OVERWRITE) {
				destino = FROMPATH((*it));
			} else {
				destino = GetFichero(wxT("dcm"));
			}

			std::string destinoStd(TOPATH(destino));
			correcto = correcto && pDICOMManager->AlmacenarFichero(destinoStd);
			resultado.push_back(destinoStd);
			m_pExportacionParams->m_outputPaths.push_back(destinoStd);
			GNC::Entorno::Instance()->GetPACSController()->LiberarInstanciaDeDICOMManager(pDICOMManager);
		}

		if(!correcto) {
			m_pExportacionParams->m_Error = _Std("Error storing file, check the permissions over the directory.");
			m_pExportacionParams->m_hasError = true;
		}
	}


	void ComandoExportacion::ExportarImagenes()
	{
 		GNC::GCS::Ptr<GNC::GUI::TipoWizardExportacion> pDatosPersistentes = m_pExportacionParams->m_pDatosPersistentes;

		if(!pDatosPersistentes->m_pExportDelegate.IsValid()){
			//error!!!! no deberia llegar porque en el paso uno no le deberia haber dejado seleccionar otra cosa que un dicom
			m_pExportacionParams->m_Error = _Std("Unexpected Error exporting, the view is not allowed to export to the format selected");
			m_pExportacionParams->m_hasError = true;
			return ;
		}

		std::list<std::string> listaPaths;
		GNC::GCS::IImageExportDelegate::ImageType::Pointer img;
		try{
			if(pDatosPersistentes->m_ficheroActual){
				wxString cadena = wxString::Format(_("Exporting file %d of %d"), 1, 1);
				if (!NotificarProgreso(0.2, std::string(cadena.ToUTF8())))
					return;

				pDatosPersistentes->m_pExportDelegate->GetCurrentImage(img, pDatosPersistentes->m_mapasValoracion, pDatosPersistentes->m_incluirWidgets, GNC::GCS::Vector::NaN());
				wxString res=ExportarImage(img);
				if(res!=wxEmptyString){
					std::string strTmp(TOPATH(res));
					m_pExportacionParams->m_outputPaths.push_back(strTmp);
				}
			}
			else
			{
				int size = pDatosPersistentes->m_pExportDelegate->GetNumberOfSlices();
				for(std::string::size_type i = 0; (int)i < size; i++){
					wxString cadena = wxString::Format(_("Exporting file %d of %d"), i+1, size);
					if (!NotificarProgreso((float)i/size, std::string(cadena.ToUTF8())))
						return;

					pDatosPersistentes->m_pExportDelegate->GetImage(img, i, pDatosPersistentes->m_mapasValoracion, pDatosPersistentes->m_incluirWidgets, GNC::GCS::Vector::NaN());
					wxString res = ExportarImage(img);
					if(res != wxEmptyString){
						std::string strTmp(TOPATH(res));
						m_pExportacionParams->m_outputPaths.push_back(strTmp);
					}
				}
			}
		}
		catch(itk::ExceptionObject&) {

			m_pExportacionParams->m_Error = _Std("Failed to store the file, check permissions on the directory");
			m_pExportacionParams->m_hasError = true;
		}
	}

	wxString ComandoExportacion::ExportarImage(GNC::GCS::IImageExportDelegate::ImageType::Pointer img)
	{
		GNC::GCS::Ptr<GNC::GUI::TipoWizardExportacion> pDatosPersistentes = m_pExportacionParams->m_pDatosPersistentes;
		if(img.IsNull()){
			m_pExportacionParams->m_Error = _Std("The key files will not be exported");
			m_pExportacionParams->m_hasError = true;
			return wxEmptyString;
		}

		wxString destino = wxEmptyString;

		typedef itk::ImageFileWriter<GNC::GCS::IImageExportDelegate::ImageType> TipoWriter;
		TipoWriter::Pointer writer = TipoWriter::New();
		writer->SetInput(img);


		switch(pDatosPersistentes->m_formatoDestino) {
			case GNC::GUI::BMP:
				{
					destino = GetFichero(wxT("bmp"));
					std::string strTmp (TOPATH(destino));
					writer->SetFileName(strTmp.c_str());
				}
				break;
			case GNC::GUI::JPEG:
				{
					destino = GetFichero(wxT("jpg"));
					std::string strTmp (TOPATH(destino));
					writer->SetFileName(strTmp.c_str());
					itk::JPEGImageIO::Pointer imageIO = itk::JPEGImageIO::New();
					writer->SetImageIO(imageIO);
					imageIO->SetUseCompression(true);
					imageIO->SetQuality(pDatosPersistentes->m_jpegCalidad);
				}
				break;
			case GNC::GUI::PNG:
				{
					destino = GetFichero(wxT("png"));
					std::string strTmp (TOPATH(destino));
					writer->SetFileName(strTmp.c_str());
				}
				break;
			case GNC::GUI::DICOM:
				break;
		}

		writer->Update();
		return destino;
	}

	wxString ComandoExportacion::GetFichero(const wxString& extension) {
		wxString dir;
		if (m_pExportacionParams->m_pDatosPersistentes->m_target == GNC::GUI::TipoWizardExportacion::EXTERNAL_FOLDER) {
			dir = FROMPATH(m_pExportacionParams->m_pDatosPersistentes->m_pathDestino);
		} else {
			dir = FROMPATH(m_pExportacionParams->m_tempDir);
		}
		wxString destino(wxEmptyString);
		std::string nombre (wxDateTime::Now().Format(_("image_%m-%d-%Y_")).ToUTF8());
		std::string stdDir(TOPATH(dir));
		std::string stdExtension(TOPATH(extension));
		int indice=0;
		//yy-mm-dd_imagen_indice
		do {
			std::ostringstream ostr;
			ostr << stdDir << (char)wxFileName::GetPathSeparator() << nombre << indice++ << "." << stdExtension;
			destino = FROMPATH(ostr.str());
		} while(wxFile::Exists(destino));
		return destino;
	}
};

#ifdef _MSC_VER
#pragma warning(pop)
#endif

