/***************************************************************************
                          SIMPLY POWERFUL TOOLKIT (SPTK)
                          CXmlNode.h  -  description
                             -------------------
    begin                : Wed June 21 2006
    based on the code    : Mikko Lahteenmaki <Laza@Flashmail.com>
    copyright            : (C) 2003-2006 by Alexey S.Parshin
    email                : alexeyp@gmail.com
 ***************************************************************************/

/***************************************************************************
   This library is free software; you can redistribute it and/or modify it
   under the terms of the GNU Library General Public License as published by
   the Free Software Foundation; either version 2 of the License, or (at
   your option) any later version.

   This library is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library
   General Public License for more details.

   You should have received a copy of the GNU Library General Public License
   along with this library; if not, write to the Free Software Foundation,
   Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.

   Please report all bugs and problems to "alexeyp@gmail.com"
 ***************************************************************************/

#ifndef __CXMLATTRIBUTES_H__
#define __CXMLATTRIBUTES_H__

#include <sptk3/cxml>
#include <sptk3/CDateTime.h>

namespace sptk {

   /// @addtogroup XML
   /// @{

	class CXmlNode;
	class CXmlDoc;

   /// @brief XML node attribute
   ///
   /// A single node attribute that contains a name and a value
	class SP_EXPORT CXmlAttribute : public std_string {

	public:
      /// @brief Default constructor
      ///
      /// Creates an empty XML attribute
		CXmlAttribute() {}

      /// @brief Constructor
      ///
      /// Creates an XML attribute from character string
		CXmlAttribute(const char *v) : std_string(v) {}

      /// @brief Constructor
      ///
      /// Creates an XML attribute from std::string
		CXmlAttribute(std::string v) : std_string(v) {}

      /// @brief Constructor
      ///
      /// Creates an XML attribute from integer
		CXmlAttribute(int v)         { operator = (v); }

      /// @brief Constructor
      ///
      /// Creates an XML attribute from integer
		CXmlAttribute(unsigned v)    { operator = (v); }

      /// @brief Constructor
      ///
      /// Creates an XML attribute from long
		CXmlAttribute(long v)        { operator = (v); }

      /// @brief Constructor
      ///
      /// Creates an XML attribute from unsigned long
		CXmlAttribute(unsigned long v) { operator = (v); }

      /// @brief Constructor
      ///
      /// Creates an XML attribute from double
		CXmlAttribute(double v)      { operator = (v); }

      /// @brief Constructor
      ///
      /// Creates an XML attribute from bool
		CXmlAttribute(bool v)         { operator = (v); }

      /// @brief Constructor
      ///
      /// Creates an XML attribute from CDateTime
		CXmlAttribute(CDateTime v)   : std_string(v) {}

      /// @brief Assignment of the value
      ///
      /// @param v bool, a new value
		CXmlAttribute& operator = (bool v);

      /// @brief Assignment of the value
      ///
      /// @param v int, a new value
		CXmlAttribute& operator = (int v);

      /// @brief Assignment of the value
      ///
      /// @param v unsigned, a new value
		CXmlAttribute& operator = (unsigned v);

      /// @brief Assignment of the value
      ///
      /// @param v int, a new value
		CXmlAttribute& operator = (long v);

      /// @brief Assignment of the value
      ///
      /// @param v unsigned, a new value
		CXmlAttribute& operator = (unsigned long v);

      /// @brief Assignment of the value
      ///
      /// @param v double, a new value
		CXmlAttribute& operator = (double v);

      /// @brief Assignment of the value
      ///
      /// @param s const std::string, a new value
		CXmlAttribute& operator = (const std::string& s) { assign(s); return *this; }

      /// @brief Assignment of the value
      ///
      /// @param s const char *, a new value
		CXmlAttribute& operator = (const char *s)        { assign(s); return *this; }

      /// @brief Assignment of the value
      ///
      /// @param s CDateTime, a new value
		CXmlAttribute& operator = (CDateTime s)          { assign(s); return *this; }

      /// @brief Returns the value with the conversion
		operator unsigned () const                       { return atoi(c_str()); }

      /// @brief Returns the value with the conversion
		operator int () const                            { return atoi(c_str()); }

      /// @brief Returns the value with the conversion
		operator unsigned long () const                  { return atol(c_str()); }

      /// @brief Returns the value with the conversion
		operator long () const                           { return atol(c_str()); }

       /// @brief Returns the value with the conversion
		operator bool () const;

      /// @brief Returns the value with the conversion
		operator double () const                         { return atof(c_str()); }
	};

   /// @brief Custom compare attributes method
	struct less_attr : public std::binary_function<const char*,const char*,bool> {
	   /// @brief Compares two strings
	   /// @returns true if s1 < s2
		bool operator() (const char* s1,const char* s2) const { return strcmp(s1,s2) < 0; }
	};

   /// @brief The map of character strings to attributes
   ///
   /// Designed to be used together with SST (Shared Strings Table)
	typedef std::map<const char*,CXmlAttribute,less_attr> CXmlAttributeMap;

   /// @brief XML node attributes
   ///
   /// The CXmlAttributes class is map for node attributes.
	class SP_EXPORT CXmlAttributes {
		static const CXmlAttributeMap emptyMap;
		CXmlAttributeMap*             m_map;
		CXmlDoc*                      m_document; ///< An XML document that contains a shared string table
	public:

		typedef CXmlAttributeMap::iterator iterator;              ///< The class iterator
		typedef CXmlAttributeMap::const_iterator const_iterator;  ///< The class const iterator

      /// @brief Constructor
      ///
      /// The XML attributes object uses the shared strings table (SST)
      /// that belongs to the XML document, the parent XML node belongs to.
      /// @param parentNode CXmlNode*, the parent XML node
		CXmlAttributes(CXmlNode* parentNode);

      /// @brief Assign operator
      ///
      /// Makes copy of an attribute set to another.
      /// @param src as copy source
		CXmlAttributes& operator = (const CXmlAttributes& src);

      /// @brief Searches for named attribute
      ///
      /// Returns true, if given attribute is found.
      /// @param attr std::string, name of attribute to search
		bool hasAttribute(std::string attr) const;

      /// @brief Returns an attribute value
      ///
      /// If the attribute is not found, empty string is returned.
      /// HTML tags can have empty attributes, for those you should use has_attribute() method.
      /// @param attr std::string, name of attribute
      /// @param defaultValue const char *, a default value. If attribute doesn't exist then default value is returned.
		CXmlAttribute getAttribute(std::string attr,const char *defaultValue=0L) const;

      /// @brief Sets attribute value for given attribute
      ///
      /// @param attr std::string, name of attribute
      /// @param value CXmlAttribute, an attribute value. See CXmlAttribute class description for data convertions.
      /// @param defaultValue const char *, a default value. If attribute value is matching default value than attribute isn't stored (or removed if it existed).
		void setAttribute(std::string attr,CXmlAttribute value,const char *defaultValue=0L);

      /// @brief Number of attributes
		size_t size() const;

	   /// @brief Access to an attribute by name
	   /// @param attrName const char*, attribute name
		CXmlAttribute& operator[] (const char* attrName);

	   /// @brief Access to an attribute by name
	   /// @param attrName const std::string&, attribute name
		CXmlAttribute& operator[] (const std::string& attrName) {
			return operator[](attrName.c_str());
		}

	   /// @brief Access to an attribute by name
	   /// @param attrName const char*, attribute name
		CXmlAttribute operator[] (const char* attrName) const {
			return getAttribute(attrName);
		}

	   /// @brief Access to an attribute by name
	   /// @param attrName const std::string&, attribute name
		CXmlAttribute operator[] (const std::string& attrName) const {
			return getAttribute(attrName);
		}

	   /// @brief Removes all the attributes	
		void clear();

	   /// @brief Returns an iterator to the first attribute 
		iterator begin();

	   /// @brief Returns an iterator to the first attribute 
		const_iterator begin() const;

	   /// @brief Returns an iterator to the end of attributes 
		iterator end();

	   /// @brief Returns an iterator to the end of attributes 
		const_iterator end() const;
	};	
   /// @}
}
#endif
