/*
 * modsAX Javascript Library
 * modsAX.com 2009 squall
 * modsAX are licensed under a Creative Commons Attribution 3.0 license.
 * http://creativecommons.org/licenses/by/3.0/deed.ko
 * If you don't want to author Link
 * You must register. Join the modsAX license member then you free use modsAX
 * http://www.modsAX.com
 */

var modsTree = Class.create(modsAX, {
    version: "modsTree V1.0",
    author: "SQUALL",
    createDate: "2009.09.28",
    lastModifyDate: "2010.04.23",
    initialize: function($super) {
        $super();
        this.coverA = "href=\"#modsExceptionScript\"";
        this.config.easing = { open: { duration: 0, easing: "quintInOut" }, close: { duration: 0, easing: "quintInOut"} };
        this.config.DBLclickable = true;
    },
    /* ------------------------------------------------------------------------------------------------------------------ */
    /* _set ~~~~~~ */
    setConfig: function(configs) {
        var _self = this;
        jQuery.each(Object.keys(configs), function(i, n) { // update to {this.config}
            _self.config[n] = configs[n];
            if (n == "rootElementID")
                if ($M(configs[n])) { // Element check
                jQuery("#" + configs[n]).attr("unselectable", "on");
                jQuery("#" + configs[n]).attr("align", "left");
            }
        });
        this.init();
    },
    init: function() {
        var rootOnclick = this.rootOnclick.bind(this);
        jQuery("#" + this.config.rootElementID).unbind("click");
        jQuery("#" + this.config.rootElementID).bind("click", function(event) {
            rootOnclick(this, event);
        });

        //if(this.config.DBLclickable){
        var rootOndblclick = this.rootOndblclick.bind(this);
        jQuery("#" + this.config.rootElementID).unbind("dblclick");
        jQuery("#" + this.config.rootElementID).bind("dblclick", function(event) {
            rootOndblclick(this, event);
        });
        //}

        if (this.config.quickMenu) {
            var rootOncontextmenu = this.rootOncontextmenu.bind(this);
            jQuery("#" + this.config.rootElementID).unbind("contextmenu");
            jQuery("#" + this.config.rootElementID).bind("contextmenu", function(event) {
                rootOncontextmenu(this, event);
            });
        }

        if (this.config.quickMenu) {
            this.myQmenu = new modsQmenu();
            this.myQmenu.setConfig(this.config.quickMenu);
        }
    },
    load: function(objs) {
        if (this.config.dataType == "script") { //스크립트 지정 방식
            this.trees = this.uniqTree(objs); // convert tree
            this.insertTree(null, this.trees);
        } else { // url load 방식
            this._setConfigLoad(objs); // config loader
            var url = this._getUrl("load");
            var pars = this._getPars();
            var onreq = this.responseData.bind(this, null);
            if (url == "") this.outMsg("You will set the Load URL");
            new modsreq(url, { pars: pars, onsucc: onreq });
        }

        if (this.config.drag) {
            var onDrop = this.onDrop.bind(this);
            this.myDrager = new modsDrag();
            this.myDrager.setConfig({
                dragStage: this.config.rootElementID,
                dragBoxClassName: this.config.drag.dragBoxClassName,
                bedragClassName: this.config.drag.bedragClassName,
                bedropClassName: this.config.drag.bedropClassName,
                dragClassName: this.config.drag.dragClassName,
                dropClassName: this.config.drag.dragClassName,
                onDrag: "",
                onDrop: onDrop
            });
            this.myDrager.active();
        }
    },
    /* ------------------------------------------------------------------------------------------------------------------ */
    /* on observe method ~~~~~~ */
    rootOncontextmenu: function(element, event) {
        if (!(event.target.tagName == "A")) return;
        var eA = event.target;
        if (!eA.id) return;
        var clickIDs = eA.id.split("_"); // 0 : rootElementID, 1:_id, 2:클릭위치

        if (clickIDs[0] == this.config.rootElementID) {
            var clickLiID = clickIDs[0] + "_" + clickIDs[1];
            if (clickIDs[2] == "i") { // 오픈시도
                this.objOpen(clickLiID, "", event);
            } else if (clickIDs[2] == "t") { //클릭 시도
                this.objOpen(clickLiID, "onlyopen", event);
                this.objClick(clickLiID, event);
            }
            var obj = this._getObj(clickLiID);
            this.myQmenu.show({ target: this.config.rootElementID, pointer: { x: event.pageX, y: event.pageY }, message: obj, forFm: obj.fm });
        }
    },
    rootOnclick: function(element, event) {
        if (!(event.target.tagName == "A")) return;
        var eA = event.target;
        if (!eA.id) return;
        var clickIDs = eA.id.split("_"); // 0 : rootElementID, 1:_id, 2:클릭위치

        if (clickIDs[0] == this.config.rootElementID) {
            var clickLiID = clickIDs[0] + "_" + clickIDs[1];
            if (clickIDs[2] == "i") { // 오픈시도
                this.objOpen(clickLiID, "", event);
            } else if (clickIDs[2] == "t") { //클릭 시도
                if (!this.config.DBLclickable) {
                    // dblclick 사용안함
                    //닫힌 경우에만 열기 허용
                    this.objOpen(clickLiID, "onlyopen", event);
                }
                this.objClick(clickLiID, event);
            }
        }
    },
    rootOndblclick: function(element, event) {
        if (!(event.target.tagName == "A")) return;
        var eA = event.target;
        if (!eA.id) return;
        var clickIDs = eA.id.split("_"); // 0 : rootElementID, 1:_id, 2:클릭위치

        if (clickIDs[0] == this.config.rootElementID) {
            var clickLiID = clickIDs[0] + "_" + clickIDs[1];
            if (clickIDs[2] == "i") { // 무시

            } else if (clickIDs[2] == "t") { //오픈 시도
                this.objOpen(clickLiID);
            }
        }
    },
    objClick: function(clickLiID, event) {
        var clickDiv = $("#" + clickLiID + " > div");
        clickDiv.addClass("sted");
        if (this.selects != clickLiID && this.selects != "")
            if ($M(this.selects))
            $("#" + this.selects + " > div").removeClass("sted");

        this.selects = clickLiID;
        if (this.config.onclick && event.button == 0) {
            var paObj = this._getObj(clickLiID);
            if (paObj) this.config.onclick(paObj, event);
        }
    },
    objOpen: function(clickLiID, att, event) {
        // open child node
        var paObj = this._getObj(clickLiID);
        if (this.config.dataType == "script") { //스크립트 지정 방식
            if (paObj._cn == 1) { //have child tree;
                if (paObj._op) {
                    if (att) { // !this.config.DBLclickable
                    } else {
                        this.removeTree(clickLiID, paObj.cn);
                        paObj._op = false;
                    }
                } else {
                    this.insertTree(clickLiID, paObj.cn);
                    paObj._op = true;
                }
            } else {
                if (att != "onlyopen") this.objClick(clickLiID, event);
            }
        } else { // url load 방식
            if (paObj._cn == 1) { //have child tree;
                if (paObj._op) {
                    if (att) { // !this.config.DBLclickable
                    } else {
                        this.removeTree(clickLiID, paObj.cn);
                        paObj._op = false;
                    }
                } else {
                    var url = this._getUrl("load");
                    var pars = this._getPars(paObj);
                    var onreq = this.responseData.bind(this, paObj);
                    new modsreq(url, { pars: pars, onsucc: onreq });
                    paObj._op = true;
                }
            } else {
                if (att != "onlyopen") this.objClick(clickLiID, event);
            }
        }
    },
    /* ------------------------------------------------------------------------------------------------------------------ */
    /* class method ~~~~~~ */
    responseData: function(_parent, req) {
        var res = req;
        if (res.result == mods.okCode) {
            if (!_parent) {
                //clear tree container

                this.trees = this.uniqTree(res.ds); // convert tree
                this.insertTree(null, this.trees);
            } else {
                _parent.cn = this.uniqTree(res.ds, _parent._id);
                //부모 노드 취하기
                var objID = this.config.rootElementID + "_" + _parent._id;
                this.insertTree(objID, res.ds);
            }
        }
    },
    insertTree: function(_parent, _obj) {
        var coverA = this.coverA;
        var dragClassName = (this.config.drag) ? this.config.drag.dragClassName : "";
        if (_parent == null) {
            _parent = this.config.rootElementID;
            $("#" + _parent).empty();
        }

        if (_parent == this.config.rootElementID) {
            var myUL = $("<ul class='rootUL'></ul>");
            _parent = "#" + _parent;
        } else {
            var myUL = $("<ul id='" + _parent.id + "_s'></ul>");
            jQuery("#" + _parent + " > div").addClass("open");
            _parent = "#" + _parent;
        }
        myUL.css("display", "none");

        var l = _obj.length;
        var s = 0;

        while (s < l) {
            var etags = [];
            var objID = this.config.rootElementID + "_" + _obj[s]._id;
            var objClass = "nd";
            var dragClass = "";
            if (_obj[s]._cn) objClass += " havecn";
            if (_obj[s]._op) objClass += " open";
            if (_obj[s]._sl) {
                objClass += " sted";
                this.selects = objID;
            }
            if (dragClassName != "") dragClass += " " + dragClassName;

            etags.push("<li id=\"" + objID + "\"><div class=\"" + objClass + "\">");
            etags.push("<a " + coverA + " id=\"" + objID + "_i\" class=\"i\">-</a>");
            etags.push("<a " + coverA + " id=\"" + objID + "_t\" class=\"t " + _obj[s].fm + dragClass + "\" title=\"" + _obj[s].nm.dec().replace(/\"/g, "''") + "\">" + _obj[s].nm.dec() + "</a>");
            etags.push("</div><div class=\"sp\"></div>");
            if (_obj[s]._op && _obj[s]._cn) { //자식 개체 확인
                etags.push(this.getSubTree(_obj[s], _obj[s].cn));
            }
            etags.push("</li>");
            myUL.append(etags.join(''));
            s++;
        }
        jQuery(_parent).append(myUL);

        var config = this.config;
        myUL.slideDown({ duration: this.config.easing.open.duration, easing: this.config.easing.open.easing, complete: function() {
            if (config.onOpen) config.onOpen({ parent: _parent, obj: _obj });
        }
        });
        if (this.selects) $("#" + this.selects).children().addClass("sted");
    },
    getSubTree: function(_paObj, _obj) {
        if (!_obj) return;
        var coverA = this.coverA;
        var paobjID = this.config.rootElementID + "_" + _paObj._id + "_s";
        var etags = [];
        etags.push("<ul id=\"" + paobjID + "\">");

        var l = _obj.length;
        var s = 0;
        while (s < l) {
            var objID = this.config.rootElementID + "_" + _obj[s]._id;
            var objClass = "nd";
            if (_obj[s]._cn) objClass += " havecn";
            if (_obj[s]._op) objClass += " open";
            if (_obj[s]._sl) {
                objClass += " sted";
                this.selects = objID;
            }

            etags.push("<li id=\"" + objID + "\"><div class=\"" + objClass + "\">");
            etags.push("<a " + coverA + " id=\"" + objID + "_i\" class=\"i\">-</a>");
            etags.push("<a " + coverA + " id=\"" + objID + "_t\" class=\"t " + _obj[s].fm + "\" title=\"" + _obj[s].nm.dec().replace(/\"/g, "''") + "\">" + _obj[s].nm.dec() + "</a>");
            etags.push("</div><div class=\"sp\"></div>");
            if (_obj[s]._op) { //자식 개체 확인
                etags.push(this.getSubTree(_obj[s], _obj[s].cn));
            }
            etags.push("</li>");
            s++;
        }
        etags.push("</ul>");
        return etags.join('');
    },
    removeTree: function(_parent, _obj) {
        //자식 개체 찾기
        var myTarget = jQuery("#" + _parent + " > ul").children();
        jQuery("#" + _parent + " > div").removeClass("open");

        if (mods.browser.browser == "ie" && mods.browser.version < 8) {
            myTarget.remove();
        } else {
            myTarget.slideUp({ duration: this.config.easing.close.duration, easing: this.config.easing.close.easing, complete: function() {
                myTarget.remove();
            }
            });
        }
    },
    onInsert: function(req) {
	    var coverA = this.coverA;
	    var Obj = req.target, adder = req.adder, callBack = req.callBack;
	
	    
	    if(!adder){
	      alert("adder 개체가 없습니다.");
	      return;
	    }
	
	    var reID = this.config.rootElementID;    
		var new_id = 0;
		var addRoot = false;
	    if(!Obj){
	    	addRoot = true;
	    	Obj = this.tree;
	    	var paobjID = reID+"_rootUL";
	    	new_id = this.trees.length;
	    	var objID = reID+"_"+new_id;
	    	adder._id = new_id;
	    }else{
	    	var paobjID = reID+"_"+Obj._id;	
	    	if(Obj.cn) new_id = Obj.cn.length;
	    	var objID = paobjID+"_"+new_id;
	    	adder._id = objID.replace(reID+"_", "");
	    }
	    var inputID = objID+"_input";
	    var objClass = "nd";
	
	    var etags = [];
	    etags.push("<li id=\""+objID+"\"><div class=\""+objClass+"\">");
	    etags.push("<a "+coverA+" id=\""+objID+"_i\" class=\"i\">-</a>");
	    etags.push("<a "+coverA+" id=\""+objID+"_t\" class=\"t "+adder.fm+"\"><input type=\"text\" name=\"modifyer\" value=\""+adder.nm+"\" id=\""+inputID+"\"></a>");
	    etags.push("</div><div class=\"sp\"></div>");
	    etags.push("</li>");
	    
	    if(!addRoot){
		    if($M(paobjID+"_s")) jQuery("#"+paobjID+"_s").append(etags.join(''));
		    else jQuery("#"+paobjID).append("<ul id=\""+paobjID+"_s\">"+etags.join('')+"</ul>");
		}else{
			jQuery("#"+paobjID).append(etags.join(''));
		}
	    
	    var inputObj = jQuery("#"+inputID);
	    jQuery("#"+inputID).css({width:inputObj.width()-8+"px"});
	
	    //enter esc blur - observe init
	    inputObj.unbind("keyup");
	    inputObj.unbind("blur");
	
	    var insertE = this.insertE.bind(this);
	    inputObj.bind("keyup", function(event){insertE(event, Obj, adder, callBack);});
	    inputObj.bind("blur", function(event){insertE(event, Obj, adder, callBack);});
	
	    var insertReady = this.insertReady.bind(this);
	    setTimeout(function(){ insertReady({inputID:inputID}); }, 100);
    },
    insertReady: function(req) {
        var inputID = req.inputID;
        jQuery("#" + inputID).select();
    },
    insertE: function(event, Obj, adder, callBack) {
        var reID = this.config.rootElementID;
        var objID = reID + "_" + adder._id;
        var inputID = reID + "_" + adder._id + "_input";
        var inputObj = jQuery("#" + inputID);
        if (event.type == "blur" || (event.type == "keyup" && event.keyCode == mods.Event.KEY_RETURN)) {
            inputObj.unbind("keyup");
            inputObj.unbind("blur");
            adder.nm = inputObj.val().enc();
            if (callBack) callBack({ result: "insert", target: Obj, insertObj: adder });
            else this.insert({ result: true, target: Obj, insertObj: adder });
        } else {
            if (event.keyCode == mods.Event.KEY_ESC) {
                inputObj.unbind("keyup");
                inputObj.unbind("blur");
                if (Obj.cn) jQuery("#" + objID).remove();
                else jQuery("#" + reID + "_" + Obj._id + "_s").remove();
                if (callBack) callBack({ result: "cancle", target: Obj });
            }
        }
    },
    insert: function(req) {
        var Obj = req.target, result = req.result, adder = req.insertObj;
        var reID = this.config.rootElementID;
        var objID = reID + "_" + adder._id + "_t";
        var inputID = reID + "_" + adder._id + "_input";
        var inputObj = jQuery("#" + inputID);
        if (result) {
            //push Object
            if (Obj.cn) Obj.cn.push(adder);
            else {
                Obj.cn = [];
                Obj.cn.push(adder);
                //부모개체 클래스 추가
                Obj._cn = 1;
                Obj._op = true;
                var paobjID = reID + "_" + Obj._id;
                var paobj_div = jQuery("#" + paobjID + " > div");
                paobj_div.addClass("havecn");
                paobj_div.addClass("open");
            }
            inputObj.unbind("keyup");
            inputObj.unbind("blur");
            jQuery("#" + objID).html(adder.nm.dec());
        } else {
            inputObj.unbind("keyup");
            inputObj.unbind("blur");
            if (Obj.cn) jQuery("#" + objID).remove();
            else jQuery("#" + reID + "_" + Obj._id + "_s").remove();
        }
    },
    onModify: function(req) {
        var Obj = req.target, callBack = req.callBack;
        var reID = this.config.rootElementID;
        var objID = reID + "_" + Obj._id + "_t";
        var inputID = reID + "_" + Obj._id + "_input";
        jQuery("#" + objID).html("<input type=\"text\" name=\"modifyer\" value=\"\" id=\"" + inputID + "\">");

        var inputObj = jQuery("#" + inputID);
        inputObj.val(Obj.nm.dec());
        var insertReady = this.insertReady.bind(this);
        setTimeout(function() { insertReady({ inputID: inputID }); }, 100);
        inputObj.css({ width: inputObj.width() - 8 + "px" });

        //enter esc blur - observe init
        inputObj.unbind("keyup");
        inputObj.unbind("blur");

        var modify = this.modify.bind(this);
        inputObj.bind("keyup", function(event) { modify(event, Obj, callBack); });
        inputObj.bind("blur", function(event) { modify(event, Obj, callBack); });
    },
    modify: function(event, Obj, callBack) {
        var reID = this.config.rootElementID;
        var objID = reID + "_" + Obj._id + "_t";
        var inputID = reID + "_" + Obj._id + "_input";
        var inputObj = jQuery("#" + inputID);

        if (event.type == "blur" || (event.type == "keyup" && event.keyCode == mods.Event.KEY_RETURN)) {
            var oldText = Obj.nm;
            Obj.nm = inputObj.val().enc();
            inputObj.unbind("keyup");
            inputObj.unbind("blur");
            jQuery("#" + objID).html(Obj.nm.dec());
            if (callBack) callBack({ result: "change", target: Obj, prevnm: oldText });
        } else {
            if (event.keyCode == mods.Event.KEY_ESC) {
                inputObj.unbind("keyup");
                inputObj.unbind("blur");
                jQuery("#" + objID).html(Obj.nm.dec());
                if (callBack) callBack({ result: "cancle", target: Obj });
            }
        }
    },
    cancelModify: function(req) {
        var Obj = req.target, nm = req.prevnm;
        var reID = this.config.rootElementID;
        var objID = reID + "_" + Obj._id + "_t";
        Obj.nm = nm;
        jQuery("#" + objID).html(Obj.nm.dec());
    },
    updateObj: function(Obj) {
        var reID = this.config.rootElementID;
        var objID = reID + "_" + Obj._id + "_t";
        jQuery("#" + objID).html(Obj.nm.dec());
    },
    onDel: function(req) {
        var Obj = req.target, callBack = req.callBack;
        var ans = confirm("선택된 개체를 삭제하시겠습니까? ");
        if (ans) {
            if (callBack) callBack({ result: "delete", target: Obj });
            else this.del({ target: Obj, result: true });
        }
    },
    del: function(req) {
        var Obj = req.target, result = req.result;
        var reID = this.config.rootElementID;
        var objID = reID + "_" + Obj._id;
        if (result) {
            Obj._isDel = true;
            this.selects = "";
            jQuery("#" + objID).remove();
        } else {
            return;
        }
    },
    onMove: function(req) {

    },
    move: function(req) {

    },
    onDrop: function(req) {
        if (this.config.drag.onDrop) this.config.drag.onDrop(req);
    },
    scrollToSelect: function() {
        //alert($M(this.selects));
        if ($M(this.selects)) jQuery("#" + this.selects).scrollToDiv({ left: 0, top: -50 });
    }
});
