/*
*  
*  $Id: comandoincluirhistorial.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
*
*/
//#define _GINKGO_TRACE
#include <wx/filename.h>
#include <wx/file.h>
#include <wx/dir.h>
#include <wx/msgdlg.h>

#include <api/globals.h>
#include <api/internationalization/internationalization.h>
#include <api/ivista.h>
#include <api/controllers/icontroladorvistas.h>
#include <api/imodelointegracion.h>
#include <api/controllers/icontroladorcarga.h>
#include <api/dicom/imodelodicom.h>
#include <main/entorno.h>
#include "comandoincluirhistorial.h"
#include <main/controllers/commandcontroller.h>
#include <main/controllers/historycontroller.h>
#include <main/gui/history3/historypanel3.h>
#include <main/controllers/controladoreventos.h>
#include <main/controllers/controladorlog.h>
#include <main/controllers/pacscontroller.h>

#include "dialogopathssobreescribirbase.h"

#define IDC_INCLUIR       101
#define IDC_AVISAR		  102

class SubComandoAvisarModelos : public GNC::GCS::IComando {
public:
	SubComandoAvisarModelos() : IComando(NULL)
	{
		SetId(IDC_AVISAR);
	}

	virtual void Execute()
	{
	}

	virtual void Update()
	{
		GNC::GUI::HistoryPanel3::Instance()->RefreshSearch();
	}

	virtual void LiberarRecursos()
	{
	}

protected:
};

namespace GADAPI {

	//lee un directorio en profundidad y lo incluye en el dicomdir
	namespace ComandoIncluirHistorial {
		ComandoIncluirHistorialParams::ComandoIncluirHistorialParams(const std::string& path, bool recursivo, GNC::GCS::HistoryController::TAddAction addAction) :
				m_numberOfFiles(0),
				m_path(path),
				m_recursivo(recursivo),
				m_abrirDespuesDeCargar(false),
				m_informar(true),
				m_addAction(addAction)

		{ }

		ComandoIncluirHistorialParams::ComandoIncluirHistorialParams(const std::list<std::string>& listaPaths, bool abrirDespuesDeCargar, GNC::GCS::HistoryController::TAddAction addAction) :
				m_numberOfFiles(0),
				m_recursivo(true),
				m_abrirDespuesDeCargar(abrirDespuesDeCargar),
				m_informar(true),
				m_addAction(addAction)
		{
			if (listaPaths.size() == 1) {
				m_path = listaPaths.front();
			} else {
				m_listaPaths = listaPaths;
			}
		}

		ComandoIncluirHistorialParams::~ComandoIncluirHistorialParams()
		{
		}


		ComandoIncluirHistorial::ComandoIncluirHistorial(ComandoIncluirHistorialParams* pParams) : IComando(pParams)
		{
			GTRACE(">> ComandoCarga::ComandoCarga(): " << this);
			m_pIncluirParams = pParams;
			SetId(IDC_INCLUIR);
			GTRACE("<< ComandoCarga::ComandoCarga(): " << this);
		}

		void ComandoIncluirHistorial::Execute()
		{
			std::list<long>* insertedSeriesPtr = &(m_pIncluirParams->m_InsertedSeries);

			NotificarProgreso(0.0f,_Std("Exploring directory ..."));

			if(m_pIncluirParams->m_path != "") {
				GNC::GCS::HistoryController::StringList listaFicheros;
				wxString wxPath = FROMPATH(m_pIncluirParams->m_path);
				if(wxFileExists(wxPath)) {
					wxFileName filename(wxPath);
					if(filename.GetExt().Lower() == wxT("dcm") || GIL::DICOM::PACSController::Instance()->EsDICOM(TOPATH(wxPath), false, true) ) {
						listaFicheros.push_back(m_pIncluirParams->m_path);

						GNC::GCS::HistoryController::Instance()->AddFiles(listaFicheros, m_pIncluirParams->m_ErrorList, insertedSeriesPtr, this, m_pIncluirParams->m_addAction);
						m_pIncluirParams->m_numberOfFiles += listaFicheros.size();
					} else if (GIL::DICOM::PACSController::Instance()->EsDICOM(TOPATH(wxPath), true, false)) {
						//it's a DICOMDIR file...
						NotificarProgreso(0.05f,_Std("Reading DICOMDIR ..."));
						IModeloDicom dicomDirModel;
						if(GIL::DICOM::PACSController::Instance()->LeerDicomDir(m_pIncluirParams->m_path,&dicomDirModel) && dicomDirModel.ListaPacientes().size()!=0) {
							for (IModeloDicom::ListaPacientesType::const_iterator it = dicomDirModel.ListaPacientes().begin(); it != dicomDirModel.ListaPacientes().end(); ++it) {
								const IModeloPaciente& p = *it;
								for (IModeloPaciente::ListaEstudiosType::const_iterator it2 = p.ListaEstudios().begin(); it2 != p.ListaEstudios().end(); ++it2) {
									const IModeloEstudio& e = *it2;
									listaFicheros.clear();
									for (IModeloEstudio::ListaSeriesType::const_iterator it3 = e.ListaSeries().begin(); it3 != e.ListaSeries().end(); ++it3) {
										const IModeloSerie& s = *it3;
										for(IModeloSerie::ListaImagenesType::const_iterator it4 = s.ListaImagenes().begin(); it4 != s.ListaImagenes().end(); ++it4) {
											const IModeloImagen& i = *it4;
											if(i.GetPathImagen() != "") {
												listaFicheros.push_back(i.GetPathImagen());
											}
										}
									}
									GNC::GCS::HistoryController::Instance()->AddFiles(listaFicheros, m_pIncluirParams->m_ErrorList, insertedSeriesPtr, this, m_pIncluirParams->m_addAction);
									m_pIncluirParams->m_numberOfFiles += listaFicheros.size();
									SubComandoAvisarModelos * pCmd = new SubComandoAvisarModelos();
									GNC::GCS::ICommandController::Instance()->ProcessAsync(_Std("Including files in the history .."),pCmd,NULL);
								}
							}
						}
					}
				} else if (wxDirExists(wxPath) && m_pIncluirParams->m_recursivo) {
					//caso especial en el que se va avisando poco a poco...
					TListaListas listaListas;
					LeerDirectorioRecursivo(wxPath,listaListas);
					for (TListaListas::iterator it = listaListas.begin(); it != listaListas.end(); ++it) {
						//se incluyen "por paquetes los ficheros"
						GNC::GCS::HistoryController::Instance()->AddFiles((*it), m_pIncluirParams->m_ErrorList, insertedSeriesPtr, this, m_pIncluirParams->m_addAction);
						m_pIncluirParams->m_numberOfFiles += (*it).size();
						SubComandoAvisarModelos * pCmd = new SubComandoAvisarModelos();
						GNC::GCS::ICommandController::Instance()->ProcessAsync(_Std("Including files in the history .."),pCmd,NULL);
					}
				} else if(wxDirExists(wxPath)){
					//leer el directorio normal
					wxDir dir;
					if (dir.Open(wxPath)) {
						wxString wxPathFich;
						bool cont = dir.GetFirst(&wxPathFich,wxEmptyString, wxDIR_FILES | wxDIR_DIRS);
						while (cont) {
							wxPathFich = dir.GetName()+ wxFileName::GetPathSeparator(wxPATH_NATIVE) + wxPathFich;
							wxFileName filename(wxPathFich);
							if(filename.GetExt().Lower() == wxT("dcm") || GIL::DICOM::PACSController::Instance()->EsDICOM(TOPATH(wxPathFich), false, true) ) {
								std::string pathStd(TOPATH(wxPathFich));
								listaFicheros.push_back(pathStd);
							}
							cont = dir.GetNext(&wxPathFich);
						}
					}
					GNC::GCS::HistoryController::Instance()->AddFiles(listaFicheros, m_pIncluirParams->m_ErrorList, insertedSeriesPtr, this, m_pIncluirParams->m_addAction);
					m_pIncluirParams->m_numberOfFiles += listaFicheros.size();
					SubComandoAvisarModelos * pCmd = new SubComandoAvisarModelos();
					GNC::GCS::ICommandController::Instance()->ProcessAsync(_Std("Including files in the history .."),pCmd,NULL);
				}
			} else {
				GNC::GCS::HistoryController::Instance()->AddFiles(m_pIncluirParams->m_listaPaths, m_pIncluirParams->m_ErrorList, insertedSeriesPtr, this, m_pIncluirParams->m_addAction);
				m_pIncluirParams->m_numberOfFiles += m_pIncluirParams->m_listaPaths.size();
			}
			//remove duplicated series ids
			std::set<long> setOfIds;
			for (std::list<long>::iterator it = m_pIncluirParams->m_InsertedSeries.begin(); it != m_pIncluirParams->m_InsertedSeries.end(); ++it) {
				setOfIds.insert((*it));
			}
			m_pIncluirParams->m_InsertedSeries.clear();
			m_pIncluirParams->m_InsertedSeries.insert(m_pIncluirParams->m_InsertedSeries.begin(), setOfIds.begin(), setOfIds.end());
		}

		void  ComandoIncluirHistorial::LeerDirectorioRecursivo(wxString& dirPath, TListaListas& listaListasPaths, int profundidadMaxima, const int profundidadActual)
		{
			{
				std::ostringstream ostr;
				ostr << _Std("Exploring directory ") << dirPath.ToUTF8();
				NotificarProgreso(0.0f, ostr.str());
				if (EstaAbortado())
				{
					return;
				}
			}
			TListaPaths listaCurrentPaths;
			wxArrayString listaDirectoriosCurrent;
			bool dicomEncontrado = false;
			if(wxDirExists(dirPath)) {
				//vaciar
				wxDir dir;
				if (dir.Open(dirPath)) {
					wxString fileName;
					//no se listan los ocultos
					bool cont = dir.GetFirst(&fileName,wxEmptyString,wxDIR_FILES | wxDIR_DIRS);
					while (cont) {
						fileName=dir.GetName()+ wxFileName::GetPathSeparator(wxPATH_NATIVE) + fileName;
						if(wxDir::Exists(fileName) ){
							listaDirectoriosCurrent.push_back(fileName);
						}else if (wxFileExists(fileName)) {
							wxFileName filename(fileName);
							if(filename.GetExt().Lower() == wxT("dcm") || GIL::DICOM::PACSController::Instance()->EsDICOM(TOPATH(fileName), false, true) ) {
								std::string pathStd(TOPATH(fileName));
								listaCurrentPaths.push_back(pathStd);
								dicomEncontrado = true;
							}
						}
						cont = dir.GetNext(&fileName);
					}
				}
			} else if (wxFileExists(dirPath)) {
				wxFileName filename(dirPath);
				if(filename.GetExt().Lower() == wxT("dcm") || GIL::DICOM::PACSController::Instance()->EsDICOM(TOPATH(dirPath), false, true)) {
					std::string pathStd(TOPATH(dirPath));
					listaCurrentPaths.push_back(pathStd);
					dicomEncontrado = true;
				}
			}

			int siguienteProfundidad = profundidadActual;
			if(dicomEncontrado) {
				//se resetea la profundidad actual
				siguienteProfundidad = 0;
			} else {
				siguienteProfundidad ++;
			}
			if(siguienteProfundidad <= profundidadMaxima) {
				for(wxArrayString::iterator it =listaDirectoriosCurrent.begin(); it != listaDirectoriosCurrent.end(); ++it) {
					LeerDirectorioRecursivo((*it),listaListasPaths,profundidadMaxima,siguienteProfundidad);
				}
			}

			listaListasPaths.push_back(listaCurrentPaths);
		}

		void ComandoIncluirHistorial::Update()
		{
			wxString message = wxT("");
			message += _("Image acquisition finished.");
			message += wxT(" ");
			message += wxString::Format(_("There have been included %d images."), (int)(m_pIncluirParams->m_numberOfFiles));
			message += wxT("\n");
			if (m_pIncluirParams->m_ErrorList.size() > 0)
				message += wxString::Format(_("\nThere are %d errors (see log for more detailed description)"), (int)(m_pIncluirParams->m_ErrorList.size()));

			//log
			{
				std::ostringstream errorOstr;
				if (!m_pIncluirParams->m_ErrorList.empty()) {

					bool first = true;
					for (GNC::GCS::HistoryController::TAddErrorList::iterator it = m_pIncluirParams->m_ErrorList.begin();it != m_pIncluirParams->m_ErrorList.end(); ++it)
					{
						if ((*it).error == GNC::GCS::HistoryController::TAddError::TE_FileNotExist) {
							if (first) {
								errorOstr<< "\t" << _Std("This files doesn't exist:") << std::endl;
								first = false;
							}
							errorOstr << "\t\t" << (*it).path << std::endl;
						}
					}
					first = true;
					for (GNC::GCS::HistoryController::TAddErrorList::iterator it = m_pIncluirParams->m_ErrorList.begin();it != m_pIncluirParams->m_ErrorList.end(); ++it)
					{
						if ((*it).error == GNC::GCS::HistoryController::TAddError::TE_WrongFormat) {
							if (first) {
								errorOstr<< "\t" << _Std("This files doesn't have DICOM format:") << std::endl;
								first = false;
							}
							errorOstr << "\t\t" << (*it).path << std::endl;
						}
					}
					
					first = true;
					for (GNC::GCS::HistoryController::TAddErrorList::iterator it = m_pIncluirParams->m_ErrorList.begin();it != m_pIncluirParams->m_ErrorList.end(); ++it)
					{
						if ((*it).error == GNC::GCS::HistoryController::TAddError::TE_DICOMDir) {
							if (first) {
								errorOstr << "\t" <<_Std("This files are Dicom Dirs:") << std::endl;
								first = false;
							}
							errorOstr << "\t\t" << (*it).path << std::endl;
						}
					}
				}
				
				std::string errorString = errorOstr.str();
				if (!errorString.empty()) {
					LOG_ERROR("ComandoIncluirHistorial", errorOstr.str());
				}
			}

			GNC::GUI::HistoryPanel3::Instance()->ReloadCombos(false);
			GNC::GUI::HistoryPanel3::Instance()->RefreshSearch();
			const int MAX_OPENED_STUDIES = 3;
			if (m_pIncluirParams->m_abrirDespuesDeCargar){
				std::set<long> openedStudies;
				for (std::list<long>::iterator it = m_pIncluirParams->m_InsertedSeries.begin(); it != m_pIncluirParams->m_InsertedSeries.end() && openedStudies.size() < MAX_OPENED_STUDIES; ++it) {
					GNC::GCS::HistoryController::SeriesModel seriesModel = GNC::GCS::HistoryController::Instance()->GetSeriesModel((*it));
					GNC::GUI::HistoryPanel3::Instance()->OpenSeriesOrStudy(seriesModel.study_fk, false);
				}				
			}
		}
	}
}

