#pragma once
#ifdef WIN32
#include <windows.h>
#include <conio.h>
#else
#include <unistd.h>
#include <dlfcn.h>
#include <termios.h>
#include <strings.h>
#include <nl_types.h>
#include <sys/time.h>
#include <sys/times.h>
#include <pthread.h>
#ifndef MAX_PATH
#ifdef PATH_MAX
#define MAX_PATH PATH_MAX
#else
#define MAX_PATH 1024
#endif
#endif
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <memory.h>
#include <sys/types.h>
#include <sys/timeb.h>
#include "pkcs11t_gost.h"

#define STR_EVALUATE(x)		#x
#define STRINGIFY(x)		STR_EVALUATE(x)

extern char					*api_path;
extern CK_UTF8CHAR			*user_pin;
extern CK_UTF8CHAR			*so_pin;

#define PIN_SIZE            80
#define BACK_SPACE          '\b'
#define LINE_FEED           '\n'
#define CARRIAGE_RETURN     '\r'
#define END_OF_TEXT         0x03 // ETX (Ctrl-C) - Сбрасывает процесс в Linux
#define CANCEL_TEXT_INPUT   0x18 // CAN (Ctrl-X) - Сбрасывает ввод в get_pin

#ifdef WIN32
extern HMODULE              dll;
#else
extern void                 *dll;
#endif
extern CK_FUNCTION_LIST_PTR funcs;
extern CK_C_INITIALIZE_ARGS *pinit_args_os_locking;
extern CK_C_INITIALIZE_ARGS *pinit_args_app_locking;
extern CK_SLOT_ID           SlotId;
extern CK_SLOT_ID_PTR       SlotList;
extern CK_ULONG             SlotCount;

#ifdef WIN32
#define sleep_in_msec(T) Sleep(T)
#else
#define sleep_in_msec(T) usleep((T)*1000)
#endif

#define SYSTEMTIME			struct timeb
#define GetSystemTime(x)	ftime(x)
long process_time(struct timeb t1, struct timeb t2);
const char *get_ckr_name(CK_RV rc);
void show_error(char *str, CK_RV rc);
#define PROCESS_ERROR(str, rc, end) \
	{ show_error(str, rc); if (rc != CKR_OK) goto end; }
CK_RV check_value(CK_BYTE *value, CK_ULONG len, CK_BYTE *eth, CK_ULONG eth_len);
#define CHECK(v, len, ethalon) \
    if ((rc = check_value(v, len, ethalon, sizeof(ethalon))) != CKR_OK) { return rc; }
void print_bytes(CK_BYTE *buf, CK_ULONG len);
int print_bytes_str(CK_BYTE *buf, CK_ULONG len, char *str);
void revert(unsigned char *buf, unsigned int len);
CK_RV AppCreateMutex(void **pmutex);
CK_RV AppDestroyMutex(void *mutex);
CK_RV AppLockMutex(void *mutex);
CK_RV AppUnlockMutex(void *mutex);
CK_RV get_function_list(char *api_path, CK_FUNCTION_LIST_PTR *pfuncs);
CK_RV init(char *api_path,
    CK_FUNCTION_LIST_PTR *pfuncs,
    CK_C_INITIALIZE_ARGS *pinit_args);
CK_RV init_all(void);
CK_RV cleanup(CK_FUNCTION_LIST_PTR funcs);
CK_RV get_slot_list(CK_FUNCTION_LIST_PTR funcs,
    CK_SLOT_ID **ppSlotList,
    CK_ULONG *pulSlotCount);
CK_RV find_slot_with_token(CK_FUNCTION_LIST_PTR funcs,
    CK_SLOT_ID *pSlotList,
    CK_ULONG ulSlotCount,
    CK_SLOT_ID *pSlotId);
CK_RV find_obj(CK_SESSION_HANDLE sess,
    CK_ATTRIBUTE *attr, CK_ULONG count, 
	CK_OBJECT_HANDLE *hObj_res);
CK_ULONG get_random_size(CK_SESSION_HANDLE sess,
	CK_ULONG size_min, CK_ULONG size_max); 
const char *get_mechanism_name(CK_MECHANISM_TYPE mech_type);
CK_RV display_pkcs11_info(CK_FUNCTION_LIST_PTR funcs);
CK_RV display_slot_info(CK_FUNCTION_LIST_PTR funcs, CK_SLOT_ID SlotId);
CK_RV display_token_info(CK_FUNCTION_LIST_PTR funcs, CK_SLOT_ID SlotId);
CK_RV display_mechanisms(CK_FUNCTION_LIST_PTR funcs, CK_SLOT_ID slot_id);
void display_mech_flags(CK_FLAGS flags);
CK_RV enum_objects(CK_FUNCTION_LIST_PTR funcs, 
	CK_SLOT_ID SlotId, CK_UTF8CHAR_PTR user_pin, CK_ULONG user_pin_len);
CK_RV get_pin(CK_UTF8CHAR_PTR *pin);
#ifndef WIN32
int echo(int bbool);
#endif
CK_RV pin_callback(
    CK_SESSION_HANDLE hSession,
    CK_NOTIFICATION event,        // CKN_LISSI_PIN_CALLBACK
    CK_VOID_PTR pApplication      // output PIN buffer here
);
CK_RV test_main(int argc, char *argv[]);

