/***********************************************************************
 * FXRuby -- the Ruby language bindings for the FOX GUI toolkit.
 * Copyright (c) 2001-2003 by J. Lyle Johnson. All Rights Reserved.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * For further information please contact the author by e-mail
 * at "lyle@users.sourceforge.net".
 ***********************************************************************/

/// Stream data flow direction
enum FXStreamDirection { 
  FXStreamDead=0,               // Unopened stream
  FXStreamSave=1,               // Saving stuff to stream
  FXStreamLoad=2                // Loading stuff from stream
  };

    
/// Stream status codes
enum FXStreamStatus {
  FXStreamOK=0,                 // OK
  FXStreamEnd=1,                // Try read past end of stream
  FXStreamFull=2,               // Filled up stream buffer or disk full
  FXStreamNoWrite=3,            // Unable to open for write
  FXStreamNoRead=4,             // Unable to open for read
  FXStreamFormat=5,             // Stream format error
  FXStreamUnknown=6,            // Trying to read unknown class
  FXStreamAlloc=7,              // Alloc failed
  FXStreamFailure=8             // General failure
  };


/*********************  Persistent Store Definition  *************************/


%rename(getPosition) FXStream::position() const;
%rename(setPosition) FXStream::position(unsigned long);
%rename(setSwapBytes) FXStream::swapBytes(FXbool s);
%rename(getSwapBytes) FXStream::swapBytes() const;
  
/// Persistent store definition
class FXStream {
protected:
  FXStreamDirection  dir;       // Direction of current transfer
  FXStreamStatus     code;      // Status code
  unsigned long      pos;       // Position
  
protected:

  /// Save bunch of items
  virtual void saveItems(const void *buf,FXuint n);

  /// Load bunch of items
  virtual void loadItems(void *buf,FXuint n);

public:

  /// Constructor
  %extend {
    FXStream(const FXObject* cont=NULL){
      return new FXRbStream(cont);
      }
    }

  /// Open archive return TRUE if OK
  FXbool open(FXStreamDirection save_or_load);

  /// Close; return TRUE if OK
  FXbool close();

  /// Get status code
  FXStreamStatus status() const;

  /// Set status code
  void setError(FXStreamStatus err);

  /// Obtain direction
  FXStreamDirection direction() const;

  /// Get parent object
  const FXObject* container() const;

  /// Get position
  unsigned long position() const;

  /// Change swap bytes flag
  void swapBytes(FXbool s);

  /// Get swap bytes flag
  FXbool swapBytes() const;

  /// Return implementation's endianness
  static FXbool isLittleEndian();
  
  /// Destructor
  virtual ~FXStream();
  };


DECLARE_FXSTREAM_VIRTUALS(FXStream)


/***************************  File Store Definition  ***************************/


/// File Store Definition
class FXFileStream : public FXStream {
protected:
  virtual void saveItems(const void *buf,FXuint n);
  virtual void loadItems(void *buf,FXuint n);

public:

  /// Create file store
  %extend {
    FXFileStream(const FXObject* cont=NULL){
      return new FXRbFileStream(cont);
      }
    }

  /// Open file store
  FXbool open(const FXString& filename,FXStreamDirection save_or_load);

  /// Close file store
  FXbool close();

  /// Destructor
  virtual ~FXFileStream();
  };


DECLARE_FXSTREAM_VIRTUALS(FXFileStream)

/**************************  Memory Store Definition  **************************/


/// Memory Store Definition
class FXMemoryStream : public FXStream {
protected:
  virtual void saveItems(const void *buf,FXuint n);
  virtual void loadItems(void *buf,FXuint n);

public:

  /// Create memory store
  %extend {
    FXMemoryStream(const FXObject* cont=NULL){
      return new FXRbMemoryStream(cont);
      }
    }

  %extend {
    // Open memory store
    FXbool open(VALUE str,FXStreamDirection save_or_load){
      FXuchar* data=NULL;
      FXuint sp=0;
      FXbool result;
      if(!NIL_P(str)){
        Check_Type(str,T_STRING);
	long len=RSTRING(str)->len;
	if(len>0 && FXMALLOC(&data,FXuchar,len)){
	  sp=len;
          memcpy(reinterpret_cast<void*>(data),reinterpret_cast<void*>(RSTRING(str)->ptr),sp);
	  }
	}
      if(sp==0){
        FXCALLOC(&data,FXuchar,1);
	sp=1;
        }

      /**
       * To ensure that the FXMemoryStream always owns the buffer, we're going to first
       * open it with a NULL buffer, then hand over our copy.
       */
      result=self->open(NULL,0,save_or_load);
      self->giveBuffer(data,sp);
      
      // Done
      return result;
      }
  }

  /// Get available space
  FXuint getSpace() const;

  /// Set available space
  void setSpace(FXuint sp);
  
  %extend {
    // Take buffer away from stream
    VALUE takeBuffer(){
      FXuchar* buffer;
      FXuint sp;
      
      // Grab the current contents
      self->takeBuffer(buffer,sp);
      VALUE result=rb_str_new(reinterpret_cast<char*>(buffer),sp);
      FXFREE(&buffer);

      // Ensure that the stream always owns a buffer
      FXCALLOC(&buffer,FXuchar,1);
      self->giveBuffer(buffer,1);
      
      // Done
      return result;
      }
  
    // Give buffer to stream
    void giveBuffer(VALUE str){
      FXuchar* buffer=NULL;
      FXuint sp=0;
      if(!NIL_P(str)){
        Check_Type(str,T_STRING);
	long len=RSTRING(str)->len;
	if(len>0 && FXMALLOC(&buffer,FXuchar,len)){
	  sp=len;
          memcpy(reinterpret_cast<void*>(buffer),reinterpret_cast<void*>(RSTRING(str)->ptr),sp);
	  }
	}
      if(sp==0){
        FXCALLOC(&buffer,FXuchar,1);
	sp=1;
        }
      self->giveBuffer(buffer,sp);
      }
  }
  
  /// Close memory store
  FXbool close();
  
  /// Destructor
  virtual ~FXMemoryStream();
  };


DECLARE_FXSTREAM_VIRTUALS(FXMemoryStream)

