/*
*  
*  $Id: generaldata.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
*
*
*/

#include <string>
#include <sstream>
#include <cmath>

#include <wx/msgdlg.h>
#include <wx/filedlg.h>
#include <wx/valtext.h>
#include <wx/busyinfo.h>
#include <wx/image.h>
#include <wx/filename.h>
#include <wx/dir.h>
#include <wx/msgdlg.h>
#include <wx/tokenzr.h>

#include <main/controllers/configurationcontroller.h>
#include <main/controllers/controladorpermisos.h>

#include <api/ientorno.h>

#include <api/dicom/idicommanager.h>

#include <main/controllers/commandcontroller.h>

#include <commands/comandopacs.h>

#include <export/tagsprivadoscomunes.h>

#include "generaldata.h"

namespace GNC {
	namespace GUI {
		void SetStringField(GIL::DICOM::DicomDataset& tagsDicom, const std::string& tagDICOM, wxTextCtrl* field, bool autodisable = true) 
		{
			std::string value;
			if (tagsDicom.getTag(tagDICOM, value)) {
				field->SetValue(wxString::FromUTF8(value.c_str()));
				if (autodisable) {
					field->Enable(false);
				}
			}
		}

		void SetDateField(GIL::DICOM::DicomDataset& tagsDicom, const std::string& tagDICOM, wxDatePickerCtrl* field, bool autodisable = true) 
		{
			std::string value;
			if (tagsDicom.getTag(tagDICOM, value)) {
				wxDateTime fecha;
				fecha.ParseFormat(wxString::FromUTF8(value.c_str()),wxT("%Y%m%d"));
				if(fecha.IsValid()){
					field->SetValue(fecha);
				}
				if (autodisable) {
					field->Enable(false);
				}
			}
		}

		void SetTimeField(GIL::DICOM::DicomDataset& tagsDicom, const std::string& tagDICOM, wxMaskedTextCtrl* field, bool autodisable = true) 
		{
			std::string value;
			if (tagsDicom.getTag(tagDICOM, value)) {
				wxDateTime fecha;
				fecha.ParseFormat(wxString::FromUTF8(value.c_str()),wxT("%H%M%S"));
				if(fecha.IsValid()){
					field->SetDateTimeValue(fecha);
				}
				if (autodisable) {
					field->Enable(false);
				}
			}
		}

		GeneralData::GeneralData(wxWindow* pParent,IWizard* pWizard,const GNC::GCS::Ptr<ImportationData>& importationData, bool seriesDescription):PanelDatosGeneralesBase(pParent),IPasoWizard(pWizard)
		{
			Hide();
			m_pImportData=importationData;

			wxTextValidator OnlyNum = wxTextValidator(wxFILTER_NUMERIC);
			m_pPacienteAltura->SetValidator(OnlyNum);
			m_pPacientePeso->SetValidator(OnlyNum);

			wxDateTime date = wxDateTime::Now();
			m_pEstudioTime->SetDateTimeValue(date);
			m_pSerieTime->SetDateTimeValue(date);

			if(m_pImportData->m_pIntegrationModel.IsValid()) {
				GIL::DICOM::DicomDataset& tagsDicom = m_pImportData->m_pIntegrationModel->TagsDICOMOverwrite;
				SetStringField(tagsDicom, "0008|1030", m_pEstudioDescripcion, false);
				SetDateField(tagsDicom, "0008|0020", m_pEstudioFecha);
				SetTimeField(tagsDicom, "0008|0030", m_pEstudioTime);
				SetStringField(tagsDicom, "0008|103e", m_pSerieDescripcion);
				SetDateField(tagsDicom, "0008|0021", m_pSerieFecha);
				SetTimeField(tagsDicom, "0008|0031", m_pSerieTime);
				SetDateField(tagsDicom, "0010|0030", m_pPacienteFechaNacimiento);
				std::string tmp;
				if (tagsDicom.getTag("0010|1020", tmp)) { //height
					wxString value = wxString::FromUTF8(tmp.c_str());
					double height;
					if (value.ToDouble(&height)) {
						height *= 100.0;
						wxString wstraltura;
						wstraltura << ((int)height);
						m_pPacienteAltura->SetValue(wstraltura);
						m_pPacienteAltura->Enable(false);
					}
				}
				if (tagsDicom.getTag("0010|0040", tmp)) { //sex
					wxString value = wxString::FromUTF8(tmp.c_str());
					if(value.CompareTo(wxT("M"), wxString::ignoreCase) == 0){
						m_pPacienteSexo->SetSelection(1);
					}else if(value.CompareTo(wxT("F"), wxString::ignoreCase) == 0){
						m_pPacienteSexo->SetSelection(2);
					}else if(value.CompareTo(wxT("O"), wxString::ignoreCase) == 0){
						m_pPacienteSexo->SetSelection(3);
					}else{
						m_pPacienteSexo->SetSelection(0);
					}
					m_pPacienteSexo->Enable(false);
				}
				if (tagsDicom.getTag("0010|0020", tmp)) { // patient id
					SetStringField(tagsDicom, "0010|0020", m_pPacienteId);
				} else {
					m_pPacienteId->SetBackgroundColour(wxColor(255, 213, 213));
					m_pPacienteId->SetFocus();
				}
				//name and surname
				if (tagsDicom.getTag("0010|0010", tmp)) { //name of patient
					wxString value = wxString::FromUTF8(tmp.c_str());
					wxStringTokenizer tokenizer(value, wxT("^"));
					if(tokenizer.HasMoreTokens()) {
						m_pPatientSurname->SetValue(tokenizer.GetNextToken());
					} 
					if(tokenizer.HasMoreTokens()) {
						m_pPacienteNombre->SetValue(tokenizer.GetNextToken());
					} 
					m_pPatientSurname->Enable(false);
					m_pPacienteNombre->Enable(false);
				}

				// Populate Accno
				if (GNC::GCS::IControladorPermisos::Instance()->Get("core.importacion", "input_accno").Activo()) {
					SetStringField(tagsDicom, "0008|0050", m_pAccessionNumber);
					m_pAccessionNumber->Show();
					m_pLabelAccNumber->Show();
				} else {
					m_pAccessionNumber->Hide();
					m_pLabelAccNumber->Hide();
				}
			}
			m_pSeriesPanel->Show(seriesDescription);
			m_panelStudyDetails->Layout();
			Layout();
		}

		GeneralData::~GeneralData()
		{
		}


		//region "Metodos heredados de Ipasowizard"

		bool GeneralData::Attach()
		{
			return true;
		}

		std::string GeneralData::GetTitle(){
			return _Std("Overview data of DICOM files");
		}

		std::string GeneralData::GetSubTitle(){
			return _Std("DICOM data from the files to be generated can be populated");
		}

		bool GeneralData::Siguiente(){
			return true;
		}

		bool GeneralData::Anterior(){
			return false;
		}

		bool GeneralData::Cancelar(){
			return true;
		}

		bool GeneralData::Validar()
		{
			return Validar(false);
		}

		bool GeneralData::Validar(bool silent){
			wxString mensaje = wxEmptyString;

			if (m_pPacienteId->GetValue().IsEmpty()) {
				mensaje += _("\n* The patient ID is required.");
			}

			if(m_pPacienteNombre->GetValue().size() + m_pPatientSurname->GetValue().size() > 61) {
				mensaje += _("\n* Concatenation of patient name and surnames can't be higher than 61.");
			}

			if(!ValidarDouble(std::string(m_pPacienteAltura->GetValue().ToUTF8()),0.0f,400.0f, false, false)){
				mensaje += _("\n* The format of the height in centimeters is not correct. ");
			}

			if ( m_pPacienteFechaNacimiento->GetValue().IsLaterThan(m_pEstudioFecha->GetValue()) ) {
				mensaje += _("\n* The patient's birth date is after the date of study");
			}

			if(!ValidarDouble(std::string(m_pPacientePeso->GetValue().ToUTF8()),0.0f,400.0f, false, false)){
				mensaje += _("\n* The format of the weight is not correct. Valid range is between 0 and 400 Kg.");
			}

			if(mensaje != wxEmptyString){
				if (!silent) {
					wxMessageBox(_("The following errors have occurred when validating fields") + mensaje, _("Error validating fields"), wxICON_ERROR);
				}

				return false;
			} else {
				GetPacienteAltura();
				GetPacienteNombre();
				GetPacienteIdentificador();				
				GetPacienteEdad();
				GetPacienteFechaNacimiento();
				GetPacientePeso();
				GetPacienteSexo();
				GetEstudioDescripcion();
				GetEstudioFecha();
				GetEstudioTime();
				GetSerieDescripcion();
				GetSerieFecha();
				GetSerieTime();
				if (GNC::GCS::IControladorPermisos::Instance()->Get("core.importacion", "input_accno").Activo()) {
					GetAccno();
				}
				return true;
			}
		}

		bool GeneralData::IsSkipped()
		{
			return GNC::GCS::IControladorPermisos::Instance()->ObtenerPermiso("core.importacion", "skip_demographic") && Validar(true);
		}

		void GeneralData::GetPacienteNombre()
		{
			std::ostringstream ostr;
			ostr << m_pPatientSurname->GetValue().ToUTF8();
			ostr << "^" << m_pPacienteNombre->GetValue().ToUTF8();

			m_pImportData->baseImages.tags["0010|0010"] = ostr.str();
		}

		void GeneralData::GetPacienteIdentificador(){
			m_pImportData->baseImages.tags["0010|0020"] = std::string(m_pPacienteId->GetValue().ToUTF8());
		}

		void GeneralData::GetPacienteFechaNacimiento(){
			m_pImportData->baseImages.tags["0010|0030"] =  std::string(m_pPacienteFechaNacimiento->GetValue().Format(wxT("%Y%m%d")).ToUTF8());
		}

		void GeneralData::GetPacienteEdad()
		{
			int edad = CalcularEdad();
			std::ostringstream os;
			os.fill('0');
			os.width(3);
			os << edad << "Y";
			m_pImportData->baseImages.tags["0010|1010"] =  os.str();
		}

		void GeneralData::GetPacientePeso(){
			std::string peso = std::string(m_pPacientePeso->GetValue().ToUTF8());
			if (peso.size() != 0) {
				m_pImportData->baseImages.tags["0010|1030"] =peso;
			}
		}

		void GeneralData::GetPacienteAltura(){
			if (!m_pPacienteAltura->GetValue().IsEmpty()) {
				std::istringstream is (std::string(m_pPacienteAltura->GetValue().ToUTF8()));
				float altura = 0.0f;
				is >> altura;
				altura = std::floor(altura);
				altura /= 100.0f;
				std::ostringstream os;
				os << altura;
				m_pImportData->baseImages.tags["0010|1020"] = os.str();
			}
		}

		void GeneralData::GetPacienteSexo(){
			switch(m_pPacienteSexo->GetSelection()){
				case 1:
					m_pImportData->baseImages.tags["0010|0040"] = "M";
					break;
				case 2:
					m_pImportData->baseImages.tags["0010|0040"] = "F";
					break;
				case 3:
					m_pImportData->baseImages.tags["0010|0040"] = "O";
					break;
				default:
					break;
			}
		}

		void GeneralData::OnKillFocusEstudioTimeControl(wxFocusEvent &){
			if(!m_pEstudioTime->GetDateTimeValue().IsValid()){
				wxDateTime ahora = wxDateTime::Now();
				m_pEstudioTime->SetDateTimeValue(ahora);
			}
		}

		void GeneralData::EnableComponents(bool enable){
			m_pEstudioDescripcion->Enable(enable);
			m_pEstudioFecha->Enable(enable);
			m_pEstudioTime->Enable(enable);
			m_pSerieDescripcion->Enable(enable);
			m_pSerieFecha->Enable(enable);
			m_pSerieTime->Enable(enable);
		}


		void GeneralData::GetEstudioFecha(){
			if(m_pEstudioFecha->GetValue().IsValid()){
				 m_pImportData->baseImages.tags["0008|0020"] = std::string(m_pEstudioFecha->GetValue().Format(wxT("%Y%m%d")).ToUTF8());
			}
		}

		void GeneralData::GetEstudioTime(){
			if(m_pEstudioTime->GetDateTimeValue().IsValid()){
				m_pImportData->baseImages.tags["0008|0030"] = std::string(m_pEstudioTime->GetDateTimeValue().Format(wxT("%H%M%S")).ToUTF8());
			}
		}

		void GeneralData::GetEstudioDescripcion(){
			m_pImportData->baseImages.tags["0008|1030"] = std::string(m_pEstudioDescripcion->GetValue().ToUTF8());
		}

		void GeneralData::OnKillFocusSerieTimeControl(wxFocusEvent &){
			if(!m_pSerieTime->GetDateTimeValue().IsValid()){
				wxDateTime ahora = wxDateTime::Now();
				m_pSerieTime->SetDateTimeValue(ahora);
			}
		}

		void GeneralData::GetSerieFecha(){
			if (m_pSeriesPanel->IsShown()) {
				if(m_pSerieFecha->GetValue().IsValid()){
					m_pImportData->baseImages.tags["0008|0021"] = std::string(m_pSerieFecha->GetValue().Format(wxT("%Y%m%d")).ToUTF8());
				}
			} else {
				if(m_pEstudioFecha->GetValue().IsValid()){
					 m_pImportData->baseImages.tags["0008|0021"] = std::string(m_pEstudioFecha->GetValue().Format(wxT("%Y%m%d")).ToUTF8());
				}
			}
		}

		void GeneralData::GetSerieTime(){
			if (m_pSeriesPanel->IsShown()) {
				if(m_pSerieTime->GetDateTimeValue().IsValid()){
					m_pImportData->baseImages.tags["0008|0031"] = std::string(m_pSerieTime->GetDateTimeValue().Format(wxT("%H%M%S")).ToUTF8());
				}
			} else {
				if(m_pEstudioTime->GetDateTimeValue().IsValid()){
					m_pImportData->baseImages.tags["0008|0031"] = std::string(m_pEstudioTime->GetDateTimeValue().Format(wxT("%H%M%S")).ToUTF8());
				}
			}
		}

		void GeneralData::GetAccno() {
			if (m_pAccessionNumber->IsShown()) {
				m_pImportData->baseImages.tags["0008|0050"] = std::string(m_pAccessionNumber->GetValue().ToUTF8());
			}
		}

		void GeneralData::GetSerieDescripcion(){
			if (m_pSeriesPanel->IsShown()) {
				m_pImportData->baseImages.tags["0008|103e"] =  std::string(m_pSerieDescripcion->GetValue().ToUTF8());
			} else {
				m_pImportData->baseImages.tags["0008|103e"] =  std::string(m_pEstudioDescripcion->GetValue().ToUTF8());
			}
		}

		int GeneralData::CalcularEdad()
		{
			wxDateTime fechaEstudio = m_pEstudioFecha->GetValue();
			wxDateTime fechaNacimiento = m_pPacienteFechaNacimiento->GetValue();
			int edad = 0;
			if( (fechaEstudio.GetMonth() > fechaNacimiento.GetMonth()) ||
				(fechaEstudio.GetMonth() == fechaNacimiento.GetMonth() && fechaEstudio.GetDay() >= fechaNacimiento.GetDay()) ){
					edad = fechaEstudio.GetYear() - fechaNacimiento.GetYear();
			} else {
				edad = fechaEstudio.GetYear() - fechaNacimiento.GetYear() - 1;
			}
			return edad;
		}
	}
}
