;
(function($) {
    $.extend({
        "cuiTree":function(options){
            return new CuiTree(options);
        }
    });
    $.fn.extend({
       "cuiTree":function(options){
           var g = new CuiTree(options);
           return g.show(this);
       }
    });
})(jQuery);
/***
 * -CLASS-
 * @name CuiTree
 * @package cui.widget
 * @description cui树列表
 * @pageTag <div></div>
 * @depend CuiTreeView
 * @paramType JSON
 * @param id string <tree显示到的元素id>
 * @param tid string <数据中树主键的索引名称>
 * @param idx string <数据中树内容的索引名称>
 * @param data json <树的数据>
 * @param callback function <点击树的回调函数,函数参数为(tid,isLeaf),tid为该主键，isLeaf(boolean)是否为叶子节点>
 * @param config json <tree的设置，详细参数见setConfig方法的参数>
 * @param style json <样式，详细参数见setStyle方法的参数>
 * @author ypu<ypu@ceno.cn>
 * @version 2011-10-09
 * @since 0.1
 */
var CuiTree = function(options) {
    //解析后的数据,tid作为索引，内容为该索引的数据对象
    var _data_;
    //树结构，tid作为索引，内容为该索引的子节点tid
    var _tree_;
    //tree显示到的id
    var _id_;
    //数据中组织关系的id，一般为数据的id
    var _tid_;
    //显示内容的索引
    var _idx_;
    //样式
    var _style_;
    //回调函数
    var _callback_;
    //cell回调函数
    var _cellCallback_;
    //当前Cuitree对象
    var _self_ = this;
    //tree视图
    var _view_ = new CuiTreeView();
    //数据缓存
    var _tmp_ ;
    //tree上下文
    var _context_;
    //设置
    var _config_ = {
        parent_tag:"parent",      //数据中关联父节点的属性名
        children_tag:"children", //数据中关联子节点的属性名
        node_css:"cui_treeNode", //节点样式
        leaf_css:"cui_treeLeaf", //叶子样式
        process_data:1,    //数据解析方式
        collapsed:false   //默认是否展开
    }


    if (options) {
        _tid_ = options.tid;
        _idx_ = options.idx;
        _tmp_ = options.data;
        _callback_ = options.callback;
        options.data = null;
        options.callback = null;
        _config_ = $.extend(_config_,options.config);
        _style_ = {};
        _style_ =  $.extend(_style_,options.style);
    }
     /**
     * -METHOD-
     * @summary 设置数据
     * @description 设置tree的数据内容
     * @method setData
     * @param data json <tree data数据>
     * @return CuiTree
     * @since 0.1
     */
    this.setData = function(data) {
        _tmp_ = data;
        return _self_;
    }
     /**
     * -METHOD-
     * @summary 获取数据
     * @description 获取tree的数据内容
     * @method getData
     * @param id id <数据id(treeIdx)>
     * @return json
     * @since 0.1
     */
    this.getData = function(id){
        if(typeof id !='undefined'){
            return _data_[id];
        }else{
            return _data_;
        }
    }

    this.privateProcessDataChild = function(data, parentId) {
        for (var i in data) {
            id = data[i][_tid_]
            _data_[id] = data[i];
            if (typeof parentId != 'undefined') {
                if (_tree_[parentId]) {
                    _tree_[parentId].push(id);
                } else {
                    var t = [id];
                    _tree_[parentId] = t;
                }
            } else {
                if (_tree_["_root"]) {
                    _tree_["_root"].push(id);
                } else {
                    var t = [id];
                    _tree_["_root"] = t;
                }
            }

            if (typeof data[i][_config_["children_tag"]] != "undefined") {
                this.privateProcessDataChild(data[i][_config_["children_tag"]], id);
            }
        }
    }

    this.privateProcessData = function(data){
        if (!_tid_)return _self_;
        _data_ = [];
        _tree_ = [];
        for (var i in data) {
            _data_[data[i][_tid_]] = data[i];
            var tag = data[i][_config_["parent_tag"]];
            if (tag) {
                if (_tree_[tag]) {
                    _tree_[tag].push(data[i][_tid_]);
                } else {
                    var t = [];
                    t.push(data[i][_tid_]);
                    _tree_[tag] = t;
                }
            } else {
                if (_tree_["_root"]) {
                    _tree_["_root"].push(data[i][_tid_]);
                } else {
                    var t = [];
                    t.push(data[i][_tid_]);
                    _tree_["_root"] = t;
                }
            }
        }
    }
     /**
     * -METHOD-
     * @summary 设置tree结构索引
     * @description 设置tree结构索引
     * @method setTreeIdx
     * @param tid string <数据中树主键的索引名称>
     * @param cid string <数据中树内容的索引名称>
     * @return CuiTree
     * @since 0.1
     */
    this.setTreeIdx = function(tid,idx) {
        _tid_ = tid;
        _idx_ = idx;
        return _self_;
    }
    /**
     * -METHOD-
     * @summary 设置tree节点样式
     * @description 设置tree节点样式
     * @method setStyle
     * @param style json <样式内容>
     * @param width int <node的宽度> style
     * @param height int <node的高度> style
     * @param maxlength int <node显示的最大长度> style
     * @param title string <node显示的title> style
     * @param css string <node的class> style
     * @param style string <node的style样式> style
     * @return CuiTree
     * @since 0.1
     */
    this.setStyle = function(style) {
        _style_ = style;
        return _self_;
    }

    this.privateSetStyle = function(obj, styles) {
        if (!styles)return;
        if (styles.width)obj.attr('width', styles.width);
        if (styles.height)obj.attr('height', styles.height);
        if (styles.title)obj.attr('title', styles.title);
        if (styles.style)obj.css(styles.style);
        if (styles.css)obj.addClass(styles.css);
    }
    /**
     * -METHOD-
     * @summary 显示tree
     * @description 显示tree
     * @method show
     * @param id string <设置显示id，树根据此id显示>
     * @return CuiTree
     * @since 0.1
     */
    this.show = function(id) {
//        _id_ = id;
        if (id) {
            if (typeof id == 'string') {
                _context_ = $('#' + id);
            } else if (id.jquery) {
                _context_ = id;
            } else {
                _context_ = $(id);
            }
        }
        this.initData();
        this.refreshData();
        return _self_;
    }

    this.initData = function(){
        _tree_ = [];
        _data_ = [];
        if (_config_["process_data"] == 2) {
            this.privateProcessData(_tmp_);
        } else {
            this.privateProcessDataChild(_tmp_);
        }
        return _self_;
    }

     /**
     * -METHOD-
     * @summary 刷新tree内容
     * @description 刷新tree内容
     * @method refreshData
     * @return CuiTree
     * @since 0.1
     */
    this.refreshData = function() {
        _context_.empty();
        _context_.append(_view_.frameHtml);

        this.privateShowNodes(_tree_["_root"], $('.cui_treeBar',_context_));

        $('.cui_treeBar',_context_).treeview({
            collapsed: _config_["collapsed"],
            animated: "fast",
            unique: false,
		    persist: "location"
        });
        return _self_;
    }

//    this.privateShowNodes = function(data, tag) {
//        for (var i in data) {
//            _data_[data[i][_tid_]] = data[i];
//            if (data[i][_config_["children_tag"]] && data[i][_config_["children_tag"]].length > 0) {
//                var leaf = $(_view_.leafHtml);
//
////                leaf.addClass(_view_.expandableCss);
////                if (i == (data.length - 1)) {
////                    leaf.addClass(_view_.lastExpandableCss);
////                    leaf.append($(_view_.lastExpandHtml));
////                } else {
////                    leaf.append($(_view_.expandHtml));
////                }
//                var content = data[i][_idx_];
//                var nick = content;
//                if (typeof content == "string" && _style_ && _style_.maxlength) {
//                    content = content.substr(0, _style_.maxlength)
//                }
//                if (_cellCallback_) {
//                    content = _cellCallback_.apply(_self_, [data[i]]);
//                }
//                leaf.append($(_view_.contentHtml).text(content).addClass(_config_["node_css"]).attr("cuitreeid", data[i][_tid_]).attr("title", nick).click(function() {
//                    _self_.privateClick($(this));
//                }));
//                var childNode = $(_view_.nodeHtml);
//                leaf.append(childNode);
//                this.privateSetStyle(leaf, _style_);
//                tag.append(leaf);
//                this.privateShowNodes(data[i][_config_["children_tag"]], childNode);
//            } else {
//                var leaf = $(_view_.leafHtml);
//
////                if (i == (data.length - 1)) leaf.addClass(_view_.leafLastCss);
//                var content = data[i][_idx_];
//                var nick = content;
//                if (typeof content == "string" && _style_ && _style_.maxlength) {
//                    content = content.substr(0, _style_.maxlength)
//                }
//                if (_cellCallback_) {
//                    content = _cellCallback_.apply(_self_, [data[i]]);
//                }
//                leaf.append($(_view_.contentHtml).text(content).addClass(_config_["leaf_css"]).attr("cuitreeid", data[i][_tid_]).attr("title", nick).click(function() {
//                    _self_.privateClick($(this));
//                }));
//                this.privateSetStyle(leaf, _style_);
//                tag.append(leaf);
//            }
//        }
//    }

    this.privateShowNodes = function(tlist, tag) {
        //display leaf first
//        var leafs = [];
//        var nodes = [];
//        var last = tlist.length - 1;
//        var now = 1;
//        for (var i in tlist) {
//            if (_tree_[tlist[i]] && _tree_[tlist[i]].length>0) {
//                nodes.push(tlist[i]);
//            } else {
//                leafs.push(tlist[i]);
//            }
//        }


        for (var i in tlist) {
            var leaf = $(_view_.leafHtml);
            var id = tlist[i];
            var content = _data_[id][_idx_];
            var nick = content;
            if (typeof content == "string" && _style_ && _style_.maxlength) {
                content = content.substr(0, _style_.maxlength)
            }
            if (_cellCallback_) {
                content = _cellCallback_.apply(_self_, [_data_[id]]);
            }
            if (_tree_[id] && _tree_[id].length > 0) {
                leaf.append($(_view_.contentHtml).text(content).addClass(_config_["node_css"]).attr("cuitreeid", id).attr("title", nick).click(function() {
                    _self_.privateClick($(this));
                }));
                var childNode = $(_view_.nodeHtml);
                leaf.append(childNode);
                this.privateSetStyle(leaf, _style_);
                tag.append(leaf);
                this.privateShowNodes(_tree_[id], childNode);
            }else{
                leaf.append($(_view_.contentHtml).text(content).addClass(_config_["leaf_css"]).attr("cuitreeid", id).attr("title", nick).click(function() {
                    _self_.privateClick($(this));
                }));
                this.privateSetStyle(leaf, _style_);
                tag.append(leaf);
            }
        }


//        for (var i in nodes) {
//            var leaf = $(_view_.leafHtml);
//            var id = nodes[i];
//            var content = _data_[id][_idx_];
//            var nick = content;
//            if (typeof content == "string" && _style_ && _style_.maxlength) {
//                content = content.substr(0, _style_.maxlength)
//            }
//            if (_cellCallback_) {
//                content = _cellCallback_.apply(_self_, [_data_[id]]);
//            }
//            leaf.append($(_view_.contentHtml).text(content).addClass(_config_["node_css"]).attr("cuitreeid", id).attr("title", nick).click(function() {
//                _self_.privateClick($(this));
//            }));
//            var childNode = $(_view_.nodeHtml);
//            leaf.append(childNode);
//            this.privateSetStyle(leaf, _style_);
//            tag.append(leaf);
//            this.privateShowNodes(_tree_[id], childNode);
//
//        }

//        for (var i in leafs) {
//            var leaf = $(_view_.leafHtml);
//            var id = leafs[i];
//
//            var content = _data_[id][_idx_];
//            var nick = content;
//            if (typeof content == "string" && _style_ && _style_.maxlength) {
//                content = content.substr(0, _style_.maxlength)
//            }
//            if (_cellCallback_) {
//                content = _cellCallback_.apply(_self_, [_data_[id]]);
//            }
//            leaf.append($(_view_.contentHtml).text(content).addClass(_config_["leaf_css"]).attr("cuitreeid", id).attr("title", nick).click(function() {
//                _self_.privateClick($(this));
//            }));
//            this.privateSetStyle(leaf, _style_);
//            tag.append(leaf);
//
//        }
    }

    this.privateClick = function(tag) {
        $( '.'+_view_.selectedCss,_context_).removeClass(_view_.selectedCss);
        tag.addClass(_view_.selectedCss);
        if (!_callback_)return
        _callback_.apply(_self_,[tag.attr("cuitreeid"), tag.hasClass(_config_["node_css"])]);
    }
    /**
     * -METHOD-
     * @summary 设置tree设置
     * @description 设置tree设置
     * @method setConfig
     * @param config json <tree设置内容>
     * @param parent_tag string <tree数据中父节点的标记名称，默认为"parent"> config
     * @param children_tag string <tree数据中子节点的标记名称，默认为"children"> config
     * @param node_css string <tree节点的css,默认为“cui_treeNode”> config
     * @param leaf_css string <tree叶子的css,默认为“cui_treeLeaf”> config
     * @param process_data int <处理数据模式，1为自身包含children的组织结构[{"id":"1","children":[{"id":"2","children":[]}]},{"id":3,"children":[]}]，2为只包含parent主键无组织结构[{"id":1,"parent":""},{"id":2,"parent":1},{"id":3,"parent":""}]> config
     * @param collapsed boolean <树默认是否关闭，true或者false，默认为false> config
     * @param dataAdapter func <loadData函数，请求返回数据的转换函数，返回转换后的数据内容> config
     * @return CuiTree
     * @since 0.1
     */
    this.setConfig = function(config) {
        if (!config)return _self_;
//        if (config["parent_tag"])_config_["parent_tag"] = config["parent_tag"];
//        if (config["node_css"])_config_["node_css"] = config["node_css"];
//        if (config["leaf_css"])_config_["leaf_css"] = config["leaf_css"];
//        if (config["process_data"])_config_["process_data"] = config["process_data"];
//        if (config["collapsed"])_config_["collapsed"] = config["collapsed"];
//        if (config["dataAdapter"] && typeof config["dataAdapter"] == "function" ){
//            _config_["dataAdapter"] = config["dataAdapter"];
//        }
        _config_ = $.extend(_config_,config);
        return _self_;
    }
        /**
     * -METHOD-
     * @summary 设置点击tree节点的回调函数
     * @description 设置点击tree节点的回调函数
     * @method setCallback
     * @param func function <tree节点click回调函数>
     * @param idx string <触发节点的树idx>  func
     * @param isNode boolean <是否有子节点>  func
     * @return CuiTree
     * @since 0.1
     */
    this.setCallback = function(func) {
        if (typeof func == "function") {
            _callback_ = func;
        }
        return _self_;

    }
    /**
     * -METHOD-
     * @summary 设置tree节点显示的回调函数
     * @description 设置tree节点显示的回调函数
     * @method setCellCallback
     * @param func function <tree节点显示回调函数，返回显示内容>
     * @param data json <此节点的data对象>  func
     * @return CuiTree
     * @since 0.1
     */
    this.setCellCallback = function(func){
        if (typeof func == "function") {
            _cellCallback_ = func;
        }
        return _self_;

    }
         /**
     * -METHOD-
     * @summary 设置tree自动加载数据
     * @description 设置tree自动加载数据
     * @method loadData
     * @param url string <请求数据地址>
     * @param params json <请求参数>
     * @param func function <数据显示完的回调函数>
     * @param data json <返回的数据>  func
     * @param flag boolean <是否请求成功>  func
     * @return CuiTree
     * @since 0.1
     */
    this.loadData = function(url, params, func) {
        if (!params) {
            params = {};
        }
        $.cuiAjax(url, params, function(data, flag) {
            if (!flag) {
                if (typeof func == 'function') {
                    func(data, flag);
                }
                return;
            }
            if(_config_["dataAdapter"]){
                data = _config_["dataAdapter"].apply(_self_,[data]);
            }
            _self_.setData(data);
            _self_.initData();
            _self_.refreshData();
            if (typeof func == 'function') {
                func(data, flag);
            }
        });
        return _self_;
    }
    /**
     * -METHOD-
     * @summary 添加树节点
     * @description 添加树节点
     * @method addNode
     * @param parentId int/string <父节点id，tid>
     * @param data json <节点数据>
     * @return CuiTree
     * @since 0.1
     */
    this.addNode = function(data,parentId){
        if (!data && typeof data[_tid_] == "undefined" &&typeof data[_idx_] == "undefined" )return _self_;


        var select = $('span[cuitreeid=' + parentId + ']',_context_).parent();
        if(typeof parentId == 'undefined'){
            parentId = "_root";
        }else if(typeof _data_[parentId] == 'undefined'){
            return _self_;
        }
        if (_tree_[parentId]) {
            _tree_[parentId].push(data[_tid_]);
        } else {
            _tree_[parentId] = [data[_tid_]];
        }
        _data_[data[_tid_]] = data;
        if(select.find('ul').length==0){
            this.refreshData();
        }else{
            var leaf = $(_view_.leafHtml);
            var content = data[_idx_];
            var nick = content;
            if (typeof content == "string" && _style_ && _style_.maxlength) {
                content = content.substr(0, _style_.maxlength)
            }
            if (_cellCallback_) {
                content = _cellCallback_.apply(_self_, [data]);
            }
            leaf.append($(_view_.contentHtml).text(content).addClass(_config_["leaf_css"]).attr("cuitreeid", data[_tid_]).attr("title", nick).click(function() {
                _self_.privateClick($(this));
            }));
            this.privateSetStyle(leaf, _style_);
            var t = leaf.appendTo(select.find('ul'));
            $('.cui_treeBar',_context_).treeview({
                add: t
            });
        }
        return _self_;
    }
    /**
     * -METHOD-
     * @summary 更新树节点
     * @description 更新树节点
     * @method updateNode
     * @param data json <节点数据>
     * @return CuiTree
     * @since 0.1
     */
    this.updateNode = function(data) {
        if (!data && typeof data[_tid_] == "undefined" &&typeof data[_idx_] == "undefined" )return _self_;
        var content = data[_idx_];
        var nick = content;
        if (typeof content == "string" && _style_ && _style_.maxlength) {
            content = content.substr(0, _style_.maxlength)
        }
        if (_cellCallback_) {
            content = _cellCallback_.apply(_self_, [data]);
        }
        $('span[cuitreeid=' + data[_tid_] + ']',_context_).html(content).attr("title",nick);
        _data_[data[_tid_]] = data;
        return _self_;
    }
    /**
     * -METHOD-
     * @summary 删除树节点
     * @description 删除树节点
     * @method removeNode
     * @param id int/string <节点id，tid>
     * @return CuiTree
     * @since 0.1
     */
    this.removeNode = function(tid){
        var node = $('span[cuitreeid=' + tid + ']',_context_).parent();
        var parentNode = node.parent().parent();
        var pid = node.parent().prev().attr('cuitreeid');
        if(!node)return _self_;
        if(node.find('ul').length > 0)return _self_;
        if(node.hasClass(_view_.leafLastCss)){
            if(node.prev().length > 0){
                node.prev().addClass(_view_.leafLastCss);
            }else{
                parentNode.removeClass(_view_.collapsableCss).removeClass(_view_.expandableCss).children().removeClass(_config_["node_css"]).addClass(_config_["leaf_css"]).first().remove().last().remove();
            }
        }

        if(parentNode.hasClass(_view_.lastExpandableCss)){
            parentNode.removeClass(_view_.lastExpandableCss).addClass(_view_.leafLastCss);
        }

        if(parentNode.hasClass(_view_.lastCollapsableCss)){
            parentNode.removeClass(_view_.lastCollapsableCss).addClass(_view_.leafLastCss);
        }
        node.remove();
        _data_[tid] = null;
        if(!pid){
            pid = '_root';
        }
        var plist = _tree_[pid];
        var nlist = [];
        for (var i in plist) {
            if (plist[i] != tid)nlist.push(plist[i])
        }
        _tree_[pid] = nlist;

        return _self_;
    }
    /**
     * -METHOD-
     * @summary 设置tree内容显示器
     * @description 设置tree内容显示器
     * @method setView
     * @param view CuiTreeView <CuiTreeView内容显示器>
     * @since 0.1
     */
    this.setView = function(view) {
        if (view)_view_ = view;
        return _self_;
    }
}
///EndClass
var CuiTreeView = function() {

    this.frameHtml = '<ul class="cui_treeBar"></ul>';

    this.expandHtml = '<div class="cui_hitArea expandable-hitarea"></div>';

//    this.lastExpandHtml = '<div class="cui_hitArea expandable-hitarea lastExpandable-hitarea"></div>';
     <!--class="cui_hidden"-->
    this.nodeHtml = '<ul></ul>';

    this.leafHtml = '<li></li>';

    this.contentHtml = '<span class="cui_hand"></span>';

    this.expandableCss = 'expandable';

    this.collapsableCss = 'collapsable';

    this.lastExpandableCss = 'lastExpandable';

    this.lastCollapsableCss = 'lastCollapsable';

    this.leafLastCss = 'last';

    this.selectedCss = 'cui_treeSelect';

}

;(function($) {

	$.extend($.fn, {
		swapClass: function(c1, c2) {
			var c1Elements = this.filter('.' + c1);
			this.filter('.' + c2).removeClass(c2).addClass(c1);
			c1Elements.removeClass(c1).addClass(c2);
			return this;
		},
		replaceClass: function(c1, c2) {
			return this.filter('.' + c1).removeClass(c1).addClass(c2).end();
		},
		hoverClass: function(className) {
			className = className || "hover";
			return this.hover(function() {
				$(this).addClass(className);
			}, function() {
				$(this).removeClass(className);
			});
		},
		heightToggle: function(animated, callback) {
			animated ?
				this.animate({ height: "toggle" }, animated, callback) :
				this.each(function(){
					jQuery(this)[ jQuery(this).is(":hidden") ? "show" : "hide" ]();
					if(callback)
						callback.apply(this, arguments);
				});
		},
		heightHide: function(animated, callback) {
			if (animated) {
				this.animate({ height: "hide" }, animated, callback);
			} else {
				this.hide();
				if (callback)
					this.each(callback);
			}
		},
		prepareBranches: function(settings) {
			if (!settings.prerendered) {
				// mark last tree items
				this.filter(":last-child:not(ul)").addClass(CLASSES.last);
				// collapse whole tree, or only those marked as closed, anyway except those marked as open
				this.filter((settings.collapsed ? "" : "." + CLASSES.closed) + ":not(." + CLASSES.open + ")").find(">ul").hide();
			}
			// return all items with sublists
			return this.filter(":has(>ul)");
		},
		applyClasses: function(settings, toggler) {
//          remove by ypu .
//			this.filter(":has(>ul):not(:has(>a))").find(">span").click(function(event) {
//				toggler.apply($(this).next());
//			}).add( $("a", this) ).hoverClass();

			if (!settings.prerendered) {
				// handle closed ones first
				this.filter(":has(>ul:hidden)")
						.addClass(CLASSES.expandable)
						.replaceClass(CLASSES.last, CLASSES.lastExpandable);

				// handle open ones
				this.not(":has(>ul:hidden)")
						.addClass(CLASSES.collapsable)
						.replaceClass(CLASSES.last, CLASSES.lastCollapsable);

	            // create hitarea
				this.prepend("<div class=\"" + CLASSES.hitarea + "\"/>").find("div." + CLASSES.hitarea).each(function() {
					var classes = "";
					$.each($(this).parent().attr("class").split(" "), function() {
						classes += this + "-hitarea ";
					});
					$(this).addClass( classes );
				});
			}

			// apply event to hitarea
			this.find("div." + CLASSES.hitarea).click( toggler );
		},
		treeview: function(settings) {

			settings = $.extend({
				cookieId: "treeview"
			}, settings);

			if (settings.add) {
				return this.trigger("add", [settings.add]);
			}

			if ( settings.toggle ) {
				var callback = settings.toggle;
				settings.toggle = function() {
					return callback.apply($(this).parent()[0], arguments);
				};
			}

			// factory for treecontroller
			function treeController(tree, control) {
				// factory for click handlers
				function handler(filter) {
					return function() {
						// reuse toggle event handler, applying the elements to toggle
						// start searching for all hitareas
						toggler.apply( $("div." + CLASSES.hitarea, tree).filter(function() {
							// for plain toggle, no filter is provided, otherwise we need to check the parent element
							return filter ? $(this).parent("." + filter).length : true;
						}) );
						return false;
					};
				}
				// click on first element to collapse tree
				$("a:eq(0)", control).click( handler(CLASSES.collapsable) );
				// click on second to expand tree
				$("a:eq(1)", control).click( handler(CLASSES.expandable) );
				// click on third to toggle tree
				$("a:eq(2)", control).click( handler() );
			}

			// handle toggle event
			function toggler() {
				$(this)
					.parent()
					// swap classes for hitarea
					.find(">.cui_hitArea")
						.swapClass( CLASSES.collapsableHitarea, CLASSES.expandableHitarea )
						.swapClass( CLASSES.lastCollapsableHitarea, CLASSES.lastExpandableHitarea )
					.end()
					// swap classes for parent li
					.swapClass( CLASSES.collapsable, CLASSES.expandable )
					.swapClass( CLASSES.lastCollapsable, CLASSES.lastExpandable )
					// find child lists
					.find( ">ul" )
					// toggle them
					.heightToggle( settings.animated, settings.toggle );
				if ( settings.unique ) {
					$(this).parent()
						.siblings()
						// swap classes for hitarea
						.find(">.cui_hitArea")
							.replaceClass( CLASSES.collapsableHitarea, CLASSES.expandableHitarea )
							.replaceClass( CLASSES.lastCollapsableHitarea, CLASSES.lastExpandableHitarea )
						.end()
						.replaceClass( CLASSES.collapsable, CLASSES.expandable )
						.replaceClass( CLASSES.lastCollapsable, CLASSES.lastExpandable )
						.find( ">ul" )
						.heightHide( settings.animated, settings.toggle );
				}
			}

			function serialize() {
				function binary(arg) {
					return arg ? 1 : 0;
				}
				var data = [];
				branches.each(function(i, e) {
					data[i] = $(e).is(":has(>ul:visible)") ? 1 : 0;
				});
				$.cookie(settings.cookieId, data.join("") );
			}

			function deserialize() {
				var stored = $.cookie(settings.cookieId);
				if ( stored ) {
					var data = stored.split("");
					branches.each(function(i, e) {
						$(e).find(">ul")[ parseInt(data[i]) ? "show" : "hide" ]();
					});
				}
			}

			// add treeview class to activate styles
			this.addClass("treeview");
            this.find("span").add( $("a", this) ).hoverClass();//add by ypu
			// prepare branches and find all tree items with child lists
			var branches = this.find("li").prepareBranches(settings);

			switch(settings.persist) {
			case "cookie":
				var toggleCallback = settings.toggle;
				settings.toggle = function() {
					serialize();
					if (toggleCallback) {
						toggleCallback.apply(this, arguments);
					}
				};
				deserialize();
				break;
			case "location":
				var current = this.find("a").filter(function() { return this.href.toLowerCase() == location.href.toLowerCase(); });
				if ( current.length ) {
					current.addClass("selected").parents("ul, li").add( current.next() ).show();
				}
				break;
			}

			branches.applyClasses(settings, toggler);

			// if control option is set, create the treecontroller and show it
			if ( settings.control ) {
				treeController(this, settings.control);
				$(settings.control).show();
			}

			return this.bind("add", function(event, branches) {
				$(branches).prev()
					.removeClass(CLASSES.last)
					.removeClass(CLASSES.lastCollapsable)
					.removeClass(CLASSES.lastExpandable)
				.find(">.cui_hitArea")
					.removeClass(CLASSES.lastCollapsableHitarea)
					.removeClass(CLASSES.lastExpandableHitarea);
				$(branches).find("li").andSelf().prepareBranches(settings).applyClasses(settings, toggler);
			});
		}
	});

	// classes used by the plugin
	// need to be styled via external stylesheet, see first example
	var CLASSES = $.fn.treeview.classes = {
		open: "open",
		closed: "closed",
		expandable: "expandable",
		expandableHitarea: "expandable-hitarea",
		lastExpandableHitarea: "lastExpandable-hitarea",
		collapsable: "collapsable",
		collapsableHitarea: "collapsable-hitarea",
		lastCollapsableHitarea: "lastCollapsable-hitarea",
		lastCollapsable: "lastCollapsable",
		lastExpandable: "lastExpandable",
		last: "last",
		hitarea: "cui_hitArea"
	};

	// provide backwards compability
	$.fn.Treeview = $.fn.treeview;

})(jQuery);
