#include "licReaderELC3.h"
#ifndef EZ_APPLICATION_LICENCE_DISABLE

namespace Reader
{

  Licence3::Licence3() {}

  Licence3::~Licence3() {}

  Licence3::Licence3(LicenceIdentification &licIdentification) : LicenceELC3(licIdentification)
  {
  }

  /// @brief načte seznam licenčních bodů do obecné struktury
  /// @param licences
  /// @return
  bool Licence3::readLicence(LicenceInfoGeneral *licences)
  {

    if (getUID() == false) throw LicenceException((int)GeneralError::UIDReadError, "Nepodařilo se načíst UID: " + uid_path);
    if (this->uid.length() < UID_LENGTH) throw LicenceException((int)GeneralError::UIDReadError, "UID nemá požadovanou velikost: " + uid_path);
    
    string licFileName = getLicenceName();
    string licFilePath = this->licenceFilePath + licFileName;

    this->licFileName = licFileName;
    this->licenceFilePath = licFilePath;

    vector<char> content{};
    if (readFile(licFilePath, content) == false)
    {
      throw LicenceException((int)GeneralError::FileOpenError, "Chyba otevření souboru licence: " + licFilePath);
    }

#ifdef EZ_LIC_DEBUG_SHOW_DETAILS
    cout << "Celý vstup zašifrovaný: \n";
    for (const auto &x : content)
      cout << (int)x << "-";
    cout << "\n";
#endif

    this->licBody.licId.licIdent[0] = content[0];
    this->licBody.licId.licIdent[1] = content[1];
    this->licBody.licId.licIdent[2] = content[2];
    this->licBody.licId.licIdent[3] = content[3];
    this->licBody.licId.licIdent[4] = content[4];

    this->licBody.licenceIdentHeader.licenceType = content[5];
    this->licBody.licenceIdentHeader.licenceTypeVersion = content[6];
    this->licBody.licenceIdentHeader.licenceIndex = content[7];
    this->licBody.licenceIdentHeader.compatibilityVersion = content[8];
    this->licBody.licenceIdentHeader.licItemCount = content[9];
    this->licBody.licenceIdentHeader.publicHeaderLength = bytesToWord(content[10], content[11]);
    
    int elcVersion = (int)licBody.licId.licIdent[3] - 48; // verze je text, musí se odečíst 48

    if (elcVersion != (int)this->lIdentification.licElcType)
    {
      throw LicenceException((int)GeneralError::ELCMismatch, "Nesouhlasí ELC.");
    }

    vector<unsigned char> publicPart(content.begin(), content.begin() + 12 + this->licBody.licenceIdentHeader.publicHeaderLength);


#ifdef EZ_LIC_DEBUG_SHOW_DETAILS
    cout << "CRC read public size: " << publicPart.size() << "\n";
    cout << "CRC read public: " << calculateCRC16(publicPart) << "\n";
#endif

#ifdef EZ_LIC_DEBUG_SHOW_DETAILS
    cout << "\n public header length: " << licBody.licenceIdentHeader.publicHeaderLength << "\n";
#endif

    vector<unsigned char> encryptedPart{};

    for (unsigned int i = licBody.licenceIdentHeader.publicHeaderLength + 12; i<content.size(); i++)
    {
      encryptedPart.push_back(content[i]);
    }



    vector<unsigned char> privateContentDecrypted{};
    privateContentDecrypted = decryptPrivateContent(encryptedPart);



#ifdef EZ_LIC_DEBUG_SHOW_DETAILS
    cout << "private encryptedsize: " << encryptedPart.size() << "\n";
    cout << "private decryptedsize: " << privateContentDecrypted.size() << "\n";
    cout << "private decrypted: \n";
    for (const auto &x : privateContentDecrypted)
      cout << (int)x << "-";
    cout << "\n";
#endif

#ifdef EZ_LIC_DEBUG_SHOW_DETAILS
    cout << "CRC read private size: " << privateContentDecrypted.size() << "\n";
    cout << "CRC read private: " << calculateCRC16(privateContentDecrypted) << "\n";
#endif

    LicenceBody licBodyDecrypted;
    licBodyDecrypted.licenceIdentHeader.licenceType = privateContentDecrypted[0];
    licBodyDecrypted.licenceIdentHeader.licenceTypeVersion = privateContentDecrypted[1];
    licBodyDecrypted.licenceIdentHeader.licenceIndex = privateContentDecrypted[2];
    licBodyDecrypted.licenceIdentHeader.compatibilityVersion = privateContentDecrypted[3];
    licBodyDecrypted.licenceIdentHeader.licItemCount = privateContentDecrypted[4];
    licBodyDecrypted.licenceIdentHeader.publicHeaderLength = bytesToWord(privateContentDecrypted[5], privateContentDecrypted[6]);
    
    if (licBodyDecrypted.licenceIdentHeader.licItemCount != this->licBody.licenceIdentHeader.licItemCount)
    {
      throw LicenceException((int)GeneralError::ItemsCountMismatch, "Nesouhlasí počet položek licence.");
    }

#ifdef EZ_LIC_DEBUG_SHOW_DETAILS
    cout << "velikost: " << sizeof(licBodyDecrypted.licenceIdentHeader) << "\n";
#endif

    int index = 10;
    for (int i = 0; i < this->licBody.licenceIdentHeader.licItemCount; i++)
    {
      licDataItem item{};
      item.protoId = bytesToDword(privateContentDecrypted[index], privateContentDecrypted[index + 1], privateContentDecrypted[index + 2], privateContentDecrypted[index + 3]);
      item.licCount = bytesToDword(privateContentDecrypted[index + 4], privateContentDecrypted[index + 5], privateContentDecrypted[index + 7], privateContentDecrypted[index + 7]);
      index += sizeof(licDataItem);
      this->licBody.privateContent.dataItems.push_back(item);
      this->licenceInfo.licences.insert(pair<DWORD, DWORD>(item.protoId, item.licCount));
      licences->licences.insert(pair<DWORD, DWORD>(item.protoId, item.licCount));
    }

    uint16_t crcComplete = bytesToWord(privateContentDecrypted[index], privateContentDecrypted[index + 1]);
    vector<unsigned char> completeVector = joinVectors(publicPart, privateContentDecrypted);

    uint16_t crcCalculated = calculateCRC16(completeVector, 2);

#ifdef EZ_LIC_DEBUG_SHOW_DETAILS
    // cout << "content: \n";
    // for (const auto x : content) cout << (int)x << "-";

    cout << "\nvector: \n";
    for (const auto x : completeVector)
      cout << (int)x << "-";
    cout << "\n";
    cout << "crcComplete: " << crcComplete << "\n";
    cout << "crcCalculated: " << crcCalculated << "\n";
    cout << "vectorsize: " << completeVector.size() << "\n";
    cout << "public vector size: " << publicPart.size() << "\n";
    cout << "private vector size: " << privateContentDecrypted.size() << "\n";
    for (const auto &pair : this->licenceInfo.licences)
    {
      cout << "--<" << pair.first << ", " << pair.second << ">--" << endl;
    }
#endif

    if (crcCalculated != crcComplete) throw LicenceException((int)GeneralError::LicenceCRCMismatch, "Nesouhlasí CRC.");

    return true;
  }

  bool Licence3::getLicenceInfo(void *returnStructure)
  {
    if (returnStructure != nullptr)
    {
      LicenceELC2Info *resultPtr = static_cast<LicenceELC2Info *>(returnStructure);
      for (auto item : this->licBody.privateContent.dataItems)
      {
        resultPtr->licences.insert(pair<int, int>(item.protoId, item.licCount));
      }
    }
    else
    {
      errorMessage.code = 1;
      errorMessage.message = "Error: Null pointer!";
      return false;
    }

    return true;
  }

  bool Licence3::getUID()
  {
    vector<char> content;
    if (readFile(this->uid_path + "machine-id", content) == false)
    {
      return false;
    }

    this->uid = string(content.begin(), content.end()); 


    return true;
  }

}

/*
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;
*/

#endif
