// file: $isip/class/system/File/File.h
// version: $Id: File.h 9314 2003-09-30 01:29:13Z parihar $
//

// make sure definitions are only made once
//
#ifndef ISIP_FILE
#define ISIP_FILE

// isip include files
//
#ifndef ISIP_INTEGRAL
#include <Integral.h>
#endif

#ifndef ISIP_ERROR
#include <Error.h>
#endif

#ifndef ISIP_MEMORY_MANAGER
#include <MemoryManager.h>
#endif

// forward class definitions
//
class SysChar;
class SysString;

// File: a general purpose file pointer. this class abstracts file
//  manipulations, which are operating system specific, and provides
//  a general interface that all classes should use to access files.
//
//  an important feature of this class is that a polling strategy for
//  opening files is built into the class. when a file open fails, it is
//  possible that the file exists, but the network file system for the
//  computer is in error. this happens often in unix when dealing with
//  files using the network file system. an effective solution is simply
//  to wait a specified time, and try again. more often than not,
//  the next open will succeed. since all file I/O is centralized through
//  this class, this feature is automatically available to all isip classes.
//
class File {
  
  //---------------------------------------------------------------------------
  //
  // public constants
  //
  //---------------------------------------------------------------------------
public:
  
  // define the class name
  //
  static const SysString CLASS_NAME;
  
  //----------------------------------------
  //
  // other important constants
  //
  //----------------------------------------

  // define some maximum sizes
  //
  static const long MAX_FNAME_SIZE = PATH_MAX;
  static const long BUF_SIZE = 8192;
  static const long BAD_COUNT = -1;
    
  // standard file streams
  //
  enum STREAM { NO_STREAM = -1, OUT, IN, ERROR, DEF_STREAM = NO_STREAM };
  
  // seek positions
  //
  enum SEEK { POS = SEEK_SET, POS_PLUS_CUR = SEEK_CUR,
	      POS_PLUS_END = SEEK_END };
  
  // i/o modes
  //
  enum MODE { READ_ONLY = 0, READ_PLUS, WRITE_ONLY,
	      WRITE_PLUS, APPEND_ONLY, APPEND_PLUS, DEF_MODE = READ_ONLY };
  
  // i/o types
  //
  enum TYPE { TEXT = 0, BINARY, DEF_TYPE = TEXT };
  
  // byte-order modes
  //
  enum BMODE { NATIVE = 0, SWAP, BIG_ENDIAN, LITTLE_ENDIAN,
	       DEF_BMODE = NATIVE };
  
  // names for each of the enumerated file modes
  //
  static const char SYS_TEXT_READ_ONLY[];
  static const char SYS_TEXT_READ_PLUS[];
  static const char SYS_TEXT_WRITE_ONLY[];
  static const char SYS_TEXT_WRITE_PLUS[];
  static const char SYS_TEXT_APPEND_ONLY[];
  static const char SYS_TEXT_APPEND_PLUS[];
  
  static const char SYS_BINARY_READ_ONLY[];
  static const char SYS_BINARY_READ_PLUS[];
  static const char SYS_BINARY_WRITE_ONLY[];
  static const char SYS_BINARY_WRITE_PLUS[];
  static const char SYS_BINARY_APPEND_ONLY[];
  static const char SYS_BINARY_APPEND_PLUS[];
 
  // names for each of the enumerated file type
  //
  static const SysString TYPE_TEXT;
  static const SysString TYPE_BINARY;

  // indention and line wrapping
  //
  static const SysString INDENT_STR;
  static const SysString WRAP_TERM_STR;
  static const SysString WRAP_PRE_INDENT_STR;
  static const SysString WRAP_POST_INDENT_STR;

  // a string denoting a piped input/output
  //
  static const SysString STREAM_FILE;
  
  //----------------------------------------
  //
  // default values and arguments
  //  
  //----------------------------------------  
  
  // lock constants:
  //  def_lock_retry is the default number of times we try to lock a file
  //  before reporting fails, the def_lock_delay is the time in seconds before 
  //  each retry
  //
  static const long DEF_LOCK = false;
  static const long DEF_LOCK_RETRY = 5;
  static const long DEF_LOCK_DELAY = 2;

  // formatting constants
  //
  static const long DEF_INDENT = 0;
  static const long NO_WRAP = -1;
  static const long DEF_LINE_WRAP = NO_WRAP;

  // open related constants:
  //  def_open_retry is the default number of times we try to open a file
  //  before reporting fails, the def_open_delay is the time in seconds before 
  //  each retry
  //
  static const long DEF_OPEN_RETRY = 5;
  static const long DEF_OPEN_DELAY = 2;
  
  //----------------------------------------
  //
  // error codes
  //
  //----------------------------------------  

  static const long ERR = 1000;
  static const long ERR_NOTCLS = 1001;
  static const long ERR_NOTOPN = 1002;
  static const long ERR_REOPEN = 1003;
  static const long ERR_CLOSE = 1004;
  static const long ERR_FLUSH = 1005;
  static const long ERR_TRUNCT = 1006;
  static const long ERR_WRAP = 1007;
  static const long ERR_DECODE = 1008;
  
  //---------------------------------------------------------------------------
  //
  // protected data
  //
  //---------------------------------------------------------------------------
protected:
  
  // the stream type
  //
  STREAM stream_d;
  
  // the file pointer
  //
  FILE* fp_d;
  
  // open mode and type
  //
  MODE mode_d;
  TYPE type_d;
  
  // lock flag
  //
  boolean lock_d;
  
  // byte-order modes:
  //  it can be an absolute byte-order (LITTLE_ENDIAN or BIG_ENDIAN) or
  //  a relative order to the machine (NATIVE or SWAP)
  //
  BMODE byte_mode_d;

  // byte-swap flag:
  //  this is relative to the machine's byte-order
  //
  boolean byte_swap_d;
  
  // indention level
  //
  long indent_level_d;
  
  // line wrapping limit
  //
  long line_wrap_d;
  
  // current column position
  //
  long column_position_d;
  
  // file polling:
  //  open_retry_d is the number of times that the file will be polled for
  //  opening before an error is returned. open_delay_d is the delay in
  //  seconds between attempts to open the file.
  //
  long open_retry_d;
  long open_delay_d;

  // declare an array of SysString objects to keep track of temporary filenames
  //
  static SysString** temp_files_d;
  static long temp_size_d;
  static long temp_num_d;

  // declare a static debug level for all class instantiations
  //
  static Integral::DEBUG debug_level_d;

  // static memory manager
  //
  static MemoryManager mgr_d;

  //---------------------------------------------------------------------------
  //
  // required public methods
  //
  //---------------------------------------------------------------------------
public:

  // method: name
  //
  static const SysString& name() {
    return CLASS_NAME;
  }
  
  // other static methods
  //
  static boolean diagnose(Integral::DEBUG debug_level);
  
  // method: setDebug
  //
  static boolean setDebug(Integral::DEBUG level) {
    debug_level_d = level;
    return true;
  }

  // other debug methods
  //  
  boolean debug(const unichar* message) const;
  
  // destructor/constructor(s):
  //  the copy constructor is private
  //
  ~File();
  File(STREAM stream = DEF_STREAM);

  // assign methods:
  //  these methods are omitted because we do not ever want multiple file
  //  pointers on the same file. see the File::swap method
  //

  // operator= methods:
  //  these methods are omitted because we do not ever want multiple file
  //  pointers on the same file. 
  //

  // i/o methods:
  //  these methods are omitted because File can not write itself
  //  to an sof file
  //
  
  // equality methods:
  //  these methods are omitted because they are not useful for File objects
  //
  
  // memory management methods:
  //  the clear method is omitted so the user is forced to open and close
  //  files in a disciplined manner
  //
  
  // method: new
  //
  static void* operator new(size_t size) {
    return mgr_d.get();
  }

  // method: new[]
  //
  static void* operator new[](size_t size) {
    return mgr_d.getBlock(size);
  }

  // method: delete
  //
  static void operator delete(void* ptr) {
    mgr_d.release(ptr);
  }

  // method: delete[]
  //
  static void operator delete[](void* ptr) {
    mgr_d.releaseBlock(ptr);
  }

  // method: setGrowSize
  //
  static boolean setGrowSize(long grow_size) {
    return mgr_d.setGrow(grow_size);
  }
  
  //---------------------------------------------------------------------------
  //
  // class-specific public methods:
  //  extensions to the required public methods
  //
  //---------------------------------------------------------------------------
  
  // memory size methods
  //
  long memSize() const;
  
  // swap methods:
  //  this method serves as File's assignment method. we don't
  //  ever want multiple file pointers on the same file, so if you
  //  assign a pointer to another, the source loses it's data.
  //
  boolean swap(File& arg);

  //---------------------------------------------------------------------------
  //
  // class-specific public methods:
  //  get/set methods
  //
  //---------------------------------------------------------------------------
  
  // method: setStreamType
  //
  boolean setStreamType(STREAM arg) {
    return (stream_d = arg);
  }
  
  // method: setFileMode
  //
  boolean setFileMode(MODE arg) {
    return (mode_d = arg);
  }  

  // method: get temporary files
  //
  SysString** getTempFilename() {
    return temp_files_d;
  }
  
  // method: get number of temporary files
  //
  long getNumTempFiles() {
    return temp_num_d;
  }
  
  //---------------------------------------------------------------------------
  //
  // class-specific public methods:
  //  file operation methods
  //
  //---------------------------------------------------------------------------
  
  // standard file methods
  //
  boolean open(const unichar* filename, MODE mode = DEF_MODE,
	       TYPE type = DEF_TYPE);
  boolean open(const SysString& filename, MODE mode = DEF_MODE,
	       TYPE type = DEF_TYPE);
  
  boolean close();
  boolean flush();
  boolean truncate(long size);
  
  // file polling methods:
  //  this method sets the retry times that a file will be polled for
  //  opening before an error is returned
  //
  boolean setOpenRetry(long retry, long delay);

  // file locking methods
  //
  boolean lock(long retry = DEF_LOCK_RETRY, long DELAY = DEF_LOCK_DELAY);
  boolean unlock();
  
  // positioning methods
  //
  boolean seek(long offset, SEEK mode);
  long tell() const;
  
  // method: eof
  //
  boolean eof() const {
    if (fp_d == (FILE*)NULL) {
      return Error::handle(name(), L"eof", ERR_NOTOPN, __FILE__, __LINE__,
			   Error::WARNING);
    }
    return feof(fp_d);
  }

  // method: rewind
  //
  boolean rewind() {
    return seek(0, POS);
  }
  
  // method: isOpen
  //
  boolean isOpen() const {
    return (fp_d != (FILE*)NULL);
  }
  
  // method: isReadable
  //
  boolean isReadable() const {
    return ((fp_d != (FILE*)NULL) && (mode_d != WRITE_ONLY)
	    && (mode_d != APPEND_ONLY));
  }
  
  // method: isWritable
  //
  boolean isWritable() const {
    return ((fp_d != (FILE*)NULL) && (mode_d != READ_ONLY));
  }
  
  // method: isText
  //
  boolean isText() const {
    return ((fp_d != (FILE*)NULL) && (type_d == TEXT));
  }
  
  // method: isBinary
  //
  boolean isBinary() const {
    return ((fp_d != (FILE*)NULL) && (type_d == BINARY));
  }
  
  // method: isLocked
  //
  boolean isLocked() const {
    return lock_d;
  }

  // return the size of the file in bytes
  //
  long size(boolean keep_position = true) const;
  static long size(const unichar* filename);
  static long size(const SysString& filename);

  //---------------------------------------------------------------------------
  //
  // class-specific public methods:
  //  i/o methods
  //
  //---------------------------------------------------------------------------
  
  // single character i/o methods
  //
  boolean get(SysChar& chr);
  boolean put(const SysChar chr);

  // string i/o methods (recommended)
  //
  boolean get(SysString& str, long len = BUF_SIZE);
  boolean put(const SysString& str);
  
  // buffer-based i/o methods:
  //  for binary files (with byte swapping).
  //  note these are not the same as the required read/write methods in
  //  other classes which read/ write the object itself from /into sof file
  //
  long read(void* ptr, long size, long num);
  long write(const void* ptr, long size, long num);
  
  //---------------------------------------------------------------------------
  //
  // class-specific public methods:
  //  formatting methods
  //
  //---------------------------------------------------------------------------
  
  // indentation methods
  //
  boolean increaseIndention();
  boolean decreaseIndention();
  
  // method: setLineWrap
  //
  boolean setLineWrap(long num_cols) {
    line_wrap_d = num_cols;
    return true;
  }

  // method: getLineWrap
  //
  long getLineWrap() const {
    return line_wrap_d;    
  }

  // get the line length
  //
  long getLineLength() const;

  // methods to register temporary files so they can be cleanly deleted
  //
  static boolean registerTemp(SysString& name);
  static boolean cleanTemps();
  
  //---------------------------------------------------------------------------
  //
  // class-specific public methods:
  //  disk file operation methods
  //
  //---------------------------------------------------------------------------
  
  // the methods which take unichar* as arguments are not inlined because
  // they need include SysString.h. however SysString requires to include
  // File.h. therefore we don't inline these methods to avoid the compilation
  // error resulted from two classes trying to include each other.
  //
  static boolean remove(const unichar* filename);  
  static boolean remove(const SysString& filename);
  
  static boolean rename(const unichar* old_name, const unichar* new_name);
  static boolean rename(const SysString& old_name, const SysString& new_name);
  
  static boolean mkdir(const unichar* dir_name);  
  static boolean mkdir(const SysString& dir_name);
  
  static boolean rmdir(const unichar* dir_name);
  static boolean rmdir(const SysString& dir_name);
  
  static boolean exists(const unichar* filename);    
  static boolean exists(const SysString& filename);

  static boolean compare(const unichar* file1, const unichar* file2);
  static boolean compare(const SysString& file1, const SysString& file2);

  //---------------------------------------------------------------------------
  //
  // class-specific public methods:
  //  byte-order related methods
  //
  //---------------------------------------------------------------------------
  
  // set/get the absolute byte-order mode methods
  //
  boolean setBMode(BMODE mode);
  BMODE getBMode() const;
  
  // get the machine's byte order methods
  //
  BMODE getMachineByteOrder() const;
  
  // single value encode/decode methods
  //
  int16 encode(int16 value) const;
  int32 encode(int32 value) const;
  int64 encode(int64 value) const;
  
  int16 decode(int16 value) const;
  int32 decode(int32 value) const;
  int64 decode(int64 value) const;

  //---------------------------------------------------------------------------
  //
  // class-specific public methods:
  //  string manipulation methods
  //
  //---------------------------------------------------------------------------

  // array-oriented methods
  //
  boolean substr(SysString& str, long offset,
		 long num_elements = Integral::NO_POS) const;
  
  //---------------------------------------------------------------------------
  //
  // class-specific public methods:
  //  string search methods
  //
  //---------------------------------------------------------------------------

  // method: firstStr
  //
  long firstStr(const unichar* str, long start = Integral::NO_POS) const;

  // other first string methods
  //
  long firstStr(const SysString& str, long start = Integral::NO_POS) const;
  
  //---------------------------------------------------------------------------
  //
  // private methods
  //
  //---------------------------------------------------------------------------
private:
    
  // method: copy constructor
  //   this method is private so we can't copy file objects.
  //
  File(const File& arg);

  // method: encode
  //
  boolean encode(void* buf, long size, long nitems) const {
    return encode(buf, buf, size, nitems);
  }

  // other encode methods:
  //
  boolean encode(void* obuf, const void* ibuf, long size, long nitems) const;
  
  // method: decode
  //
  boolean decode(void* buf, long size, long nitems) const {
    return decode(buf, buf, size, nitems);
  }

  // other decode methods:
  //
  boolean decode(void* obuf, const void* ibuf, long size, long nitems) const;
};

// end of include file
//
#endif
