#ifndef BOOST_TEXT_BASIC_TEXT_HPP_INCLUDED
#define BOOST_TEXT_BASIC_TEXT_HPP_INCLUDED

//
//  basic_text.hpp
//
//  Copyright Anders Dalvander 2011.
//
//  Distributed under the Boost Software License, Version 1.0. (See
//  accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//

#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
#include <boost/range/algorithm/equal.hpp>
#include <algorithm>
#include <string>

namespace boost
{
   template <typename encoding>
   class basic_text
   {
   public:
      typedef encoding encoding_type;
      typedef typename encoding_type::codeunit_type codeunit_type;
      typedef typename encoding_type::codepoint_type codepoint_type;

   private:
      typedef std::basic_string<codeunit_type> string_type;
      typedef boost::shared_ptr<const string_type> pointer_type;

      template <typename codepoint_iterator>
      static pointer_type make_string(codepoint_iterator first, codepoint_iterator last)
      {
         return boost::make_shared<string_type>(
            encoding_type::encode_iterator<codepoint_iterator>
            (first, last),
            encoding_type::encode_iterator<codepoint_iterator>
            (last, last));
      }

   public:
      typedef typename string_type::const_iterator codeunit_iterator;
      typedef typename encoding_type::decode_iterator<codeunit_iterator> codepoint_iterator;
      typedef codepoint_iterator const_iterator;
      typedef codepoint_iterator iterator;

      basic_text()
         : s(boost::make_shared<string_type>())
      {
      }

      template <typename other_encoding>
      basic_text(const basic_text<other_encoding>& text)
         : s(make_string(text.begin(), text.end()))
      {
      }

      // TODO: Use some default_encoding traits type.
      template <typename container>
      explicit basic_text(const container& c)
         : s(make_string(boost::begin(c), boost::end(c)))
      {
      }

      template <typename codepoint_iterator>
      basic_text(codepoint_iterator first, codepoint_iterator last)
         : s(make_string(first, last))
      {
      }

      codepoint_iterator begin() const
      {
         return codepoint_iterator
            (codeunit_begin(), codeunit_end());
      }

      codepoint_iterator end() const
      {
         return codepoint_iterator
            (codeunit_end(), codeunit_end());
      }

      codeunit_iterator codeunit_begin() const
      {
         return s->begin();
      }

      codeunit_iterator codeunit_end() const
      {
         return s->end();
      }

   private:
      pointer_type s;
   }; // class basic_text

   template <typename lhs_encoding, typename rhs_encoding>
   inline bool operator==(const basic_text<lhs_encoding>& lhs, const basic_text<rhs_encoding>& rhs)
   {
      return boost::equal(lhs, rhs);
   }

   template <typename lhs_encoding, typename rhs_encoding>
   inline bool operator!=(const basic_text<lhs_encoding>& lhs, const basic_text<rhs_encoding>& rhs)
   {
      return !(lhs == rhs);
   }

   template <typename lhs_encoding, typename rhs_encoding>
   inline bool operator<(const basic_text<lhs_encoding>& lhs, const basic_text<rhs_encoding>& rhs)
   {
      return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
   }

   template <typename lhs_encoding, typename rhs_encoding>
   inline bool operator>(const basic_text<lhs_encoding>& lhs, const basic_text<rhs_encoding>& rhs)
   {
      return rhs < lhs;
   }

   template <typename lhs_encoding, typename rhs_encoding>
   inline bool operator<=(const basic_text<lhs_encoding>& lhs, const basic_text<rhs_encoding>& rhs)
   {
      return !(rhs < lhs);
   }

   template <typename lhs_encoding, typename rhs_encoding>
   inline bool operator>=(const basic_text<lhs_encoding>& lhs, const basic_text<rhs_encoding>& rhs)
   {
      return !(lhs < rhs);
   }
}

#endif  // #ifndef BOOST_TEXT_BASIC_TEXT_HPP_INCLUDED
