#include "licenceELC3.h"
#ifndef EZ_APPLICATION_LICENCE_DISABLE

LicenceELC3::LicenceELC3() {}

LicenceELC3::~LicenceELC3() {}

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

/// @brief get proper licencename
/// @param licPostfix
/// @return
string LicenceELC3::getLicenceName()
{
  
  BYTE uidb[UID_LENGTH] = {};
  for (unsigned int i = 0; i < this->uid.length(); i++) uidb[i] = uid[i];

  string result = "";
  char prefixChar = 97;
  int licType = (int)lIdentification.licLicenceType;
  int lVersion = lIdentification.licenceVersion;

  unordered_map<int, string> baseString;
  baseString.insert(std::pair<int, string>((int)LicenceType::EOS_EOV, "ezlic_eovosv"));
  baseString.insert(std::pair<int, string>((int)LicenceType::DDTS, "ezlic_ddts"));
  baseString.insert(std::pair<int, string>((int)LicenceType::DRT, "ezlic_drt"));

  struct Index
  {
    int index[11];
  };

  std::unordered_map<int, Index> indexes;
  Index indexes1 = {7, 16, 20, 23, 18, 4, 9, 11, 6, 9, 13};
  Index indexes2 = {12, 10, 22, 23, 24, 25, 9, 11, 2, 1, 3}; // puvodní indexy
  Index indexes3 = {8, 13, 11, 9, 7, 11, 10, 13, 5, 20, 19};

  indexes.insert(std::pair<int, Index>(1, indexes1));
  indexes.insert(std::pair<int, Index>(2, indexes2));
  indexes.insert(std::pair<int, Index>(3, indexes3));

  result = baseString.at(licType) + to_string(lIdentification.licenceIndex) + "_";

  result += prefixChar + ((uidb[indexes.at(lVersion).index[0]] + (lIdentification.licenceIndex * 11)) % 25);
  result += prefixChar + ((uidb[indexes.at(lVersion).index[1]] + (lIdentification.licenceIndex * 39)) % 25);

  result += prefixChar + ((uidb[indexes.at(lVersion).index[2]] + (lIdentification.licenceIndex * 1)) % 25);
  result += prefixChar + ((uidb[indexes.at(lVersion).index[3]] * 2) % 25);
  result += prefixChar + ((uidb[indexes.at(lVersion).index[4]] + (lIdentification.licenceIndex * 5)) % 25);
  result += prefixChar + ((uidb[indexes.at(lVersion).index[5]] * 3) % 25);

  result += prefixChar + ((uidb[indexes.at(lVersion).index[6]] + (lIdentification.licenceIndex * 52)) % 25);
  result += prefixChar + ((uidb[indexes.at(lVersion).index[7]] + (lIdentification.licenceIndex * 34)) % 25);
  result += prefixChar + ((uidb[indexes.at(lVersion).index[8]] + (lIdentification.licenceIndex * 21)) % 25);
  result += prefixChar + ((uidb[indexes.at(lVersion).index[9]] + (lIdentification.licenceIndex * 47)) % 25);
  result += prefixChar + ((uidb[indexes.at(lVersion).index[10]] + (lIdentification.licenceIndex * 7)) % 25);

  result += ".lic";
  return result;
}

vector<unsigned char> LicenceELC3::cryptPrivateContent(const std::vector<unsigned char> &content)
{

  BYTE initVector[CRYPT_INIT_VECTOR_SIZE] = {0};
  BYTE aesKey[CRYPT_INIT_KEY_SIZE] = {0};

  LicenceELC3::initVector(initVector, aesKey);

  unsigned char encrypted[10000] = {};
  const unsigned char *plainTextArray = content.data();
  int finalEncryptedLength = encrypt(plainTextArray, content.size(), aesKey, initVector, encrypted);

  if (finalEncryptedLength <= 0)
    throw LicenceException((int)GeneralError::EncryptError, "Chyba při kryptování.");

  std::vector<unsigned char> result(encrypted, encrypted + finalEncryptedLength);

  return result;
}

vector<unsigned char> LicenceELC3::decryptPrivateContent(const std::vector<unsigned char> &content)
{
  BYTE initVector[CRYPT_INIT_VECTOR_SIZE] = {0};
  BYTE aesKey[CRYPT_INIT_KEY_SIZE] = {0};

  LicenceELC3::initVector(initVector, aesKey);
  
  const unsigned char *encryptedData = content.data();
  unsigned char decrypted[10000] = {};

  int decrypted_len = decrypt(encryptedData, content.size(), aesKey, initVector, decrypted);
  if (decrypted_len <= 0)
    throw LicenceException((int)GeneralError::DecryptError, "Chyba při dekryptování.");

  vector<unsigned char> res{};
  for (int i = 0; i < decrypted_len; i++)
  {
    res.push_back(decrypted[i]);
  }

  return res;

}

void LicenceELC3::initVector(BYTE *iVector, BYTE *key)
{
  BYTE uidb[UID_LENGTH] = {};
  for (unsigned int i = 0; i < this->uid.length(); i++) uidb[i] = uid[i];

  CryptInitVector vec1 = {uidb[10],
                          uidb[12],
                          uidb[11],
                          uidb[9],
                          uidb[22]-6,
                          uidb[24]-4,
                          uidb[25]-13,
                          uidb[21]-9,
                          9, 10, 11, 12, 13, 14, 15, 16};
  CryptInitVector vec2 = {5, 1, 3, uidb[9], 4, 12, 13, 17, 9, uidb[24]-15, 2, 23, 17, 13, 4, 3};
  CryptInitVector vec3 = {2, 7, 1, uidb[6], 8, 13, 16, 6, 4, uidb[20]-15, 8, 7, 2, 14, 15, 21};

  std::unordered_map<int, CryptInitVector> vectors;
  vectors.insert(std::pair<int, CryptInitVector>(1, vec1));
  vectors.insert(std::pair<int, CryptInitVector>(2, vec2));
  vectors.insert(std::pair<int, CryptInitVector>(3, vec3));

  CryptAesKey key1 = {uidb[12],
                      uidb[23] - 15,
                      uidb[25] - 15,
                      uidb[11],
                      uidb[9],
                      uidb[21],
                      uidb[9] % 25,
                      uidb[22] - 15,
                      4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
  CryptAesKey key2 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
  CryptAesKey key3 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};


  std::unordered_map<int, CryptAesKey> keys;
  keys.insert(std::pair<int, CryptAesKey>(1, key1));
  keys.insert(std::pair<int, CryptAesKey>(2, key2));
  keys.insert(std::pair<int, CryptAesKey>(3, key3));

  int lVersion = lIdentification.licenceVersion;

  iVector[0] = vectors.at(lVersion).vec[0];
  iVector[1] = vectors.at(lVersion).vec[1];
  iVector[2] = vectors.at(lVersion).vec[2];
  iVector[3] = vectors.at(lVersion).vec[3];
  iVector[4] = vectors.at(lVersion).vec[4];
  iVector[5] = vectors.at(lVersion).vec[5];
  iVector[6] = vectors.at(lVersion).vec[6];
  iVector[7] = vectors.at(lVersion).vec[7];

  memcpy(&iVector[8], &iVector[0], 8);

  key[0] = keys.at(lVersion).key[0];
  key[1] = keys.at(lVersion).key[1];
  key[2] = keys.at(lVersion).key[2];
  key[3] = keys.at(lVersion).key[3];
  key[4] = keys.at(lVersion).key[4];
  key[5] = keys.at(lVersion).key[5];
  key[6] = keys.at(lVersion).key[6];
  key[7] = keys.at(lVersion).key[7];
  memcpy(&key[8], &key[0], 8);
  memcpy(&key[16], &key[6], 8);
  memcpy(&key[24], &key[12], 8);
}



#endif