#!/usr/bin/python

# Copyright (C) 2020 iopsys Software Solutions AB
# Author: Amin Ben Ramdhane <amin.benramdhane@pivasoftware.com>

import os, sys, time, json
from collections import OrderedDict

arrTypes = { "string": "DMT_STRING",
			"unsignedInt": "DMT_UNINT",
			"unsignedLong": "DMT_UNLONG",
			"int": "DMT_INT",
			"long": "DMT_LONG",
			"boolean": "DMT_BOOL",
			"dateTime": "DMT_TIME",
			"hexBinary": "DMT_HEXBIN",
			"base64": "DMT_BASE64"}

def removefile( filename ):
	try:
		os.remove(filename)
	except OSError:
		pass

def securemkdir( folder ):
	try:
		os.mkdir(folder)
	except:
		pass

def getlastname( name ):
	return name.replace(".{i}", "").split('.')[-2];

def getname( objname ):
	OBJSname = objname
	if (objname.count('.') > 1 and (objname.count('.') != 2 or objname.count('{i}') != 1) ):
		OBJSname = objname.replace("Device", "", 1)
	OBJSname = OBJSname.replace("{i}", "").replace(".", "")
	if (objname.count('.') == 1):
		return OBJSname
	if (objname.count('.') == 2 and objname.count('{i}') == 1):
		OBJSname = "Services" + OBJSname
		return OBJSname
	return OBJSname;

def getoptionparam( value, option ):
	if isinstance(value, dict):
		for obj, val in value.items():
			if obj == option:
				return val
	return None

def getarrayoptionparam( value, option ):
	if isinstance(value, dict):
		for obj, val in value.items():
			if obj == option and isinstance(val, list):
				return val
	return None

def getprotocolsparam( value, option ):
	if isinstance(value, dict):
		for obj, val in value.items():
			if obj == option and isinstance(val, list):
				if len(val) == 2:
					return "BBFDM_BOTH"
				elif val[0] == "usp":
					return "BBFDM_USP"
				else:
					return "BBFDM_CWMP"
	return "BBFDM_BOTH"

def getuniquekeys( value, option ):
	if isinstance(value, dict):
		for obj, val in value.items():
			if obj == option and isinstance(val, list):
				buf = "LIST_KEY{"
				for key in val:
					buf = buf + "\"%s\"" % key + ", "
				buf = buf + "NULL" + "}"
				return buf
	return None

def getargsparam( value ):
	if isinstance(value, dict):
		for obj, val in value.items():
			return obj, val
	return None, None

def getparamtype( value ):
	paramtype = getoptionparam(value, "type")
	return arrTypes.get(paramtype, None)

def objhaschild( value ):
	if isinstance(value, dict):
		for obj, val in value.items():
			if isinstance(val, dict):
				for obj1, val1 in val.items():
					if obj1 == "type" and val1 == "object":
						return 1
	return 0

def objhasparam( value ):
	if isinstance(value, dict):
		for obj, val in value.items():
			if isinstance(val, dict):
				for obj1,val1 in val.items():
					if obj1 == "type" and val1 != "object":
						return 1
	return 0

def get_mapping_param( mappingobj ):
	type = getoptionparam(mappingobj, "type")
	if type == "uci":
		uciobj = getoptionparam(mappingobj, "uci")
		file = getoptionparam(uciobj, "file")
		sectionobj = getoptionparam(uciobj, "section")
		sectiontype = getoptionparam(sectionobj, "type")
		sectionname = getoptionparam(sectionobj, "name")
		sectionindex = getoptionparam(sectionobj, "index")
		optionobj = getoptionparam(uciobj, "option")
		optionname = getoptionparam(optionobj, "name")
		path = getoptionparam(uciobj, "path")
		ref = getoptionparam(uciobj, "ref")
		return type, file, sectiontype, sectionname, sectionindex, optionname, path, ref
	elif type == "ubus":
		ubusobj = getoptionparam(mappingobj, "ubus")
		object = getoptionparam(ubusobj, "object")
		method = getoptionparam(ubusobj, "method")
		argsobj = getoptionparam(ubusobj, "args")
		arg1, arg2 = getargsparam(argsobj)
		key = getoptionparam(ubusobj, "key")
		return type, object, method, arg1, arg2, key, None, None
	elif type == "procfs" or type == "sysfs":
		file = getoptionparam(mappingobj, "file")
		return type, file, None, None, None, None, None, None
	else:
		cliobj = getoptionparam(mappingobj, "cli")
		command = getoptionparam(cliobj, "command")
		argsobj = getoptionparam(cliobj, "args")
		i = 0
		value = ""
		list_length = len(argsobj)
		while i < list_length:
			if value == "":
				value = "\"" + argsobj[i] + "\", "
			elif i == list_length-1:
				value = value + "\"" + argsobj[i] + "\""
			else:
				value = value + "\"" + argsobj[i] + "\", "
			i += 1
		return type, command, list_length, value, None, None, None, None

def printGlobalstrCommon( str_exp ):
	if "tr104" in sys.argv[1]:
		common = "tr104/common.c"
	else:
		common = "tr181/common.c"
	fp = open(common, 'a')
	print("%s" % str_exp, file=fp)
	fp.close()

def get_mapping_obj( mappingobj ):
	type = getoptionparam(mappingobj, "type")
	if type == "uci":
		uciobj = getoptionparam(mappingobj, "uci")
		file = getoptionparam(uciobj, "file")
		sectionobj = getoptionparam(uciobj, "section")
		sectiontype = getoptionparam(sectionobj, "type")
		dmmapfile = getoptionparam(uciobj, "dmmapfile")
		return type, file, sectiontype, dmmapfile, None, None
	elif type == "ubus":
		ubusobj = getoptionparam(mappingobj, "ubus")
		object = getoptionparam(ubusobj, "object")
		method = getoptionparam(ubusobj, "method")
		argsobj = getoptionparam(ubusobj, "args")
		arg1, arg2 = getargsparam(argsobj)
		key = getoptionparam(ubusobj, "key")
		return type, object, method, arg1, arg2, key
	else:
		return type, None, None, None, None, None

def generate_validate_value(dmparam, value):
	validate_value = ""
	maxsizeparam = "-1"
	itemminparam = "-1"
	itemmaxparam = "-1"
	rangeminparam = "NULL"
	rangemaxparam = "NULL"

	listparam = getoptionparam(value, "list")
	if listparam != None:
		datatypeparam = getoptionparam(listparam, "datatype")
		maxsizeparam = getoptionparam(listparam, "maxsize")
		if maxsizeparam == None: maxsizeparam = "-1"
		itemparam = getoptionparam(listparam, "item")
		if itemparam != None:
			itemminparam = getoptionparam(itemparam, "min")
			if itemminparam == None: itemminparam = "-1"
			itemmaxparam = getoptionparam(itemparam, "max")
			if itemmaxparam == None: itemmaxparam = "-1"

		rangeparam = getarrayoptionparam(listparam, "range")
		if rangeparam != None:
			range_length = len(rangeparam)
			rangeargs = "RANGE_ARGS{"
			for i in range(range_length - 1):
				rangeminparam = getoptionparam(rangeparam[i], "min")
				if rangeminparam == None: rangeminparam = "NULL"
				rangemaxparam = getoptionparam(rangeparam[i], "max")
				if rangemaxparam == None: rangemaxparam = "NULL"
				rangeargs += "{\"%s\",\"%s\"}," % (rangeminparam, rangemaxparam)
			rangeminparam = getoptionparam(rangeparam[range_length - 1], "min")
			if rangeminparam == None: rangeminparam = "NULL"
			rangemaxparam = getoptionparam(rangeparam[range_length - 1], "max")
			if rangemaxparam == None: rangemaxparam = "NULL"
			rangeargs += "{\"%s\",\"%s\"}}, %s" % (rangeminparam, rangemaxparam, range_length)
		else:
			rangeargs = "RANGE_ARGS{{NULL,NULL}}, 1"

		enumarationsparam = getarrayoptionparam(listparam, "enumerations")
		if enumarationsparam != None:
			list_enumarationsparam = enumarationsparam
			enum_length = len(list_enumarationsparam)
			enumarationsparam = dmparam if datatypeparam == "string" else datatypeparam
			str_enum = "char *%s[] = {" % enumarationsparam
			for i in range(enum_length - 1):
				str_enum += "\"%s\", " % list_enumarationsparam[i]
			str_enum += "\"%s\"};" % list_enumarationsparam[enum_length - 1]
			printGlobalstrCommon(str_enum)
		else:
			enumarationsparam = "NULL"
			enum_length = "0"

		patternparam = getarrayoptionparam(listparam, "pattern")
		if patternparam != None:
			list_patternparam = patternparam
			pattern_length = len(list_patternparam)
			patternparam = dmparam if datatypeparam == "string" else datatypeparam
			str_pattern = "char *%s[] = {" % patternparam
			for i in range(pattern_length - 1):
				str_pattern += "\"^%s$\", " % list_patternparam[i]
			str_pattern += "\"^%s$\"};" % list_patternparam[pattern_length - 1]
			printGlobalstrCommon(str_pattern)
		elif datatypeparam == "IPAddress":
			patternparam = "IPAddress"
			pattern_length = "2"
		elif datatypeparam == "IPv6Address":
			patternparam = "IPv6Address"
			pattern_length = "1"
		elif datatypeparam == "IPPrefix":
			patternparam = "IPPrefix"
			pattern_length = "3"
		elif datatypeparam == "IPv6Prefix":
			patternparam = "IPv6Prefix"
			pattern_length = "1"
		else:
			patternparam = "NULL"
			pattern_length = "0"

		if datatypeparam == "unsignedInt":
			validate_value += "			if (dm_validate_unsignedInt_list(value, %s, %s, %s, %s))\n" % (itemminparam, itemmaxparam, maxsizeparam, rangeargs)
		else:
			if rangeminparam == "NULL": rangeminparam = "-1"
			if rangemaxparam == "NULL": rangemaxparam = "-1"
			validate_value += "			if (dm_validate_string_list(value, %s, %s, %s, %s, %s, %s, %s, %s, %s))\n" % (itemminparam, itemmaxparam, maxsizeparam, rangeminparam, rangemaxparam, enumarationsparam, enum_length, patternparam, pattern_length)
	else:
		datatypeparam = getoptionparam(value, "datatype")
		rangeparam = getarrayoptionparam(value, "range")
		if rangeparam != None:
			range_length = len(rangeparam)
			rangeargs = "RANGE_ARGS{"
			for i in range(range_length - 1):
				rangeminparam = getoptionparam(rangeparam[i], "min")
				if rangeminparam == None: rangeminparam = "NULL"
				rangemaxparam = getoptionparam(rangeparam[i], "max")
				if rangemaxparam == None: rangemaxparam = "NULL"
				rangeargs += "{\"%s\",\"%s\"}," % (rangeminparam, rangemaxparam)
			rangeminparam = getoptionparam(rangeparam[range_length - 1], "min")
			if rangeminparam == None: rangeminparam = "NULL"
			rangemaxparam = getoptionparam(rangeparam[range_length - 1], "max")
			if rangemaxparam == None: rangemaxparam = "NULL"
			rangeargs += "{\"%s\",\"%s\"}}, %s" % (rangeminparam, rangemaxparam, range_length)
		else:
			rangeargs = "RANGE_ARGS{{NULL,NULL}}, 1"

		enumarationsparam = getarrayoptionparam(value, "enumerations")
		if enumarationsparam != None:
			list_enumarationsparam = enumarationsparam
			enum_length = len(list_enumarationsparam)
			enumarationsparam = dmparam if datatypeparam == "string" else datatypeparam
			str_enum = "char *%s[] = {" % enumarationsparam
			for i in range(enum_length - 1):
				str_enum += "\"%s\", " % list_enumarationsparam[i]
			str_enum += "\"%s\"};" % list_enumarationsparam[enum_length - 1]
			printGlobalstrCommon(str_enum)
		else:
			enumarationsparam = "NULL"
			enum_length = "0"

		patternparam = getarrayoptionparam(value, "pattern")
		if patternparam != None:
			list_patternparam = patternparam
			pattern_length = len(list_patternparam)
			patternparam = dmparam if datatypeparam == "string" else datatypeparam
			str_pattern = "char *%s[] = {" % patternparam
			for i in range(pattern_length - 1):
				str_pattern += "\"^%s$\", " % list_patternparam[i]
			str_pattern += "\"^%s$\"};" % list_patternparam[pattern_length - 1]
			printGlobalstrCommon(str_pattern)
		elif datatypeparam == "IPAddress":
			patternparam = "IPAddress"
			pattern_length = "2"
		elif datatypeparam == "IPv6Address":
			patternparam = "IPv6Address"
			pattern_length = "1"
		elif datatypeparam == "IPPrefix":
			patternparam = "IPPrefix"
			pattern_length = "3"
		elif datatypeparam == "IPv6Prefix":
			patternparam = "IPv6Prefix"
			pattern_length = "1"
		else:
			patternparam = "NULL"
			pattern_length = "0"

		if datatypeparam == "boolean":
			validate_value += "			if (dm_validate_boolean(value))\n"
		elif datatypeparam == "unsignedInt":
			validate_value += "			if (dm_validate_unsignedInt(value, %s))\n" % rangeargs
		elif datatypeparam == "int":
			validate_value += "			if (dm_validate_int(value, %s))\n" % rangeargs
		elif datatypeparam == "unsignedLong":
			validate_value += "			if (dm_validate_unsignedLong(value, %s))\n" % rangeargs
		elif datatypeparam == "long":
			validate_value += "			if (dm_validate_long(value, %s))\n" % rangeargs
		elif datatypeparam == "dateTime":
			validate_value += "			if (dm_validate_dateTime(value))\n"
		elif datatypeparam == "hexBinary":
			if rangeminparam == "NULL": rangeminparam = "-1"
			if rangemaxparam == "NULL": rangemaxparam = "-1"
			validate_value += "			if (dm_validate_hexBinary(value, %s))\n" % rangeargs		
		else:
			if rangeminparam == "NULL": rangeminparam = "-1"
			if rangemaxparam == "NULL": rangemaxparam = "-1"
			validate_value += "			if (dm_validate_string(value, %s, %s, %s, %s, %s, %s))\n" % (rangeminparam, rangemaxparam, enumarationsparam, enum_length, patternparam, pattern_length)
	validate_value += "				return FAULT_9007;"
	validate_value = validate_value.replace("\"NULL\"", "NULL")
	return validate_value

def printheaderObjCommon( objname ):
	fp = open('./.objparamarray.c', 'a')
	print("/* *** %s *** */" % objname, file=fp)
	fp.close()

def cprintheaderOBJS( objname ):
	fp = open('./.objparamarray.c', 'a')
	print("DMOBJ %s[] = {" % ("t" + getname(objname) + "Obj"), file=fp)
	print("/* OBJ, permission, addobj, delobj, checkdep, browseinstobj, nextdynamicobj, nextobj, leaf, linker, bbfdm_type, uniqueKeys*/", file=fp)
	fp.close()

def hprintheaderOBJS( objname ):
	fp = open('./.objparamarray.h', 'a')
	print("extern DMOBJ %s[];" % ("t" + getname(objname) + "Obj"), file=fp)
	fp.close()

def cprinttopfile (fp, filename):
	print("/*", file=fp)
	print(" * Copyright (C) 2020 iopsys Software Solutions AB", file=fp)
	print(" *", file=fp)
	print(" * This program is free software; you can redistribute it and/or modify", file=fp)
	print(" * it under the terms of the GNU Lesser General Public License version 2.1", file=fp)
	print(" * as published by the Free Software Foundation", file=fp)
	print(" *", file=fp)
	print(" *	Author: <Name> <Surname> <name.surname@iopsys.eu>", file=fp)
	print(" */", file=fp)
	print("", file=fp)
	print("#include \"%s.h\"" % filename.lower(), file=fp)
	print("", file=fp)

def hprinttopfile (fp, filename):
	print("/*", file=fp)
	print(" * Copyright (C) 2020 iopsys Software Solutions AB", file=fp)
	print(" *", file=fp)
	print(" * This program is free software; you can redistribute it and/or modify", file=fp)
	print(" * it under the terms of the GNU Lesser General Public License version 2.1", file=fp)
	print(" * as published by the Free Software Foundation", file=fp)
	print(" *", file=fp)
	print(" *	Author: <Name> <Surname> <name.surname@iopsys.eu>", file=fp)
	print(" */", file=fp)
	print("", file=fp)
	print("#ifndef __%s_H" % filename.upper(), file=fp)
	print("#define __%s_H" % filename.upper(), file=fp)
	print("", file=fp)
	print("#include <libbbf_api/dmcommon.h>", file=fp)
	print("", file=fp)

def hprintfootfile (fp, filename):
	print("", file=fp)
	print("#endif //__%s_H" % filename.upper(), file=fp)
	print("", file=fp)

def cprintAddDelObj( faddobj, fdelobj, name, mappingobj, dmobject ):
	fp = open('./.objadddel.c', 'a')
	print("static int %s(char *refparam, struct dmctx *ctx, void *data, char **instance)" % faddobj, file=fp)
	print("{", file=fp)
	if mappingobj != None:
		type, file, sectiontype, dmmapfile, path, ref = get_mapping_obj(mappingobj)
		if type == "uci":
			print("	struct uci_section *dmmap = NULL, *s = NULL;", file=fp)
			print("", file=fp)
			print("	char *inst = get_last_instance_bbfdm(\"%s\", \"%s\", \"%s\");" % (dmmapfile, sectiontype, name+"instance"), file=fp)
			print("	dmuci_add_section(\"%s\", \"%s\", &s);" % (file, sectiontype), file=fp)
			print("	//dmuci_set_value_by_section(s, \"option\", \"value\");", file=fp)
			print("", file=fp)
			print("	dmuci_add_section_bbfdm(\"%s\", \"%s\", &dmmap);" % (dmmapfile, sectiontype), file=fp)
			print("	dmuci_set_value_by_section(dmmap, \"section_name\", section_name(s));", file=fp)
			print("	*instance = update_instance(inst, 4, dmmap, \"%s\");" % (name+"instance"), file=fp)
	else:
		print("	//TODO", file=fp)
	print("	return 0;", file=fp)
	print("}", file=fp)
	print("", file=fp)
	print("static int %s(char *refparam, struct dmctx *ctx, void *data, char *instance, unsigned char del_action)" % fdelobj, file=fp)
	print("{", file=fp)
	if mappingobj != None:
		if type == "uci":
			print("	struct uci_section *s = NULL, *ss = NULL, *dmmap_section = NULL;", file=fp)
			print("	int found = 0;", file=fp)
			print("", file=fp)
	print("	switch (del_action) {", file=fp)
	if mappingobj != None:
		if type == "uci":
			print("		case DEL_INST:", file=fp)
			print("			get_dmmap_section_of_config_section(\"%s\", \"%s\", section_name((struct uci_section *)data), &dmmap_section);" % (dmmapfile, sectiontype), file=fp)
			print("			if (dmmap_section != NULL)", file=fp)
			print("				dmuci_delete_by_section(dmmap_section, NULL, NULL);", file=fp)
			print("			dmuci_delete_by_section((struct uci_section *)data, NULL, NULL);", file=fp)
			print("			break;", file=fp)
			print("		case DEL_ALL:", file=fp)
			print("			uci_foreach_sections(\"%s\", \"%s\", s) {" % (file, sectiontype), file=fp)
			print("				if (found != 0) {", file=fp)
			print("					get_dmmap_section_of_config_section(\"%s\", \"%s\", section_name(ss), &dmmap_section);" % (dmmapfile, sectiontype), file=fp)
			print("					if (dmmap_section != NULL)", file=fp)
			print("						dmuci_delete_by_section(dmmap_section, NULL, NULL);", file=fp)
			print("					dmuci_delete_by_section(ss, NULL, NULL);", file=fp)
			print("				}", file=fp)
			print("				ss = s;", file=fp)
			print("				found++;", file=fp)
			print("			}", file=fp)
			print("			if (ss != NULL) {", file=fp)
			print("				get_dmmap_section_of_config_section(\"%s\", \"%s\", section_name(ss), &dmmap_section);" % (dmmapfile, sectiontype), file=fp)
			print("				if (dmmap_section != NULL)", file=fp)
			print("					dmuci_delete_by_section(dmmap_section, NULL, NULL);", file=fp)
			print("				dmuci_delete_by_section(ss, NULL, NULL);", file=fp)
			print("			}", file=fp)
			print("			break;", file=fp)
	else:
		print("		case DEL_INST:", file=fp)
		print("			//TODO", file=fp)
		print("			break;", file=fp)
		print("		case DEL_ALL:", file=fp)
		print("			//TODO", file=fp)
		print("			break;", file=fp)
	print("	}", file=fp)
	print("	return 0;", file=fp)
	print("}", file=fp)
	print("", file=fp)
	fp.close()

def cprintBrowseObj( fbrowse, name, mappingobj, dmobject ):
	# Open file
	fp = open('./.objbrowse.c', 'a')

	### Mapping Parameter
	if mappingobj != None:
		type, res1, res2, res3, res4, res5 = get_mapping_obj(mappingobj)
		if type == "uci" :
			print("/*#%s!%s:%s/%s/%s*/" % (dmobject, type.upper(), res1, res2, res3), file=fp)
		elif type == "ubus" :
			print("/*#%s!%s:%s/%s/%s,%s/%s*/" % (dmobject, type.upper(), res1, res2, res3, res4, res5), file=fp)

	print("static int %s(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance)" % fbrowse, file=fp)
	print("{", file=fp)

	# Mapping exist
	if mappingobj != None:

		############################## UCI ########################################
		if type == "uci" :
			print("	char *inst = NULL, *max_inst = NULL;", file=fp)
			print("	struct dmmap_dup *p;", file=fp)
			print("	LIST_HEAD(dup_list);", file=fp)
			print("", file=fp)
			print("	synchronize_specific_config_sections_with_dmmap(\"%s\", \"%s\", \"%s\", &dup_list);" % (res1, res2, res3), file=fp)
			print("	list_for_each_entry(p, &dup_list, list) {", file=fp)
			print("", file=fp)
			print("		inst = handle_update_instance(1, dmctx, &max_inst, update_instance_alias, 5,", file=fp)
			print("			   p->dmmap_section, \"%s\", \"%s\", \"%s\", \"%s\");" % (name+"instance", name+"alias", res3, res2), file=fp)
			print("", file=fp)
			print("		if (DM_LINK_INST_OBJ(dmctx, parent_node, (void *)p->config_section, inst) == DM_STOP)", file=fp)
			print("			break;", file=fp)
			print("	}", file=fp)
			print("	free_dmmap_config_dup_list(&dup_list);", file=fp)


		############################## UBUS ########################################
		elif type == "ubus" :
			print("	json_object *res = NULL, *obj = NULL, *arrobj = NULL;", file=fp)
			print("	char *inst = NULL, *max_inst = NULL;", file=fp)
			print("	int id = 0, i = 0;", file=fp)
			print("", file=fp)
			if res3 == None and res4 == None:
				print("	dmubus_call(\"%s\", \"%s\", UBUS_ARGS{}, 0, &res);" % (res1, res2), file=fp)
			else:
				print("	dmubus_call(\"%s\", \"%s\", UBUS_ARGS{{\"%s\", \"%s\", String}}, 1, &res);" % (res1, res2, res3, res4), file=fp)
			print("	if (res) {", file=fp)
			print("		dmjson_foreach_obj_in_array(res, arrobj, obj, i, 1, \"%s\") {" % res5, file=fp)
			print("", file=fp)
			print("			inst = handle_update_instance(1, dmctx, &max_inst, update_instance_without_section, 1, ++id);", file=fp)
			print("", file=fp)
			print("			if (DM_LINK_INST_OBJ(dmctx, parent_node, (void *)obj, inst) == DM_STOP)", file=fp)
			print("				break;", file=fp)
			print("		}", file=fp)
			print("	}", file=fp)

	# Mapping doesn't exist
	else:
		print("	//TODO", file=fp)
	print("	return 0;", file=fp)
	print("}", file=fp)
	print("", file=fp)

	# Close file
	fp.close()

def cprintGetSetValue(getvalue, setvalue, mappingparam, instance, typeparam, parentname, dmparam, value):
	# Open file
	fp = open('./.getstevalue.c', 'a')

	# Generate Validate value
	validate_value = ""
	if setvalue != "NULL":
		validate_value = generate_validate_value(dmparam, value)

	# Mapping exist
	if mappingparam != None:
		count = len(mappingparam)
		i = 0
		mapping = ""
		tmpgetvalue = ""
		tmpsetvalue = ""
		set_value = ""
		for element in mappingparam:
			type, res1, res2, res3, res4, res5, res6, res7 = get_mapping_param(element)
			get_value = ""
			i += 1

			############################## UCI ########################################
			if type == "uci":
				### Mapping Parameter
				if res3 != None:
					mapping = "%s:%s/%s,%s/%s" % (type.upper(), res1, res2, res3, res5)
				else:
					mapping = "%s:%s/%s,%s/%s" % (type.upper(), res1, res2, res4, res5)

				### GET VALUE Parameter
				if "NumberOfEntries" in dmparam:
					get_value += "	struct uci_section *s = NULL;\n"
					get_value += "	int cnt = 0;\n"
					get_value += "\n"
					get_value += "	uci_foreach_sections(\"%s\", \"%s\", s) {\n" % (res1, res2)
					get_value += "		cnt++;\n"
					get_value += "	}\n"
					get_value += "	dmasprintf(value, \"%d\", cnt);"
				elif "Alias" in dmparam:
					get_value += "	struct uci_section *dmmap_section = NULL;\n"
					get_value += "\n"
					get_value += "	get_dmmap_section_of_config_section(\"%s\", \"%s\", section_name((struct uci_section *)data), &dmmap_section);\n" % (res1, res2)
					get_value += "	dmuci_get_value_by_section_string(dmmap_section, \"%s\", value);\n" % res5
					get_value += "	if ((*value)[0] == '\\0')\n"
					get_value += "		dmasprintf(value, \"cpe-%s\", instance);"
				elif instance == "TRUE" and res6 != None:
					get_value += "	char uci_type[32] = {0};\n"
					get_value += "\n"
					get_value += "	snprintf(uci_type, sizeof(uci_type), \"@%s[%s]\", instance ? atoi(instance)-1 : 0);\n" % (res2, "%d")
					get_value += "	*value = bbf_uci_get_value(\"%s\", \"%s\", uci_type, \"%s\");" % (res6, res1, res5)
				elif instance == "TRUE" and res7 != None:
					get_value += "	char *linker = dmstrdup(*value);\n"
					get_value += "	adm_entry_get_linker_param(ctx, \"%s\", linker, value);\n" % res7
					get_value += "	dmfree(linker);\n"
					get_value += "	if (*value == NULL)\n"
					get_value += "		*value = \"\";"
				elif res6 != None:
					get_value += "	*value = bbf_uci_get_value(\"%s\", \"%s\", \"%s\", \"%s\");" % (res6, res1, res3, res5)
				elif instance == "TRUE":
					get_value += "	dmuci_get_value_by_section_string((struct uci_section *)data, \"%s\", value);" % res5
				else:
					get_value += "	dmuci_get_option_value_string(\"%s\", \"%s\", \"%s\", value);" % (res1, res3, res5)

				### SET VALUE Parameter
				set_value += "	switch (action)	{\n"
				set_value += "		case VALUECHECK:\n"
				set_value += "%s\n" % validate_value
				set_value += "			break;\n"
				set_value += "		case VALUESET:\n"
				if typeparam == "boolean":
					set_value += "			string_to_bool(value, &b);\n"
					if instance == "TRUE":
						set_value += "			dmuci_set_value_by_section((struct uci_section *)data, \"%s\", b ? \"1\" : \"0\");" % res5
					else:
						set_value += "			dmuci_set_value(\"%s\", \"%s\", \"%s\", b ? \"1\" : \"0\");" % (res1, res3, res5)
				elif instance == "TRUE":
					set_value += "			dmuci_set_value_by_section((struct uci_section *)data, \"%s\", value);" % res5
				else:
					set_value += "			dmuci_set_value(\"%s\", \"%s\", \"%s\", value);" % (res1, res3, res5)
			

			############################## UBUS ########################################
			elif type == "ubus":
				### Mapping Parameter
				if res3 != None and res4 != None:
					mapping = "%s:%s/%s/%s,%s/%s" % (type.upper(), res1, res2, res3, res4, res5)
				else:
					mapping = "%s:%s/%s//%s" % (type.upper(), res1, res2, res5)

				### GET VALUE Parameter
				if instance == "TRUE":
					options = res5.split(".")
					if len(options) == 3:
						get_value += "	*value = dmjson_get_value((json_object *)data, 2, \"%s\", \"%s\");\n" % (options[1], options[2])
					elif len(options) == 2:
						get_value += "	*value = dmjson_get_value((json_object *)data, 1, \"%s\");\n" % options[1]
				else:
					get_value += "	json_object *res;\n"
					if res3 == None and res4 == None:
						get_value += "	dmubus_call(\"%s\", \"%s\", UBUS_ARGS{}, 0, &res);\n" % (res1, res2)
					else:
						if i == 2 and res4 == "prev_value":
							get_value += "	dmubus_call(\"%s\", \"%s\", UBUS_ARGS{{\"%s\", *value, String}}, 1, &res);\n" % (res1, res2, res3)

						elif i == 2 and res4 == "@Name":
							get_value += "	if (*value[0] == '\\0')\n"
							get_value += "	{\n"
							get_value += "	dmubus_call(\"%s\", \"%s\", UBUS_ARGS{{\"%s\", section_name((struct uci_section *)data), String}}, 1, &res);\n" % (res1, res2, res3)
						elif res4 == "@Name":
							get_value += "	dmubus_call(\"%s\", \"%s\", UBUS_ARGS{{\"%s\", section_name((struct uci_section *)data), String}}, 1, &res);\n" % (res1, res2, res3)
						else:
							get_value += "	dmubus_call(\"%s\", \"%s\", UBUS_ARGS{{\"%s\", \"%s\", String}}, 1, &res);\n" % (res1, res2, res3, res4)

					get_value += "	DM_ASSERT(res, *value = \"\");\n"
					option = res5.split(".")
					if "." in res5:
						if option[0] == "@Name":
							get_value += "	*value = dmjson_get_value(res, 2, section_name((struct uci_section *)data), \"%s\");" % (option[1])
						else:
							get_value += "	*value = dmjson_get_value(res, 2, \"%s\", \"%s\");" % (option[0], option[1])
					else:
						get_value += "	*value = dmjson_get_value(res, 1, \"%s\");" % option[0]
					if i == 2 and res4 == "@Name":
						get_value += "\n	}"

				### SET VALUE Parameter
				set_value += "	switch (action)	{\n"
				set_value += "		case VALUECHECK:\n"
				set_value += "%s\n" % validate_value
				set_value += "			break;\n"
				set_value += "		case VALUESET:\n"
				set_value += "			//TODO"


			############################## SYSFS ########################################
			elif type == "sysfs":
				### Mapping Parameter
				mapping = "%s:%s" % (type.upper(), res1)

				### GET VALUE Parameter
				if res1[:15] == "/sys/class/net/" and res1[15:20] == "@Name":
					get_value += "	get_net_device_sysfs(section_name((struct uci_section *)data), \"%s\", value);" % res1[21:]
				else:
					get_value += "	char val[64];\n"
					get_value += "\n"
					get_value += "	dm_read_sysfs_file(\"%s\", val, sizeof(val));\n" % res1
					get_value += "	*value = dmstrdup(val);"


			############################## PROCFS ########################################
			elif type == "procfs":
				### Mapping Parameter
				mapping = "%s:%s" % (type.upper(), res1)

				### GET VALUE Parameter
				get_value += "	char val[64];\n"
				get_value += "\n"
				get_value += "	dm_read_sysfs_file(\"%s\", val, sizeof(val));\n" % res1
				get_value += "	*value = dmstrdup(val);"


			############################## CLI ########################################
			elif type == "cli":
				### GET VALUE Parameter
				get_value += "	dmcmd(\"%s\", %s, %s);" % (res1, res2, res3)

			if count == 2 and i == 1:
				tmpmapping = mapping
				tmpgetvalue = get_value
				tmpsetvalue = set_value
			elif count == 2 and i == 2:
				print("/*#%s!%s&%s*/" % (parentname+dmparam, tmpmapping, mapping), file=fp)
				print("static int %s(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)" % getvalue, file=fp)
				print("{", file=fp)
				print("%s" % tmpgetvalue, file=fp)
				print("%s" % get_value, file=fp)
				print("	return 0;", file=fp)
				print("}", file=fp)
				print("", file=fp)
				if setvalue != "NULL":
					print("static int %s(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)" % setvalue, file=fp)
					print("{", file=fp)
					print("%s" % tmpsetvalue, file=fp)
					print("			break;", file=fp)
					print("	}", file=fp)
					print("	return 0;", file=fp)
					print("}", file=fp)
					print("", file=fp)
			else:
				print("/*#%s!%s*/" % (parentname+dmparam, mapping), file=fp)
				print("static int %s(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)" % getvalue, file=fp)
				print("{", file=fp)
				print("%s" % get_value, file=fp)
				print("	return 0;", file=fp)
				print("}", file=fp)
				print("", file=fp)
				if setvalue != "NULL":
					print("static int %s(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)" % setvalue, file=fp)
					print("{", file=fp)
					print("%s" % set_value, file=fp)
					print("			break;", file=fp)
					print("	}", file=fp)
					print("	return 0;", file=fp)
					print("}", file=fp)
					print("", file=fp)
	

	# Mapping doesn't exist
	else:
		print("static int %s(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)" % getvalue, file=fp)
		print("{", file=fp)
		print("	//TODO", file=fp)
		print("	return 0;", file=fp)
		print("}", file=fp)
		print("", file=fp)
		if setvalue != "NULL":
			print("static int %s(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)" % setvalue, file=fp)
			print("{", file=fp)
			print("	switch (action)	{", file=fp)
			print("		case VALUECHECK:", file=fp)
			print("%s" % validate_value, file=fp)
			print("			break;", file=fp)
			print("		case VALUESET:", file=fp)
			print("			//TODO", file=fp)
			print("			break;", file=fp)
			print("	}", file=fp)
			print("	return 0;", file=fp)
			print("}", file=fp)
			print("", file=fp)

	# Close file
	fp.close()

def cprintheaderPARAMS( objname ):
	fp = open('./.objparamarray.c', 'a')
	print("DMLEAF %s[] = {" % ("t" + getname(objname) + "Params"), file=fp)
	print("/* PARAM, permission, type, getvalue, setvalue, bbfdm_type*/", file=fp)
	fp.close()

def hprintheaderPARAMS( objname ):
	fp = open('./.objparamarray.h', 'a')
	print("extern DMLEAF %s[];" % ("t" + getname(objname) + "Params"), file=fp)
	fp.close()

def printPARAMline( parentname, dmparam, value ):
	commonname = getname(parentname) + "_" + dmparam
	ptype = getparamtype(value)
	getvalue = "get_" + commonname
	mappingparam = getoptionparam(value, "mapping")
	typeparam = getoptionparam(value, "type")
	bbfdm = getprotocolsparam(value, "protocols")
	accessparam = getoptionparam(value, "write")

	if accessparam:
		access = "&DMWRITE"
		setvalue = "set_" + commonname
	else:
		access = "&DMREAD"
		setvalue = "NULL"

	if parentname.endswith(".{i}."):
		instance = "TRUE"
	else:
		instance = "FALSE"

	cprintGetSetValue(getvalue, setvalue, mappingparam, instance, typeparam, parentname, dmparam, value)

	fp = open('./.objparamarray.c', 'a')
	print("{\"%s\", %s, %s, %s, %s, %s}," % (dmparam, access, ptype, getvalue, setvalue, bbfdm), file=fp)
	fp.close()

def printtailArray( ):
	fp = open('./.objparamarray.c', 'a')
	print("{0}", file=fp)
	print("};", file=fp)
	print("", file=fp)
	fp.close()

def printOBJline( dmobject, value ):
	commonname = getname(dmobject)
	hasobj = objhaschild(value)
	hasparam = objhasparam(value)
	accessobj = getoptionparam(value, "access")
	mappingobj = getoptionparam(value, "mapping")
	bbfdm = getprotocolsparam(value, "protocols")
	uniquekeys = getuniquekeys(value, "uniqueKeys")

	if accessobj:
		access = "&DMWRITE"
		faddobj = "addObj" + commonname
		fdelobj = "delObj" + commonname
		cprintAddDelObj(faddobj, fdelobj, (getlastname(dmobject)).lower(), mappingobj, dmobject)
	else:
		access = "&DMREAD"
		faddobj = "NULL"
		fdelobj = "NULL"

	if dmobject.endswith(".{i}."):
		fbrowse = "browse" + commonname + "Inst"
		cprintBrowseObj(fbrowse, (getlastname(dmobject)).lower(), mappingobj, dmobject)
	else:
		fbrowse = "NULL"

	if hasobj:
		objchildarray = "t" + commonname + "Obj"
	else:
		objchildarray = "NULL"

	if hasparam:
		paramarray = "t" + commonname + "Params"
	else:
		paramarray = "NULL"

	fp = open('./.objparamarray.c', 'a')
	if uniquekeys:
		print("{\"%s\", %s, %s, %s, NULL, %s, NULL, %s, %s, NULL, %s, %s}," % (getlastname(dmobject), access, faddobj, fdelobj, fbrowse, objchildarray, paramarray, bbfdm, uniquekeys), file=fp)
	else:
		print("{\"%s\", %s, %s, %s, NULL, %s, NULL, %s, %s, NULL, %s}," % (getlastname(dmobject), access, faddobj, fdelobj, fbrowse, objchildarray, paramarray, bbfdm), file=fp)
	fp.close()

def printusage():
	print("Usage: " + sys.argv[0] + " <json data model>" + " [Object path]")
	print("Examples:")
	print("  - " + sys.argv[0] + " tr181.json")
	print("    ==> Generate the C code of all data model in tr181/ folder")
	print("  - " + sys.argv[0] + " tr104.json")
	print("    ==> Generate the C code of all data model in tr104/ folder")
	print("  - " + sys.argv[0] + " tr181.json" + " Device.DeviceInfo.")
	print("    ==> Generate the C code of DeviceInfo object in tr181/ folder")
	print("  - " + sys.argv[0] + " tr181.json" + " Device.WiFi.")
	print("    ==> Generate the C code of WiFi object in tr181/ folder")
	print("  - " + sys.argv[0] + " tr104.json" + " Device.Services.VoiceService.{i}.Capabilities.")
	print("    ==> Generate the C code of Services.VoiceService.{i}.Capabilities. object in tr104/ folder")

def object_parse_childs( dmobject , value, nextlevel ):
	hasobj = objhaschild(value)
	hasparam = objhasparam(value)

	if hasobj or hasparam:
		printheaderObjCommon(dmobject)

	if hasobj:
		cprintheaderOBJS(dmobject)
		hprintheaderOBJS(dmobject)

		if isinstance(value,dict):
			for k,v in value.items():
				if isinstance(v,dict):
					for k1,v1 in v.items():
						if k1 == "type" and v1 == "object":
							printOBJline(k, v)
							break
		printtailArray()

	if hasparam:
		cprintheaderPARAMS(dmobject)
		hprintheaderPARAMS(dmobject)
		if isinstance(value,dict):
			for k,v in value.items():
				if k == "mapping":
					continue
				if isinstance(v,dict):
					for k1,v1 in v.items():
						if k1 == "type" and v1 != "object":
							printPARAMline(dmobject, k, v)
							break
		printtailArray()

	if hasobj and nextlevel == 0:
		if isinstance(value,dict):
			for k,v in value.items():
				if isinstance(v,dict):
					for k1,v1 in v.items():
						if k1 == "type" and v1 == "object":
							object_parse_childs(k , v, 0)

def generatecfromobj( pobj, pvalue, pdir, nextlevel ):
	securemkdir(pdir)
	removetmpfiles()
	object_parse_childs(pobj, pvalue, nextlevel)
	
	dmfpc = open(pdir + "/" +  getname(pobj).lower() + ".c", "w")
	dmfph = open(pdir + "/" +  getname(pobj).lower() + ".h", "w")
	cprinttopfile(dmfpc, getname(pobj).lower())
	hprinttopfile(dmfph, getname(pobj).lower())

	try:
		exists = os.path.isfile("./.objbrowse.c")
		if exists:
			print("/*************************************************************", file=dmfpc)
			print("* ENTRY METHOD", file=dmfpc)
			print("**************************************************************/", file=dmfpc)
		tmpf = open("./.objbrowse.c", "r")
		tmpd = tmpf.read()
		tmpf.close()
		dmfpc.write(tmpd)
	except:
		pass
	try:
		exists = os.path.isfile("./.objadddel.c")
		if exists:
			print("/*************************************************************", file=dmfpc)
			print("* ADD & DEL OBJ", file=dmfpc)
			print("**************************************************************/", file=dmfpc)
		tmpf = open("./.objadddel.c", "r")
		tmpd = tmpf.read()
		tmpf.close()
		dmfpc.write(tmpd)
	except:
		pass
	try:
		exists = os.path.isfile("./.getstevalue.c")
		if exists:
			print("/*************************************************************", file=dmfpc)
			print("* GET & SET PARAM", file=dmfpc)
			print("**************************************************************/", file=dmfpc)
		tmpf = open("./.getstevalue.c", "r")
		tmpd = tmpf.read()
		tmpf.close()
		dmfpc.write(tmpd)
	except:
		pass
	try:
		print("/**********************************************************************************************************************************", file=dmfpc)
		print("*                                            OBJ & PARAM DEFINITION", file=dmfpc)
		print("***********************************************************************************************************************************/", file=dmfpc)
		tmpf = open("./.objparamarray.c", "r")
		tmpd = tmpf.read()
		tmpf.close()
		dmfpc.write(tmpd)
	except:
		pass
	try:
		tmpf = open("./.objparamarray.h", "r")
		tmpd = tmpf.read()
		tmpf.close()
		dmfph.write(tmpd)
		print >> dmfph,  ""
	except:
		pass

	hprintfootfile (dmfph, getname(pobj).lower())
	removetmpfiles()
	

def removetmpfiles():
	removefile("./.objparamarray.c")
	removefile("./.objparamarray.h")
	removefile("./.objadddel.c")
	removefile("./.objbrowse.c")
	removefile("./.getstevalue.c")

### main ###
if len(sys.argv) < 2:
	printusage()
	exit(1)
	
if (sys.argv[1]).lower() == "-h" or (sys.argv[1]).lower() == "--help":
	printusage()
	exit(1)

json_file = sys.argv[1] # tr181.json

# load json file
with open(json_file) as file:
	data = json.loads(file.read(), object_pairs_hook=OrderedDict)

if "tr181" in sys.argv[1]: # TR181 JSON File
	gendir = "tr181"
elif "tr104" in sys.argv[1]: # TR104 JSON File 
	gendir = "tr104"
elif "tr106" in sys.argv[1]: # TR106 JSON File 
	gendir = "tr106"
else:
	gendir = "source_" + time.strftime("%Y-%m-%d_%H-%M-%S")

for obj, value in data.items():
	if obj == None:
		print("Wrong JSON Data model format!")
		exit(1)

	# Generate the object file if it is defined by "sys.argv[2]" argument
	if (len(sys.argv) > 2):
		if sys.argv[2] != obj:
			if isinstance(value, dict):
				for obj1, value1 in value.items():
					if obj1 == sys.argv[2]:
						if isinstance(value1, dict):
							for obj2, value2 in value1.items():
								if obj2 == "type" and value2 == "object":
									generatecfromobj(obj1, value1, gendir, 0)
									break
						break
			break

	# Generate the root object tree file if amin does not exist
	generatecfromobj(obj, value, gendir, 1)

	# Generate the sub object tree file if amin does not exist
	if isinstance(value, dict):
		for obj1, value1 in value.items():
			if isinstance(value1, dict):
				for obj2, value2 in value1.items():
					if obj2 == "type" and value2 == "object":
						generatecfromobj(obj1, value1, gendir, 0)

if (os.path.isdir(gendir)):
	print("Source code generated under \"./%s\" folder" % gendir)
else:
	print("No source code generated!")
