#include "SDCard.h"
#ifndef EZ_APPLICATION_LICENCE_DISABLE

SDCard::SDCard()
{
}

SDCard::SDCard(const string cds_cid_Path)
{
  this->filePath = cds_cid_Path;
  if (getCIDFromFile() == false)
    return;
  if (getCSDFromFile() == false)
    return;
  this->isLoaded = SDCard::readSDCard();
}

SDCard::SDCard(string cid, string csd)
{
  for (unsigned int i = 0; i < cid.length(); i++)
    this->cid[i] = cid[i];
  for (unsigned int i = 0; i < csd.length(); i++)
    this->csd[i] = csd[i];

  this->isLoaded = SDCard::readSDCard();
}

bool SDCard::readSDCard()
{

  BYTE cHexNibbleToNo[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                           0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                           0, 0, 0, 0, 0, 0, 0, 0,
                           0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
                           0, 0, 0, 0, 0, 0, 0,
                           10, 11, 12, 13, 14, 15,
                           0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                           0, 0, 0, 0, 0, 0,
                           10, 11, 12, 13, 14, 15,
                           0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                           0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                           0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                           0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                           0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                           0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                           0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                           0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};

  for (int i = 0; i < CID_LENGTH; i++)
    this->cardData.CID_nibble[i] = (BYTE)cid[i];

  for (int i = 0; i < cnibblescount / 2; i++)
  {
    this->cardData.CID[i] = cHexNibbleToNo[this->cardData.CID_nibble[2 * i]] << 4 | cHexNibbleToNo[this->cardData.CID_nibble[2 * i + 1]];
  }

  this->cardData.manufacturerID = this->cardData.CID[0];
  this->cardData.oemID[0] = this->cardData.CID[1];
  this->cardData.oemID[1] = this->cardData.CID[2];
  this->cardData.name[0] = this->cardData.CID[3];
  this->cardData.name[1] = this->cardData.CID[4];
  this->cardData.name[2] = this->cardData.CID[5];
  this->cardData.name[3] = this->cardData.CID[6];
  this->cardData.name[4] = this->cardData.CID[7];
  this->cardData.productRevision_hw = cHexNibbleToNo[this->cardData.CID[16]];
  this->cardData.productRevision_sw = cHexNibbleToNo[this->cardData.CID[17]];

  if (this->cardData.productRevision_sw < 10)
    this->cardData.productRevision = (float)this->cardData.productRevision_hw + ((float)this->cardData.productRevision_sw * 0.1);
  else
    this->cardData.productRevision = (float)this->cardData.productRevision_hw + ((float)this->cardData.productRevision_sw * 0.01);

  this->cardData.serialNumber = this->cardData.CID[9] << 24 | this->cardData.CID[10] << 16 | this->cardData.CID[11] << 8 | this->cardData.CID[12];

  this->cardData.manufacturerDate_year = cHexNibbleToNo[this->cardData.CID_nibble[27]] * 10 + cHexNibbleToNo[this->cardData.CID_nibble[28]] + 2000;
  this->cardData.manufacturerDate_month = cHexNibbleToNo[this->cardData.CID_nibble[29]];
  this->cardData.date =  to_string(this->cardData.manufacturerDate_month) + "/" + to_string(this->cardData.manufacturerDate_year);
  //string date = cSDMonthStr1[this->sdData.manufacturerDate_month] + std::to_string(this->sdData.manufacturerDate_year);

  // CSD
  for (int i = 0; i < CSD_LENGTH; i++)
    this->cardData.CSD_nibble[i] = (BYTE)csd[i];

  for (int i = 0; i < cnibblescount / 2; i++)
  {
    this->cardData.CSD[i] = cHexNibbleToNo[this->cardData.CSD_nibble[2 * i]] << 4 | cHexNibbleToNo[this->cardData.CSD_nibble[2 * i + 1]];
  }

  if (this->cardData.CSD_nibble[0] == 0x34)
  {
    this->cardData.cardSize = this->cardData.CSD[7] << 16 | this->cardData.CSD[8] << 8 | this->cardData.CSD[9];
    this->cardData.cardGSize = (this->cardData.cardSize + 1) / 2048;
  }

  BYTE sdCrc = 0;
  for (int i = 0; i <= 14; i++)
  {
    BYTE sdChar = this->cardData.CID[i];
    for (int j = 0; j <= 7; j++)
    {
      sdCrc = sdCrc << 1;
      if ((sdChar ^ sdCrc) & 0x80)
        sdCrc = sdCrc ^ 0x09;
      sdChar = sdChar << 1;
    }
    sdCrc = sdCrc & 0x7F;
  }
  this->cardData.CRCOK = ((sdCrc << 1) | 1) == this->cardData.CID[15];
  this->cardData.crcCorrect = (int)this->cardData.CID[15] == (int)((sdCrc << 1) | 1);
  return this->cardData.crcCorrect;
}

bool SDCard::getCIDFromFile()
{
  vector<char> content;
  if (readFile(this->filePath + "cid", content) == false)
  {
    return false;
  }

  if (content.size() >= CID_LENGTH)
  {
    for (int i = 0; i < 32; i++)
      this->cid[i] = content[i];
  }
  else
    return false;

  return true;
}

bool SDCard::getCSDFromFile()
{
  vector<char> content;
  if (readFile(this->filePath + "csd", content) == false)
  {
    return false;
  }
  if (content.size() >= CSD_LENGTH)
  {
    for (int i = 0; i < 32; i++)
      this->csd[i] = content[i];
  }
  else
    return false;

  return true;
}

#endif