/**
	a tree library for configuration editor
	it builds tree of nodes like below example
	
	// Node structure
	{
		name:"testkey",
		memo: "root key",
		values: [
			{
				"k": "키",
				"v": "값",
				"type":"데이터타입,
				"memo": "노드 설명",				
			},			
		],
		children: [
			{},//child Node1,
			{},//child Node2,
			...
		]
	}
	
	when export a tree for configuration result, it exports only simple result file like reg file that except memo or structures.
*/


class Node {
	values=[
	]
	children=[]
	parent=null;
	expanded=true;
	name='';
	memo=null;
	depth=0;
	constructor(name, parent){
		if (!name)
			throw "node name is needed";
		//this.attributes.name = name;
		this.name = name;
		this.parent = parent;
	}
	getPath(){
		var t = this;
		var result = '';
		while (t != null && t.name != '/')
		{
			result = t.name + '/' + result;
			t = t.parent;
		}
		return '/' + result;
	}
	findValue(key){
		for(var i in this.values) {
			if (key == this.values[i].k)
				return this.values[i];
		}
		return null;
	}
}

class Tree {
	constructor(){
		this.root = new Node("/");
	}
	/**
		make a child of presented node
	*/
	newChild(node){
		var child = new Node('new key '+(node.children.length+1));
		node.children.push(child);
		child.parent = node;		
		//console.log('newchild added ', node.children);
		return child;
	}
	/**
		k, v, 설명을 모두 포함한 전체 트리
	*/
	buildJson(obj){
		var json = this._buildJson(this.root);
		if(!obj)
			json = JSON.stringify(json);
		return json;
	}
	_buildJson(node) {
		var obj = {};
		obj.name = node.name;
		obj.memo = node.memo;
		obj.expanded = node.expanded;
		obj.values = [];
		for(var i in node.values) {
			obj.values.push(_.extend({}, node.values[i]));
		}
		obj.children = [];
		for(var i in node.children) {
			var c = node.children[i];
			obj.children.push(this._buildJson(c));
		}
		return obj;
	}
	/**
		k, v만 포함한 단순트리. 실제 설정용으로 사용
	*/
	buildResult(){
		var result = {};
		JSON.stringify(this._buildResult(this.root, result));
		return result;
	}
	_buildResult(node, obj){
		obj._key = node.name;
		for(var i in node.values) {
			var c = node.values[i];
			obj[c.k] = c.v;
		}
		for(var i in node.children) {
			var c = node.children[i];
			obj[c.name] = {};
			this._buildResult(c, obj[c.name]);
		}
		return obj;		
	}
	loadJson(json, isObj){
		var obj = json;
		if (!isObj)
			obj = JSON.parse(json);
		this._loadObj(this.root, obj);
	}
	_loadObj(node, obj){
		node.name = obj.name;
		node.memo = obj.memo;
		node.expanded = obj.expanded;
		node.values = [];
		for(var i in obj.values) {
			node.values.push(_.extend({}, obj.values[i]));
		}			
		node.children = [];
		for(var i in obj.children){
			var t = _.extend({}, obj.children[i]);
			this._loadObj(this.newChild(node), t);
		}
	}
	find(path){
		if (path == '/')
			return this.root;
		var l = path.split('/').filter(s=>s.length>0);
		var d = 0;
		var t = this.root;
		var found = null;
		while(d <= l.length){
			for(var i in t.children) {
				var c = t.children[i];
				if (c.name == l[d]) {
					t = c;
					found = c;
					break;
				}
			}
			d++;
		}
		return found;				
	}
	deleteChild(node){
		var p = node.parent;
		node.parent = null;
		var i = p.children.indexOf(node);
		delete p.children[i];
		p.children.splice(i, 1);
	}
	buildPairObj()
	{
		var obj = {}
		this._buildPairObj(obj, this.root);		
		return obj;
	}
	_buildPairObj(obj, node)
	{
		var path = node.getPath();
		for(var i in node.values) {
			var c = node.values[i];
			obj[path + c.k] = c.v;
		}
		for(var i in node.children) {
			this._buildPairObj(obj, node.children[i]);			
		}
	}
	
	/*
	_loadObj(node, obj){
		console.log(obj, obj.name);
		node.name = obj.name;
		for(var key in obj) {
			var o = obj[key];
			if (typeof(o) == 'object') {
				this._loadObj(this.newChild(node), o);
			}
		}			
	}*/	
}
