#include "resolve.h"
#include <scgms/utils/descriptor_utils.h>
#include <scgms/src/device_event.h>
#include <scgms/src/persistent_chain_configuration.h>
#include <scgms/src/filter_parameter.h>
#include <scgms/src/filter_configuration_executor.h>
#include <scgms/src/configuration_link.h>
#include <scgms/src/filters.h>
#include <iostream>

using FilterDescriptorFunction = HRESULT(*)(scgms::TFilter_Descriptor**, scgms::TFilter_Descriptor**);

MyCloaded_Filters myloaded_filters{};

MyCloaded_Filters::MyCloaded_Filters()
{
	load_descriptors();
}

void MyCloaded_Filters::load_descriptors()
{
    auto get_descriptors = [&](FilterDescriptorFunction get_filter_descriptors)
	{
		scgms::TFilter_Descriptor *desc_begin, *desc_end;
		bool result = get_filter_descriptors(&desc_begin, &desc_end) == S_OK;
		if (result)
		{
			std::copy(desc_begin, desc_end, std::back_inserter(mFilter_Descriptors));
		}
	};
	get_descriptors(do_get_filter_descriptors_data_filter);
	get_descriptors(do_get_filter_descriptors_ema_filter);
	get_descriptors(do_get_filter_descriptors_watchdog_filter);
	get_descriptors(do_get_filter_descriptors_print_filter);
	get_descriptors(do_get_filter_descriptors_signal);
}

HRESULT MyCloaded_Filters::get_filter_descriptors_body(scgms::TFilter_Descriptor **begin, scgms::TFilter_Descriptor **end)
{
	return do_get_descriptors<scgms::TFilter_Descriptor>(mFilter_Descriptors, begin, end);
}

HRESULT get_all_descriptors(scgms::TFilter_Descriptor **begin, scgms::TFilter_Descriptor **end)
{
	return myloaded_filters.get_filter_descriptors_body(begin, end);
}

scgms::SFilter create_filter_body_(const GUID &id, scgms::IFilter *next_filter)
{
	scgms::SFilter result;
	scgms::IFilter *filter;

	if (do_create_filter_data_filter(&id, next_filter, &filter) == S_OK)
	{
		result = refcnt::make_shared_reference_ext<scgms::SFilter, scgms::IFilter>(filter, false);
		return result;
	}
	if (do_create_filter_ema_filter(&id, next_filter, &filter) == S_OK)
	{
		result = refcnt::make_shared_reference_ext<scgms::SFilter, scgms::IFilter>(filter, false);
		return result;
	}
	if (do_create_filter_watchdog_filter(&id, next_filter, &filter) == S_OK)
	{
		result = refcnt::make_shared_reference_ext<scgms::SFilter, scgms::IFilter>(filter, false);
		return result;
	}
	if (do_create_filter_print_filter(&id, next_filter, &filter) == S_OK)
	{
		result = refcnt::make_shared_reference_ext<scgms::SFilter, scgms::IFilter>(filter, false);
		return result;
	}
	if (do_create_filter_signal(&id, next_filter, &filter) == S_OK)
	{
		result = refcnt::make_shared_reference_ext<scgms::SFilter, scgms::IFilter>(filter, false);
		return result;
	}


	return result;
}

void describe_loaded_filters_(refcnt::Swstr_list error_description) {
}

void* resolve_generated_symbol(const char *symbol_name) noexcept
{
	if (strcmp(symbol_name, "create_device_event") == 0) 
    {
        return reinterpret_cast<void*>(create_device_event);
    }
    if (strcmp(symbol_name, "get_filter_descriptors") == 0) 
    {
        return reinterpret_cast<void*>(get_all_descriptors);
    }
	if (strcmp(symbol_name, "create_persistent_filter_chain_configuration") == 0) 
    {
        return reinterpret_cast<void*>(create_persistent_filter_chain_configuration);
    }	
	if (strcmp(symbol_name, "execute_filter_configuration") == 0) 
    {
        return reinterpret_cast<void*>(execute_filter_configuration);
    }
	if (strcmp(symbol_name, "create_filter_parameter") == 0) 
    {
        return reinterpret_cast<void*>(create_filter_parameter);
    }
	if (strcmp(symbol_name, "create_filter_configuration_link") == 0) 
    {
        return reinterpret_cast<void*>(create_filter_configuration_link);
    }
	if (strcmp(symbol_name, "get_model_descriptors") == 0) 
    {
        return reinterpret_cast<void*>(get_model_descriptors);
    }
	if (strcmp(symbol_name, "create_discrete_model") == 0) 
    {
        return reinterpret_cast<void*>(create_discrete_model);
    }

    return nullptr;
}
