#include "SM_SysPch.h"
#include "MSystemFunctions.h"
#include "MVFSZipPack.h"
#include "MVFSZip.h"

// Nombre      : 
// Parametros  : 
// Retorno     : 
// Descripcion : 
bool MVFSZipPack::sFileName::operator<(const sFileName& sOther) const
{
  return (strcmp(pcName, sOther.pcName)<0?true:false);
}

// Nombre      : 
// Parametros  : 
// Retorno     : 
// Descripcion : 
bool MVFSZipPack::sFileName::operator==(const sFileName& sOther) const
{
  return (strcmp(pcName, sOther.pcName)==0?true:false);
}

// Nombre      : 
// Parametros  : 
// Retorno     : 
// Descripcion : 
MVFSZipPack::MVFSZipPack()
{
  m_zipFile=NULL;
  m_iFindIterator=-1;
  m_pcFindPath[0]='\0';
  m_pcFilter[0]='\0';
}

// Nombre      : 
// Parametros  : 
// Retorno     : 
// Descripcion : 
MVFSZipPack::~MVFSZipPack()
{
  Shutdown();
}


// Nombre      : 
// Parametros  : 
// Retorno     : 
// Descripcion : 
int MVFSZipPack::Init(char* pcBase)
{
  m_zipFile=unzOpen(pcBase);

  if (!m_zipFile)
  {
    return (-1);
  }

  MCleanPath(m_pcZipFileName, pcBase);
  MExtractPath(m_pcBasePath, m_pcZipFileName);
  
  m_avlFiles.Init();

  unz_file_info file_info;

  
  if (unzGoToFirstFile(m_zipFile)==UNZ_OK)
  {   
    do
    {
      char pcName[256];

      unzGetCurrentFileInfo(
               m_zipFile,
					     &file_info,
					     pcName,
					     256,
					     NULL,
					     0,
					     NULL,
					     0);

      sFileEntry sEntry;
      sFileName  sName;

      // Filtramos directorios. FIXME. probablemente hay una manera mejor de hacer esto      
      //if (pcName[strlen(pcName)-1]!='/')
      {
        sName.pcName=new char[strlen(pcName)+1];
        strcpy(sName.pcName, pcName);
        _strlwr(sName.pcName);
        
        sEntry.iFile    =file_info.file_number;
        sEntry.iPosition=file_info.file_offset;
        sEntry.pcName   =sName.pcName;      
        m_avlFiles.Insert(sName, sEntry);      
      }
    }
    while (unzGoToNextFile(m_zipFile)!=UNZ_END_OF_LIST_OF_FILE);
  }

  /*
  int iIterator;
  for (iIterator=m_avlFiles.First() ; iIterator!=-1 ; iIterator=m_avlFiles.Next(iIterator))
  {
    sFileEntry* pEntry;    
    m_avlFiles.GetFromIDP(iIterator, pEntry);        
  }
  */


  return (0);
}

// Nombre      : 
// Parametros  : 
// Retorno     : 
// Descripcion : 
int MVFSZipPack::Shutdown()
{
  if (m_zipFile)
  {
    // Chapamos arbol
    int iIterator;
    int iNext;
    for (iIterator=m_avlFiles.Last() ; iIterator!=-1 ; iIterator=iNext)
    {
      iNext=m_avlFiles.Previous(iIterator);
      sFileEntry* pEntry;    
      m_avlFiles.GetFromIDP(iIterator, pEntry);    
      
      if (pEntry->pcName)
      {
        delete[] pEntry->pcName;
        pEntry->pcName=NULL;
      }
    }
    m_avlFiles.Shutdown();

    unzClose(m_zipFile);
  }
  return (0);
}


int MVFSZipPack::FindFileID(const char* pcFileName)
{
  if (strncmp(pcFileName, m_pcBasePath, strlen(m_pcBasePath))==0)
  {  
    sFileName   fn;

    fn.pcName=(char*)pcFileName+strlen(m_pcBasePath);
    

    return (m_avlFiles.GetIDFromKey(fn));    
  }

  return (-1);
}
  
// Nombre      : 
// Parametros  : 
// Retorno     : 
// Descripcion : 
MVFSZipPack::sFileEntry* MVFSZipPack::FindFile(const char* pcFileName)
{
  if (strncmp(pcFileName, m_pcBasePath, strlen(m_pcBasePath))==0)
  {  
    sFileName   fn;
    sFileEntry* pfeReturn;

    fn.pcName=(char*)pcFileName+strlen(m_pcBasePath);
    
    if (m_avlFiles.GetFromKeyP(fn, pfeReturn)==0)
    {
      return (pfeReturn);
    }
  }

  return (NULL);
}

// Nombre      : 
// Parametros  : 
// Retorno     : 
// Descripcion : 
MVFSFILE* MVFSZipPack::fopen(const char* pcFileName, const char* pcFileAttrib)
{
  // Chequeamos que no haya escritura
  for (int i=0 ; pcFileAttrib[i]!='\0' ; i++)
  {
    if (pcFileAttrib[i]=='W' || pcFileAttrib[i]=='w' || pcFileAttrib[i]=='A' || pcFileAttrib[i]=='a')
    {
      return (NULL);
    }
  }


  sFileEntry* pEntry=FindFile(pcFileName);
  if (!pEntry)
  {
    return (NULL);
  }
  

  // Alocamos file
  MVFSFILEZip* pFile;
  pFile=new MVFSFILEZip;
  if (!pFile)
  {
    return (NULL);
  }

  pFile->m_zipFile=unzOpen(m_pcZipFileName);
  if (!pFile->m_zipFile)
  {
    delete pFile;
    return (NULL);
  }
  
  unzGoToFile(pFile->m_zipFile, pEntry->iPosition, pEntry->iFile);
  
  if (pFile->fopen(pcFileName, pcFileAttrib)!=0)
  {
    unzClose(pFile->m_zipFile);		
    delete pFile;
  }    

  return (pFile);
}

int MVFSZipPack::findfilestart(char* pcPath, char* pcFilter)
{  
  int iFileID;
  if ((iFileID=FindFileID(pcPath))!=-1)
  {
    strcpy(m_pcFindPath, pcPath+strlen(m_pcBasePath));
    strcpy(m_pcFilter, pcFilter);
    return (m_iFindIterator=m_avlFiles.Next(iFileID));
  }

  return (m_iFindIterator=-1);
}

int MVFSZipPack::findfileget(char* pcPath)
{  
  while (m_iFindIterator!=-1)
  {
    sFileEntry* pFileEntry;
    m_avlFiles.GetFromIDP(m_iFindIterator, pFileEntry);

    if (strncmp(pFileEntry->pcName, m_pcFindPath, strlen(m_pcFindPath))==0)
    {
      m_iFindIterator=m_avlFiles.Next(m_iFindIterator);

      if (Matches(pFileEntry->pcName, m_pcFilter))
      {
        strcpy(pcPath, m_pcBasePath);
        strcat(pcPath, pFileEntry->pcName);
        return (1);
      }
    }
    else
    {
      m_iFindIterator=-1;
      return (0);
    }
  }          
    
  return (0);
}

int MVFSZipPack::findfileend()
{
  m_iFindIterator=-1;
  m_pcFindPath[0]='\0';
  m_pcFilter[0]='\0';
  return (0);
}