#ifndef VENDOR_SAMSUNG_SECURITY_DRK_TLV_H
#define VENDOR_SAMSUNG_SECURITY_DRK_TLV_H

#include <vector>
#include "Bytes.h"

// TLV Size.
#define TAG_FIELD_SIZE              0x01
#define LENGTH_FIELD_SIZE           0x02
#define TAGLENGTH_FIELD_SIZE        (TAG_FIELD_SIZE + LENGTH_FIELD_SIZE)
#define TAGLENGTH_FIELD_SIZE_EX     (TAG_FIELD_SIZE + LENGTH_FIELD_SIZE * 2)

/* TLV data types */
typedef enum {
    TLV_EXPONENT = 1,
    TLV_ISSUER,
    TLV_HASH_ALGO,
    TLV_SUBJECT,
    TLV_KEYUSAGE,
    TLV_DN_QUALIFIER,
    TLV_EXT_KEYUSAGE,
    TLV_SIGN_DATA_BLOB,
    TLV_CERT_SM,
    TLV_CERT_SD,
    TLV_TIMESTAMP,
    TLV_WRAPPED_PCR,
    TLV_EXTEND_PCR_DATA,
    TLV_TID,
    TLV_WRAPPED_KEY,
    TLV_KEY_INFO,
    TLV_ATTRS,
    TLV_MODEL_NAME,
    TLV_HUID,
    TLV_PREGEN_KEYPAIR,
    TLV_CSR,
    TLV_IV,
    TLV_AUTH_TAG,
    TLV_AUTH_DATA,
    TLV_SIGNATURE,
    TLV_ENCRYPTED_DATA_BLOB,
    TLV_CERT,
    TLV_IMEI,
    TLV_SUBJECT_ALTER_NAME,
    TLV_RFNAME,
    TLV_WFNAME,
    TLV_RFDATA,
    TLV_WFDATA,
    TLV_RFSIZE,
    TLV_BRANCHID,
    TLV_SERVNAME,
    TLV_SPU_OUTDATA,
    TLV_TZ_OUTPUT,
    TLV_DI_STATUS = 101,
    TLV_DI_MODEM  = 102,
    TLV_DI_IMEI   = 104,
    TLV_DI_SN     = 108,
    TLV_DI_MODEL  = 116,
    TLV_DI_UID    = 132,
    TLV_DI_SPU    = 164,
    TLV_MAX,
    /* Identifier of the start of a TLV buffer */
    TLV_START_EX = 0xfd,
    TLV_START    = 0xfe
} TLVTAG;

namespace vendor {
namespace samsung {
namespace hardware {
namespace security {
namespace drk {

using namespace std;

class ITEM
{
protected:
    TLVTAG  Tag;
    uint32_t  Length;
    uint8_t  *Value;

public:
    ITEM();
    ITEM(const ITEM& in);
    ~ITEM();

    int32_t  set(TLVTAG t, uint32_t l, uint8_t *v);
    uint8_t *value() const;
    uint32_t length() const;
    TLVTAG   tag() const;
};

class TLV
{
private:
    TLVTAG       start_tag;
    uint32_t     start_length;
    vector<ITEM> tlv;

    int32_t encodeLength(uint8_t *in, uint32_t in_value);
    int32_t decodeLength(uint8_t *in, uint32_t *out_value);
    int32_t setTlv(TLVTAG tag, uint8_t *value, uint32_t length);

public:
    TLV();
    TLV(TLVTAG mode);
    ~TLV();

    /* native api */
    int32_t  encode(uint8_t **out, uint32_t *out_len);
    int32_t  decode(uint8_t *in, uint32_t in_len);
    int32_t  get(TLVTAG tag, uint8_t **value, uint32_t *length);
    int32_t  get(TLVTAG tag, uint8_t *value, uint32_t *length);
    int32_t  add(TLVTAG tag, uint8_t *value, uint32_t length);

    /* native api with Bytes */
    int32_t  encode(Bytes& out);
    int32_t  decode(Bytes& in);
    int32_t  get(TLVTAG tag, Bytes& value);
    int32_t  add(TLVTAG tag, Bytes& in);

    /* etc */
    int32_t  setMode(TLVTAG tag);
    uint32_t getTotalLength();

};

}  // namespace drk
}  // namespace security
}  // namespace hardware
}  // namespace samsung
}  // namespace vendor

#endif
