/*
 * Copyright (c) 2007-2009 by Oleg Trifonov <otrifonow@gmail.com>
 *
 * This file is free software; you can redistribute it and/or modify
 * it under the terms of either the GNU General Public License version 2
 * or the GNU Lesser General Public License version 2.1, both as
 * published by the Free Software Foundation.
 */


#ifndef _TR_STREAM_H_
#define _TR_STREAM_H_

#include "trTypes.h"
#include "stdio.h"
#include "zip.h"
#include "unzip.h"

// абстрактный класс потока ввода/вывода
class TrStream {
public:
   virtual bool Seek(Int64 pos) = 0;
   virtual Int64 GetPos() = 0;
   virtual bool Reset() { return Seek(0); }
   virtual bool Close() = 0;
   virtual Int64 GetSize() = 0;
	virtual bool Eof() = 0;

   virtual UInt32 ReadByte();
   virtual UInt32 ReadWord();
   virtual UInt32 Read3Byte();
   virtual UInt32 ReadDword();
   virtual Int32 ReadInt();
   virtual UInt32 Read(void *buf, UInt32 size) = 0;

	virtual UInt32 ReadLine(char *str, UInt32 maxLength);

   virtual void WriteByte(UInt32 val);
   virtual void WriteWord(UInt32 val);
   virtual void Write3Byte(UInt32 val);
   virtual void WriteDword(UInt32 val);
   virtual void WriteInt(Int32 val);
   virtual UInt32 Write(void *buf, UInt32 size) = 0;

   virtual bool Flush() { return true; } 

   virtual TrStream& operator << (TrStream &stream) { CopyStreams(*this, stream); return *this; };
   //virtual TrStream* operator << (TrStream *stream) { (*this) << (*stream); return this; };
   virtual TrStream& operator >> (TrStream &stream) { CopyStreams(stream, *this); return *this; };
   //virtual TrStream* operator >> (TrStream *stream) { (*this) >> (*stream); return this; };

	virtual bool IsError() { return iError; }

protected:
   virtual void CopyStreams(TrStream &dest, TrStream &src);   
   virtual BytePtr GetMemoryBuffer() { return NULL; }; // если поток содержит свои данные в памяти, возвращает указатель на буффер. иначе, возвращает NULL
   virtual void ResizeBuffer(UInt32 addwSize) {};   // для потоков памяти. проверяет, может ли буффер вместить еще addSize байт, и расширяет его если нет

   bool iError;

   friend Int32 trZipCompressStream(TrStream &src, TrStream &dest, UInt32 count, Int32 level);
   friend Int32 trZipDecompressStream(TrStream &src, TrStream &dest, UInt32 count);
};



// абстрактный класс потока ввода/вывода библиотеки ресурсов
class TrStreamPack : public TrStream {
   virtual bool OpenObject(const char *name) = 0;
   virtual bool ClosePack() = 0;   
   
//   virtual UInt32 GetObjectcCount() = 0;
//   virtual char* GetObjectsName(UInt32 index) = 0;
};



// буфферный поток ввода/вывода
class TrMemStream : public TrStream {
public:
   TrMemStream();
   TrMemStream(UInt32 size, UInt32 delta = 0) { iError = false; Open(size, delta); };
   TrMemStream(void *buf, UInt32 size, UInt32 delta = 0) { iError = false; Open(buf, size, delta); };
   ~TrMemStream() { Close(); };

   void Open(UInt32 size, UInt32 delta = 0);
   void Open(void *buf, UInt32 size, UInt32 delta = 0);

   virtual bool Seek(Int64 pos) { iPos = (UInt32)pos; return true; };
   virtual Int64 GetPos() { return iPos; };
   virtual bool Close();
   virtual Int64 GetSize() { return iSize; };
	virtual bool Eof() { return iPos >= iSize; };

   virtual UInt32 ReadByte();
   virtual UInt32 ReadWord();
   virtual UInt32 Read3Byte();
   virtual UInt32 ReadDword();
   virtual Int32 ReadInt();
   virtual UInt32 Read(void *buf, UInt32 size);

   virtual void WriteByte(UInt32 val);
   virtual void WriteWord(UInt32 val);
   virtual void Write3Byte(UInt32 val);
   virtual void WriteDword(UInt32 val);
   virtual void WriteInt(Int32 val);
   virtual UInt32 Write(void *buf, UInt32 size);
   
protected:
   UInt32 iPos, iSize, iDelta, iAllocated;
   BytePtr iData;
   
   virtual BytePtr GetMemoryBuffer() { return iData; }; // если поток содержит свои данные в памяти, возвращает указатель на буффер. иначе, возвращает NULL
   virtual void ResizeBuffer(UInt32 addwSize);   // проверяет, может ли буффер вместить еще addSize байт, и расширяет его если нет   
};



// файловый поток ввода/вывода
class TrFileStream : public TrStream {
public:
   enum OpenMode {
      EOpenRead          = 0, // открытие для чтения. файл должен быть создан
      ECreateWrite       = 1, // создать пустой для записи. существующий файл будет заменен пустым
      EAppendWrite       = 2, // дописать данные в конец файла. будет создан, если не существует
      EOpenReadWrite     = 3, // открыть существующий файл для чтения/записи
      ECreateReadWrite   = 4, // создать пустой файл для чтения/записи. существующий файл будет заменен пустым
      EAppendRead        = 5  // открыть файл для чтения и дозаписи. запись в существующую область запрещена. будет создан, если не существует
   };
   TrFileStream() { iOpened = false; iError = false; };
   TrFileStream(const char *fileName, OpenMode mode) { Open(fileName, mode); };   
   ~TrFileStream() { Close(); };

   bool Open(const char *fileName, OpenMode mode);

   virtual bool Seek(Int64 pos);
   virtual Int64 GetPos();
   virtual bool Close();
   virtual Int64 GetSize();
	virtual bool Eof();
   
   virtual UInt32 Read(void *buf, UInt32 size);
   virtual UInt32 Write(void *buf, UInt32 size);

   virtual bool Flush() { return fflush(iFile) == 0; } 

protected:
   bool iOpened;   
   FILE *iFile;
};



class TrZipStreamPack : public TrStreamPack {
public:
   enum OpenMode {
      EOpenRead       = 0,
      ECreateWrite    = 1,
      EAppendWrite    = 2
   };

   TrZipStreamPack();
   TrZipStreamPack(const char *fileName, OpenMode mode) { iLevel = 0; iError = false; Open(fileName, mode); };
   ~TrZipStreamPack() { Close(); ClosePack(); };

   bool Open(const char *fileName, OpenMode mode);

   virtual bool OpenObject(const char *name);
   virtual bool ClosePack();
//   virtual UInt32 GetObjectcCount();
//   virtual char* GetObjectsName(UInt32 index);

   virtual bool Seek(Int64 pos);
   virtual Int64 GetPos();   
   virtual bool Close();
   virtual Int64 GetSize();
	virtual bool Eof();

   virtual UInt32 Read(void *buf, UInt32 size);
   virtual UInt32 Write(void *buf, UInt32 size);   

   void SetCompressionLevel(UInt32 level); // 0..9


protected:
   OpenMode iMode;
   bool iZipOpen;
   bool iItemOpen;   
   zipFile iZipFile;
   unzFile iUnzipFile;
   Int64 iPos;
   UInt32 iLevel;
};





// сжимает count байт из потока src (начиная с текущей позиции) методом zip и отправляет результат 
// в поток dest. level - степень сжатия (0..9)
// возвращает размер сжатых данных (тех, что были переданы в dest) или -1 в случае ошибки
Int32 trZipCompressStream(TrStream &src, TrStream &dest, UInt32 count, Int32 level);


// сжимает поток src (начиная с текущей позиции и до конца) методом zip и отправляет результат 
// в поток dest. level - степень сжатия (0..9)
// возвращает размер сжатых данных (тех, что были переданы в dest) или -1 в случае ошибки
inline Int32 trZipCompressStream(TrStream &src, TrStream &dest, Int32 level) {
   return trZipCompressStream(src, dest, (UInt32)(src.GetSize()-src.GetPos()), level);
};


// разжимает count байт из потока src (начиная с текущей позиции) методом zip и отправляет результат
// в поток dest
// возвращает размер распакованных данных (тех, что были переданы в dest) или -1 в случае ошибки
Int32 trZipDecompressStream(TrStream &src, TrStream &dest, UInt32 count);


// разжимает count байт из потока src (начиная с текущей позиции) методом zip и отправляет результат
// в поток dest
// возвращает размер распакованных данных (тех, что были переданы в dest) или -1 в случае ошибки
inline Int32 trZipDecompressStream(TrStream &src, TrStream &dest) {
   return trZipDecompressStream(src, dest, (UInt32)(src.GetSize()-src.GetPos()));
};


#endif // _TR_STREAM_H_
