/*  Copyright (C) 2015  Povilas Kanapickas <povilas@radix.lt>

    This file is part of cppreference-doc

    This work is licensed under the Creative Commons Attribution-ShareAlike 3.0
    Unported License. To view a copy of this license, visit
    http://creativecommons.org/licenses/by-sa/3.0/ or send a letter to Creative
    Commons, 444 Castro Street, Suite 900, Mountain View, California, 94041, USA.

    Permission is granted to copy, distribute and/or modify this document
    under the terms of the GNU Free Documentation License, Version 1.3 or
    any later version published by the Free Software Foundation; with no
    Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
*/

#ifndef CPPREFERENCE_IOS_H
#define CPPREFERENCE_IOS_H

#if CPPREFERENCE_STDVER>= 2011
#include <system_error>
#endif

namespace std {

typedef int streamoff;
typedef int streamsize;
template<class StateT> class fpos;

class ios_base {
private:
    ios_base(const ios_base&);
protected:
    ios_base();
public:
    virtual ~ios_base();

#if CPPREFERENCE_STDVER <2011
    class failure : public exception {
    public:
        explicit failure(const std::string& message);
    };
#else
    class failure : public system_error {
    public:
        explicit failure(const std::string& message,
                         const std::error_code& ec = std::io_errc::stream);
        explicit failure(const char* message,
                         const std::error_code& ec = std::io_errc::stream);
    };
#endif

    class Init;

    typedef int openmode; // actually impl-defined
    static constexpr openmode app;
    static constexpr openmode binary;
    static constexpr openmode in;
    static constexpr openmode out;
    static constexpr openmode trunc;
    static constexpr openmode ate;

    typedef int fmtflags; // actually impl-defined
    static constexpr fmtflags dec;
    static constexpr fmtflags oct;
    static constexpr fmtflags hex;
    static constexpr fmtflags basefield;

    static constexpr fmtflags left;
    static constexpr fmtflags right;
    static constexpr fmtflags internal;
    static constexpr fmtflags adjustfield;

    static constexpr fmtflags scientific;
    static constexpr fmtflags fixed;
    static constexpr fmtflags floatfield;

    static constexpr fmtflags boolalpha;
    static constexpr fmtflags showbase;
    static constexpr fmtflags showpoint;
    static constexpr fmtflags showpos;
    static constexpr fmtflags skipws;
    static constexpr fmtflags unitbuf;
    static constexpr fmtflags uppercase;

    typedef int iostate; // actually impl-defined
    static constexpr iostate goodbit;
    static constexpr iostate badbit;
    static constexpr iostate failbit;
    static constexpr iostate eofbit;

    typedef int seekdir; // actually impl-defined
    static constexpr seekdir beg;
    static constexpr seekdir end;
    static constexpr seekdir cur;

    enum event {
        erase_event,
        imbue_event,
        copyfmt_event
    };

    typedef void (*event_callback)(event type, ios_base& ios, int index);

    fmtflags flags() const;
    fmtflags flags(fmtflags flags);
    fmtflags setf(fmtflags flags);
    fmtflags setf(fmtflags flags, fmtflags mask);
    void unsetf(fmtflags flags);

    streamsize precision() const;
    streamsize precision(streamsize new_precision);
    streamsize width() const;
    streamsize width(streamsize new_width);

    locale imbue(const locale& loc);
    locale getloc() const;

    static int xalloc();
    long& iword(int index);
    void*& pword(int index);

    void register_callback(event_callback function, int index);
    static bool sync_with_stdio(bool sync = true);
};

template<class CharT,
         class Traits = std::char_traits<CharT>>
class basic_ios : public ios_base {
public:
    typedef CharT char_type;
    typedef Traits traits_type;
    typedef typename Traits::int_type int_type;
    typedef typename Traits::pos_type pos_type;
    typedef typename Traits::off_type off_type;

    explicit basic_ios(std::basic_streambuf<CharT, Traits>* sb);
    virtual ~basic_ios();

    bool good() const;
    bool eof() const;
    bool fail() const;
    bool bad() const;

    bool operator!() const;
#if CPPREFERENCE_STDVER <2011
    operator void* () const;
#else
    explicit operator bool() const;
#endif

    iostate rdstate() const;
    void setstate(iostate state);
    void clear(iostate state = goodbit);

    basic_ios& copyfmt(const basic_ios& other);

    CharT fill() const;
    CharT fill(CharT ch);

    iostate exceptions() const;
    void exceptions(iostate except);

    locale imbue(const locale& loc);

    char narrow(char_type c, char dfault) const;
    char_type widen(char c) const;

    basic_streambuf<CharT, Traits>* rdbuf() const;
    basic_streambuf<CharT, Traits>* rdbuf(std::basic_streambuf<CharT, Traits>* sb);

    std::basic_ostream<CharT, Traits>* tie() const;
    std::basic_ostream<CharT, Traits>* tie(std::basic_ostream<CharT, Traits>* str);

    char narrow(char_type c, char dfault) const;
    char_type widen(char c) const;

protected:
    basic_ios();
    void init(std::basic_streambuf<CharT, Traits>* sb);
    void set_rdbuf(std::basic_streambuf<CharT, Traits>* sb);

#if CPPREFERENCE_STDVER>= 2011
    void move(basic_ios& other);
    void move(basic_ios&& other);
    void swap(basic_ios& other);
#endif
private:
    basic_ios(const basic_ios&);
};

typedef basic_ios<char> ios;
typedef basic_ios<wchar_t> wios;

// manipulators
ios_base& boolalpha(ios_base& str);
ios_base& noboolalpha(ios_base& str);
ios_base& showbase(ios_base& str);
ios_base& noshowbase(ios_base& str);
ios_base& showpoint(ios_base& str);
ios_base& noshowpoint(ios_base& str);
ios_base& showpos(ios_base& str);
ios_base& noshowpos(ios_base& str);
ios_base& skipws(ios_base& str);
ios_base& noskipws(ios_base& str);
ios_base& uppercase(ios_base& str);
ios_base& nouppercase(ios_base& str);
ios_base& unitbuf(ios_base& str);
ios_base& nounitbuf(ios_base& str);

ios_base& internal(ios_base& str);
ios_base& left(ios_base& str);
ios_base& right(ios_base& str);

ios_base& dec(ios_base& str);
ios_base& hex(ios_base& str);
ios_base& oct(ios_base& str);

ios_base& fixed(ios_base& str);
ios_base& scientific(ios_base& str);
ios_base& hexfloat(ios_base& str);
ios_base& defaultfloat(ios_base& str);

#if CPPREFERENCE_STDVER>= 2011
enum class io_errc {
    stream
};

std::error_code make_error_code(std::io_errc e);
std::error_condition make_error_condition(std::io_errc e);
const std::error_category& iostream_category();
#endif

} // namespace std

#endif // CPPREFERENCE_IOS_H
