#ifndef __cxxtest_StdValueTraits_h__
#define __cxxtest_StdValueTraits_h__

//
// This file defines ValueTraits for std:: stuff.
// It is #included by <cxxtest/ValueTraits.h> if you
// define CXXTEST_HAVE_STD
//

#include <cxxtest/ValueTraits.h>
#include <cxxtest/StdHeaders.h>

#ifdef _CXXTEST_OLD_STD
#define CXXTEST_STD( x ) x
#else  // !_CXXTEST_OLD_STD
#define CXXTEST_STD( x ) std::x
#endif  // _CXXTEST_OLD_STD

#ifndef CXXTEST_USER_VALUE_TRAITS

namespace CxxTest {
  //
  // NOTE: This should have been
  // template<class Char, class Traits, class Allocator>
  // class ValueTraits< std::basic_string<Char, Traits, Allocator> > {};
  // But MSVC doesn't support it (yet).
  //

  //
  // If we have std::string, we might as well use it
  //
  class StdTraitsBase {
    public:
    StdTraitsBase& operator<<( const CXXTEST_STD( string ) & s ) {
      _s += s;
      return *this;
    }
    const char* asString() const { return _s.c_str(); }

    private:
    CXXTEST_STD( string ) _s;
  };

  //
  // std::string
  //
  CXXTEST_TEMPLATE_INSTANTIATION
  class ValueTraits<const CXXTEST_STD( string )> : public StdTraitsBase {
    public:
    ValueTraits( const CXXTEST_STD( string ) & s ) {
      *this << "\"";

      for ( unsigned i = 0; i < s.length(); ++i ) {
        char c[sizeof( "\\xXX" )];
        charToString( s[i], c );
        *this << c;
      }

      *this << "\"";
    }
  };

  CXXTEST_COPY_CONST_TRAITS( CXXTEST_STD( string ) );

#ifndef _CXXTEST_OLD_STD
  //
  // std::wstring
  //
  CXXTEST_TEMPLATE_INSTANTIATION
  class ValueTraits<const CXXTEST_STD(basic_string<wchar_t>)>
      : public StdTraitsBase {
    public:
    ValueTraits( const CXXTEST_STD(basic_string<wchar_t>)&s ) {
      *this << "L\"";

      for ( unsigned i = 0; i < s.length(); ++i ) {
        char c[sizeof( "\\x12345678" )];
        charToString( (unsigned long)s[i], c );
        *this << c;
      }

      *this << "\"";
    }
  };

  CXXTEST_COPY_CONST_TRAITS( CXXTEST_STD( basic_string<wchar_t> ) );
#endif  // _CXXTEST_OLD_STD

  //
  // Convert a range defined by iterators to a string
  // This is useful for almost all STL containers
  //
  template <class Stream, class Iterator>
  void dumpRange( Stream& s, Iterator first, Iterator last ) {
    s << "{ ";

    while ( first != last ) {
      s << TS_AS_STRING( *first );
      ++first;
      s << ( ( first == last ) ? " }" : ", " );
    }
  }

#ifdef _CXXTEST_PARTIAL_TEMPLATE_SPECIALIZATION
  //
  // std::pair
  //
  template <class First, class Second>
      class ValueTraits<CXXTEST_STD( pair ) < First, Second>>
      : public StdTraitsBase {
    public:
    ValueTraits( const CXXTEST_STD( pair ) < First, Second > &p ) {
      *this << "<" << TS_AS_STRING( p.first ) << ", "
            << TS_AS_STRING( p.second ) << ">";
    }
  };

  //
  // std::vector
  //
  template <class Element>
      class ValueTraits<CXXTEST_STD( vector ) < Element>>
      : public StdTraitsBase {
    public:
    ValueTraits( const CXXTEST_STD( vector ) < Element > &v ) {
      dumpRange( *this, v.begin(), v.end() );
    }
  };

  //
  // std::list
  //
  template <class Element>
      class ValueTraits<CXXTEST_STD( list ) < Element>> : public StdTraitsBase {
    public:
    ValueTraits( const CXXTEST_STD( list ) < Element > &l ) {
      dumpRange( *this, l.begin(), l.end() );
    }
  };

  //
  // std::set
  //
  template <class Element>
      class ValueTraits<CXXTEST_STD( set ) < Element>> : public StdTraitsBase {
    public:
    ValueTraits( const CXXTEST_STD( set ) < Element > &s ) {
      dumpRange( *this, s.begin(), s.end() );
    }
  };

  //
  // std::map
  //
  template <class Key, class Value>
      class ValueTraits<CXXTEST_STD( map ) < Key, Value>>
      : public StdTraitsBase {
    public:
    ValueTraits( const CXXTEST_STD( map ) < Key, Value > &m ) {
      dumpRange( *this, m.begin(), m.end() );
    }
  };

  //
  // std::deque
  //
  template <class Element>
      class ValueTraits<CXXTEST_STD( deque ) < Element>>
      : public StdTraitsBase {
    public:
    ValueTraits( const CXXTEST_STD( deque ) < Element > &d ) {
      dumpRange( *this, d.begin(), d.end() );
    }
  };

  //
  // std::multiset
  //
  template <class Element>
      class ValueTraits<CXXTEST_STD( multiset ) < Element>>
      : public StdTraitsBase {
    public:
    ValueTraits( const CXXTEST_STD( multiset ) < Element > &ms ) {
      dumpRange( *this, ms.begin(), ms.end() );
    }
  };

  //
  // std::multimap
  //
  template <class Key, class Value>
      class ValueTraits<CXXTEST_STD( multimap ) < Key, Value>>
      : public StdTraitsBase {
    public:
    ValueTraits( const CXXTEST_STD( multimap ) < Key, Value > &mm ) {
      dumpRange( *this, mm.begin(), mm.end() );
    }
  };

  //
  // std::complex
  //
  template <class Number>
      class ValueTraits<CXXTEST_STD( complex ) < Number>>
      : public StdTraitsBase {
    public:
    ValueTraits( const CXXTEST_STD( complex ) < Number > &c ) {
      if ( !c.imag() )
        *this << TS_AS_STRING( c.real() );
      else if ( !c.real() )
        *this << "(" << TS_AS_STRING( c.imag() ) << " * i)";
      else
        *this << "(" << TS_AS_STRING( c.real() ) << " + "
              << TS_AS_STRING( c.imag() ) << " * i)";
    }
  };
#endif  // _CXXTEST_PARTIAL_TEMPLATE_SPECIALIZATION
}

#endif  // CXXTEST_USER_VALUE_TRAITS

#endif  // __cxxtest_StdValueTraits_h__
