// File: crn_data_stream.cpp
// See Copyright Notice and license at the end of inc/crnlib.h
#include "crn_core.h"
#include "crn_data_stream.h"

namespace crnlib
{
   data_stream::data_stream() :
      m_attribs(0),
      m_opened(false), m_error(false), m_got_cr(false)
   {
   }

   data_stream::data_stream(const char* pName, uint attribs) :
      m_name(pName),
      m_attribs(static_cast<uint16>(attribs)),
      m_opened(false), m_error(false), m_got_cr(false)
   {
   }

   uint64 data_stream::skip(uint64 len)
   {
      uint64 total_bytes_read = 0;

      const uint cBufSize = 1024;
      uint8 buf[cBufSize];

      while (len)
      {
         const uint64 bytes_to_read = math::minimum<uint64>(sizeof(buf), len);
         const uint64 bytes_read = read(buf, static_cast<uint>(bytes_to_read));
         total_bytes_read += bytes_read;

         if (bytes_read != bytes_to_read)
            break;

         len -= bytes_read;
      }

      return total_bytes_read;
   }

   bool data_stream::read_line(dynamic_string& str)
   {
      str.empty();

      for ( ; ; )
      {
         const int c = read_byte();

         const bool prev_got_cr = m_got_cr;
         m_got_cr = false;

         if (c < 0)
         {
            if (!str.is_empty())
               break;

            return false;
         }
         else if ((26 == c) || (!c))
            continue;
         else if (13 == c)
         {
            m_got_cr = true;
            break;
         }
         else if (10 == c)
         {
            if (prev_got_cr)
               continue;

            break;
         }

         str.append_char(static_cast<char>(c));
      }

      return true;
   }

   bool data_stream::printf(const char* p, ...)
   {
      va_list args;

      va_start(args, p);
      dynamic_string buf;
      buf.format_args(p, args);
      va_end(args);

      return write(buf.get_ptr(), buf.get_len() * sizeof(char)) == buf.get_len() * sizeof(char);
   }

   bool data_stream::write_line(const dynamic_string& str)
   {
      if (!str.is_empty())
         return write(str.get_ptr(), str.get_len()) == str.get_len();

      return true;
   }

   bool data_stream::read_array(vector<uint8>& buf)
   {
      if (buf.size() < get_remaining())
      {
         if (get_remaining() > 1024U*1024U*1024U)
            return false;

         buf.resize((uint)get_remaining());
      }

      if (!get_remaining())
      {
         buf.resize(0);
         return true;
      }

      return read(&buf[0], buf.size()) == buf.size();
   }

   bool data_stream::write_array(const vector<uint8>& buf)
   {
      if (!buf.empty())
         return write(&buf[0], buf.size()) == buf.size();
      return true;
   }

} // namespace crnlib