// This file is part of the aMule Project
//
// Copyright (c) 2003-2004 aMule Project ( http://www.amule-project.net )
// Copyright (C) 2002 Merkur ( merkur-@users.sourceforge.net / http://www.emule-project.net )
//
// 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.
// 
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//

#include "sys.h"
#include "CMemFile.h"		// Needed for CMemFile

CMemFile::CMemFile(unsigned int growBytes)
{
  fGrowBytes=growBytes;
  fLength=0;
  fPosition=0;
  fBufferSize=0;
  fFileSize=0;
  fBuffer=NULL;
  deleteBuffer=TRUE;
}

CMemFile::CMemFile(BYTE* buffer,unsigned int bufferSize,unsigned int growBytes)
{
  fBufferSize=bufferSize;
  fPosition=0;
  fGrowBytes=growBytes;
  if(!growBytes)fFileSize=bufferSize; else fFileSize=0;
  fBuffer=buffer; // uh
  deleteBuffer=FALSE;
}

void CMemFile::Attach(BYTE* buffer,unsigned int bufferSize,unsigned int growBytes)
{
  fBufferSize=bufferSize;
  fPosition=0;
  fGrowBytes=growBytes;
  if(!growBytes)fFileSize=bufferSize; else fFileSize=0;
  fBuffer=buffer; // uh
  deleteBuffer=FALSE;
}

BYTE* CMemFile::Detach()
{
  BYTE* retval=fBuffer;
  fBuffer=NULL;
  fFileSize=fBufferSize=fPosition=fFileSize=0;
  return retval;
}

CMemFile::~CMemFile()
{
  fGrowBytes=fPosition=fBufferSize=fFileSize=0;
  // should the buffer be free'd ?
  if(fBuffer && deleteBuffer) free(fBuffer);
  fBuffer=NULL;
}


off_t CMemFile::Seek(off_t offset,wxSeekMode from)
{
  off_t newpos=0;
  switch(from) {
  case wxFromStart:
    newpos=offset;
    break;
  case wxFromCurrent:
    newpos=fPosition+offset;
    break;
  case wxFromEnd:
    newpos=fFileSize-offset;
    break;
  default:
    return -1;
  }
  if(newpos<0) {
    return -1;
  }

  // what if we seek over the end??
  fPosition=newpos;
  return fPosition;
}

void CMemFile::enlargeBuffer(unsigned long size)
{
  unsigned long newsize=fBufferSize;

  // hmm.. mitähän jos growbytes==0??
  while(newsize<size)
    newsize+=fGrowBytes;

  if(fBuffer)
    fBuffer=(BYTE*)realloc((void*)fBuffer,newsize);
  else fBuffer=(BYTE*)malloc(newsize);

  if(fBuffer==NULL) {
    // jaa-a. mitähän tekis
    printf("out of memory experience\n");
    exit(1);
  }

  fBufferSize=newsize;
}

void CMemFile::SetLength(unsigned long newLen)
{
  if(newLen>fBufferSize) {
    // enlarge buffer
    enlargeBuffer(newLen);
  }
  if(newLen<fPosition) {
    fPosition=newLen;
  }
  fFileSize=newLen;
}

off_t CMemFile::Read(void* buf,off_t length)
{
  if(length==0) 
    return 0;
  // dont' read over buffer end
  if(fPosition>fFileSize)
    return 0;
  unsigned int readlen=length;
  if(length+fPosition>fFileSize)
    readlen=fFileSize-fPosition;

  memcpy(buf,fBuffer+fPosition,readlen);
  fPosition+=readlen;
  return readlen;
}

size_t CMemFile::Write(const void* buf,size_t length)
{
  if(length==0)
    return 0;
  // need more space?
  if(fPosition+length>fBufferSize)
    enlargeBuffer(fPosition+length);
  memcpy(fBuffer+fPosition,buf,length);
  fPosition+=length;
  if(fPosition>fFileSize)
    fFileSize=fPosition;
  return length;
}

bool CMemFile::Close()
{
  // do-nothing :)
  return TRUE;
}
