#ifndef _ABSTRACT_XMLLIGHT_H
#define _ABSTRACT_XMLLIGHT_H

// WORK IN PROGRESS THERE MUST BE SYNTAX ERROR AND OTHER BOGUS THING 

#include "Behavioural/include/IXMLLight.h"
#include "Behavioural/include/XMLLightVector.h"
#include "Behavioural/include/XMLLightFunctors.h"
#include <sstream>
#include <iterator>
#include <string>
#include <iostream>

using std::basic_stringstream ;
using std::basic_string;
using std::basic_ostream;
using std::basic_istream;

namespace morpheo {
	namespace XMLUtils {

	
	//******************************************Class Declaration***************************************//
	
		template< typename char_type, typename ReferenceCounter = ClassicReferenceCounter >
			 class AbstractXMLLight : public IXMLLight<char_type,ReferenceCounter> {
		protected : 
			basic_string<char_type>  m_internalString;
		public :
			inline basic_string<char_type> getInternalString(void) const; 
		protected :		
			inline explicit AbstractXMLLight ( const basic_string<char_type> & str);
			inline explicit AbstractXMLLight( const basic_istream<char_type> & s ,IXMLLight<char_type,ReferenceCounter> *parent = NULL);
			inline ~AbstractXMLLight(void); 

			XMLLightVector<IXMLLight<char_type, ReferenceCounter> > getNodes ( const basic_string<char_type> & pattern );
			
			//vector<XMLLight *>  getNodes ( const string & pattern ); 
			//XMLLight & getFirstNode ( const string & pattern = ""); 

 	
			//IXMLLightImpl & getRoot ( void ); 
                        basic_string<char_type>  getName ( void ) ; 
                        //string &   getValue ( void )  ;
                        //string & getValue ( const string & firstNodeName ) ; 
                        bool containsAttribute ( const basic_string<char_type> & attributeName );
                        map<basic_string<char_type> , basic_string<char_type> > getAttributes ( void ); 
                        basic_string<char_type>  getAttributeValue ( const basic_string<char_type> & attributeName );
					                                
			friend basic_ostream<char_type> & operator<<
				( basic_ostream<char_type> & os, const AbstractXMLLight<char_type, ReferenceCounter> * xl) {
				return os << endl << "\t\t" << xl->m_internalString << endl; 
			}

		private:
			inline basic_string<char_type> extractEndRootTag(void);
			inline void trim(void) ;
			
		};

	//******************************************Inline implementation***********************************//
	
	// implementation of constructors and destructors	
	template < typename char_type, typename ReferenceCounter> 
	AbstractXMLLight<char_type,ReferenceCounter>::AbstractXMLLight ( const basic_string<char_type> & str) 
		: m_internalString(str) { 
		trim();
	} 
	// CHANGE HERE 
	
	template< typename char_type, typename ReferenceCounter>			
	AbstractXMLLight<char_type,ReferenceCounter>::AbstractXMLLight
 	( const basic_istream<char_type> & str, IXMLLight<char_type, ReferenceCounter> * parent) {
		basic_stringstream<char_type> st ;
		st << str.rdbuf() ; 
		m_internalString = st.str(); 
		trim();
		if ( parent == NULL ) {
			typename basic_string<char_type>::iterator iterator = m_internalString.begin();
			while ( *(++iterator) != BEGIN_TAG );
			m_internalString = basic_string<char_type>(iterator, m_internalString.end() );
		}
	}

	template< typename char_type, typename ReferenceCounter>	
	AbstractXMLLight<char_type,ReferenceCounter>::~AbstractXMLLight( void ) {} 
	//
	// implementation of getter.
	template< typename char_type, typename ReferenceCounter> 
	basic_string<char_type> AbstractXMLLight<char_type,ReferenceCounter>::getInternalString(void) const {
		return m_internalString;
	}
	
	// implementation of helper method.
	template < typename char_type, typename ReferenceCounter>
	void AbstractXMLLight<char_type,ReferenceCounter>::trim(void) {
				
		int index = m_internalString.find_first_of(BEGIN_TAG); 
		int lastIndex = m_internalString.find_last_of(END_TAG);
		basic_string<char_type> reducedString = m_internalString.substr(index,lastIndex - index + 1 );
		m_internalString = reducedString; 
	}

	template < typename char_type, typename ReferenceCounter>
	basic_string<char_type> AbstractXMLLight<char_type, ReferenceCounter>::extractEndRootTag(void) {
		basic_string<char_type> internal = m_internalString.substr(0,m_internalString.find_last_of(BEGIN_TAG));
		return internal.substr(0, m_internalString.find_last_of(END_TAG) + 1 );
	}

	template < typename char_type, typename ReferenceCounter>
	XMLLightVector<IXMLLight<char_type,ReferenceCounter> > AbstractXMLLight<char_type, ReferenceCounter>::getNodes ( const basic_string<char_type> & pattern ) 
	{
		XMLLightVector<IXMLLight<char_type,ReferenceCounter> > returnedNodesVector; 
		basic_string<char_type> reduceString = extractEndRootTag();
		if ( reduceString.empty() )
		{
			return returnedNodesVector; 
		}
		typename basic_string<char_type>::iterator iterator = reduceString.begin();
		typename basic_string<char_type>::iterator endStringIterator = reduceString.end();
		typename basic_string<char_type>::iterator tempIterator = iterator;
		bool first = true;
	
		while ( iterator != endStringIterator )
		{
			if ( first ) 
			{
				while ( *(++iterator) != END_TAG ) ;
				if ( ++iterator == endStringIterator ) 
				{	
					return returnedNodesVector; 
				}
				first = false; 		
			}
			tempIterator = iterator; 
			iterator  = adjacent_find(iterator, endStringIterator, XMLLightComparator());
			if ( iterator != endStringIterator )
			{
				iterator+=2;
			}
	
			basic_string<char_type> s ( tempIterator, iterator );
			if ( s.empty() || s.find_first_of(BEGIN_TAG) == basic_string<char_type>::npos )
			{
				return returnedNodesVector;
			}
			AbstractXMLLight<char_type, ReferenceCounter> * abstractXMLLight = new AbstractXMLLight<char_type, ReferenceCounter>(s);
			if ( pattern.empty() || abstractXMLLight->getName() == pattern )
			{
				returnedNodesVector.push_back(abstractXMLLight);
			}
			else 
			{
				delete abstractXMLLight;
			}
			if ( iterator != endStringIterator )
			{
				iterator++;
			}
		}
		return returnedNodesVector; 
	}

	
	template < typename char_type, typename ReferenceCounter>
	basic_string<char_type> AbstractXMLLight<char_type,ReferenceCounter>::getName( void ) 
	{
		if ( m_internalString.empty() ) {
                  std::cout << " oups chaine non copie " << std::endl ; 
		}
		typename basic_string<char_type>::iterator iterator = m_internalString.begin();
		basic_string<char_type> resultString ;
		while ( *( ++ iterator ) != END_TAG && *iterator != ' ' && *iterator != '\n' && *iterator != '\t' && *iterator != SECOND_TAG ) 
	
		{
			resultString.append(1,*( iterator) ); 
		}
		return resultString; 
	}
	
	
	template < typename char_type, typename ReferenceCounter>
	map< basic_string<char_type>, basic_string<char_type> > AbstractXMLLight<char_type,ReferenceCounter>::getAttributes(void)
	{
		char equalSeparator = '=';
		basic_string<char_type> separator(" \a\b\n\t\f\r\v");
		basic_string<char_type> key; 
		basic_string<char_type> value; 
	
		map<basic_string<char_type>, basic_string<char_type> > returnedMap; 
		size_t last_position = 0;
		size_t previous_position = 0; 
		size_t begin_position = 0; 
		size_t end_position = m_internalString.find_first_of(END_TAG);
		basic_string<char_type> nodeString = m_internalString.substr(0,end_position);
	
		while ( last_position = nodeString.find_first_of(equalSeparator,last_position) , last_position != basic_string<char_type>::npos )
		{
			begin_position = last_position; 
			last_position = nodeString.find_last_not_of(separator,begin_position-1); 	
			previous_position = nodeString.find_last_of(separator,last_position);
			key = nodeString.substr(previous_position+1, last_position-previous_position );
			last_position = nodeString.find_first_not_of(separator, begin_position +1) ; 
			previous_position = last_position; 
			last_position = nodeString.find_first_of(nodeString[previous_position] , previous_position +1 ); 
			value = nodeString.substr(previous_position +1 ,last_position - previous_position - 1);
			returnedMap.insert(make_pair(key,value));
			// test d'erreur pour l'insertion a ajouter 
	
		}
		
		return returnedMap;
	}
	
	
	template < typename char_type, typename ReferenceCounter>
	bool AbstractXMLLight<char_type,ReferenceCounter>::containsAttribute ( const basic_string<char_type> & attributeName ) 
	{
		map<basic_string<char_type>,basic_string<char_type> > attributeMap = getAttributes();
		if ( ! attributeMap.empty() && attributeMap.count(attributeName) == 1 ) 
		{
			return true; 
		}
			
		return false; 
	}
	
	template < typename char_type, typename ReferenceCounter>
	basic_string<char_type>  AbstractXMLLight<char_type,ReferenceCounter>::getAttributeValue ( const basic_string<char_type> & attributeName ) 
	{
 		map<basic_string<char_type>, basic_string<char_type> > attributeMap  =  getAttributes() ;
		typename map<basic_string<char_type>,basic_string<char_type> >::iterator it = attributeMap.find(attributeName);
		if ( it == attributeMap.end() )
		{
			return basic_string<char_type>(""); 
		}
		return (*it).second;
	}
	}
	}
	#endif
	
