include "primitives.alh"
include "services.alh"
include "constructors.alh"
include "modelling.alh"

String function json_connect():
	String port
	port = ""
	while (port == ""):
		port = comm_connect("JSON")
	return port!

Void function json_send_data(port : String, data : Element):
	// Send the current value to the service
	// First determine what it is!

	if (is_physical_none(data)):
		comm_set(port, "N")
		
	elif (has_value(data)):
		// Primitive value, so send as-is
		comm_set(port, "P")
		comm_set(port, data)

	else:
		// Is a dict or list
		// Problem is that we don't know which it is, as everything is a dictionary in the Modelverse...
		// We will do a simple check: if it is a dictionary with keys the contiguous range of integers from 0 to length - 1, it is a list!
		Element keys
		Element expected
		Element copy
		Element entry
		Element key

		keys = dict_keys(data)
		expected = list_to_set(range(dict_len(data)))
		if (set_equality(keys, expected)):
			// Equal, so we are (most likely...) dealing with a list
			comm_set(port, "L")
			comm_set(port, list_len(data))
			
			copy = list_copy(data)
			while (list_len(copy) > 0):
				entry = list_pop(copy, 0)
				json_send_data(port, entry)
		else:
			// Not equal, so we are surely dealing with a dict
			comm_set(port, "D")
			comm_set(port, dict_len(data))

			while (set_len(keys) > 0):
				key = set_pop(keys)
				comm_set(port, key)
				json_send_data(port, data[key])
	return!

Element function process_JSON_data(port : String):
	String type
	Element result
	type = comm_get(port)

	if (type == "P"):
		// Primitive data type, so just return as-is
		result = comm_get(port)
	elif (type == "N"):
		result = !none
	elif (type == "L"):
		// List, so fetch elements in turn
		Integer length

		length = comm_get(port)
		result = list_create()
		while (length > 0):
			list_append(result, process_JSON_data(port))
			length = length - 1
	elif (type == "D"):
		// Dict, so fetch elements in turn
		Integer length

		length = comm_get(port)
		result = dict_create()
		while (length > 0):
			dict_add(result, comm_get(port), process_JSON_data(port))
			length = length - 1
	return result!

String function json_serialize(data : Element):
	String port
	String response
	port = json_connect()
	comm_set(port, "encode")
	response = comm_get(port)

	if (response == "OK"):
		// Send data to the service...
		json_send_data(port, data)
		response = comm_get(port)
		comm_close(port)
		return response!
	else:
		log("Error: " + response)
		comm_close(port)
		return ""!

Element function json_deserialize(str : String):
	String port
	String response
	Element rval
	port = json_connect()
	comm_set(port, "decode")

	response = comm_get(port)

	if (response == "OK"):
		comm_set(port, str)
		rval = process_JSON_data(port)
		comm_close(port)
		return rval!
	else:
		log("Error: " + response)
		comm_close(port)
		return read_root()!
