/*
 *
 */
(function($) {

var uiTreeClasses =
	        'ui-owntree ';

$.widget("ui.owntree", {
    options: {
        source: {
            url: null,
            nodelist: []
        },
        expand: 'all',
        height: 200,
        show: true,
        targetURL: null,
        classTree: '',
        classNode: '',
        classActiveNode: '',
        width: 200,
        debug: false
    },

    // private Funktionen setzen
    _create: function() {
        var self = this, options = self.options;

        self.element.hide();
        
        if (self.element.children('ul, dl').length > 0) {
            self.parseTree();
        } else {
            self.buildTree();
        }

        if (options.show) {
            self.element.show();
        }
    },
    // - rootnode muss ein jQuery-Object sein
    // - toappend muss ein Hash sein, in der Struktur, wie er auch im Source
    //      verwendet wird
    _appendNode: function(rootnode, toappend) {
        var self = this, options = self.options, element = null;
        if (rootnode.is('dt')) {
            // wir haben ein richtiges node
            if (rootnode.next().length == 0 || rootnode.next().is('dt')) {
                self._appendNodeList(rootnode);
            }
            toappend['id'] = rootnode.attr('id') + '-' + rootnode.next().children('dl').children('dt').length
            self._trigger('beforeAppend', 0, {source: toappend});
            element = $.each(self._createTreeNode(toappend), function(key, item) {rootnode.next().children('dl').append(item)});
            self._trigger('afterAppend', 0, {node: element[0], source: toappend});
        } else if (rootnode.is('dl.ui-owntree')) {
            // wir haben die wurzel allen uebels
            toappend['id'] = 'owntree-' + rootnode.children('dt').length;
            self._trigger('beforeAppend', 0, {source: toappend});
            element = $.each(self._createTreeNode(toappend), function(key, item) {rootnode.append(item)});
            self._trigger('afterAppend', 0, {node: element[0], source: toappend});
        }
        // der Inhalt koennte sich aendern, so dass wir den Click erst hier drauf packen koennen
        element[0].children('span')
                .click(function(event) {
                    self.setActive($(this).parent());
                    return self._toggle(event, $(this).parent());
                })
        if (toappend.leaf != null) {
            self._appendNodes(element[0], toappend.leaf)
        }
    },
    // nodelist fuer das node vorbereiten
    _appendNodeList: function(rootnode, return_created_node) {
        var node = $('<dd><dl></dl></dd>')
                .addClass('ui-owntree-leaf ui-widget-content')
                .hide();

        if (return_created_node) {
            return node;
        } else {
            node.insertAfter(rootnode);
            return null;
        }
    }, 
    // mehrere Nodes auf einmal anhaengen
    _appendNodes: function(rootnode, nodelist) {
        var self = this, options = self.options;

        $.each(nodelist, function(key, item){
            self._appendNode(rootnode, item);
        })
    },
    // Baum aus dem Source bauen
    buildTree: function() {
        var self = this, options = self.options;

        self._clearStructure();
        
        var ownTree = (self.ownTree = $('<dl></dl>'))
                .appendTo(self.element)
                .addClass(uiTreeClasses + options.classTree)
                .hide();

        // wenn wir bereits eine nodelist haben, dann die aufbauen
        if (options.source.nodelist.length > 0) {
            $.each(options.source.nodelist, function(key, item) {
                self._appendNode(ownTree, item);
            })
            ownTree.show();
        } else if (options.source.url != null) {
            // nodelist extern laden, weil wir nix haben
            $.getJSON(options.source.url, {}, function(json) {
                    options.source.nodelist = json;
                    self._appendNodes(ownTree, json);
                    ownTree.show();
                })
        }
        self.ownTree = ownTree;
    },
    // die Struktur komplett loeschen
    _clearStructure: function() {
        var self = this, options = self.options;
        self.element.children('*').remove();
    },
    _collapse: function(event, node) {
        var self = this, options = self.options;
        
        var list = node.next();
        if (list.is('dd')) {
            list.hide();
            node.addClass('ui-owntree-closed')
                .removeClass('ui-owntree-opened')
                .children('span.ui-icon')
                    .removeClass('ui-icon-triangle-1-s')
                    .addClass('ui-icon-triangle-1-e');
        }
        return false;
    },
    // creates a list of jQuery objects, which contain all infos of the node_struc
    _createTreeNode: function(node_struc) {
        var self = this, options = self.options, node = [];
        // node erstellen
        node[0] = $('<dt><span class="ui-icon ui-owntree-trigger float_left"></span></dt>');
        if (options.targetURL == null || node_struc.parameter_self == null) {
            node[0].append('<span class="ui-heading">'+node_struc.name+'</span>');
        } else {
            node[0].append('<a class="ui-heading" href="'+self._generateURL({
                url: options.targetURL,
                options: node_struc.parameter_self
            })+'">'+node_struc.name+'</a>');
        }
        if (node_struc.id != null) {
            node[0].attr('id', node_struc.id);
        }
        node[0].addClass('ui-owntree-node ui-owntree-closed ui-owntree-state-default ui-state-default');

        if (node_struc.parameter_leaf != null) {
            node[0].children('span.ui-icon')
                .addClass('ui-icon-triangle-1-e')
        } else {
            node[0].children('span.ui-icon')
                .addClass('ui-icon-carat-1-e')
        }

        // leaf ans node haengen
        if (node_struc.leaf != null) {
            node[1] = self._appendNodeList(node[0], true);
        }
        
        return node;
    },
    _debug: function(msg){
        var self = this, options = self.options;
        if (options.debug) {
            console.log(msg)
        }
    },
    _expand: function(event, node) {
        var self = this, options = self.options;

        var list = node.next();
        var data = self._getSource(node)
        if (options.expand == 'one') {
            self.ownTree.find('dd:not(dd:has(#'+node.attr('id')+'))').each(function(key, item){
                self._collapse(0, $(item).prev());
            })
        }
        if (list.is('dd')) {
            node.addClass('ui-owntree-opened')
                .removeClass('ui-owntree-closed')
                .children('span.ui-icon')
                    .removeClass('ui-icon-triangle-1-e')
                    .addClass('ui-icon-triangle-1-s');
                list.show();
                self._trigger('afterClick', event, {node: node, tree: self});
        } else {
            if (data.leaf == null && data.parameter_leaf != null) {
                $.getJSON(options.source.url, data.parameter_leaf, function(json) {
                    if (json.length > 0) {
                        data.leaf = json;
                        self._appendNodes(node, json);
                        node.addClass('ui-owntree-opened')
                            .removeClass('ui-owntree-closed')
                            .children('span.ui-icon')
                                .removeClass('ui-icon-triangle-1-e')
                                .addClass('ui-icon-triangle-1-s');
                        node.next().show();
                        self._trigger('afterClick', event, {node: node, tree: self});
                    } else {
                        node.addClass('ui-owntree-nochilds')
                            .children('span.ui-icon')
                            .removeClass('ui-icon-triangle-1-e ui-icon-triangle-1-s')
                            .addClass('ui-icon-carat-1-e');
                    }
                })
            } else {
                node.addClass('ui-owntree-nochilds')
                    .children('span.ui-icon')
                    .removeClass('ui-icon-triangle-1-e ui-icon-triangle-1-s')
                    .addClass('ui-icon-carat-1-e');
            }
        }
        return false;
    },
    _generateURL: function(hash) {
        var startchar = '?', url = hash.url.toString();
        if (url.indexOf('?') >= 0) {
            startchar = '&amp;';
        }
        $.each(hash.options, function(key, item){
            url = url + startchar + key + '=' + item;
            if (startchar == '?') {
                startchar = '&amp;';
            }
        })
        return url;
    },
    // versucht anhand des nodes den Source zu suchen
    // zuerst rueckwaerts zu root hangeln und dann wieder vorwaerts durch die arrays
    _getSource: function(node) {
        var self = this, options = self.options;

        var path = [], abort = false, curnode = node, parent = node.parent();
        while (!abort) {
            if (parent.is('.ui-owntree')) {
                abort = true;
            }
            path.push(parent.children('dt').index(curnode));
            curnode = parent.parent().prev();
            parent = curnode.parent();
        }
        path = path.reverse();

        curnode = self.options.source.nodelist[path.shift()];
        while(path.length > 0) {
            curnode = curnode.leaf[path.shift()];
        };
        return curnode;
    },
    // Tree aus dem html ableiten
    parseTree: function() {
        var self = this, options = self.options;
        self._debug('ich soll hier was parsen');
    },
    setActive: function(node) {
        var self = this, options = self.options;

        self.ownTree.find('.ui-owntree-state-active')
            .removeClass('ui-owntree-state-active ui-state-active '+options.classActiveNode)
            .addClass('ui-owntree-state-default ui-state-default');
        node.addClass('ui-owntree-state-active ui-state-active'+options.classActiveNode).removeClass('ui-state-default ui-owntree-state-default');
    },
    // toogle the status of the node
    _toggle: function(event, node) {
        var self = this, options = self.options;
        if (node.is('.ui-owntree-opened')) {
            return self._collapse(event, node);
        } else if (node.is('.ui-owntree-closed')) {
            return self._expand(event, node);
        }
        return false;
    }
})

})(jQuery);
