/*!
    \file
    \copyright  (c) 2015 Jascha Wetzel. All rights reserved.
 */

#ifndef TFD_API_STRING_H
#define TFD_API_STRING_H

#include "api/base.h"

#include <string>
#include <ostream>
#include <utility>

namespace tfd {
namespace api {

/*!
    String interface for use across API boundaries.
    Use tfd::String to create the string and pass a tfd::api::String*.
 */
struct String : Base
{
    virtual const char* data() const = 0;
    virtual size_t size() const = 0;

    virtual String& operator=(const String&) = 0;

    operator std::string() const {
        return std::string(data(), size());
    }
};

inline std::ostream&
operator<<(std::ostream& os, const String& str) {
    os << static_cast<std::string>(str);
    return os;
}

} // namespace api

/*!
    String container for use across API boundaries.
    Ensures that string memory is released on the same side of the API that allocated it.
 */
class String : public api::String
{
public:
    String()
    {}

    String(const String& arg) : data_(arg.data_)
    {}

    String(char* arg) : data_(arg)
    {}

    String(const char* arg) : data_(arg)
    {}

    String(const std::string& arg) : data_(arg)
    {}

#if !defined(__APPLE__) || _LIBCPP_VERSION >= 1100
    String(std::string&& arg) : data_(std::move(arg))
    {}

    String& operator=(String&& rhs) {
        data_ = std::move(rhs.data_);
        return *this;
    }

    String& operator=(std::string&& rhs) {
        data_ = std::move(rhs);
        return *this;
    }
#endif

    api::String& operator=(const api::String& rhs) {
        data_ = std::string(rhs.data(), rhs.size());
        return *this;
    }

    String& operator=(const std::string& rhs) {
        data_ = rhs;
        return *this;
    }

    void release() {
        delete this;
    }

    const char* data() const {
        return data_.c_str();
    }

    size_t size() const {
        return data_.size();
    }

    operator std::string() const {
        return data_;
    }

private:
    std::string
        data_;
};

} // namespace tfd

#endif // TFD_API_STRING_H
