(function(exports) {
	let main_eds_file_name = 'system_od.eds.gz'
	let app_sw_eds_file_name = 'app_sw_od.eds.gz'
	
	let DataTypeValuesMap = {
		'0x0021': 'pdo_mapping',
		'0x001B': 'uint64',
		'0x001A': 'uint56',
		'0x0008': 'real32',
		'0x008': 'real32',
		'0x0009': 'string',
		'0x0004': 'int32',
		'0x0023': 'identity',
		'0x0020': 'pdo_communication_parameter',
		'0x0007': 'uint32',
		'0x0001': 'bool',
		'0x0002': 'int8',
		'0x0003': 'int16',
		'0x000D': 'time_difference',
		'0x000F': 'domain_type',
		'0x000A': 'octet_string',
		'0x000B': 'unicode_string',
		'0x000C': 'time_of_day',
		'0x0019': 'uint48',
		'0x0018': 'uint40',
		'0x0016': 'uint24',
		'0x0015': 'int64',
		'0x0014': 'int56',
		'0x0013': 'int48',
		'0x0012': 'int40',
		'0x0011': 'real64',
		'0x0010': 'int24',
		'0x0022': 'sdo_parameter',
		'0x0005': 'uint8',
		'0x0006': 'uint16'
	}

	/*
	* data[].index = "AAAA:B", A - index, B - subindex;
	* data[].AccessType = "rw","ro","wo";
	* data[].DataType = "uint8","int16",ets. - for validation.
	*/
	exports.get_eds_object = async function ()
	{
		//console.log('get_eds_object')
		let eds_object
		//const start= new Date().getTime();

        await fetch(main_eds_file_name)
		.then(response => get_response(response))
		.then(text => 
		{	
			if (text != '')
			{
				eds_object = eds.parse(text, 'sub', true)
			}
			else
			{
				try 
				{
					eds_object = JSON.parse(get_json())
				}
				catch 
				{
					console.log('Файл eds не обнаружен')
				}
			}
		})
		.then(() => fetch(app_sw_eds_file_name))
		.then(response => get_response(response))
		.then(text => {
			if (text != '')
			{
				app_sw_eds_object = eds.parse(text, 'sub', true)
				eds_object = Object.assign(eds_object, app_sw_eds_object)

			}
			else
			{
				try 
				{
					app_sw_od = JSON.parse(app_sw_get_obj())
					eds_object = Object.assign(eds_object, app_sw_od)
				}
				catch 
				{
					console.log('Файл eds прикладного ПО не обнаружен')
				}
			}

			eds_object = eds_processing(eds_object)
		})
		//console.log(eds_object)
		return eds_object

		//const end = new Date().getTime();
		//console.log(`SecondWay: ${end - start}ms`);
	}

	function get_response(response)
	{	
		if (response.ok)
		{
			return response.text()
		}
		else
		{
			return ''
		}	
	}

	function eds_processing(eds_object)
	{
		$.each(eds_object, function(index, item)
		{
			if (item.subs == undefined)
			{
				if (item.ObjectType != undefined)
				{
					if (parseInt(item.ObjectType) == 0x7)
					{
						let buf = {}
						Object.assign(buf, item)
						buf.index = `${item.index}:0`
						item.subs = {}
						item.subs[0] = buf
					}
				}
				else
				{
					delete eds_object[index]
				}
			}		
		})

		return eds_object
	}

// base part

	exports.stringify = function(data, levelDelimiter) {
		levelDelimiter = validateDelimiter(levelDelimiter)
		let result = ''
		 
		$.each(data, function(index, value) {
			data_chank = {}
			result_chank_arr = []

			data_chank[index] = value
			walk(result_chank_arr, data_chank, '', levelDelimiter)
			result += '\n' + result_chank_arr.join('\n')
		})
		return result
	}

	function walk(result, data, upperLevel, levelDelimiter) {
		let section = []
		for (let key in data) {
			if (!data.hasOwnProperty(key)) {
				continue
			}
			let value = data[key]
			let type = Object.prototype.toString.call(value)

			if (type == '[object Object]') {
				section.push('\n[' + upperLevel + key + ']')
				walk(section, value, upperLevel + key + levelDelimiter, levelDelimiter)
				continue
			}
			else {
				value = [].concat(value)
				for (let i = 0; i < value.length; i++) {
					let parametr_value = value[i]
					if (key == 'index') {
						continue
					}
					if (key == 'DataType') {
						$.each(DataTypeValuesMap, function(datatype_key, datatype_value) {
							if(datatype_value == value[i]) {
								parametr_value = datatype_key
							}
						})
					}

					result.push(`${key}=${parametr_value}`)
				}
			}
			
		}
		result.push.apply(result, section)
	}

	exports.parse = function(text, levelDelimiter, deepen) {
		levelDelimiter = validateDelimiter(levelDelimiter)
		let result = {}
		let ptr = result
		let setPtr = (function() {
			if (!deepen) {
				return function(section) {
					if (!result.hasOwnProperty(section)) {
						result[section] = {}
					}
					ptr = result[section]
				}
			}
			return function(section) {
				let t = section.split(levelDelimiter)
				ptr = result
				let index = ''

				for (let i = 0; i < t.length; i++) {
					
					let u = t[i]
					if (!u) {
						continue
					}
					
					if (i == 0) {
						if (!ptr.hasOwnProperty(u)) {
							ptr[u] = {}
						}
						ptr = ptr[u]
						index = u
					}
					else {
						let sub_index = parseInt(u, 16)
						if (!ptr.hasOwnProperty('subs')) {
							ptr.subs = {}
						}
						if (!ptr.subs.hasOwnProperty(sub_index)) {
							ptr.subs[sub_index] = {}
						}
						ptr = ptr.subs[sub_index]
						index += `:${sub_index}`
					}
					//console.log(ptr.DataType)
					ptr.index = index
				}
			}
		})()

		let nextLine = (function() {
			if (typeof text == 'function') {
				return text
			}
			if (Object.prototype.toString.call(text) == '[object Array]') {
				let n = text.length
				let i = 0
				return function() {
					return n-- ? text[i++] : null
				};
			}
			let re = /[^\r\n]+/g
			return function() {
				let r = re.exec(text)
				return r && r[0]
			}
		})()

		let reSec = /^\s*\[([^\[\]]+)\]\s*$/
		//let reKey = /^\s*([^;#\s][^=]*?)\s*=([^\r\n]*?)$/
		let reKey = /^\s*([^;#\s][^=]*?)\s*=\s*([^\r\n]*?)\s*$/
		
		let line, m, key, value
		while ((line = nextLine()) != null) {
			m = line.match(reSec)
			if (m) {
				setPtr(m[1])
				continue
			}
			m = line.match(reKey)
			if (m) {
				key = m[1]			
				value = m[2]

				if (key == 'DataType') {
					value = DataTypeValuesMap[value]
				}

				if (!ptr.hasOwnProperty(key)) {
					ptr[key] = value
				} else {
					if (typeof ptr[key] == 'string') {
						ptr[key] = [ptr[key]]
					}
					ptr[key].push(value)
				}
				continue
			}
		}
		return result
	}

	let validateDelimiter = function(delimiter) {
		//delimiter = String(delimiter || '/').charAt(0);
		if (delimiter == '[' || delimiter == ']' || delimiter <= ' ') {
			throw new Error('Illegal delimiter: "' + delimiter + '"')
		}
		return delimiter
	}



})(this.eds = {})