//###################################################################################
//#						                Definition Of Class Profile								            #
//#						  Used to create a binary handle to handle a user profile             #
//#						                          Author : 							                      #
//#						                      Aymeric SUTEAU									                #
//#						                       LISA - ANGERS									                #
//###################################################################################


/*------------------------------------ INCLUDES -----------------------------------*/
#include "Profile.h"


/*------------------------------- GLOBAL VARIABLES --------------------------------*/
int length;
char* buffer;
unsigned int currentSize = 0;


/*---------------------------- CONSTRUCTOR / DESTRUCTOR ---------------------------*/
Profile::Profile(char* fileName)
{
  // Try to open a user profile from system file (both Read and Write modes)
  if (IsReadable(fileName))
  {
    MMechostr(MSKDEBUG, ">>> File already exists and is readable.\n");
    ioFile.open(fileName, ios::in | ios::out | ios::binary);
    if (ioFile.is_open()) 
    {
      MMechostr(MSKDEBUG, ">>> Binary file [%s] created in [IO] mode...\n", fileName);
      SetFileName(fileName);
    }
    else
      MMechostr(MSKDEBUG, ">>> Error when creating [%s] !\n", fileName);
  }

  // Else open it as Write only (new user profile)
  else
  {
    MMechostr(MSKDEBUG, ">>> File doesn't exist or is not readable.\n");
    oFile.open(fileName, ios::out | ios::trunc | ios::binary);
    if (oFile.is_open()) 
    {
      MMechostr(MSKDEBUG, ">>> Binary file [%s] created in [O] mode...\n", fileName);
      SetFileName(fileName);
    }
    else
      MMechostr(MSKDEBUG, ">>> Error when creating [%s] !\n", fileName);
  }

  // Initialize file size and binary content
  SetFileLength(0);
  SetFileData(NULL);
}

Profile::~Profile(void)
{
  // Delete memory allocated for buffer data
  delete [] buffer;

  if (oFile.is_open())
    oFile.close();
  else if (ioFile.is_open())
    ioFile.close();
}


/*-------------------------------- GETTERS / SETTERS ------------------------------*/
char* Profile::GetFileName()
{
  return this->sFileName;
}

void Profile::SetFileName(char* fileName)
{
  this->sFileName = fileName;
}

int Profile::GetFileLength()
{
  return this->iFileSize;
}

void Profile::SetFileLength(int fileSize)
{
  this->iFileSize = fileSize;
}

char* Profile::GetFileData()
{
  return this->sFileData;
}

void Profile::SetFileData(char* fileData)
{
  this->sFileData = fileData;
}


/*------------------------------------ WRITE DATA ---------------------------------*/
// Write new text data to file
void Profile::WriteString(string fileLine)
{
  if (oFile.is_open())
    oFile << fileLine << endl;
  else if (ioFile.is_open())
    ioFile << fileLine << endl;
}


// Write new binary data to file
void Profile::WriteBinaryData(char* data, unsigned int size)
{
  if (oFile.is_open())
  {
    // Get current Output file size
    oFile.seekp(0, ios::cur);
    currentSize = oFile.tellp();    //unsigned int currentSize = oFile.tellp();
    MMechostr(MSKDEBUG, ">>> Old [O] file size = %u\n", currentSize);
    oFile.seekp(0, ios::beg);

    // Write additional data only if new buffer size is greater than current buffer size
    if (size >= currentSize) 
    {
      oFile.seekp(0);             // Rewind to the beginning of the binary file
      oFile.write(data, size);    // Write binary file
    }

    // Else, file must be re-written
    else
    {
      // Close file, and open it again to rewrite it from the beginning
      MMechostr(MSKDEBUG, "> File [O] must be re-written...\n");
      oFile.close();
      oFile.open(GetFileName(), ios::out | ios::trunc | ios::binary);
      if (oFile)
        oFile.write(data, size);
    }
  }
  else if (ioFile.is_open())
  {
    // Get current Input / Output file size
    ioFile.seekg(0, ios::cur);
    currentSize = ioFile.tellg();   //unsigned int currentSize = ioFile.tellg();
    MMechostr(MSKDEBUG, ">>> Old [IO] file size = %u\n", currentSize);
    ioFile.seekg(0, ios::beg);

    // Write additional data only if new buffer size is greater than current buffer size
    if (size >= currentSize) 
    {
      ioFile.seekp(0);            // Rewind to the beginning of the binary file
      ioFile.write(data, size);   // Write binary file
    }

    // Else, file must be re-written
    else 
    {
      // Close file, and open it again to rewrite it from the beginning
      MMechostr(MSKDEBUG, "> File [IO] must be re-written...\n");
      ioFile.close();
      ioFile.open(GetFileName(), ios::in | ios::out | ios::trunc | ios::binary);
      if (ioFile)
        ioFile.write(data, size);
    }
  }
  MMechostr(MSKDEBUG, ">>> Binary data written to file...\n");
}


/*------------------------------------- READ DATA ---------------------------------*/
// Read binary data from file
bool Profile::ReadBinaryData()
{
  if (ioFile.is_open())
  {
    // Get length of data stream
    ioFile.seekg(0, ios::end);
    length = ioFile.tellg();
    MMechostr(MSKDEBUG, ">>> Data length = %d\n", length);
    ioFile.seekg(0, ios::beg);

    // If size equals 0, user profile has just been created so we don't have to read any data from file
    if (length > 0)
    {
      // Initialize buffer according to file size
      buffer = new char[length];

      // Read data as a block
      ioFile.read(buffer, length);
      
      // Update file size and binary data
      SetFileLength(length);
      SetFileData(buffer);
    }
    return true;
  }
  else
    return false;
}

// Make sure the file can be read
bool Profile::IsReadable(const string& file)
{ 
  ifstream fichier(file.c_str()); 
  return !fichier.fail(); 
}
