// ------------------------------------------------
// File : stream.h
// Date: 4-apr-2002
// Author: giles
// Desc: 
//
// (c) 2002 peercast.org
// ------------------------------------------------
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.

// This program 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 General Public License for more details.
// ------------------------------------------------


#ifndef _STREAM_H
#define _STREAM_H

// -------------------------------------

#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include "common.h"
#include "sys.h"

// -------------------------------------
class Stream
{
public:
	Stream()
	{
		writeCRLF = true;
		totalBytesIn = totalBytesOut = 0;
		lastBytesIn = lastBytesOut = 0;
		bytesInPerSec = bytesOutPerSec = 0;
		lastUpdate = 0;
	}

	virtual int read(void *,int)=0;
	virtual void write(const void *,int) = 0;
    virtual bool eof()
    {
    	throw StreamException("Stream can`t eof");
		return false;
    }

	virtual void rewind()
	{
    	throw StreamException("Stream can`t rewind");
	}

	virtual void skip(int i)
	{
		while ((!eof()) && (i--))
		{
			char c;
			read(&c,1);
		}
	}

	virtual void close()
	{
	}



	// binary
    char	readChar()
    {
    	char v;
        read(&v,1);
        return v;
    }
    short	readShort()
    {
    	short v;
        read(&v,2);
        v = sys->convertEndian((unsigned short)v);
        return v;
    }
    long	readLong()
    {
    	long v;
        read(&v,4);
        v = sys->convertEndian((unsigned int)v);
        return v;
    }
	long readTag()
	{
		long v = readLong();
		return SWAP4(v);
	}

	int	readString(char *s, int max)
	{
		int cnt=0;
		while (max)
		{
			char c = readChar();
			*s++ = c;
			cnt++;
			max--;
			if (!c)
				break;
		}
		return cnt;
	}


	void	writeChar(char v)
	{
		write(&v,1);
	}
	void	writeShort(short v)
	{
        v = sys->convertEndian((unsigned short)v);
		write(&v,2);
	}
	void	writeLong(long v)
	{
        v = sys->convertEndian((unsigned int)v);
		write(&v,4);
	}

	void	writeTag(long v)
	{
		writeLong(SWAP4(v));
	}

	void	writeTag(char id[4])
	{
		write(id,4);
	}

	// text
    int	readLine(char *in, int max);

    int		readWord(char *, int);
	int		readBase64(char *, int);

	void	write(const char *,va_list);
	void	writeLine(const char *,...);
	void	writeString(const char *,...);

	bool	writeCRLF;


	void	updateTotals(unsigned int,unsigned int);

	unsigned int totalBytesIn,totalBytesOut;
	unsigned int lastBytesIn,lastBytesOut;
	unsigned int bytesInPerSec,bytesOutPerSec;
	unsigned int lastUpdate;

};


// -------------------------------------
class FileStream : public Stream
{
public:
	FileStream() {file=NULL;}

    void	openReadOnly(const char *);
    void	openWriteReplace(const char *);
	bool	isOpen(){return file!=NULL;}

	virtual void	flush();
    virtual int		read(void *,int);
    virtual void	write(const void *,int);
    virtual bool	eof();
    virtual void	rewind();
    virtual void	close();

	FILE *file;
};
// -------------------------------------
class MemoryStream : public Stream
{
public:
	MemoryStream(void *p, int l)
	{
		buf = (char *)p;
		len = l;
		pos = 0;
	}

	virtual int read(void *p,int l)
    {
		if (pos+l <= len)
		{
			memcpy(p,&buf[pos],l);
			pos += l;
			return l;
		}else
		{
			memset(p,0,l);
			return 0;
		}
    }

	virtual void write(const void *p,int l)
    {
		if (pos+l <= len)
		{
			memcpy(&buf[pos],p,l);
			pos += l;
		}
    }

    virtual bool eof()
    {
        return pos >= len;
    }

	virtual void rewind()
	{
		pos = 0;
	}

	void	convertFromBase64();


	char *buf;
	int len,pos;
};
// --------------------------------------------------
class IndirectStream : public Stream
{
public:

	void init(Stream *s)
	{
		stream = s;
	}

	virtual int read(void *p,int l)
    {
		return stream->read(p,l);
    }

	virtual void write(const void *p,int l)
    {
		stream->write(p,l);
    }

    virtual bool eof()
    {
        return stream->eof();
    }

    virtual void close()
    {
        stream->close();
    }

	Stream *stream;
};


#endif

