/* -*- c++ -*- */
/*
 * Copyright (C) 2010 The Android Open Source Project
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *  * Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *  * Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#ifndef ANDROID_ASTL_SSTREAM__
#define ANDROID_ASTL_SSTREAM__

#include <char_traits.h>
#include <ios_base.h>
#include <streambuf>
#include <string>
#include <ostream>

namespace std {

// Declare basic_stringbuf which is a buffer implemented using a std::string.
// Then declare stringstream which implement a stream using basic_stringbuf.

struct basic_stringbuf : public streambuf {
  public:
    typedef streambuf::traits_type  traits_type;
    typedef streambuf::char_type    char_type;
    typedef streambuf::int_type     int_type;
    typedef streambuf::pos_type     pos_type;
    typedef streambuf::off_type     off_type;

    // Construct an instance, in/out by default.
    explicit basic_stringbuf(ios_base::openmode mode =
                             ios_base::in | ios_base::out);

    // Construct an instance and copy str into the underlying buffer
    // and initialize the input and output sequence according to the
    // flags set in mode.
    explicit basic_stringbuf(const string& str,
                             ios_base::openmode mode =
                             ios_base::in | ios_base::out);

    virtual ~basic_stringbuf();

    // @return A copy of the underlying buffer. If the buffer was
    // creted in input mode, this is equal to the the input
    // sequence. Otherwise it is equal to the output sequence.
    // TODO: In the standard a copy is returned instead of const ref -
    // not sure why.
    const string& str() const;

    // Clear the current buffer then copy the content of str into
    // it. Initialize the input/output sequences according to the mode
    // used.
    // @param str The string to use as a new sequence.
    void str(const string & str);

    // @return -1 on output stream otherwise the number char available
    // for reading.
    streamsize in_avail();

  protected:
    // Override the default impl from ostream to do the work.
    virtual streamsize xsputn(const char_type* str, streamsize num);

    ios_base::openmode  mMode;
    string              mString;
};

// In a regular STL this is <char> full specialization.
typedef basic_stringbuf stringbuf;


class stringstream : public ostream {
  public:
    explicit stringstream(ios_base::openmode mode =
                          ios_base::in | ios_base::out);

    explicit stringstream(const string& str,
                          ios_base::openmode mode =
                          ios_base::in | ios_base::out);
    virtual ~stringstream();

    const string& str() const { return mStringBuf.str(); }
    void str(const string & str) { mStringBuf.str(str); }

    // TODO: move this to ostream.
    ostream& put(char c);

  private:
    basic_stringbuf mStringBuf;
};

// In a regular STL stringstream inherits from ostringstream and
// istringstream. Since we use stringstream everywhere we just declare
// ostringstream as an alias to pass compilation.
typedef stringstream ostringstream;

}  // namespace std

#endif  // ANDROID_ASTL_SSTREAM__