/*
 *  
 *  $Id: ecgstudy.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 <wx/app.h>
#include <wx/xml/xml.h>
#include <wx/file.h>
#include <wx/filename.h>
#include <wx/mstream.h>
#include <wx/tokenzr.h>

#include <api/globals.h>
//#include <api/filename.h>
#include <api/ientorno.h>
#include <api/toolsystem/itoolsregistry.h>
#include <api/internationalization/internationalization.h>

#include <main/controllers/controladorlog.h>

#include <api/controllers/icontroladorcarga.h>
#include <api/imodelointegracion.h>

#include <api/dicom/idicommanager.h>
#include <api/dicom/idicomizador.h>
#include <main/entorno.h>
#include <main/controllers/historycontroller.h>

#include "ecgstudy.h"

#include <vtkPointData.h>
#include <vtkImageData.h>



namespace UIDS {
	
	const char* HemodynamicWaveformStorage = "1.2.840.10008.5.1.4.1.1.9.2.1";
	const char* TwelveLeadECGWaveformStorage = "1.2.840.10008.5.1.4.1.1.9.1.1";
	const char* GeneralECGWaveformStorage = "1.2.840.10008.5.1.4.1.1.9.1.2";
}

namespace TAGS {
	const char* MediaStorageSOPClassUID = "0002|0002";
	const char* WaveformOriginality = "003a|0004";
	const char* NumberOfWaveformChannels = "003a|0005";
	const char* NumberOfWaveformSamples = "003a|0010";
	const char* SamplingFrequency = "003a|001a";
	const char* MultiplexGroupLabel = "003a|0020";
	const char* ChannelDefinitionSequence = "003a|0200";
	const char* WaveformChannelNumber = "003a|0202";
	const char* ChannelLabel = "003a|0203";
	const char* ChannelStatus = "003a|0205";
	const char* ChannelSourceSequence = "003a|0208";
	const char* ChannelSourceModifiersSequence = "003a|0209";
	const char* SourceWaveformSequence = "003a|020a";
	const char* ChannelDerivationDescription = "003a|020c";
	const char* ChannelSensitivity = "003a|0210";
	const char* ChannelSensitivityUnitsSequence = "003a|0211";
	const char* ChannelSensitivityCorrectionFactor = "003a|0212";
	const char* ChannelBaseline = "003a|0213";
	const char* ChannelTimeSkew = "003a|0214";
	const char* ChannelSampleSkew = "003a|0215";
	const char* ChannelOffset = "003a|0218";
	const char* WaveformBitsStored = "003a|021a";
	const char* FilterLowFrequency = "003a|0220";
	const char* FilterHighFrequency = "003a|0221";
	const char* NotchFilterFrequency = "003a|0222";
	const char* NotchFilterBandwidth = "003a|0223";
	const char* WaveformDataDisplayScale = "003a|0230";
	const char* WaveformDisplayBkgCIELabValue = "003a|0231";
	const char* WaveformPresentationGroupSequence = "003a|0240";
	const char* PresentationGroupNumber = "003a|0241";
	const char* ChannelDisplaySequence = "003a|0242";
	const char* ChannelRecommendDisplayCIELabValue = "003a|0244";
	const char* ChannelPosition = "003a|0245";
	const char* DisplayShadingFlag = "003a|0246";
	const char* FractionalChannelDisplayScale = "003a|0247";
	const char* AbsoluteChannelDisplayScale = "003a|0248";
	const char* MultiplexAudioChannelsDescrCodeSeq = "003a|0300";
	const char* ChannelIdentificationCode = "003a|0301";
	const char* ChannelMode = "003a|0302";

	const char* WaveFormSequence = "5400|0100";
	const char* ChannelMinimumValue = "5400|0110";
	const char* ChannelMaximumValue = "5400|0112";
	const char* WaveformBitsAllocated = "5400|1004";
	const char* WaveformSampleInterpretation = "5400|1006";
	const char* WaveformPaddingValue = "5400|100a";
	const char* WaveformData = "5400|1010";

	const char* AnnotationSequence = "0040|b020";
	const char* UnformattedTextValue = "0070|0006";
	const char* AnnotationGroupNumber = "0040|a180";
	const char* ReferencedChannels = "0040|a0b0";
	const char* TemporalRangeType = "0040|a130";
	const char* RefSamplePositions = "0040|a132";
	const char* NumericValue = "0040|a30a";

	const char* ConceptCodeSequence = "0040|a168";
	const char* ConceptNameCodeSequence = "0040|a043";
	const char* MeasurementsUnitsCodeSequence = "0040|08ea";
	const char* CodingSchemeDesignator = "0008|0102";
	const char* CodingValue ="0008|0100";
	const char* CodingSchemeVersion = "0008|0103";
}

template<class T> void Get(const std::string& str, T& val)
{
	std::istringstream is(str);
	is >> val;
}

typedef std::vector<std::pair<std::string, std::string> > TVectorPairStrings;
typedef std::vector<std::string> TVectorStrings;
typedef std::map<int,TVectorStrings > TMapVectorStrings;

bool IsCodeSequence(GIL::DICOM::DicomDataset& base, const std::string& tag, std::string& codeValue, std::string codingSchemeDesignator, std::string codingSchemeVersion)
{
	GIL::DICOM::DicomDataset* seq = base.buscar_secuencia(tag);
	if (seq != NULL && seq->items.size() > 0) {
		if (seq->items.front().getTag(TAGS::CodingSchemeDesignator) == codingSchemeDesignator || seq->items.front().getTag(TAGS::CodingSchemeVersion) == codingSchemeVersion) {
			seq->items.front().getTag(TAGS::CodingValue, codeValue);
			return true;
		}
	} 
	return false;
}

int calcNrOfValues(const TMapVectorStrings& vals)
{
	int nr = 0;

	for (TMapVectorStrings::const_iterator it = vals.begin(); it != vals.end(); ++it) {
		for (TVectorStrings::const_iterator itV = (*it).second.begin(); itV != (*it).second.end(); ++itV) {
			if ((*itV) != "") {
				nr ++;
			}
		}		
	}

	return nr;
}

TMapVectorStrings GetValues(GIL::DICOM::DicomDataset* sequence, TVectorPairStrings& items, TVectorPairStrings& units, std::list<int>& rwc, bool special)
{
	TMapVectorStrings result;

	TMapVectorStrings sl;

	for (GIL::DICOM::DicomDataset::DatasetList::reverse_iterator itAnnotations = sequence->items.rbegin(); itAnnotations != sequence->items.rend(); ++itAnnotations) 
	{
		GIL::DICOM::DicomDataset& base = (*itAnnotations);
		std::string itemName;

		if (IsCodeSequence(base, TAGS::ConceptNameCodeSequence, itemName, "SCPECG", "1.3"))
		{
			unsigned int nr = 0;

			for (;nr < (int)items.size();nr++) {
				if (items[nr].first == itemName) {
					break;
				}
			}

			if (nr == items.size())
				continue;

			std::string val;
			int groupNr;
			Get(base.getTag(TAGS::AnnotationGroupNumber),groupNr);

			if (units[nr].second == "")
			{
				if (units[nr].first == base.getTag(TAGS::TemporalRangeType))
					val = base.getTag(TAGS::RefSamplePositions);
			}
			else if (IsCodeSequence(base, TAGS::MeasurementsUnitsCodeSequence, val, "UCUM", "1.4"))
			{
				val = base.getTag(TAGS::NumericValue);
			}

			/*int[] tempRWC = ds.GetInts(Tags.RefWaveformChannels);

			if ((val != null)
			&&	(groupNr >= 0)
			&&	(tempRWC.Length == rwc.Length))
			{
				for (int k=0;k < rwc.Length;k++)
					if (tempRWC[k] != rwc[k])
						continue;

				string[] temp = null;

				if (sl.Contains(groupNr))
					temp = (string[]) sl[groupNr];
				else
				{
					temp = new string[items.GetLength(1)];

					sl.Add(groupNr, temp);
				}

				temp[nr] = val;
			}*/
			if (val != "" && groupNr>=0) {
				if (sl.find(groupNr) == sl.end()) {
					sl[groupNr] = TVectorStrings(items.size());
				}
				sl[groupNr][nr] = val;
			}
		}
	}//for

	if (sl.size() > 0)
	{	
		if (special && sl.size() >= 2
			&&	(items.size() < 64))
		{
			size_t temp1 = items.size();
			unsigned long a = 0, b = 0; 

			TVectorStrings& temp2 = sl.begin()->second;
			int i = 0;
			for (TVectorStrings::iterator it = temp2.begin(); it != temp2.end(); ++it,++i) {
				if ((*it) != "") {
					a |= (1UL << i);
				}
			}

			TMapVectorStrings::iterator itSecond = sl.begin();
			itSecond++;
			TVectorStrings& temp3 = itSecond->second;
			i = 0;
			for (TVectorStrings::iterator it = temp3.begin(); it != temp3.end(); ++it,++i) {
				if ((*it) != "") {
					b |= (1UL << i);
				}
			}

			if ((a ^ b) == (a + b))
			{
				for (size_t i = 0; i < temp1; i++) {
					if (temp2[i] != "") {
						temp3[i] = temp2[i];
					}
				}

				sl.erase(sl.begin());
			}
		}

		for (TMapVectorStrings::iterator it = sl.begin(); it != sl.end(); ++it)
		{
			result[(*it).first] = TVectorStrings();

			for (TVectorStrings::iterator itStr = (*it).second.begin(); itStr != (*it).second.end(); ++itStr)
				result[(*it).first].push_back((*itStr));
			std::ostringstream ostr;
			ostr << (*it).first;
			result [(*it).first].push_back(ostr.str());
		}
	}
	return result;
}


///////////////////////////////////////////////////////////////////////
void GNKVisualizator::ChannelInfo::SetLead(const std::string& codingSchemeDesignator, const std::string& codingValue)
{
	if (codingSchemeDesignator == "SCPECG") 
	{		
		wxStringTokenizer tkz(wxString::FromUTF8(codingValue.c_str()), wxT("-"));
		//code is the last token
		wxString code(wxT("0"));
		while (tkz.HasMoreTokens()) {
			code = tkz.GetNextToken();
		}
		long lead = 0;
		if (code.ToLong(&lead) && lead > 0 && lead < 185) {
			this->LeadType = (TLeadType)(lead);
		}
	} else if (codingSchemeDesignator == "MDC") {

		const char* mdc0[] = { "MDC_ECG_LEAD_CONFIG", "MDC_ECG_LEAD_I", "MDC_ECG_LEAD_II", "MDC_ECG_LEAD_V1", "MDC_ECG_LEAD_V2", "MDC_ECG_LEAD_V3", "MDC_ECG_LEAD_V4", "MDC_ECG_LEAD_V5", "MDC_ECG_LEAD_V6",
			"MDC_ECG_LEAD_V7", "MDC_ECG_LEAD_V2R", "MDC_ECG_LEAD_V3R", "MDC_ECG_LEAD_V4R", "MDC_ECG_LEAD_V5R", "MDC_ECG_LEAD_V6R", "MDC_ECG_LEAD_V7R", "MDC_ECG_LEAD_X", "MDC_ECG_LEAD_Y", "MDC_ECG_LEAD_Z",
			"MDC_ECG_LEAD_CC5", "MDC_ECG_LEAD_CM5", "MDC_ECG_LEAD_LA", "MDC_ECG_LEAD_RA", "MDC_ECG_LEAD_LL", "MDC_ECG_LEAD_fI", "MDC_ECG_LEAD_fE", "MDC_ECG_LEAD_fC", "MDC_ECG_LEAD_fA", " MDC_ECG_LEAD_fM",
			"MDC_ECG_LEAD_fF", "MDC_ECG_LEAD_fH", "MDC_ECG_LEAD_dI", "MDC_ECG_LEAD_dII", "MDC_ECG_LEAD_dV1", "MDC_ECG_LEAD_dV2", "MDC_ECG_LEAD_dV3", "MDC_ECG_LEAD_dV4", "MDC_ECG_LEAD_dV5", "MDC_ECG_LEAD_dV6"
		};
		for (int i = 0; i< 39; ++i) {
			if (codingValue == mdc0[i]) {
				this->LeadType = (TLeadType)i;
				return;
			}
		}
		const char* mdc61[] = {"MDC_ECG_LEAD_III", "MDC_ECG_LEAD_aVR", "MDC_ECG_LEAD_aVL", "MDC_ECG_LEAD_aVF", "MDC_ECG_LEAD_aVRneg", "MDC_ECG_LEAD_V8", "MDC_ECG_LEAD_V9", "MDC_ECG_LEAD_V8R", "MDC_ECG_LEAD_V9R",
			"MDC_ECG_LEAD_D", "MDC_ECG_LEAD_A", "MDC_ECG_LEAD_J", "MDC_ECG_LEAD_Defib", " MDC_ECG_LEAD_Extern", "MDC_ECG_LEAD_A1", "MDC_ECG_LEAD_A2", "MDC_ECG_LEAD_A3", "MDC_ECG_LEAD_A4"
		};
		for (int i = 0; i< 18; ++i) {
			if (codingValue == mdc61[i]) {
				this->LeadType = (TLeadType)(i+61);
				return;
			}
		}
		const char* mdc86[] = {"MDC_ECG_LEAD_C", "MDC_ECG_LEAD_V", "MDC_ECG_LEAD_VR", "MDC_ECG_LEAD_VL", "MDC_ECG_LEAD_VF", "MDC_ECG_LEAD_MCL", "MDC_ECG_LEAD_MCL1", "MDC_ECG_LEAD_MCL2", "MDC_ECG_LEAD_MCL3",
			"MDC_ECG_LEAD_MCL4", " MDC_ECG_LEAD_MCL5", "MDC_ECG_LEAD_MCL6", "MDC_ECG_LEAD_CC", "MDC_ECG_LEAD_CC1", "MDC_ECG_LEAD_CC2", "MDC_ECG_LEAD_CC3", "MDC_ECG_LEAD_CC4", "MDC_ECG_LEAD_CC6", "MDC_ECG_LEAD_CC7",
			"MDC_ECG_LEAD_CM", "MDC_ECG_LEAD_CM1", "MDC_ECG_LEAD_CM2", "MDC_ECG_LEAD_CM3", "MDC_ECG_LEAD_CM4", "MDC_ECG_LEAD_CM6", "MDC_ECG_LEAD_dIII", " MDC_ECG_LEAD_daVR", "MDC_ECG_LEAD_daVL", "MDC_ECG_LEAD_daVF" 
		};
		for (int i = 0; i< 29; ++i) {
			if (codingValue == mdc86[i]) {
				this->LeadType = (TLeadType)(i+86);
				return;
			}
		}
		const char* mdc121[] = {"MDC_ECG_LEAD_CM7", "MDC_ECG_LEAD_CH5", "MDC_ECG_LEAD_CS5", "MDC_ECG_LEAD_CB5", "MDC_ECG_LEAD_CR5", "MDC_ECG_LEAD_ML", "MDC_ECG_LEAD_AB1", "MDC_ECG_LEAD_AB2", "MDC_ECG_LEAD_AB3",
			"MDC_ECG_LEAD_AB4", "MDC_ECG_LEAD_ES", "MDC_ECG_LEAD_AS", "MDC_ECG_LEAD_AI", "MDC_ECG_LEAD_S"
		};
		for (int i = 0; i< 14; ++i) {
			if (codingValue == mdc121[i]) {
				this->LeadType = (TLeadType)(i+121);
				return;
			}
		}
		const char* mdc147[] = {"MDC_ECG_LEAD_RL", "MDC_ECG_LEAD_CV5RL", "MDC_ECG_LEAD_CV6LL", "MDC_ECG_LEAD_CV6LU", "MDC_ECG_LEAD_V10"
		};
		for (int i = 0; i< 5; ++i) {
			if (codingValue == mdc147[i]) {
				this->LeadType = (TLeadType)(i+147);
				return;
			}
		}
	} else {
		LOG_WARN("EGCStudy", "Unsupported coding scheme designator: " << codingSchemeDesignator);
	}
}

std::string GNKVisualizator::ChannelInfo::GetTitle() const
{
	const char* leadStrings[] = {"Unknown", "I", "II", "V1", "V2", "V3", "V4", "V5", "V6", "V7", "V2R", "V3R", "V4R", "V5R", "V6R", "V7R", "X", "Y", "Z",
		"CC5", "CM5", "LA", "RA", "LL", "fI", "fE", "fC", "fA", "fM", "fF", "fH", "dI", "dII", "dV1", "dV2", "dV3", "dV4", "dV5", "dV6",
		"dV7", "dV2R", "dV3R", "dV4R", "dV5R", "dV6R", "dV7R", "dX", "dY", "dZ", "dCC5", "dCM5", "dLA", "dRA", "dLL", "dfI", "dfE",
		"dfC", "dfA", "dfM", "dfF", "dfH", "III", "aVR", "aVL", "aVF", "aVRneg", "V8", "V9", "V8R", "V9R", "D", "A", "J", "Defib",
		"Extern", "A1", "A2", "A3", "A4", "dV8", "dV9", "dV8R", "dV9R", "dD", "dA", "dJ", "Chest", "V", "VR", "VL", "VF", "MCL", "MCL1",
		"MCL2", "MCL3", "MCL4", "MCL5", "MCL6", "CC", "CC1", "CC2", "CC3", "CC4", "CC6", "CC7", "CM", "CM1", "CM2", "CM3", "CM4", "CM6",
		"dIII", "daVR", "daVL", "daVF", "daVRneg", "dChest", "dV", "dVR", "dVL", "dVF", "CM7", "CH5", "CS5", "CB5", "CR5", "ML", "AB1",
		"AB2", "AB3", "AB4", "ES", "AS", "AI", "S", "dDefib", "dExtern", "dA1", "dA2", "dA3", "dA4", "dMCL1", "dMCL2", "dMCL3",
		"dMCL4", "dMCL5", "dMCL6", "RL", "CV5RL", "CV6LL", "CV6LU", "V10", "dMCL", "dCC", "dCC1", "dCC2", "dCC3", "dCC4", "dCC6",
		"dCC7", " dCM", "dCM1", "dCM2", "dCM3", "dCM4", "dCM6", "dCM7", "dCH5", "dCS5", "dCB5", "dCR5", "dML", "dAB1", "dAB2", "dAB3",
		"dAB4", "dES", "dAS", "dAI", "dS", "dRL", "dCV5RL", "dCV6LL", "dCV6LU", "dV10"};
	return std::string(leadStrings[(int)LeadType]);
}

void GNKVisualizator::ChannelInfo::SetUnitsValue(const std::string& unitsvalue) {
	UnitsValue = unitsvalue;
	if (UnitsValue == "mV") {
		Multiplier = 100.0;
	} else if (UnitsValue == "uV") {
		Multiplier = 0.1;
	} else if (UnitsValue == "MV" ) {
		Multiplier = 100000000000.0;
	} else if (UnitsValue == "kV") {
		Multiplier = 100000000.0;
	} else if (UnitsValue ==  "V") {
		Multiplier = 100000.0;
	} else if (UnitsValue == "dV") {
		Multiplier = 10000.0;
	} else if (UnitsValue == "cV") {
		Multiplier = 1000.0;
	} else {
		std::ostringstream ostr;
		ostr << _Std("We are working to support ") << UnitsValue;
		throw GNC::GCS::ControladorCargaException(ostr.str(), "ECGStudy");
	}
}


///////////////////////////////////////////////////////////////////////

GNKVisualizator::ECGStudy::ECGStudy(){
	GTRACE(">> ECGStudy::ECGStudy()" << this);
	GTRACE("<< ECGStudy::ECGStudy()" << this);
}

GNKVisualizator::ECGStudy::~ECGStudy(){
	GTRACE(">> ECGStudy::~ECGStudy()" << this);
	ECGFiles.clear();
	GTRACE("<< ECGStudy::~ECGStudy()" << this);
}


void GNKVisualizator::ECGStudy::InitializeContext(long pkSeries)
{
	GNC::GCS::IHistoryController::FileModelList fileModels;
	GNC::GCS::HistoryController::Instance()->GetSeriesSortedFileModels(pkSeries, fileModels);

	std::list<std::string> rutas;
	for (GNC::GCS::IHistoryController::FileModelList::iterator itFile = fileModels.begin(); itFile != fileModels.end(); ++itFile) 
	{
		rutas.push_back((*itFile).real_path);
	}

	GNC::GCS::IStudyContext::InitializeContext(rutas);

	for (int i = 0; i < (int)rutas.size(); ++i) {
		ECGFiles.push_back(NULL);
	}
}
	
void GNKVisualizator::ECGStudy::SetIndexOfActualMultiplexGroup(int index)
{
	LoadChannels();
	ECGFiles[ActiveFileIndex]->SetIndexOfActualMultiplexGroup(index);
}

GNKVisualizator::ECGStudy::TListChannelInfo& GNKVisualizator::ECGStudy::GetListOfChannels()
{
	LoadChannels();
	return ECGFiles[ActiveFileIndex]->GetListOfChannels();
}

std::list<std::string> GNKVisualizator::ECGStudy::GetLabelOfMultiplexGroups()
{
	LoadChannels();
	return ECGFiles[ActiveFileIndex]->GetLabelOfMultiplexGroups();
}

const std::string GNKVisualizator::ECGStudy::GetGlobalMeasurement()
{
	LoadChannels();
	std::ostringstream ostr;
	if (ECGFiles[ActiveFileIndex]->globalMeasurements.IsValid()) {
		GNKVisualizator::GlobalMeasurements& mes = (*ECGFiles[ActiveFileIndex]->globalMeasurements);

		int ventRate = (mes.getVentRate() == MeasurementNoValue) ? 0 : (int) mes.getVentRate(),
			PRint = (mes.getPRint() == MeasurementNoValue) ? 0 : (int) mes.measurment[0]->PRint(),
			QRSdur = (mes.getQRSdur() == MeasurementNoValue) ? 0 : (int) mes.measurment[0]->QRSdur(),
			QT = (mes.getQTdur() == MeasurementNoValue) ? 0 : (int) mes.measurment[0]->QTdur(),
			QTc = (mes.getQTc() == MeasurementNoValue) ? 0 : (int) mes.getQTc();

		ostr << _Std("Vent rate:      ");
		ostr << ventRate;
		ostr << _Std(" BPM") << std::endl;

		ostr << _Std("PR int:      ");
		ostr << PRint;
		ostr << _Std(" ms") << std::endl;

		ostr << _Std("QRS dur:      ");
		ostr << QRSdur;
		ostr << _Std(" ms") << std::endl;

		ostr << _Std("QT\\QTc:      ");
		ostr << QT << "/" << QTc;
		ostr << _Std(" ms") << std::endl;
		
		ostr << _Std("P-R-T axes: ");
		if (mes.measurment[0]->Paxis != MeasurementNoAxisValue) {
			ostr << mes.measurment[0]->Paxis;
		} else {
			ostr << 999;
		}
		ostr << ' ';
		if (mes.measurment[0]->QRSaxis != MeasurementNoAxisValue) {
			ostr << mes.measurment[0]->QRSaxis;
		} else {
			ostr << 999;
		}
		ostr << ' ';
		if (mes.measurment[0]->Taxis != MeasurementNoAxisValue) {
			ostr << mes.measurment[0]->Taxis;
		} else {
			ostr << 999;
		}
	} else {
		ostr << _Std("Measurements not found");
	}
	return ostr.str();
}

const std::string& GNKVisualizator::ECGStudy::GetDiagnosis()
{
	LoadChannels();
	return ECGFiles[ActiveFileIndex]->GetDiagnosis();
}

void GNKVisualizator::ECGStudy::LoadChannels()
{
	if (!ECGFiles[ActiveFileIndex].IsValid()) 
	{
		GNC::GCS::Ptr<TECGFile> ecgFile(new TECGFile);
		ECGFiles[ActiveFileIndex] = ecgFile;
		
		GNC::GCS::Ptr<GIL::DICOM::DicomDataset> base(new GIL::DICOM::DicomDataset());
		GIL::DICOM::IDICOMManager* pDICOMManager = GNC::GCS::IEntorno::Instance()->GetPACSController()->CrearInstanciaDeDICOMManager();

		GIL::DICOM::TipoMetaInfo metaInfo;

		pDICOMManager->CargarMetaInfo(GetPathActiveImage(), metaInfo);

		std::string sopClassUID = metaInfo.getTag(TAGS::MediaStorageSOPClassUID);

		GIL::DICOM::TagPrivadoUndefined tag;
		
		if (sopClassUID == UIDS::GeneralECGWaveformStorage ||
			sopClassUID == UIDS::HemodynamicWaveformStorage ||
			sopClassUID == UIDS::TwelveLeadECGWaveformStorage )
		{
			
			pDICOMManager->CargarFichero(GetPathActiveImage(), *base, false);
			pDICOMManager->FindTag(0x5400, 0x1010, tag);

			GNC::GCS::IEntorno::Instance()->GetPACSController()->LiberarInstanciaDeDICOMManager(pDICOMManager);
		}
		else {
			GNC::GCS::IEntorno::Instance()->GetPACSController()->LiberarInstanciaDeDICOMManager(pDICOMManager);
			return;
		}

		GIL::DICOM::DicomDataset* waveformSeq = base->buscar_secuencia(TAGS::WaveFormSequence);

		int numChannels = 0;
		int numSamples = 0;
		double samplingFreq = 0.0;
		short paddingValue = 0;
		std::string orig;
		std::string groupLabel;	
		int bitsAllocated;
		std::string waveFormSampleInterpretation;
		
		for (GIL::DICOM::DicomDataset::DatasetList::reverse_iterator itSequences = waveformSeq->items.rbegin(); itSequences != waveformSeq->items.rend(); ++itSequences) 
		{
			//multiplex group
			GIL::DICOM::DicomDataset& wf = (*itSequences);
			ecgFile->Groups.push_back(TMultiplexGroup());
			TMultiplexGroup& group = ecgFile->Groups.back();
					
			Get(wf.getTag(TAGS::NumberOfWaveformChannels), numChannels);
			Get(wf.getTag(TAGS::NumberOfWaveformSamples), numSamples);
			Get(wf.getTag(TAGS::SamplingFrequency), samplingFreq);
			//FIXME mal no pilla bien el padding value porque es de tipo ox
			Get(wf.getTag(TAGS::WaveformPaddingValue), paddingValue);
			wf.getTag(TAGS::WaveformOriginality, orig);
			wf.getTag(TAGS::MultiplexGroupLabel, groupLabel);
			Get(wf.getTag(TAGS::WaveformBitsAllocated), bitsAllocated);
			wf.getTag(TAGS::WaveformSampleInterpretation, waveFormSampleInterpretation);
			if (bitsAllocated != 16 || waveFormSampleInterpretation != "SS") {
				LOG_ERROR("ECGStudy", "We are unnable to interpret bitsAllocated=" << bitsAllocated << " waveFormSampleInterpretation=" << waveFormSampleInterpretation);
				throw GNC::GCS::ControladorCargaException(_Std("ECG format not supported"), "ECGStudy");
			}

			if (groupLabel != "") {
				group.Label = groupLabel;
			}
			
			//std::cout << wf;

			GIL::DICOM::DicomDataset* channel_def_seq = wf.buscar_secuencia(TAGS::ChannelDefinitionSequence);

			if (channel_def_seq->items.size() == (unsigned int) numChannels) {

				int i = 0;
				for (GIL::DICOM::DicomDataset::DatasetList::reverse_iterator it = channel_def_seq->items.rbegin(); it != channel_def_seq->items.rend(); ++it, i++) {
					group.Channels.push_back(GNKVisualizator::ChannelInfo());

					GIL::DICOM::DicomDataset& channel_def = (*it);

					//>> SQ Items (1): (003A,0208) - Channel Source Sequence
					//   > (0008|0104, LO, "Lead I")  # 0x6 - Code Meaning  OK
					//   > (003A|0210, DS, "0.00122")  # 0x8 - Channel sensitivity  OK

					
					GIL::DICOM::DicomDataset* channel_src_seq = channel_def.buscar_secuencia(TAGS::ChannelSourceSequence);

					//>> SQ Items (1): (003A,0211) - Channel sensitivity units
					//  > (0008|0100, SH, "mV")  # 0x2 - Code Value  OK
					//  > (0008|0104, LO, "millivolt")  # 0xA - Code Meaning  OK
					//  > (003A|0212, DS, "1")  # 0x2 - Sensitivity correction factor  OK
					//  > (003A|0213, DS, "0")  # 0x2 - Channel baseline  OK
					//  > (003A|0214, DS, "0")  # 0x2 - Channel Time skew  OK
					//  > (003A|021A, US, 0x0010)  # 0x2 - Bits per sample  OK
					//  > (003A|0220, DS, ".05")  # 0x4 - Filter low frequency  OK
					//  > (003A|0221, DS, "100")  # 0x4 - filter high frequency  OK

					GIL::DICOM::DicomDataset* channel_sen_seq = channel_def.buscar_secuencia("003a|0211");

					if ( channel_src_seq != NULL && channel_src_seq->items.size() > 0 && channel_sen_seq != NULL && channel_sen_seq->items.size() > 0) {					
						GIL::DICOM::DicomDataset& channel_src = channel_src_seq->items.front();
						GIL::DICOM::DicomDataset& channel_sen = channel_sen_seq->items.front();
						
						ChannelInfo& channelInfo = group.Channels[i];

						channelInfo.NumSamples = numSamples;
						channelInfo.SamplingFrecuency = samplingFreq;

						std::string codingValue = channel_src.getTag("0008|0100");
						std::string codingSchemeDesignator = channel_src.getTag("0008|0102");
						channelInfo.SetLead                       (codingSchemeDesignator, codingValue);

						channelInfo.SetUnitsValue                  (channel_sen.getTag                ("0008|0100"));
						channelInfo.SetUnitsMeaning                (channel_sen.getTag                ("0008|0104"));

						channelInfo.SetSensitivity                 (channel_def.getTagAs<double>      ("003a|0210", 1.0));
						channelInfo.SetSensitivityCorrectionFactor (channel_def.getTagAs<double>      ("003a|0212", 1.0));
						channelInfo.SetChannelBaseline             (channel_def.getTagAs<double>      ("003a|0213", 0.0));
						channelInfo.SetChannelTimeSkew             (channel_def.getTagAs<double>      ("003a|0214", 0.0));
						channelInfo.SetBitsPerSample               (channel_def.getTagAs<unsigned int>("003a|021a", 16));
						channelInfo.SetFilterLowFrequency          (channel_def.getTagAs<double>      ("003a|0220", 0.0));
						channelInfo.SetFilterHighFrequency         (channel_def.getTagAs<double>      ("003a|0221", 0.0));
					}
				}			
			}//for channels

			{
				short* data = (short*)tag.GetValor();
				for (int i = 0; i < numSamples; i++) {
					for (TListChannelInfo::iterator it = group.Channels.begin(); it != group.Channels.end(); ++it) {
						GNKVisualizator::ChannelInfo& c = *it;
						c.Samples.push_back(*(data++));
					}
				}

#if defined(_DEBUG)
				GNKVisualizator::ChannelInfo& c = group.Channels.front();
				for (int i = 0; i < 100; i ++) {
					c.Samples[i] = (short) 10.0/(c.Multiplier * c.Sensitivity * c.SensitivityCorrectionFactor);
				}
#endif
			}
		}//for secuencias waveforms
		//annotation
		{
			GIL::DICOM::DicomDataset* annotation_seq = base->buscar_secuencia(TAGS::AnnotationSequence);
			//TODO read referenced channel to read information about each channel

			if (annotation_seq != NULL) {
				//for each annotation group one list of strings
				typedef std::map<int, std::list<std::string> > TMapMultiplexedGroup;
				typedef std::map<int, TMapMultiplexedGroup> TMapAnnotations;
				TMapAnnotations annotationsMap;
				for (GIL::DICOM::DicomDataset::DatasetList::reverse_iterator itAnnotations = annotation_seq->items.rbegin(); itAnnotations != annotation_seq->items.rend(); ++itAnnotations) 
				{
					GIL::DICOM::DicomDataset& an = (*itAnnotations);
					std::string textValue = an.getTag(TAGS::UnformattedTextValue);

					if (textValue != "") {
						int group = 0, multiplexedGroup = 0;
						Get(an.getTag(TAGS::AnnotationGroupNumber), group);
						Get(an.getTag(TAGS::ReferencedChannels), multiplexedGroup);
						multiplexedGroup -= 1;
						annotationsMap[multiplexedGroup][group].push_back(textValue);
					}
				}//for annotations


				for (TMapAnnotations::iterator itAnnotations = annotationsMap.begin(); itAnnotations != annotationsMap.end(); ++itAnnotations) {
					for (int i = 0; i < (int)ecgFile->Groups.size(); ++i) {
						if ((*itAnnotations).second.find(i) != (*itAnnotations).second.end()) 
						{
							TMapMultiplexedGroup& annotationsMultiplexed = (*itAnnotations).second;
							std::ostringstream ostr;
							for (TMapMultiplexedGroup::iterator itGroups = annotationsMultiplexed.begin(); itGroups != annotationsMultiplexed.end(); ++itGroups) {
								for (std::list<std::string>::iterator itStrings = (*itGroups).second.begin(); itStrings != (*itGroups).second.end(); ++itStrings) {
									ostr << (*itStrings) << std::endl;
								}
								ostr << std::endl;
							}
							ecgFile->Groups[i].Diagnosis = ostr.str();
						}
					}
				}
				/////////////////////////////////////////////////////////
				////////////////GLOBAL MEASUREMENTS//////////////////////
				/////////////////////////////////////////////////////////
				std::string s_AvgRRPPItemsCodes[] = {"5.10.2.1-3", "5.10.2.1-5", "5.10.2.5-5", "5.10.2.5-1"};
				std::string s_AvgRRPPItemsMeaning[] = {_Std("RR Interval"), _Std("PP Interval"), _Std("QTc Interval"), _Std("Vent Rate")};
				TVectorPairStrings s_AvgRRPPItems;
				for (int i = 0; i < 4; ++i) {
					s_AvgRRPPItems.push_back(std::pair<std::string, std::string>(s_AvgRRPPItemsCodes[i], s_AvgRRPPItemsMeaning[i]));
				}
				std::string s_AvgRRPPUnitsCodes[] = {"ms", "ms", "ms", "/min"};
				std::string s_AvgRRPPUnitsMeaning[] = {"milliseconds", "milliseconds", "milliseconds", "heartbeat per minute"};
				TVectorPairStrings s_AvgRRPPUnits;
				for (int i = 0; i < 4; ++i) {
					s_AvgRRPPUnits.push_back(std::pair<std::string, std::string>(s_AvgRRPPUnitsCodes[i], s_AvgRRPPUnitsMeaning[i]));
				}
				std::string s_MeasurementItemsCodes[] = {"5.10.3-1", "5.10.3-2", "5.10.3-3", "5.10.3-4", "5.10.3-5", "5.10.3-11", "5.10.3-13", "5.10.3-15"};
				std::string s_MeasurementItemsMeaning[] = {"P onset", "P offset", "QRS onset", "QRS offset", "T offset", "P Axis", "QRS Axis", "T Axis"};
				TVectorPairStrings s_MeasurementItems;
				for (int i = 0; i < 8; ++i) {
					s_MeasurementItems.push_back(std::pair<std::string, std::string>(s_MeasurementItemsCodes[i], s_MeasurementItemsMeaning[i]));
				}
				std::string s_MeasurementUnitsCode[] = {"ms", "ms", "ms", "ms", "ms", "deg", "deg", "deg"};
				std::string s_MeasurementUnitsValue[]= {"milliseconds", "milliseconds", "milliseconds", "milliseconds", "milliseconds", "degrees", "degrees", "degrees"};
				TVectorPairStrings s_MeasurementUnits;
				for (int i = 0; i < 8; ++i) {
					s_MeasurementUnits.push_back(std::pair<std::string, std::string>(s_MeasurementUnitsCode[i], s_MeasurementUnitsValue[i]));
				}
				std::string s_MeasurementUnitsPointsCode[] = {"POINT", "POINT", "POINT", "POINT", "POINT", "deg", "deg", "deg"};
				std::string s_MeasurementUnitsPointsValue[]= {"", "", "", "", "", "degrees", "degrees", "degrees"};
				TVectorPairStrings s_MeasurementUnitsPoints;
				for (int i = 0; i < 8; ++i) {
					s_MeasurementUnitsPoints.push_back(std::pair<std::string, std::string>(s_MeasurementUnitsPointsCode[i], s_MeasurementUnitsPointsValue[i]));
				}
				std::list<int> s_MeasurementRWC;
				s_MeasurementRWC.push_back(1);
				s_MeasurementRWC.push_back(0);

				TMapVectorStrings resultAvgRR_PP = GetValues(annotation_seq, s_AvgRRPPItems, s_AvgRRPPUnits, s_MeasurementRWC, false);
				TMapVectorStrings resultMeasurments = GetValues(annotation_seq, s_MeasurementItems, s_MeasurementUnits, s_MeasurementRWC, true);

				float factor = 1.0f;

				if (!resultAvgRR_PP.empty())
				{
					TMapVectorStrings temp1 = GetValues(annotation_seq, s_MeasurementItems, s_MeasurementUnitsPoints, s_MeasurementRWC, true);

					if ((!temp1.empty()) && ((!resultMeasurments.empty())	|| (resultMeasurments.size() < temp1.size()) || (calcNrOfValues(resultMeasurments) < calcNrOfValues(temp1))))
					{
						if (!ecgFile->Groups.empty()) {
							factor = 1000.0f / ecgFile->Groups[0].Channels[0].SamplingFrecuency;
						}

						resultMeasurments = temp1;
					}
				}

				if ( (!resultAvgRR_PP.empty()) && (!resultMeasurments.empty()) )
				{
					ecgFile->globalMeasurements = GNC::GCS::Ptr<GlobalMeasurements>(new GlobalMeasurements());
					GNKVisualizator::GlobalMeasurements& mes = (*ecgFile->globalMeasurements);

					TVectorStrings& resultVector = resultAvgRR_PP.begin()->second;

					if (resultVector.size() >= 1)
					{
						if (resultVector[0] != "") {
							Get(resultVector[0], mes.AvgRR);
						}

						if (resultVector[1] != "") {
							Get(resultVector[1], mes.AvgPP);
						}

						if (resultVector[2] != "") {
							unsigned short qtc;
							Get(resultVector[2], qtc);
							mes.setQTc(qtc);
						}

						if (resultVector[3] != "") {
							unsigned short ventRate;
							Get(resultVector[3], ventRate);
							mes.setVentRate(ventRate);
						}
					}

					if ( (!resultMeasurments.empty()) && ( ((*resultMeasurments.begin()).second.size() -1) == 8) )
					{
						for (TMapVectorStrings::iterator itMap = resultMeasurments.begin(); itMap != resultMeasurments.end(); ++itMap) {
							GNC::GCS::Ptr<GNKVisualizator::GlobalMeasurement> measurement(new GNKVisualizator::GlobalMeasurement());

							TVectorStrings& vectorStrings = (*itMap).second;
							unsigned short tempUnsignedShort;
							short tempShort;

							Get(vectorStrings[0], tempUnsignedShort);
							measurement->Ponset = (unsigned short)(tempUnsignedShort*factor);
							Get(vectorStrings[1], tempUnsignedShort);
							measurement->Poffset = (unsigned short)(tempUnsignedShort*factor);
							Get(vectorStrings[2], tempUnsignedShort);
							measurement->QRSonset = (unsigned short)(tempUnsignedShort*factor);
							Get(vectorStrings[3], tempUnsignedShort);
							measurement->QRSoffset = (unsigned short)(tempUnsignedShort*factor);
							Get(vectorStrings[4], tempUnsignedShort);
							measurement->Toffset = (unsigned short)(tempUnsignedShort*factor);
							Get(vectorStrings[5], tempShort);
							measurement->Paxis = tempShort;
							Get(vectorStrings[6], tempShort);
							measurement->QRSaxis = tempShort;
							Get(vectorStrings[7], tempShort);
							measurement->Taxis = tempShort;


							mes.measurment.push_back(measurement);
						}
					}
				}

			}//annotation_seq != NULL			
		}//annotation
	}
}


