#include "fat12prj.h"
#include "flash_group.h"
#include "fat12inf.h"
#include "os_specific.h"

typedef struct TFlashEnum_ {
    TCHAR* names_buffer;
    TCHAR* cur_name;
} TFlashEnum;

static TCHAR* get_next_string(TCHAR* in_buffer) {
    return in_buffer + _tcslen(in_buffer) + 1;
}

static size_t find_biggest_len(TCHAR* buffer) {
    size_t max_len = 0;
    size_t cur_len = 0;
    TCHAR* cur_name = buffer;
    while (*cur_name != TEXT('\0')) {
	cur_len = _tcslen(cur_name);
	if(cur_len > max_len)
	    max_len = cur_len;
	cur_name = get_next_string(cur_name);
    }
    return max_len;
}

static DWORD create_buf_with_usb_names(const TCHAR* path_to_item, TCHAR** out_buf, size_t* out_buf_len) {
    TCHAR* buf = NULL;
    size_t buf_len = 0;
    DWORD err = get_usb_labels(path_to_item, buf, &buf_len);
    if (err)
	return err;
    buf = (TCHAR*)malloc((buf_len + 1) * sizeof(TCHAR));
    if (!buf)
	return (DWORD)NTE_NO_MEMORY;
    err = get_usb_labels(path_to_item, buf, &buf_len);
    if (err) {
	free(buf);
	return err;
    }
    *out_buf = buf;
    *out_buf_len = buf_len;
    return ERROR_SUCCESS;
}

DWORD flash_group_enum_open(TSupSysContext *context, TSupSysInfo* info) {
    TSupSysInfoGroupEnum *inf = (TSupSysInfoGroupEnum*)info;
    TCHAR* usb_names_buf = NULL;
    size_t usb_names_buf_len = 0;
    size_t longest_usb_name_len = 0;
    DWORD err = 0;
    TFat12GroupContext* ctx = (TFat12GroupContext*) context;
    if (NULL == inf || NULL == ctx || NULL == ctx->path_to_item)
	return (DWORD)ERROR_INVALID_PARAMETER;
    //expect buf_len = size of buffer in TCHAR, not including final null-terminator.
    err = create_buf_with_usb_names(ctx->path_to_item, &usb_names_buf, &usb_names_buf_len);
    if (err)
	return err;
    longest_usb_name_len = find_biggest_len(usb_names_buf);
    if (longest_usb_name_len == 0) {
	free(usb_names_buf);
	return (DWORD)SCARD_E_READER_UNAVAILABLE;
    }

    TFlashEnum* enum_ctx = (TFlashEnum*) malloc(sizeof(TFlashEnum));
    if (!enum_ctx) {
	free(usb_names_buf);
	return (DWORD)NTE_NO_MEMORY;
    }

    inf->name.length = longest_usb_name_len;
    enum_ctx->names_buffer = usb_names_buf;
    enum_ctx->cur_name = usb_names_buf;
    inf->add_info.info = (unsigned char*)enum_ctx;
    inf->add_info.length = sizeof(*enum_ctx);
    if (inf->compute_mark_func) {
	inf->compute_mark_func(enum_ctx->names_buffer, &inf->change_mark);
    }
    return ERROR_SUCCESS;
}

DWORD flash_group_enum_next(TSupSysContext *context, TSupSysInfo* info) {
    UNUSED(context);
    TSupSysInfoGroupEnum * inf = (TSupSysInfoGroupEnum*)info;
    if (!inf || !inf->add_info.info)
	return (DWORD)ERROR_INVALID_PARAMETER;
    TFlashEnum* flash_enum = (TFlashEnum*)inf->add_info.info;
    TCHAR* cur_name = flash_enum->cur_name;
    if (*cur_name == TEXT('\0'))
	return (DWORD)SCARD_E_READER_UNAVAILABLE;
    _tcscpy(inf->name.text, cur_name);
    inf->name.length = _tcslen(cur_name);
    flash_enum->cur_name = get_next_string(flash_enum->cur_name);
    return ERROR_SUCCESS;
}

DWORD flash_group_enum_close(TSupSysContext *context, TSupSysInfo* info) {

    UNUSED(context);
    TSupSysInfoGroupEnum * inf = (TSupSysInfoGroupEnum*)info;
    if (!inf)
	return (DWORD)ERROR_INVALID_PARAMETER;
    TFlashEnum* flash_enum = (TFlashEnum*)inf->add_info.info;

    if (flash_enum) {
	free(flash_enum->names_buffer);
	free(flash_enum);
    }

    inf->add_info.info = NULL;
    inf->add_info.length = 0;

    return ERROR_SUCCESS;
}

DWORD flash_group_info_system_flag(TSupSysContext *context, TSupSysInfo* info) {
    UNUSED(context); //сюда приходит групповой контекст FLASH, который не содержит никакой информации для обычных функций (не-enum)
    return fat12_group_info_system_flag(NULL, info);
}
