/*
** HDL4SE: 软件Verilog综合仿真平台
** Copyright (C) 2021-2021, raoxianhong<raoxianhong@163.net>
** LCOM: 轻量级组件对象模型
** Copyright (C) 2021-2021, raoxianhong<raoxianhong@163.net>
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are met:
**
** * Redistributions of source code must retain the above copyright notice,
**   this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright notice,
**   this list of conditions and the following disclaimer in the documentation
**   and/or other materials provided with the distribution.
** * The name of the author may be used to endorse or promote products
**   derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
** AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
** ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
** LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
** INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
** CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
** ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
** THE POSSIBILITY OF SUCH DAMAGE.
*/
 
/*
* hdl4se_module.c
  修改记录：
	202105222014: rxh, initial version
	202105241522：rxh, 增加Detector接口，修改了unit列表的实现方式，
	    从双向链表改为了数组
*/
#include "stdlib.h" 
#include "stdio.h"
#include "string.h"
#include "object.h"
#include "dlist.h"
#include "bignumber.h"
#include "hdl4secell.h"

typedef struct sModulePort {
	int width;
	int type;
	char* name;
	IHDL4SEUnit** unit;
	int unitindex;
}ModulePort;

/* 
HDL4SE_MODULE 
instance parameter: 
*/
typedef struct _sHDL4SEModule {
	OBJECT_HEADER
	INTERFACE_DECLARE(IHDL4SEModule)
	HDL4SEMODULE_VARDECLARE
	INTERFACE_DECLARE(IHDL4SEUnit)
	HDL4SEUNIT_VARDECLARE
	INTERFACE_DECLARE(IHDL4SEDetector)
	HDL4SEDETECTOR_VARDECLARE
	DLIST_VARDECLARE
	
	IHDL4SEModule** parent;
	char* name;

	int ports_count;
	int ports_arraysize;
	ModulePort* ports;

	int units_count;
	int units_arraysize;
	IHDL4SEUnit*** units;
}sHDL4SEModule;

OBJECT_FUNCDECLARE(hdl4se_module, CLSID_HDL4SE_MODULE);
HDL4SEUNIT_FUNCDECLARE(hdl4se_module, CLSID_HDL4SE_MODULE, sHDL4SEModule);
HDL4SEDETECTOR_FUNCDECLARE(hdl4se_module, CLSID_HDL4SE_MODULE, sHDL4SEModule);
HDL4SEMODULE_FUNCDECLARE(hdl4se_module, CLSID_HDL4SE_MODULE, sHDL4SEModule);
DLIST_FUNCIMPL(hdl4se_module, CLSID_HDL4SE_MODULE, sHDL4SEModule);

OBJECT_FUNCIMPL(hdl4se_module, sHDL4SEModule, CLSID_HDL4SE_MODULE);


QUERYINTERFACE_BEGIN(hdl4se_module, CLSID_HDL4SE_MODULE)
QUERYINTERFACE_ITEM(IID_HDL4SEUNIT, IHDL4SEUnit, sHDL4SEModule)
QUERYINTERFACE_ITEM(IID_HDL4SEDETECTOR, IHDL4SEDetector, sHDL4SEModule)
QUERYINTERFACE_ITEM(IID_DLIST, IDList, sHDL4SEModule)
QUERYINTERFACE_ITEM(IID_HDL4SEMODULE, IHDL4SEModule, sHDL4SEModule)
QUERYINTERFACE_END

static const char* hdl4se_moduleModuleInfo()
{
	return "1.0.0-20210522.2014 HDL4SE Module cell";
}

static int hdl4se_moduleCreate(const PARAMITEM* pParams, int paramcount, HOBJECT* pObject)
{
	sHDL4SEModule* pobj;
	int i;
	pobj = (sHDL4SEModule*)malloc(sizeof(sHDL4SEModule));
	if (pobj == NULL)
		return -1;
	*pObject = 0;
	HDL4SEUNIT_VARINIT(pobj, CLSID_HDL4SE_MODULE);
	INTERFACE_INIT(IHDL4SEUnit, pobj, hdl4se_module, hdl4se_unit);
	INTERFACE_INIT(IHDL4SEDetector, pobj, hdl4se_module, hdl4se_detector);
	INTERFACE_INIT(IHDL4SEModule, pobj, hdl4se_module, hdl4se_module);
	DLIST_VARINIT(pobj, hdl4se_module);
	
	pobj->name = NULL; 
	pobj->parent = NULL;

	for (i = 0; i < paramcount; i++) {
		if (pParams[i].name == PARAMID_HDL4SE_UNIT_NAME) {
			if (pobj->name != NULL)
				free(pobj->name);
			pobj->name = strdup(pParams[i].pvalue);
		} 
		else if (pParams[i].name == PARAMID_HDL4SE_UNIT_PARENT) {
			pobj->parent = (IHDL4SEModule **)pParams[i].pvalue;
		}
		else if (pParams[i].name == PARAMID_HDL4SE_UNIT_INSTANCE_PARAMETERS) {
		}
	}

	pobj->ports_count = 0;
	pobj->ports_arraysize = 32;
	pobj->ports = (ModulePort*)malloc(pobj->ports_arraysize * sizeof(ModulePort));

	pobj->units_count = 0;
	pobj->units_arraysize = 32;
	pobj->units = (IHDL4SEUnit***)malloc(pobj->units_arraysize * sizeof(IHDL4SEUnit **));

	/* 返回生成的对象 */
	OBJECT_RETURN_GEN(hdl4se_module, pobj, pObject, CLSID_HDL4SE_MODULE);
	return EIID_OK;
}

static void hdl4se_moduleDestroy(HOBJECT object)
{
	int i;
	sHDL4SEModule* pobj;
	pobj = (sHDL4SEModule*)objectThis(object);
	if (pobj->name != NULL)
		free(pobj->name);
	for (i = 0; i < pobj->ports_count; i++) {
		if (pobj->ports[i].name != NULL)
			free(pobj->ports[i].name);
		objectRelease(pobj->ports[i].unit);
	}
	free(pobj->ports);

	for (i = 0; i < pobj->units_count; i++) {
		objectRelease(pobj->units[i]);
	}
	free(pobj->units);

	memset(pobj, 0, sizeof(sHDL4SEModule));
	free(pobj);
}

static int hdl4se_moduleValid(HOBJECT object)
{
	sHDL4SEModule* pobj;
	pobj = (sHDL4SEModule*)objectThis(object);
	return 1;
}

static int hdl4se_module_hdl4se_unit_Connect(HOBJECT object, int index, HOBJECT from, int fromindex) 
{
	sHDL4SEModule* pobj;
	IHDL4SEUnit** unit = NULL;
	pobj = (sHDL4SEModule*)objectThis(object);
	if (index >= 0 && index < pobj->ports_count) {
		if (0 == objectQueryInterface(from, IID_HDL4SEUNIT, (void**)&unit)) {
			objectRelease(pobj->ports[index].unit);
			pobj->ports[index].unit = unit;
			pobj->ports[index].unitindex = fromindex;
			return 0;
		}
		else {
			return -2;
		}
	}
	return -1;
}

static int hdl4se_module_hdl4se_unit_GetValue(HOBJECT object, int index, int width, IBigNumber ** value)
{
	sHDL4SEModule* pobj;
	pobj = (sHDL4SEModule*)objectThis(object);
	if (index >= 0 && index < pobj->ports_count) {
		objectCall3(pobj->ports[index].unit, GetValue, pobj->ports[index].unitindex, width, value);
	}
	return 0;
}

static int hdl4se_module_hdl4se_unit_ClkTick(HOBJECT object)
{
	sHDL4SEModule* pobj;
	int i;
	pobj = (sHDL4SEModule*)objectThis(object);
	for (i = 0; i < pobj->units_count; i++) {
		objectCall0(pobj->units[i], ClkTick);
	}
	return 0;
}

static int hdl4se_module_hdl4se_unit_Setup(HOBJECT object)
{
	sHDL4SEModule* pobj;
	int i;
	pobj = (sHDL4SEModule*)objectThis(object);
	for (i = 0; i < pobj->units_count; i++) {
		objectCall0(pobj->units[i], Setup);
	}
	return 0;
}

static int hdl4se_module_hdl4se_module_AddPort(HOBJECT object, int width, int type, const char* name)
{
	sHDL4SEModule* pobj;
	pobj = (sHDL4SEModule*)objectThis(object);
	if (pobj->ports_count >= pobj->ports_arraysize) {
		int i;
		ModulePort* ports = (ModulePort*)malloc(pobj->ports_arraysize * 2 * sizeof(ModulePort));
		if (ports == NULL)
			return -1;
		for (i = 0; i < pobj->ports_count; i++) {
			ports[i] = pobj->ports[i];
		}
		free(pobj->ports);
		pobj->ports = ports;
		pobj->ports_arraysize *= 2;
	}
	pobj->ports[pobj->ports_count].width = width;
	pobj->ports[pobj->ports_count].type = type;
	pobj->ports[pobj->ports_count].name = strdup(name);
	pobj->ports[pobj->ports_count].unit = NULL;
	pobj->ports[pobj->ports_count].unitindex = 0;
	pobj->ports_count++;
	return 0;
}

static int hdl4se_module_hdl4se_module_AddUnit(HOBJECT object, IHDL4SEUnit ** unit)
{
	sHDL4SEModule* pobj;
	pobj = (sHDL4SEModule*)objectThis(object);
	if (pobj->units_count >= pobj->units_arraysize) {
		int i;
		IHDL4SEUnit*** units = (IHDL4SEUnit***)malloc(pobj->units_arraysize * 2 * sizeof(IHDL4SEUnit**));
		if (units == NULL)
			return -1;
		for (i = 0; i < pobj->units_count; i++) {
			units[i] = pobj->units[i];
		}
		free(pobj->units);
		pobj->units = units;
		pobj->units_arraysize *= 2;
	}
	pobj->units[pobj->units_count] = unit;
	pobj->units_count++;
	return 0;
}

static int hdl4se_module_hdl4se_detector_GetName(HOBJECT object, const char** pname)
{
	sHDL4SEModule* pobj;
	pobj = (sHDL4SEModule*)objectThis(object);
	*pname = pobj->name;
	return 0;
}

static int hdl4se_module_hdl4se_detector_GetSignalCount(HOBJECT object)
{
	sHDL4SEModule* pobj;
	pobj = (sHDL4SEModule*)objectThis(object);
	return pobj->ports_count;
}

static int hdl4se_module_hdl4se_detector_GetSignalInfo(HOBJECT object, int index, const char** pname, int *width)
{
	sHDL4SEModule* pobj;
	pobj = (sHDL4SEModule*)objectThis(object);
	if (index < 0 || index >= pobj->ports_count)
		return -1;
	*pname = pobj->ports[index].name;
	*width = pobj->ports[index].width;
	return 0;
}

static int hdl4se_module_hdl4se_detector_GetSignalValue(HOBJECT object, int index, IBigNumber** value)
{
	sHDL4SEModule* pobj;
	pobj = (sHDL4SEModule*)objectThis(object);
	if (index < 0 || index >= pobj->ports_count)
		return -1;
	return hdl4se_module_hdl4se_unit_GetValue(object, index, pobj->ports[index].width, value);
}

static int hdl4se_module_hdl4se_detector_GetUnitCount(HOBJECT object)
{
	sHDL4SEModule* pobj;
	pobj = (sHDL4SEModule*)objectThis(object);
	return pobj->units_count;
}

static int hdl4se_module_hdl4se_detector_GetUnit(HOBJECT object, int index, HOBJECT* unit)
{
	sHDL4SEModule* pobj;
	pobj = (sHDL4SEModule*)objectThis(object);
	if (index < 0 || index >= pobj->units_count)
		return -1;
	*unit = pobj->units[index];
	return 0;
}
