// File: crn_data_stream.h
// See Copyright Notice and license at the end of inc/crnlib.h
#pragma once

namespace crnlib
{
   enum data_stream_attribs
   {
      cDataStreamReadable = 1,
      cDataStreamWritable = 2,
      cDataStreamSeekable = 4
   };

   const int64 DATA_STREAM_SIZE_UNKNOWN = cINT64_MAX;
   const int64 DATA_STREAM_SIZE_INFINITE = cUINT64_MAX;

   class data_stream
   {
      data_stream(const data_stream&);
      data_stream& operator= (const data_stream&);

   public:
      data_stream();
      data_stream(const char* pName, uint attribs);

      virtual ~data_stream() { }

      virtual data_stream *get_parent() { return NULL; }

      virtual bool close() { m_opened = false; m_error = false; m_got_cr = false; return true; }

      typedef uint16 attribs_t;
      inline attribs_t get_attribs() const { return m_attribs; }

      inline bool is_opened() const { return m_opened; }

      inline bool is_readable() const { return utils::is_bit_set(m_attribs, cDataStreamReadable); }
      inline bool is_writable() const { return utils::is_bit_set(m_attribs, cDataStreamWritable); }
      inline bool is_seekable() const { return utils::is_bit_set(m_attribs, cDataStreamSeekable); }

      inline bool get_error() const { return m_error; }

      inline const dynamic_string& get_name() const { return m_name; }
      inline void set_name(const char* pName) { m_name.set(pName); }

      virtual uint read(void* pBuf, uint len) = 0;
      virtual uint64 skip(uint64 len);

      virtual uint write(const void* pBuf, uint len) = 0;
      virtual bool flush() = 0;

      virtual bool is_size_known() const { return true; }

      // Returns DATA_STREAM_SIZE_UNKNOWN if size hasn't been determined yet, or DATA_STREAM_SIZE_INFINITE for infinite streams.
      virtual uint64 get_size() = 0;
      virtual uint64 get_remaining() = 0;

      virtual uint64 get_ofs() = 0;
      virtual bool seek(int64 ofs, bool relative) = 0;

      virtual const void* get_ptr() const { return NULL; }

      inline int read_byte() { uint8 c; if (read(&c, 1) != 1) return -1; return c; }
      inline bool write_byte(uint8 c) { return write(&c, 1) == 1; }

      bool read_line(dynamic_string& str);
      bool printf(const char* p, ...);
      bool write_line(const dynamic_string& str);
      bool write_bom() { uint16 bom = 0xFEFF; return write(&bom, sizeof(bom)) == sizeof(bom); }

      bool read_array(vector<uint8>& buf);
      bool write_array(const vector<uint8>& buf);

   protected:
      dynamic_string m_name;

      attribs_t      m_attribs;
      bool           m_opened : 1;
      bool           m_error : 1;
      bool           m_got_cr : 1;

      inline void set_error() { m_error = true; }
      inline void clear_error() { m_error = false; }

      inline void post_seek() { m_got_cr = false; }
   };

} // namespace crnlib