// clang-format off
//
// Created by Ivan Sidyakin on 6/9/20.
//
#ifndef _L2API_H_

#include <vector>
#include <stdint.h>
#include <string>

namespace L2Api
{
typedef std::vector<uint8_t> ByteArray;

#define STATUS_SUCCESS 0
#define STATUS_TIMEOUT    -1
#define STATUS_INVALID_PARAMETER -4
#define STATUS_WRITE_ERROR    -3
#define STATUS_READ_ERROR    -5
#define STATUS_MEMORY_ERROR    -6
#define STATUS_FORMAT_ERROR    -7
#define STATUS_FAILED    -8
#define STATUS_NOT_PRESENT -9
#define STATUS_PROTOCOL_ERROR -10
#define STATUS_TRANSMISSION_ERROR -11
#define STATUS_STOP -12
#define STATUS_COLLISION_ERROR  -13
#define STATUS_NOT_IMPLEMENTED -14

#define JCB_OR_VISA_KERNEL_ID		0x01
#define MASTERCARD_KERNEL_ID		0x02
#define VISA_KERNEL_ID			0x03
#define AMERICAN_EXPRESS_KERNEL_ID	0x04
#define JCB_KERNEL_ID			0x05
#define DISCOVER_KERNEL_ID 		0x06
#define UNIONPAY_KERNEL_ID 		0x07
#define GEMALTO_KERNEL_ID               0xFC
#define MIR_KERNEL_ID			0xFD // real kid is 810643
#define CONTACT_KERNEL_ID               0xFE


// pin entry result codes
#define PIN_ENTERED 0
#define PIN_BYPASSED 1
#define PIN_PINPAD_NOT_PRESENT_OR_MALUNCTION 2

#define LX2_LOG_LEVEL_TRACE 0
#define LX2_LEVEL_DEBUG 1
#define LX2_LEVEL_INFO 2
#define LX2_LEVEL_WARN 3
#define LX2_LEVEL_ERROR 4
#define LX2_LEVEL_CRITICAL 5
#define LX2_LEVEL_OFF 6

//ioctl control codes
#define TIOCTL_GET_TRANSACTION_COUNTER 0x00000001
#define TIOCTL_READ_TRANSACTION_LOG 0x00000002
#define TIOCTL_SAVE_TRANSACTION_LOG 0x00000003
#define TIOCTL_GET_TERMINAL_IDENTIFICATION 0x00000004
#define TIOCTL_GET_MERCHANT_IDENTIFIER 0x00000005

// ioctl result codes
#define TIO_OK 0
#define TIO_ERROR_NOT_IMPLEMENTED -1
#define TIO_ERROR_OUTPUT_BUFFER_TOO_SMALL -2
#define TIO_FILE_OPEN_ERROR -3
#define TIO_FILE_READ_ERROR -4
#define TIO_FILE_WRITE_ERROR -5
#define TIO_MISSING_DATA -6

// led states
#define EMVL1_LEDS_STATE_NOT_READY        0x00
#define EMVL1_LEDS_STATE_IDLE             0x01
#define EMVL1_LEDS_STATE_READY_TO_READ    0x02
#define EMVL1_LEDS_STATE_PROCESSING       0x03
#define EMVL1_LEDS_STATE_CR_SUCCESSFULLY  0x04
#define EMVL1_LEDS_STATE_ERROR            0x05

#define EMVL1_BEEP_SUCCESS                true
#define EMVL1_BEEP_ERROR                  false

#define LOG_TYPE_SYSLOG 0
#define LOG_TYPE_CONSOLE 1

  typedef struct _L2Events
  {
      void (*message) (const ByteArray& msg);
      ByteArray (*onlineRequest) (const ByteArray& req);
      int (*getOnlinePinblock)(const ByteArray & pan, std::string lpref, ByteArray & pb);
      int (*verifyOfflinePinPlain)(int ptc, std::string lpref, ByteArray & sw12);
      int (*verifyOfflinePinEncrypted)(int ptc, std::string lpref,
                                       const ByteArray & mod, const ByteArray & exp, const ByteArray & challenge, ByteArray & sw12);
      ByteArray (*dek)(const ByteArray& req);
      int (*ioctl)(int code, const ByteArray & din, ByteArray & dout);
      int (*selectAid) (const std::vector<std::string> names, int initialSelection);
      std::string (*getLanguage) (const std::string lpref);
      ByteArray (*advice) (const ByteArray& req);
      ByteArray (*referral) (const ByteArray& req);
      ByteArray (*reversal)(const ByteArray& req);
      ByteArray (*batch)(const ByteArray& req);
  } L2Events;

  enum class outcome_id : int
  {
      otp_timeout = 1,
      otp_stop = 2,
      otp_reader_error = 3,
      otp_preprocessing_failed = 4,
  };

  int init(const L2Events &evs);
  void done();

  void initLog(int level);
  void setLogLevel(int level);
  void setLogType(int type);
  int getLogLevel();
  void contactlessSetLogLevel(int level);
  void contactSetLogLevel(int level);
  void getEvents(L2Events & evs);
  void setEvents(const L2Events &evs);

  int configurePublicKeys(const ByteArray & cdb);
  int configureTef(const ByteArray & tef);
  int configureVendor(const ByteArray & cnf);
  int configureEmvContactless(const ByteArray & cnf);
  int configureEmvContact(const ByteArray & cnf);

#if ((L2API_QR_ENABLED == 1) || (JPAY_CFG_ENABLE_QR == 1))
  int configureEmvQR(const ByteArray & cnf);
#endif // #if L2API_QR_ENABLED == 1

  int contactlessSetCardRemovalTimeout(int ms);
  bool contactlessPreprocessing(const ByteArray & trd);
  bool contactPreprocessing(const ByteArray & trd);
  ByteArray contactlessPayment(const ByteArray & trd);
  ByteArray contactlessKernelPayment(const ByteArray & trd);
  ByteArray contactPayment(const ByteArray & trd);
  ByteArray qrPayment(const ByteArray & trd, const ByteArray & qr);

  void stopPayment();
  void setFlags(uint8_t flags);

  int setEmvLedsState(int state);
  int setLeds(int state);

  int readerBeep(bool ok);

  uint32_t contactGetVersion();
  int contactOpen();
  int contactStart();
  int contactStop();
  int contactClose();
  int contactProbe();

  uint32_t contactlessGetVersion();

  int contactlessOpen();
  int contactlessStart();
  int contactlessStop();
  int contactlessClose();
  int contactlessProbe();
  int contactlessBlockingProbe(uint16_t timeout_ms);
  int qrRead(ByteArray & qr);
  int qrOpen();
  int qrClose();

  int contactlessPowerOff () ;
  int contactlessPowerOn () ;


#ifdef MIFARE
  int samSetHostKey(uint8_t * key, int keyNum, int keyType, int keyPos, int keyVer);
  int samEnable(int port, int authtype, int keyNum, int keyVer, int samKeyNum, int samKeyVer);
  int mifareAuthorizeWithSam(int blockNum, int keyType, int keyNum, int keyVer, uint8_t * uid, int usz);
  int mifareAutorizeWithKey(int no, int keyType, uint8_t * key, uint8_t * uid, int usz);
  int mifareReadBlock(int no, uint8_t * data);
  int mifareWriteBlock(int no, uint8_t * data);
  int mifareProbe (uint8_t * buf);
  int mifareReprobe(uint8_t * buf);
  int samDisable ();
  int mifareReadValue(int no, uint32_t * value, uint8_t addr);
  int mifareWriteValue(int no, uint32_t value, uint8_t addr);
  int mifareOperate(char type, int no, uint32_t value, int updateNo);
#endif

  ByteArray contactlessClean(const ByteArray & trd);
  ByteArray contactClean(const ByteArray & trd);
  uint32_t emvL2GetVersion();
  uint32_t emvL2GetKernelVersion(uint8_t kernelId);


  void displayMessage(const ByteArray &msg);
  void displayMessage(int id, int status);

  // helpers
  ByteArray parseTef(std::string xml);
  ByteArray parsePublicKeys(std::string xml);
  ByteArray parseEmvContactlessConfig (std::string xml);
  ByteArray parseEmvContactConfig (std::string xml);
  ByteArray parseEmvVendorConfig(std::string xml);

  ByteArray getTagValue (std::string tagName, const ByteArray& data);
  ByteArray makeTag(std::string tagName, const ByteArray& value);

  void setSupportedIso8859codeTables(const ByteArray & ct);
#if L2API_PLATFORM == L2API_PLATFORM_AQSI
#define DEVICE_MODEL_CS10 0
#define DEVICE_MODEL_CS50 1
#define DEVICE_MODEL_CS10CLASSIC 2
#define DEVICE_MODEL_CS20 3

  void selectDeviceModel(int model);
#endif

}
#define _L2API_H_

#endif // _L2API_H_
