"""
STC2 Functions
"""
from ctypes import byref, cast, POINTER, string_at, c_ulong, create_string_buffer
from six import b

from pycryptoki.common_utils import AutoCArray, refresh_c_arrays
from pycryptoki.cryptoki.c_defs import CK_BYTE, CK_CHAR, CK_ULONG
from pycryptoki.cryptoki.ck_defs import CK_SESSION_HANDLE, CK_SLOT_ID
from pycryptoki.cryptoki.func_defs import (
    CA_STCRegister,
    CA_STCRegisterV2,
    CA_STCDeregister,
    CA_STCGetPubKey,
    CA_STCGetClientsList,
    CA_STCGetClientInfo,
    CA_STCGetClientInfoV2,
    CA_STCGetPartPubKey,
    CA_STCGetAdminPubKey,
    CA_STCGetPID,
    CA_STCGetAdminPID,
    CA_STCSetCipherAlgorithm,
    CA_STCGetCipherAlgorithm,
    CA_STCClearCipherAlgorithm,
    CA_STCSetDigestAlgorithm,
    CA_STCGetDigestAlgorithm,
    CA_STCClearDigestAlgorithm,
    CA_STCSetKeyLifeTime,
    CA_STCGetKeyLifeTime,
    CA_STCSetKeyActivationTimeOut,
    CA_STCGetKeyActivationTimeOut,
    CA_STCSetMaxSessions,
    CA_STCGetMaxSessions,
    CA_STCSetSequenceWindowSize,
    CA_STCGetSequenceWindowSize,
    CA_STCIsEnabled,
    CA_STCGetState,
    CA_STCGetChannelID,
    CA_STCGetCipherID,
    CA_STCGetDigestID,
    CA_STCGetCurrentKeyLife,
    CA_STCGetCipherIDs,
    CA_STCGetCipherNameByID,
    CA_STCGetDigestIDs,
    CA_STCGetDigestNameByID,
)
from pycryptoki.defines import CKR_OK
from pycryptoki.exceptions import make_error_handle_function


SHA512_DIGEST_LENGTH = 64
STC_USERNAME_BUFFER_SIZE = 128
STC_PID_BUFFER_SIZE = 4096
STC_MODULUS_BUFFER_SIZE = 2048
STC_EXPONENT_BUFFER_SIZE = 512
STC_MIN_KEY_LIFE = 0
STC_DEFAULT_KEY_LIFE = 432  # approx. 24 hours
STC_MAX_KEY_LIFE = 4000  # approx. 9 days
CRYPTO_NAME_BUFFER_SIZE = 255


def ca_stc_register(session, slot, name, access, modulus, exponent):
    """
    Register client

    :param session: session handle
    :param slot: slot id
    :param name: name of client
    :param access:
    :param modulus: client public modulus
    :param exponent: client public exponent
    """
    h_session = CK_SESSION_HANDLE(session)
    h_slot = CK_SLOT_ID(slot)
    c_name = AutoCArray(ctype=CK_CHAR, data=name)
    c_access = CK_ULONG(access)
    c_mod = AutoCArray(ctype=CK_CHAR, data=modulus)
    c_exp = AutoCArray(ctype=CK_CHAR, data=exponent)

    ret = CA_STCRegister(
        h_session, h_slot, c_name.array, c_access, c_mod.array, len(c_mod), c_exp.array, len(c_exp)
    )
    return ret


ca_stc_register_ex = make_error_handle_function(ca_stc_register)


def ca_stc_register_v2(session, slot, name, id_type, credential):
    """
    Register client, STC2

    :param session: session handle
    :param slot: slot id
    :param name: name of client
    :param id_type: type of client id
    :param credential: X9.62 encoded uncompressed EC point
    """
    h_session = CK_SESSION_HANDLE(session)
    h_slot = CK_SLOT_ID(slot)
    c_name = AutoCArray(ctype=CK_CHAR, data=name)
    c_id_type = CK_ULONG(id_type)
    c_id_data = AutoCArray(ctype=CK_BYTE, data=credential)
    ret = CA_STCRegisterV2(
        h_session,
        h_slot,
        c_name.array,
        c_name.size.contents,
        c_id_type,
        c_id_data.array,
        c_id_data.size.contents,
    )
    return ret


ca_stc_register_v2_ex = make_error_handle_function(ca_stc_register_v2)


def ca_stc_deregister(session, slot, name):
    """
    Deregister client

    :param session: session handle
    :param slot: slot id
    :param name: client name to deregister
    """
    h_session = CK_SESSION_HANDLE(session)
    h_slot = CK_SLOT_ID(slot)
    c_name = create_string_buffer(b(name))
    c_name_ptr = cast(c_name, POINTER(CK_CHAR))
    ret = CA_STCDeregister(h_session, h_slot, c_name_ptr)
    return ret


ca_stc_deregister_ex = make_error_handle_function(ca_stc_deregister)


def ca_stc_get_pub_key(session, slot, name):
    """