#include "SM_SysPch.h"
#include "MSystemFunctions.h"
#include "MVfs.h"
#include "MVFSStdio.h"
#include "MBStaticList.h"
#include "MVFSPack.h"
#include "MVFSResourcePack.h"

#define MVFS_ZIP 
#ifdef MVFS_ZIP

#include "MVFSZipPack.h"

#endif

#ifdef _DEBUG 
  //#define _CAPTUREFILELEAKS
#endif

namespace MVFS
{
  
  

// Locales
bool                      g_bInit=false;
char                      g_pcBaseDirectory[256];
MBStaticList<MVFSPack*>   g_slPackList;

int   g_iFindFilePack=-1;
bool  g_bFoundInPack =false;


struct sLocalFile
{
  MVFSFILE* m_f;
  char      m_pcFile[256];
};

#ifdef _CAPTUREFILELEAKS
MBStaticList<sLocalFile> g_slOpenFiles;
#endif
  
}
// Publicas
int __cdecl MVFS::Init(char* pcBaseDirectory)
{
  strcpy(g_pcBaseDirectory, pcBaseDirectory);
  g_slPackList.Init();
  
  #ifdef _CAPTUREFILELEAKS
  g_slOpenFiles.Init();
  #endif

  g_bInit=true;  
  return (0);
}

int __cdecl MVFS::Shutdown()
{
  int iNext;
  int iIterator;

  for (iIterator=g_slPackList.First() ; iIterator!=-1 ; iIterator=iNext)
  {
    iNext=g_slPackList.Next(iIterator);
    RemovePackage(iIterator);
  }

  #ifdef _CAPTUREFILELEAKS
  if (g_slOpenFiles.GetNumberElements())
  {
    assert(0);
  }
  g_slOpenFiles.Shutdown();
  #endif

  g_slPackList.Shutdown();
  g_bInit=false;
  return(0);
}

const char* MVFS::GetBaseDirectory()
{
  assert(g_bInit);
  return (g_pcBaseDirectory);
}

// Nombre      : 
// Parametros  : 
// Retorno     : 
// Descripcion : 
int MVFS::AddPackage(eVFSType eType, char* pcBase)
{
  MVFSPack* pPack;
  int       iPackID;

  switch (eType)
  { 

  case E_ZIP:
    pPack=new MVFSZipPack;
    if (!pPack)
    {
      return (-1);
    }

    if (pPack->Init(pcBase)!=0)
    {
      delete pPack;
      return (-1);
    }        
  }

  iPackID=g_slPackList.InsertHead(pPack);
  if (iPackID==-1)
  {
      assert(0);
      delete pPack;
      return(-1);
  }

    
  return (0);
}

// Nombre      : 
// Parametros  : 
// Retorno     : 
// Descripcion : 
int MVFS::RemovePackage(int iID)
{
  MVFSPack* pPack;

  g_slPackList.Get(iID, pPack);
  delete pPack;

  g_slPackList.Delete(iID);
  
  return (0);
}

// Nombre      : 
// Parametros  : 
// Retorno     : 
// Descripcion : 
MVFSFILE* MVFS::fopen(const char* pcFileName, const char* pcFileAttrib)
{
  MVFSFILE* pFile=0;

  char pcAuxName[256];
  MCleanPath(pcAuxName, pcFileName);
  
  
  pFile=new MVFSFILEStdio;
  if (!pFile)
  {
    return (NULL);
  }

  if (pFile->fopen(pcAuxName, pcFileAttrib)==-1)
  {
    delete pFile;    
    pFile=0;
  }

  if (!pFile)
  {
    int iIterator;
    for (iIterator=g_slPackList.First() ; iIterator!=-1 && !pFile; iIterator=g_slPackList.Next(iIterator))
    {
      MVFSPack* pPack;
      g_slPackList.Get(iIterator, pPack);

      pFile=pPack->fopen(pcAuxName, pcFileAttrib);   
    }  
  }

  if (pFile)
  {
    #ifdef _CAPTUREFILELEAKS
    sLocalFile FileID;
    FileID.m_f=pFile;
    strcpy(FileID.m_pcFile, pcFileName);

    g_slOpenFiles.InsertTail(FileID);
    #endif
  }
  
  return (pFile);
}

// Nombre      : 
// Parametros  : 
// Retorno     : 
// Descripcion : 
int MVFS::fclose(MVFSFILE* f)
{
  f->fclose();

  #ifdef _CAPTUREFILELEAKS
  int iIterator, iNext;
  for (iIterator=g_slOpenFiles.First() ; iIterator!=-1 ; iIterator=iNext)
  {
    sLocalFile* pFileID;
    iNext=g_slOpenFiles.Next(iIterator);

    g_slOpenFiles.Get(iIterator, pFileID);
    if (pFileID->m_f==f)
    {
      g_slOpenFiles.Delete(iIterator);
    }
  }
  #endif

  delete f;
  return (0);
}

// Nombre      : 
// Parametros  : 
// Retorno     : 
// Descripcion : 
unsigned MVFS::fread(void * pvDest, size_t uItemSize, size_t uItem , MVFSFILE* f)
{
  return (f->fread(pvDest, uItemSize, uItem));
}

// Nombre      : 
// Parametros  : 
// Retorno     : 
// Descripcion : 
unsigned MVFS::fwrite(void * pvSrc,  size_t uItemSize, size_t uItem , MVFSFILE* f)
{
  return (f->fwrite(pvSrc, uItemSize, uItem));
}

// Nombre      : 
// Parametros  : 
// Retorno     : 
// Descripcion : 
int MVFS::ftell(MVFSFILE* f)
{
  return (f->ftell());
}

// Nombre      : 
// Parametros  : 
// Retorno     : 
// Descripcion : 
int MVFS::fseek(MVFSFILE* f, long lDisplace, int iRelative)
{
  return (f->fseek(lDisplace, iRelative));
}

// Nombre      : 
// Parametros  : 
// Retorno     : 
// Descripcion : 
int MVFS::fexists(const char* pcFileName)
{
  MVFSFILE* f;
  if (f=fopen(pcFileName, "rb"))
  {
    fclose(f);
    return (1);
  }

  return (0);
}

// Nombre      : 
// Parametros  : 
// Retorno     : 
// Descripcion : 
static char pcAuxString[8192];
int __cdecl MVFS::fprintf(MVFSFILE* f, const char* pcDString, ...)
{
  va_list lst;	
	va_start (lst, pcDString);
	int iResult=vsprintf( pcAuxString, pcDString, lst);
	va_end (lst);

  f->fprintf(pcAuxString);

  return (iResult);
}

// Nombre      : 
// Parametros  : 
// Retorno     : 
// Descripcion : 
int MVFS::fflush(MVFSFILE* f)
{
  return (f->fflush());
}

// Nombre      : 
// Parametros  : 
// Retorno     : 
// Descripcion : 
int MVFS::unlink(const char* pcFileName)
{
  return (_unlink(pcFileName));
}

// Nombre      : 
// Parametros  : 
// Retorno     : 
// Descripcion : 
char* MVFS::fgets(char* pcBuffer, int iBufferSize, MVFSFILE* f)
{
  return (f->fgets(pcBuffer, iBufferSize));
}

int MVFS::findfilestart(const char* pcPath, char* pcFilter)
{
  g_iFindFilePack=-1;
  g_bFoundInPack =false;

  char pcCleanPath[256];
  MCleanPath(pcCleanPath, pcPath);


  int iIterator;
  for (iIterator=g_slPackList.First() ; iIterator!=-1 ; iIterator=g_slPackList.Next(iIterator))
  {
    MVFSPack* pPack;
    g_slPackList.Get(iIterator, pPack);

    if (pPack->findfilestart(pcCleanPath, pcFilter))
    {
      g_iFindFilePack=iIterator;
      g_bFoundInPack =true;

      return (1);
    }
  }

  return (MStartFileFind(pcCleanPath, pcFilter));
}

int MVFS::findfileget(char* pcPath)
{
  if (g_bFoundInPack)
  {
    MVFSPack* pPack=NULL;
    g_slPackList.Get(g_iFindFilePack, pPack);
    
    if (!pPack)
    {
      return (0);
    }

    return (pPack->findfileget(pcPath));
  }
  else
  {
    return (MGetFileCompletePath(pcPath));
  }  
}

int MVFS::findfileend()
{
  g_iFindFilePack=-1;
  g_bFoundInPack =false;

  return (0);
}
