/*
 * Copyright(C) 2000 Проект ИОК
 *
 * Этот файл содержит информацию, являющуюся
 * собственностью компании Крипто Про.
 *
 * Любая часть этого файла не может быть скопирована,
 * исправлена, переведена на другие языки,
 * локализована или модифицирована любым способом,
 * откомпилирована, передана по сети с или на
 * любую компьютерную систему без предварительного
 * заключения соглашения с компанией Крипто Про.
 */

/*!
 * \file $RCSfile$
 * \version $Revision: 220316 $
 * \date $Date:: 2020-10-23 13:58:02 +0300#$
 * \author $Author: markova $
 * \brief Глобальная структура списка считывателей.
 */

#include "rdr_prj.h"

/* Инициализация списка считывателей. */
static DWORD rdr_init_list( TSupSysContext *list, TSupSysInfo *info );
/* Деинициализация списка считывателей. */
static DWORD rdr_done_list( TSupSysContext *list, TSupSysInfo *info );
/* Освобождение контекста считывателя. */
static DWORD rdr_free_item( TSupSysContext *list, TSupSysInfo *info );
/* Освобождение контекста считывателя. */
/* Дублирование контекста считывателя. */
static DWORD rdr_dup_item( TSupSysContext *list, TSupSysInfo *info );
static DWORD rdr_compare_item(TSupSysContext* context, TSupSysInfo* info);
static DWORD rdr_alloc_item( TSupSysContext *list, TSupSysInfo *info );
static DWORD rdr_refresh_media_list(TSupSysContext *context, TSupSysInfo *info);
static DWORD rdr_info_base_path( TSupSysContext *context, TSupSysInfo *info );
static DWORD media_info_base_path( TSupSysContext *context, TSupSysInfo *info );
static DWORD rdr_info_version( TSupSysContext *context, TSupSysInfo *info );

static DWORD media_msi_title(TSupSysContext *context, TSupSysInfo *info);
static DWORD media_prefix_name(TSupSysContext *context, TSupSysInfo *info);
static DWORD media_group_name(TSupSysContext *context, TSupSysInfo *info);

static DWORD reader_msi_title(TSupSysContext *context, TSupSysInfo *info);
static DWORD reader_prefix_name(TSupSysContext *context, TSupSysInfo *info);
static DWORD reader_group_name(TSupSysContext *context, TSupSysInfo *info);

static const TSupSysInfoIDSBaseItem RDR_IDS_BASE_ITEMS[] = 
{
    {
	SUPSYS_IDS_BLOCK_WND,
	IDS_RDR_WND_BASE,
	SUPSYS_IDS_WND_LAST
    },
    {
	READER_IDS_BLOCK,
	READER_IDS_BASE,
	READER_IDS_QUANT_V1
    }
};

static const TSupSysInfoIDSBaseItem MEDIA_IDS_BASE_ITEMS[] = 
{
    {
	SUPSYS_IDS_BLOCK_WND,
	IDS_MEDIA_WND_BASE,
	SUPSYS_IDS_WND_LAST
    },
    {
	READER_IDS_BLOCK,
	READER_IDS_BASE,
	READER_IDS_QUANT_V1
    }
};

/*!
 * \ingroup rdr_internal
 * \brief Таблица баз и границ строк в ресурсе по умолчанию.
 */
static const TSupSysInfoIDSBase RDR_IDS_BASE =
{
    sizeof( RDR_IDS_BASE_ITEMS ) / sizeof( TSupSysInfoIDSBaseItem ),
    RDR_IDS_BASE_ITEMS
};

/*!
 * \ingroup rdr_internal
 * \brief Таблица баз и границ строк в ресурсе по умолчанию.
 */
static const TSupSysInfoIDSBase MEDIA_IDS_BASE =
{
    sizeof( MEDIA_IDS_BASE_ITEMS ) / sizeof( TSupSysInfoIDSBaseItem ),
    MEDIA_IDS_BASE_ITEMS
};

static DWORD rdr_info_ids(
    TSupSysContext *context, 
    TSupSysInfo *info )
{
    UNUSED( context );

    SUPSYS_PRE_INFO( info, TSupSysInfoIDSBase );
    memcpy( info, &RDR_IDS_BASE, sizeof( TSupSysInfoIDSBase ) );
    return ERROR_SUCCESS;
}

static DWORD media_info_ids(
    TSupSysContext *context, 
    TSupSysInfo *info )
{
    UNUSED( context );

    SUPSYS_PRE_INFO( info, TSupSysInfoIDSBase );
    memcpy( info, &MEDIA_IDS_BASE, sizeof( TSupSysInfoIDSBase ) );
    return ERROR_SUCCESS;
}

static const TSupSysFunctionTableItem RDR_FUNS[] =
{
    { SUPSYS_FUN_IDS_BLOCK, rdr_info_ids },

    { SUPSYSL_FUN_BASE_PATH, rdr_info_base_path },
    { SUPSYSL_FUN_MSI_TITLE, reader_msi_title },
    { SUPSYSL_FUN_PREFIX_NAME, reader_prefix_name },
    { SUPSYSL_FUN_PREFIX_GROUP, reader_group_name },

    { SUPSYSL_FUN_REGISTER, rdr_init_list },
    { SUPSYSL_FUN_UNREGISTER, rdr_done_list },
    { SUPSYSL_FUN_ITEM_ALLOC, rdr_alloc_item },
    { SUPSYSL_FUN_ITEM_FREE, rdr_free_item },
    { SUPSYSL_FUN_ITEM_DUP, rdr_dup_item },
    { SUPSYSL_FUN_ITEM_COMPARE, rdr_compare_item },
    { SUPSYSL_FUN_ITEM_INFO_VERSION, rdr_info_version },
    { SUPSYSL_FUN_REFRESH, rdr_refresh_media_list }
};

static const TSupSysFunctionTable RDR_TABLE =
{
    sizeof( RDR_FUNS ) / sizeof( TSupSysFunctionTableItem ),
    RDR_FUNS
};

static const TSupSysFunctionTableItem MEDIA_FUNS[] =
{
    { SUPSYS_FUN_IDS_BLOCK, media_info_ids },
    { SUPSYSL_FUN_BASE_PATH, media_info_base_path },
    { SUPSYSL_FUN_MSI_TITLE, media_msi_title },
    { SUPSYSL_FUN_PREFIX_NAME, media_prefix_name },
    { SUPSYSL_FUN_PREFIX_GROUP, media_group_name },
    { SUPSYSL_FUN_ITEM_INFO_VERSION, rdr_info_version }
};

static const TSupSysFunctionTable MEDIA_TABLE =
{
    sizeof( MEDIA_FUNS ) / sizeof( TSupSysFunctionTableItem ),
    MEDIA_FUNS
};


DWORD rdr_register_start(TSupSysEList **list)
{
    return supsys_register_start(list, &RDR_TABLE);
}

DWORD rdr_register_one(TSupSysEList *list, const TCHAR *reader)
{
    return supsys_register_one(list, reader);
}

DWORD rdr_register_all(TSupSysEList *list)
{
    return supsys_register_all(list);
}

DWORD rdr_register_all_ext(TSupSysEList *list, unsigned flags)
{
    return supsys_register_all_ext(list, flags);
}

DWORD rdr_media_register_start(TSupSysEList **list)
{
    return supsys_register_start(list, &MEDIA_TABLE);
}

static DWORD rdr_init_list(TSupSysContext *context, TSupSysInfo *info)
{
    TSupSysInfoRegister *inf = (TSupSysInfoRegister*)info;
    TSupSysEList *media_list = NULL;
    DWORD code;
    SUPSYS_PRE_INFO(info, TSupSysInfoRegister);
    UNUSED(context);
    code = supsys_register_start(&media_list, &MEDIA_TABLE);
    if (code)
	return code;
    inf->context = (TSupSysEContext*)media_list;
    return ERROR_SUCCESS;
}

static DWORD rdr_done_list(TSupSysContext *context, TSupSysInfo *info)
{
    TSupSysEList *media_list = (TSupSysEList*)context;
    int *done = (int*)info;
    SUPSYS_PRE_INFO(info, int);

    supsys_unregister_all(media_list, *done);
    return ERROR_SUCCESS;
}

static DWORD rdr_free_item( TSupSysContext *context, TSupSysInfo *info )
{
    UNUSED(context);
    UNUSED(info);
    return ERROR_SUCCESS;
}

static DWORD rdr_dup_item( TSupSysContext *context, TSupSysInfo *info )
{
    TSupSysListItemDup *inf = (TSupSysListItemDup*)info;

    SUPSYS_PRE_INFO( info, TSupSysListItemDup );
    UNUSED( context );
    inf->dest_owner = supsys_owner_context(inf->src);
    return ERROR_SUCCESS;
}

static DWORD rdr_compare_item(TSupSysContext* context, TSupSysInfo* info)
{
    TSupSysListItemCompare* inf = (TSupSysListItemCompare*)info;
    DWORD code;
    SUPSYS_PRE_INFO(info, TSupSysListItemCompare);
    UNUSED(context);

    // Вроде бы, ошибки тут могут быть только критичными, но поведение ломать хочется в самую последнюю очередь.
    // Возвращаем ERROR_NOT_SUPPORTED, потому что на неё заложен вызывающий код
    int res1 = 0;
    code = rdr_get_support_flag(inf->item1, RDR_FLAG_RDR_SLOW, &res1);
    if (code) {
	return (DWORD)ERROR_NOT_SUPPORTED;
    }
    int res2 = 0;
    code = rdr_get_support_flag(inf->item2, RDR_FLAG_RDR_SLOW, &res2);
    if (code) {
	return (DWORD)ERROR_NOT_SUPPORTED;
    }

    /* Могут быть 4 ситуации:
       1) Оба модуля медленные - вернем -1, чтобы порядок не отличался от старого
       2) Оба модуля быстрые - вернем -1, чтобы порядок не отличался от старого
       3) Первый медленный, второй быстрый - вернем +1, чтобы первый был ниже
       4) Первый быстрый, второй медленный - вернем -1, чтобы первый был выше
    */
    if (res1 && !res2) {
	inf->res = 1;
    }
    else {
	inf->res = -1;
    }

    return ERROR_SUCCESS;
}

static DWORD rdr_alloc_item( TSupSysContext *context, TSupSysInfo *info )
{
    TSupSysListItemAlloc *inf = (TSupSysListItemAlloc*)info;
    TSupSysEList *lst = (TSupSysEList *)context;

    SUPSYS_PRE_CCONTEXT( inf, TSupSysListItemAlloc );
    inf->owner = (TSupSysEContext*)lst;
    return 0;
}

static DWORD rdr_refresh_media_list(TSupSysContext *context, TSupSysInfo *info)
{
    TSupSysListRefreshFlags *inf = (TSupSysListRefreshFlags*)info;
    TSupSysEList *lst = (TSupSysEList*)context;

    SUPSYS_PRE_CCONTEXT(inf, TSupSysListRefreshFlags);
    return supsys_register_all_ext(lst, *inf);
}

DWORD rdr_info_carrier_type(const TSupSysEContext *context, TSupSysNickname carrier_type)
{
    TReaderInfoCarrierType info_type = { {0}, 0 };
    DWORD code;
    /* Вызов функции элемента. */
    info_type.path_to_item = NULL;
    code = supsys_call( context, READER_FUN_CARRIER_TYPE, &info_type);
    if( code == (DWORD)ERROR_NOT_SUPPORTED )
    {
	size_t length = SUPSYSE_NICKNAME_LENGTH;
	code = supsys_get_string_local( context, READER_IDS_BLOCK,
	    READER_IDS_CARRIER_TYPE, &length, carrier_type );
	if( code )
	    LOGRETURN((code==(DWORD)ERROR_NOT_SUPPORTED)?(DWORD)NTE_PROVIDER_DLL_FAIL:code);
	/* В данном случае UNSUPPORTED считался бы нормальным завершением */
	if( length <= SUPSYSE_NICKNAME_LENGTH )
	    LOGRETURN(ERROR_SUCCESS);
    }
    /* Копирование прозвища. */
    _tcsncpy( carrier_type, info_type.type, SUPSYSE_NICKNAME_LENGTH );
    carrier_type[SUPSYSE_NICKNAME_LENGTH] = 0;
    LOGRETURN(ERROR_SUCCESS);
}

DWORD rdr_connect_current(const TSupSysEContext *context, size_t *length, TCHAR *name)
{
    return supsys_connect_current(context, length, name);
}

static const TCHAR RDR_BASE_PATH[] = _TEXT( "\\CONFIG\\KeyDevices\\" );

/* MEDIA_BASE_PATH[] определён в pscs/pscatr.c и в rdr/rglob.c -- это сделано, чтобы переменные не выходили за пределы DLL
 * "правильное" исправление м.б. сделано 2-мя способами:
 * -- завести #define и вытащить строку вообще на самый верх. Так делать не хочется
 * -- завести функцию, которая будет возвращать эту строку. Так тоже делать не хочется
 * ===> оставляем как есть и не забываем изменять в обоих местах синхронно
*/
static const TCHAR MEDIA_BASE_PATH[] = _TEXT( "\\CONFIG\\KeyCarriers\\" );

static const TCHAR TC_MEDIA_MSI_TITLE[] = _TEXT("media");
static const TCHAR TC_MEDIA_ENTRY_POINT[] = _TEXT("_media_get_table");
static const TCHAR TC_MEDIA_GROUP_POINT[] = _TEXT("_media_get_group_table");

static const TCHAR TC_READER_MSI_TITLE[] = _TEXT("reader");
static const TCHAR TC_READER_ENTRY_POINT[] = _TEXT("_reader_get_table");
static const TCHAR TC_READER_GROUP_POINT[] = _TEXT("_reader_get_group_table");


static DWORD info_base_path( TSupSysEContext *context, TSupSysInfo *info,
    const TCHAR *path )
{
    TSupSysInfoText *inf = (TSupSysInfoText*)info;

    UNUSED( context );
    SUPSYS_PRE_INFO(info, TSupSysInfoText);
    if(inf->length && inf->text)
    {
	_tcsncpy(inf->text, path, inf->length);
	inf->text[inf->length] = 0;
    }
    inf->length = _tcslen(path);
    return ERROR_SUCCESS;
}

static DWORD rdr_info_base_path( TSupSysContext *context, TSupSysInfo *info )
{
    return info_base_path( context, info, RDR_BASE_PATH );
}

static DWORD rdr_info_version( TSupSysContext *context, TSupSysInfo *info )
{  
    static const TSupSysInfoVersion _VERSION = {3,6,0,0};
    UNUSED( context );

    if(info == NULL)
	return (DWORD)ERROR_INVALID_PARAMETER;

    memcpy(info, &_VERSION, sizeof(_VERSION));
    return ERROR_SUCCESS;
}

static DWORD media_info_base_path( TSupSysContext *context, TSupSysInfo *info )
{
    return info_base_path( context, info, MEDIA_BASE_PATH );
}

static DWORD retTCHARConst(TSupSysContext *context, TSupSysInfo *info, SHORT reason)
{
    TSupSysInfoNickname * nick;
    nick = (TSupSysInfoNickname *)info;

    UNUSED(context);

    if (info == NULL)
	return (DWORD)ERROR_INVALID_PARAMETER;
	
    switch (reason) {
    case 1:
	_tcscpy(nick->nickname, TC_READER_MSI_TITLE);
	break;
    case 2:
	_tcscpy(nick->nickname, TC_READER_ENTRY_POINT);
	break;
    case 3:
	_tcscpy(nick->nickname, TC_READER_GROUP_POINT);
	break;
    case 4:
	_tcscpy(nick->nickname, TC_MEDIA_MSI_TITLE);
	break;
    case 5:
	_tcscpy(nick->nickname, TC_MEDIA_ENTRY_POINT);
	break;
    case 6:
	_tcscpy(nick->nickname, TC_MEDIA_GROUP_POINT);
	break;
    default:
	return (DWORD)ERROR_INVALID_PARAMETER;
    }
    return 0;
}

static DWORD reader_msi_title(TSupSysContext *context, TSupSysInfo *info)
{
	return retTCHARConst(context, info, 1);
}

static DWORD reader_prefix_name(TSupSysContext *context, TSupSysInfo *info)
{
	return retTCHARConst(context, info, 2);
}

static DWORD reader_group_name(TSupSysContext *context, TSupSysInfo *info)
{
	return retTCHARConst(context, info, 3);
}

static DWORD media_msi_title(TSupSysContext *context, TSupSysInfo *info)
{
	return retTCHARConst(context, info, 4);
}

static DWORD media_prefix_name(TSupSysContext *context, TSupSysInfo *info)
{
	return retTCHARConst(context, info, 5);
}
static DWORD media_group_name(TSupSysContext *context, TSupSysInfo *info)
{
	return retTCHARConst(context, info, 6);
}
