/*
 *
 *  $Id: historycontroller.h $
 *  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
 *
 *
 */
#pragma once
#include <string>
#include <list>

#include <api/dicom/dicomdataset.h>
#include <api/api.h>
#include <api/controllers/ihistorycontroller.h>
#include <api/globals.h>
#include <wx/datetime.h>

class wxSQLite3Database;
class wxCriticalSection;

namespace GNC {
	class IProxyNotificadorProgreso;
	namespace GCS {
		
		namespace History {
			class EXTAPI IHistoryFilter {
			public:
				IHistoryFilter() {
					Enabled = false;
				}
				virtual ~IHistoryFilter(){}

				virtual std::string GetSQLFilter() = 0;
				void Enable(bool enabled) {
					this->Enabled = enabled;
				}
				bool IsEnabled() {
					return this->Enabled;
				}
			protected:
				bool Enabled;
			};

			class EXTAPI StudyModalityFilter: public IHistoryFilter
			{
			public:
				StudyModalityFilter(){}

				StudyModalityFilter(const std::list<std::string>& listOfModalities) {
					this->listOfModalities = listOfModalities;
				}
				StudyModalityFilter(const std::string& modality) {
					this->listOfModalities.push_back(modality);
				}

				void SetModalities(const std::list<std::string>& listOfModalities) {
					this->listOfModalities = listOfModalities;
				}

				const std::list<std::string>& GetModalities() {
					return listOfModalities;
				}

				virtual std::string GetSQLFilter();
			protected:

				std::list<std::string> listOfModalities;
			};

			class EXTAPI IHistoryDateFilter: public IHistoryFilter
			{
			public:
				IHistoryDateFilter() {}

				IHistoryDateFilter(const wxDateTime& from, const wxDateTime& to) {
					this->from = from;
					this->to = to;
				}

				virtual void SetDates(const wxDateTime& from, const wxDateTime& to) {
					this->from = from;
					this->to = to;
				}

				const wxDateTime& GetFromDate() {
					return from;
				}

				const wxDateTime& GetToDate() {
					return to;
				}
			protected:
				wxDateTime from;
				wxDateTime to;
			};

			class EXTAPI AcquisitionDateFilter: public IHistoryDateFilter
			{
			public:
				AcquisitionDateFilter() {}
				AcquisitionDateFilter(const wxDateTime& from, const wxDateTime& to): IHistoryDateFilter(from,to)
				{}

				virtual std::string GetSQLFilter();
			};

			class EXTAPI StudyPatientFilter: public IHistoryFilter
			{
			public:
				StudyPatientFilter() {}

				StudyPatientFilter(const std::string& pat_id) {
					this->pat_id = pat_id;
				}

				void SetPatientId(const std::string& pat_id) {
					this->pat_id = pat_id;
				}

				const std::string& GetPatientId() {
					return pat_id;
				}

				virtual std::string GetSQLFilter();
			protected:
				std::string pat_id;
			};

			class EXTAPI StudyLocationFilter: public IHistoryFilter
			{
			public:
				StudyLocationFilter(GNC::GCS::IHistoryController::TLocation location): Location(location) {}

				StudyLocationFilter() {
					;
				}

				virtual std::string GetSQLFilter();
			protected:
				GNC::GCS::IHistoryController::TLocation Location;
			};

		}
		class EXTAPI HistoryController: public IHistoryController{
		public:
			typedef std::list<long> IdList;
			typedef struct TaskModel {
				long pk;
				std::string uid;
				int status;
				std::string statusDescription;
				std::string data;
				std::string description;
				std::string	created_time;
				IdList seriesId;
				TaskModel() {
					pk = 0;
					status = 0;
				}
			} TaskModel;

	//region "Patron singleton"
		public:
			static HistoryController* Instance();
			static void FreeInstance();
			
			/* Constructor*/
			HistoryController();
			HistoryController(const std::string& pathOfDataBase);
		protected:
			void InitController(const std::string& pathOfDataBase);
		public:
			virtual ~HistoryController();

			bool IsOk();
			bool IsReadOnly();
			virtual std::string GetGinkgoDicomDir(bool barraAlFinal = false);
			void ReloadHistory(const std::string& pathDicomDir = "", bool tryTemp = true);			
			static std::string GetDefaultDicomDirPath(bool ignoreConfig = false);
		protected:
			//	//sincrono con la interfaz
			static HistoryController* m_pInstance;
	//endregion
		public:

			//region "metodos propios del historial"
			bool AddFiles(const StringList& listaPaths, TAddErrorList& errorList, std::list<long>* insertedSeries, GNC::IProxyNotificadorProgreso* pNotificador = NULL, TAddAction action = TAA_COPY);
			bool UpdateFiles(const GNC::GCS::HistoryController::FileModelList& files);
			bool LinkFilesToSeries(long seriesPk, GNC::GCS::HistoryController::DICOMFileModelList& files, GNC::IProxyNotificadorProgreso* pNotificador = NULL);
		protected:
			bool UpdateFileModel(FileModel& fileModel);
			void FindOrInsertStudy(DICOMFileModel& model);
			void FindOrInsertSeries(DICOMFileModel& model);
			bool FindOrInsertFile(DICOMFileModel& model);
			bool FindOrLink(DICOMFileModel& model);

			void UpdateStudy(DICOMFileModel& model);
			void UpdateSeries(DICOMFileModel& model);
			void UpdateFile(DICOMFileModel& model);

			std::string GetPathOfFile(GNC::GCS::IHistoryController::TLocation location, long pk, const std::string& file_path);
			std::string GetPathOfFile(long file_pk);
			std::string GetRelativePath(const std::string& absolutePath);
			std::string GetAbsolutePath(const std::string& relativePath);
			void UpdateSeriesSummaryInfo(long series_pk);
			void UpdateStudySummaryInfo(long study_pk);
		public:
			SeriesModel GetSeriesModel(long series_pk);
			void GetDatabaseDatasetFromSeries(long series_pk, GIL::DICOM::DicomDataset& dataset);
			void GetSeriesModelFromUIDs(const StringList& uids, SeriesModelList& series);
			void GetSeriesModelFromUID(const std::string& uids, SeriesModelList& series);
			void GetSeriesFromStudy(long study_pk, SeriesModelList& listOfSeries);
			StudyModel GetStudyModel(long study_pk);
			void GetStudyModelFromUID(const std::string& uids, StudyModelList& studies);
			/**
			gets dicom tags from study stored in database
			*/
			void GetDatabaseDatasetFromStudy(long study_pk, GIL::DICOM::DicomDataset& dataset);
			void GetStudies(GNC::GCS::History::IHistoryFilter* historyFilter, StudyModelList& listOfStudies);
			void GetStudies(std::list<GNC::GCS::History::IHistoryFilter*>& historyFilter, StudyModelList& listOfStudies);
			FileModel GetFrameOfReference(long series_pk);
			FileModel GetFrameOfReference(const std::string& series_pk);
			FileModel GetFileModel(long file_pk);
			FileModel GetFileModelFromSopInstance(const std::string& sopInstanceUID, long study_pk = -1);

			void GetAllPatients(GNC::GCS::HistoryController::PatientModelList& patientList);
			
			bool ExistsSeriesWithUID(const std::string& seriesUID);
			bool ExistsStudyWithUID(const std::string& studyUID);
			int GetNumberOfFiles();
			/**this method take a lot of time, if you don't need verbose information, use LightFileModelList...**/
			virtual void GetSeriesSortedFileModels(long series_pk, FileModelList& fileList, bool onlyFirst = false);
			virtual void GetSeriesSortedFileModels(long series_pk, LightFileModelList& fileList, bool onlyFirst = false);
			StringList GetSeriesSortedPathsByUID(const std::string& seriesUID);
			StringList GetSeriesSortedPaths(const std::string& series_pk);
			StringList GetSeriesSortedPaths(long series_pk);
			virtual StringList GetSeriesSopClasses(long series_pk);
			char GetSeriesOrientation(long series_pk);

			bool DeleteSeriesList(const IdList& pks);
			bool DeleteSopInstanceUIDs(const StringList& sopInstanceUIds);

			bool EmptyHistory(bool eliminarDelDisco);
		//	//thumbnails...
			void SetThumbnail(long file_pk, int ancho, int alto, const unsigned char* imagen);
			void GetThumbnail(long file_pk, int& ancho, int& alto, unsigned char*& imagen);
			void DeleteThumbnails(IdList& listPks);

			//deprecated persistent commands are deprecated
			virtual void SaveTask(GNC::GCS::IPersistentCommand* pTask);
			virtual void DeleteTasks(const std::list<TaskModel>& tasks);
			virtual bool IsPendingTasks();
			virtual void GetPendingTasks(std::list<TaskModel>& tasks);
			virtual void GetSeriesPendingTasks(const std::list<long>& seriesPk, std::list<TaskModel>& tasks);
			virtual void GetSeriesTasks(const std::list<long>& seriesPk, std::list<TaskModel>& tasks);
			virtual TaskModel GetTask(long idTask);
			virtual void GetAllTasks(std::list<TaskModel>& tasks);
		//	//
		//protected:
		//	//region "helpers"
		//	//devuelve false si !copia y no esta donde deberia
		public:
			bool ReadFile(DICOMFileModel& modelo,const std::string& pathAbsoluto, TAddErrorList& errorList, TAddAction action);
			bool ReadFile(DICOMFileModel& modelo,const std::string& pathAbsoluto, TAddErrorList& errorList);

		protected:
			void RemoveFilesFromDisk(StringList&listOfFiles);

			//endergion

			wxSQLite3Database* m_pConexion;
			wxSQLite3Database* m_pConexionThumbnails;
			wxCriticalSection* m_pCriticalSection;
			wxCriticalSection* m_pCriticalSectionThumbnails;
			bool m_readOnly;
			std::string m_GinkgoDicomDir;
		};
	}
}
