/*
 *  
 *  $Id: imodelohl7.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 <list>
#include <map>
#include <sstream>

#include <api/api.h>
#include <api/globals.h>
#include <api/iexception.h>

#define RECORD_SEPARATOR "\x0D"

namespace GIL {

	namespace HL7 {

		std::string DefaultEscapeER7(const std::string& str);

		/* Este namespace contiene una implementación completa de mensajeria HL7 generica */

		class HL7Exception : public GNC::GCS::IException {
		public:
			HL7Exception(const std::string& msg, const std::string& component="HL7", bool fatal = true) throw() : GNC::GCS::IException(msg ,component, fatal) {}
		};

		class HL7XMLException : public GNC::GCS::IException {
		public:
			HL7XMLException(const std::string& msg, const std::string& component="XMLIntegration", bool fatal = true) throw() : GNC::GCS::IException(msg ,component, fatal) {}			
		};

		namespace Util {
			inline std::list<std::string> split(const std::string& str, const std::string& separador)
			{
				std::list<std::string> lista;
				std::string::size_type start = 0;
				std::string::size_type end = 0;

				while ((end = str.find (separador, start)) != std::string::npos) {
					lista.push_back (str.substr (start, end-start));
					start = end + separador.size();
				}
				lista.push_back (str.substr (start));
				return lista;
			}

			inline std::string tolower(const std::string& input_string)
			{
				std::string str = input_string;

				// iterate through all the characters.  If uppercase,
				// convert to lowercase.
				for (std::string::size_type i = 0 ; i < str.length() ; ++i)
					if (isupper(str[i]) )
						str[i] |= 32;

				return str;
			}
		}


		class Component {

		private:
			size_t       m_Num;
			std::string  m_Header;
			std::string  m_Value;
			bool         m_Null;

		public:
			Component()
			{
				m_Num = 0;
				m_Null = true;
			}

			Component(size_t num)
			{
				m_Num = num;
				m_Null = true;
			}

			Component(size_t num, const std::string& header) : m_Num(num), m_Header(header), m_Null(true)
			{
			}

			Component(size_t num, const std::string& header, const std::string& value) : m_Num(num), m_Header(header), m_Value(value), m_Null(false)
			{
			}

			Component(const Component& otro)
			{
				*this = otro;
			}

			Component& operator=(const Component& otro)
			{
				m_Num    = otro.m_Num;
				m_Header = otro.m_Header;
				m_Value  = otro.m_Value;
				m_Null  = otro.m_Null;
				return *this;
			}

			Component& operator=(const std::string& valor)
			{
				m_Value = valor;
				m_Null = false;
				return *this;
			}

			bool operator==(const std::string& valor)
			{
				return m_Value == valor;
			}

			bool operator==(const char* valor)
			{
				return m_Value == valor;
			}

			operator const std::string& ()
			{
				return m_Value;
			}

			size_t GetNum() const
			{
				return m_Num;
			}

			const std::string& GetName() const
			{
				return m_Header;
			}

			const std::string& GetValue() const
			{
				return m_Value;
			}

			bool IsNull() const
			{
				return m_Null;
			}

			friend std::ostream& operator<<(std::ostream& out, const Component& sf)
			{
				if (!sf.IsNull()) {
					if (sf.m_Value.size() == 0) {
						out << "\"\"";
					}
					else {
						out << sf.m_Value;
					}
				}
				return out;
			}

			friend std::ostream& operator<<(std::ostream& out, const Component* sf)
			{
				out << *sf;
				return out;
			}
		};

		class Field : public std::map<size_t, Component> {

		private:
			typedef std::map<size_t, Component> Base;

		protected:
			size_t m_Num;
			std::string  m_Header;
			std::string  m_CS;       // component separator
			std::string  m_ES;       // escape separator
			std::string  m_SCS;      // subcomponent separator

		public:

			Field()
			{
				m_Num = 0;
			}

			Field(size_t num, const std::string& header = "", const std::string& sfs ="^", const std::string& es = "\\", const std::string& cs = "&") : m_Num(num), m_Header(header), m_CS(sfs), m_ES(es), m_SCS(cs)
			{
			}

			Field(const Field& otro)
			{
				*this = otro;
			}

			Field& operator=(const Field& otro)
			{
				m_Num    = otro.m_Num;
				m_Header = otro.m_Header;
				m_CS     = otro.m_CS;
				m_ES     = otro.m_ES;
				m_SCS    = otro.m_SCS;
				Base::operator = ((const Base&)otro);
				return *this;
			}

			Field& operator<<(const Component& sf)
			{
				Field::operator[] (sf.GetNum()) = sf;
				return *this;
			}

			Component GetComponent(size_t num) const
			{
				if (num == 0) {
					throw HL7Exception("Indice de componente invalido: 0", "MODEL");
				}

				const_iterator it;
				for (it = begin(); it != end(); ++it) {
					size_t numComponent = (*it).first;
					if (numComponent == num) {
						const Component& c = (*it).second;
						return Component(c);
					}
				}
				return Component(num, "");
			}

			const std::string& GetSFS() const
			{
				return m_CS;
			}

			void SetSFS(const std::string& sfs)
			{
				m_CS = sfs;
			}

			size_t GetNum() const
			{
				return m_Num;
			}

			const std::string& GetName() const
			{
				return m_Header;
			}

			Component& operator[](size_t indice)
			{
				if (indice == 0) {
					throw HL7Exception("Indice de sub-campo invalido: 0", "MODEL");
				}

				Base& t = *this;

				size_t numLast = size();

				if ( indice > numLast) {
					for (size_t i = numLast + 1; i <= indice; i++) {
						t[i] = Component(i);
					}
				}

				return t[indice];
			}

			friend std::ostream& operator<<(std::ostream& out, const Field& f)
			{
				bool first = true;
				for(Field::const_iterator it= f.begin(); it != f.end(); ++it)
				{
					if (first) {
						first = false;
						out << (*it).second;
					}
					else {
						out << f.m_CS << (*it).second;
					}
				}
				return out;
			}

			friend std::ostream& operator<<(std::ostream& out, const Field* f)
			{
				return out << *f;
			}

			const std::string EscapeER7(const std::string& str) const;
			const std::string UnEscapeER7(const std::string& str) const;
		};

		class Segment : protected std::map<size_t, std::list<Field> > {

		private:
			typedef std::map<size_t, std::list<Field> > Base;

		protected:
			std::string m_Header;
			std::string m_RS;
			std::string m_FS;
			std::string m_CS;
			std::string m_FRS;
			std::string m_ES;
			std::string m_SCS;

		public:

			Segment()
			{
			}

			Segment(const std::string& header, const std::string& rs = RECORD_SEPARATOR, const std::string& fs = "|", const std::string& sfs = "^", const std::string& frs = "~", const std::string& es = "\\", const std::string& cs = "&" ) : m_Header(header), m_RS(rs), m_FS(fs), m_CS(sfs), m_FRS(frs), m_ES(es), m_SCS(cs)
			{
			}

			Segment(const Segment& otro)
			{
				*this = otro;
			}

			Segment& operator=(const Segment& otro)
			{
				m_Header       = otro.m_Header;
				m_RS           = otro.m_RS;
				m_FS           = otro.m_FS;
				m_CS           = otro.m_CS;
				m_FRS          = otro.m_FRS;
				m_ES           = otro.m_ES;
				m_SCS          = otro.m_SCS;
				Base::operator = ((const Base&)otro);
				return *this;
			}

			Field& operator<<=(const Field& f)
			{
				size_t indice = f.GetNum();

				if (indice == 0) {
					throw HL7Exception("Indice de campo invalido: 0", "MODEL");
				}

				Base& t = *this;

				size_t numLast = size();

				if ( indice > numLast) {
					for (size_t i = numLast + 1; i < indice; i++) {
						t[i] = std::list<Field>();
						t[i].push_back(Field(i));
					}
				}

				t[indice].clear();
				t[indice].push_back(f);
				return t[indice].back();
			}

			Field& operator<<(const Field& f)
			{
				size_t indice = f.GetNum();

				if (indice == 0) {
					throw HL7Exception("Indice de campo invalido: 0", "MODEL");
				}

				Base& t = *this;

				size_t numLast = size();

				if ( indice > numLast) {
					for (size_t i = numLast + 1; i < indice; i++) {
						t[i] = std::list<Field>();
						t[i].push_back(Field(i));
					}
				}

				t[indice].push_back(f);
				return t[indice].back();
			}

			Field GetField(size_t num, size_t repnum = 1) const
			{
				if (num == 0) {
					throw HL7Exception("Indice de campo invalido: 0", "MODEL");
				}
				if (repnum == 0) {
					throw HL7Exception("Indice de repeticion de campo invalido: 0", "MODEL");
				}

				const_iterator it;
				size_type i;
				for (it = begin(), i = 1; it != end(); ++it, i++) {
					if (i == num) {
						const std::list<Field>& fl = (*it).second;
						std::list<Field>::const_iterator itr = fl.begin();
						if (itr != fl.end()) {
							return Field(*itr);
						}
						else {
							return Field(num, "", m_RS, m_FS, m_CS);
						}
					}
				}
				return Field(num, "", m_RS, m_FS, m_CS);
			}

			const std::string& GetSFS() const
			{
				return m_CS;
			}

			void SetSFS(const std::string& sfs)
			{
				m_CS = sfs;
			}

			const std::string& GetName() const
			{
				return m_Header;
			}

			Field& operator[](size_t indice)
			{
				if (indice == 0) {
					throw HL7Exception("Indice de campo invalido: 0", "MODEL");
				}

				Base& t = *this;

				size_t numLast = size();

				if ( indice > numLast) {
					for (size_t i = numLast + 1; i <= indice; i++) {
						t[i] = std::list<Field>();
						t[i].push_back(Field(i));
					}
				}
				return t[indice].front();
			}

			Field& RepeatedField(size_t indiceCampo, size_t indiceRepeticion)
			{
				if (indiceCampo == 0) {
					throw HL7Exception("Indice de campo invalido: 0", "MODEL");
				}
				if (indiceRepeticion == 0) {
					throw HL7Exception("Indice de repeticion de campo invalido: 0", "MODEL");
				}

				Base& t = *this;

				size_t numLast = size();

				if ( indiceCampo > numLast) {
					for (size_t i = numLast + 1; i <= indiceCampo; i++) {
						t[i] = std::list<Field>();
						t[i].push_back(Field(i));
					}
				}

				std::list<Field>& fields = t[indiceCampo];
				numLast = fields.size();

				if ( indiceRepeticion > numLast) {
					for (size_t i = numLast + 1; i <= indiceRepeticion; i++) {
						fields.push_back(Field(i));
					}
				}

				std::list<Field>::iterator it;
				size_t i;

				for (i = 1, it = fields.begin(); it != fields.end() && i != indiceRepeticion; ++it, i++);

				if ( it == fields.end() || i != indiceRepeticion) {
					throw HL7Exception("Error al localizar el indice de repeticion", "MODEL");
				}

				return *it;
			}

			friend std::ostream& operator<<(std::ostream& out, const Segment& s)
			{
				out << s.GetName();
				size_t i = 1;

				if (s.m_Header == "MSH") {
					bool firstField = true;
					for(Segment::const_iterator it = s.begin(); it != s.end(); ++it, i++)
					{
						if (firstField) {
							firstField = false;
						}
						else {
							bool fieldRepeated = false;
							for (std::list<Field>::const_iterator it2 = (*it).second.begin(); it2 != (*it).second.end(); ++it2) {
								if (fieldRepeated) {
									out << "~" << (*it2);
								}
								else {
									out << s.m_FS <<  (*it2);
									fieldRepeated = true;
								}
							}
						}
					}
				}
				else {
					for(Segment::const_iterator it = s.begin(); it != s.end(); ++it, i++)
					{
						bool fieldRepeated = false;
						for (std::list<Field>::const_iterator it2 = (*it).second.begin(); it2 != (*it).second.end(); ++it2) {
							if (fieldRepeated) {
								out << "~" << (*it2);
							}
							else {
								out << s.m_FS <<  (*it2);
								fieldRepeated = true;
							}
						}
					}
				}
				out << s.m_RS;
				return out;
			}

			friend std::ostream& operator<<(std::ostream& out, const Segment* s)
			{
				return out << *s;
			}

			EXTAPI Field& ParseField (size_t fieldNum, const std::string& record, bool unscape = true);

			EXTAPI const std::string EscapeER7(const std::string& str) const;
			EXTAPI const std::string UnEscapeER7(const std::string& str) const;

		};

		class Message : public std::list<Segment> {

		private:

			typedef std::list<Segment> Base;
			std::string m_Header;  // message header
			std::string m_RS;      // record separator
			std::string m_FS;      // (|) Field separator
			std::string m_CS;      // (^) Component separator
			std::string m_FRS;     // (~) Field repeat separator
			std::string m_ES;      // (\) Escape separator
			std::string m_SCS;     // (&) SubComponent separator

		public:

			Message(const std::string& header = "", const std::string& rs = RECORD_SEPARATOR, const std::string& fs = "|", const std::string& sfs ="^") : m_Header(header), m_RS(rs), m_FS(fs), m_CS(sfs)
			{
			}

			Message(const Message& otro)
			{
				*this = otro;
			}

			Message& operator=(const Message& otro)
			{
				m_FRS          = otro.m_FRS;
				m_ES           = otro.m_ES;
				m_SCS          = otro.m_SCS;
				m_Header       = otro.m_Header;
				m_RS           = otro.m_RS;
				m_FS           = otro.m_FS;
				m_CS           = otro.m_CS;
				Base::operator = ((const Base&)otro);
				return *this;
			}

			static Message FromER7(const std::string& msgStr)
			{
				Message msg;
				msg.LoadFromER7(msgStr);
				return msg;
			}

			void LoadFromXML(const std::string& /*msgStr*/)
			{
			}

			void LoadFromER7(const std::string& msgStr)
			{
				Clear();

				std::list<std::string> records;

				std::string::size_type l_loc = 0; // Last Location
				std::string::size_type c_loc = std::string::npos; // Current Location
				bool cont = true;

				while(cont) {
					c_loc = msgStr.find(RECORD_SEPARATOR, l_loc);
					if (c_loc == std::string::npos) {
						const std::string& record = msgStr.substr(l_loc);
						if (record.size() > 0) {
							records.push_back(record);
						}
						cont = false;
					}
					else {
						const std::string& record = msgStr.substr(l_loc, c_loc - l_loc);
						if (record.size() > 0) {
							records.push_back(record);
						}
						l_loc = c_loc + 1;
					}
				}

				if (records.empty())
				{
					throw HL7Exception(std::string("Error al interpretar la cabecera del mensaje no se han encontrado registros"));
				}
				std::list<std::string>::iterator itr = records.begin();
				std::string& mshrecord = *itr;

				Message& msg = *this;

				if (mshrecord.size() >= 8 && mshrecord[0] == 'M' && mshrecord[1] == 'S' && mshrecord[2] == 'H')
				{
					m_FS  = mshrecord[3];
					m_CS  = mshrecord[4];
					m_FRS = mshrecord[5];
					m_ES  = mshrecord[6];
					m_SCS = mshrecord[7];

					Segment& segment = (msg << Segment("MSH", m_RS, m_FS, m_CS, m_FRS, m_ES, m_SCS));
					segment << Field(1, "MSH.1") << Component(1, "", m_FS);
					segment << Field(2, "MSH.2") << Component(1, "", m_CS + m_FRS + m_ES + m_SCS);

					ParseER7Segment(segment, mshrecord, 9, 3);

				}
				else {
					throw HL7Exception(std::string("Error al interpretar la cabecera del mensaje: ") + mshrecord.substr(0,8));
				}

				for (itr++; itr != records.end(); ++itr)
				{

					std::string& record = *itr;
					//std::cout << "Parsing Record: [" << record << "]" << std::endl;

					Segment& segment = (msg << Segment(record.substr(0,record.find(m_FS, 0)), m_RS, m_FS, m_CS, m_FRS, m_ES, m_SCS));
					ParseER7Segment(segment, record, 4);
				}
			}

		private:

			void ParseER7Segment(Segment& segment, const std::string& record, std::string::size_type offsetFirstField=5, int numFirstField=1)
			{
				std::string::size_type l_loc = offsetFirstField;
				std::string::size_type c_loc = std::string::npos;

				std::string::size_type start = std::string::npos;
				std::string::size_type size = std::string::npos;
				bool cont = true;

				size_t fieldNum = numFirstField;

				//std::cout << "Record = [" << record << "]" << std::endl;

				if (offsetFirstField >= record.size()) {
					return;
				}

				while (cont) {

					c_loc = record.find(m_FS, l_loc);
					if (c_loc == std::string::npos) {
						start = l_loc;
						size  = std::string::npos;
						cont  = false;
					}
					else {
						start = l_loc;
						size  = c_loc - l_loc;
						l_loc = c_loc + 1;
					}

					const std::string& str = record.substr(start, size);

					//std::cout << "Field " << fieldNum << " = [" << str << "] ";

					// Repeticion de campos.

					std::string::size_type l_locfr = 0;
					std::string::size_type c_locfr = std::string::npos;

					std::string::size_type startfr = std::string::npos;
					std::string::size_type endfr = std::string::npos;
					bool contfr = true;

					while (contfr) {
						c_locfr = str.find(m_FRS, l_locfr);
						if (c_locfr == std::string::npos) {
							startfr = l_locfr;
							endfr = c_locfr;
							l_locfr = std::string::npos;
							contfr = false;
						}
						else {
							startfr = l_locfr;
							endfr = c_locfr - l_locfr;
							l_locfr = c_locfr + 1;
						}

						segment.ParseField(fieldNum, str.substr(startfr, endfr));

					}

					//std::cout << std::endl;

					fieldNum++;
				}
			}

		public:

			EXTAPI const std::string EscapeER7(const std::string& str) const;
			EXTAPI const std::string UnEscapeER7(const std::string& str) const;

			void Clear()
			{
				Base::clear();
			}

			Segment& operator<<(const Segment& s)
			{
				push_back(s);
				return back();
			}

			/* Devuelve el primer mensaje encontrado con la cabecera parametrizada. */
			Segment& operator[] (const std::string& key)
			{
				return Segments(key, 1);
			}

			/* Devuelve el num-avo mensaje encontrado con la cabecera parametrizada. */
			Segment& Segments(const std::string& key, size_t num)
			{
				if (num == 0) {
					throw HL7Exception("Indice de segmento invalido: 0", "MODEL");
				}

				iterator it;
				size_type i;
				for (it = begin(), i = num; it != end()  && i > 0; ++it) {
					Segment& s = *it;
					if (s.GetName() == key) {
						--i;
					}
					if (i == 0) {
						return s;
					}
				}
				return (*this) << Segment(key, m_RS, m_FS, m_CS);
			}

			Segment GetSegment(const std::string& key, size_t num = 1) const
			{
				if (num == 0) {
					throw HL7Exception("Indice de segmento invalido: 0", "MODEL");
				}

				const_iterator it;
				size_type i;
				for (it = begin(), i = num; it != end() && i > 0; ++it) {
					const Segment& s = *it;
					if (s.GetName() == key) {
						--i;
					}
					if (i == 0) {
						return Segment(s);
					}
				}
				return Segment(key, m_RS, m_FS, m_CS);
			}

			void SetHeader(const std::string& header)
			{
				m_Header = header;
			}

			const std::string& GetHeader()
			{
				return m_Header;
			}

			friend std::ostream& operator<<(std::ostream& out, const Message& m) {
				for(Message::const_iterator it = m.begin(); it != m.end(); ++it)
				{
					out << *it;
				}
				return out;
			}

			friend std::ostream& operator<<(std::ostream& out, const Message* m) {
				return out << *m;
			}

		public:
			typedef enum ErrorCode {
				EC_MessageAccepted          = 0,
				EC_SegmentSequenceError     = 100,
				EC_RequiredFieldMissing     = 101,
				EC_DataTypeError            = 102,
				EC_TableValueNotFound       = 103,
				EC_UnsuportedMessageType    = 200,
				EC_UnsuportedProcessingId   = 201,
				EC_UnsupportedEventCode     = 202,
				EC_UnsupportedVersionId     = 203,
				EC_UnknownKeyIdentifier     = 204,
				EC_DupplicateKeyIdentifier  = 205,
				EC_ApplicationRecordLocked  = 206,
				EC_ApplicationInternalError = 207
			} ErrorCode;

			static const std::string GetErrorCodeDescription(ErrorCode errorCode)
			{
				std::stringstream ss;
				ss << errorCode << ": ";

				switch (errorCode) {
					case EC_MessageAccepted:
						ss << "Mensaje aceptado";
						break;
					case EC_SegmentSequenceError:
						ss << "Error en la secuencia del segmento";
						break;
					case EC_RequiredFieldMissing:
						ss << "Campo requerido inexistente";
						break;
					case EC_DataTypeError:
						ss << "Error en el tipo de dato";
						break;
					case EC_TableValueNotFound:
						ss << "Valor de la tabla no encontrado";
						break;
					case EC_UnsuportedMessageType:
						ss << "Tipo de mensaje no soportado";
						break;
					case EC_UnsuportedProcessingId:
						ss << "Id de procesamiento no soportado";
						break;
					case EC_UnsupportedEventCode:
						ss << "Codigo de evento no soportado";
						break;
					case EC_UnsupportedVersionId:
						ss << "Id de version no soportado";
						break;
					case EC_UnknownKeyIdentifier:
						ss << "Identificador desconocido";
						break;
					case EC_DupplicateKeyIdentifier:
						ss << "Identificador clave duplicado";
						break;
					case EC_ApplicationRecordLocked:
						ss << "Registro de la aplicacion bloqueado";
						break;
					case EC_ApplicationInternalError:
						ss << "Error interno de la aplicacion";
						break;
					default:
						ss << "Codigo invalido";
						break;
				}
				return ss.str();
			}

			static const std::string GetErrorCodeAsString(ErrorCode errorCode)
			{
				std::stringstream ss;
				ss << errorCode;
				std::string errorCodeString = ss.str();

				switch (errorCode) {
					case EC_MessageAccepted:
					case EC_SegmentSequenceError:
					case EC_RequiredFieldMissing:
					case EC_DataTypeError:
					case EC_TableValueNotFound:
					case EC_UnsuportedMessageType:
					case EC_UnsuportedProcessingId:
					case EC_UnsupportedEventCode:
					case EC_UnsupportedVersionId:
					case EC_UnknownKeyIdentifier:
					case EC_DupplicateKeyIdentifier:
					case EC_ApplicationRecordLocked:
					case EC_ApplicationInternalError:
						return errorCodeString;
					default:
						throw HL7Exception(std::string("[Error Code] invalido: ") + errorCodeString, "MODEL/LOGIC");
				}
			}

			static ErrorCode GetErrorCodeFromErrorCodeAsString(const std::string& errorCodeString)
			{
				if (errorCodeString == "0") {
					return EC_MessageAccepted;
				}
				else if (errorCodeString == "100") {
					return EC_SegmentSequenceError;
				}
				else if (errorCodeString == "101") {
					return EC_RequiredFieldMissing;
				}
				else if (errorCodeString == "102") {
					return EC_DataTypeError;
				}
				else if (errorCodeString == "103") {
					return EC_TableValueNotFound;
				}
				else if (errorCodeString == "200") {
					return EC_UnsuportedMessageType;
				}
				else if (errorCodeString == "201") {
					return EC_UnsuportedProcessingId;
				}
				else if (errorCodeString == "202") {
					return EC_UnsupportedEventCode;
				}
				else if (errorCodeString == "203") {
					return EC_UnsupportedVersionId;
				}
				else if (errorCodeString == "204") {
					return EC_UnknownKeyIdentifier;
				}
				else if (errorCodeString == "205") {
					return EC_DupplicateKeyIdentifier;
				}
				else if (errorCodeString == "206") {
					return EC_ApplicationRecordLocked;
				}
				else if (errorCodeString == "207") {
					return EC_ApplicationInternalError;
				}
				else {
					throw HL7Exception(std::string("[Error Code] invalido: ") + errorCodeString, "MODEL/LOGIC");
				}
			}

			typedef enum ErrorSeverity {
				ES_Warning     = 0,
				ES_Information = 1,
				ES_Error       = 2
			} ErrorSeverity;

			static const char* GetErrorSeverityString(ErrorSeverity es)
			{
				switch (es) {
					case ES_Information:
						return "I";
						break;
					case ES_Error:
						return "E";
						break;
					case ES_Warning:
						return "W";
					default:
						{
							std::stringstream ss;
							ss << es;
							throw HL7Exception(std::string("[Error Severity] invalido: ") + ss.str(), "MODEL/LOGIC");
						}
				}
			}

			static ErrorSeverity GetErrorSeverityFromString(const std::string& ess)
			{
				if (ess == "I") {
					return ES_Information;
				}
				else if (ess == "E") {
					return ES_Error;
				}
				else if (ess == "W") {
					return ES_Warning;
				}
				else {
					throw HL7Exception(std::string("[Error Severity String] invalida: ") + ess, "MODEL/LOGIC");
				}
			}
		};
	}
}
