(function() {

    tinymce.create('tinymce.plugins.JiveListsPlugin', {


        fixLists : function(ed){
            var n = ed.selection.getNode();
            n = ed.dom.getParent(n, "li");
            if(n != null && n.nodeType == 1 && n.nodeName.toLowerCase() == "li"){
                var l = ed.dom.getParent(n, "ol,ul");
                if(tinymce.isGecko){
                    for(var i=0;i<l.childNodes.length;i++){
                        var li = l.childNodes[i];
                        if(li.nodeType == 1 && li.nodeName.toLowerCase() == "li" && li.childNodes.length == 0){
                            // add an empty <br> to the li. empty li's are bad :(
                            li.appendChild(ed.plugins.jivemacros.createMozBR(ed.getDoc()));
                        }
                    }
                }

                if(l.parentNode.nodeName.toLowerCase() == "p"){
                    var p = l.parentNode;
                    p.parentNode.insertBefore(l, p);
                    p.parentNode.removeChild(p);
                    ed.selection.select(n).collapse(true);
                }
                var ps = l.previousSibling;
                if(ps != null && l.nodeName == ps.nodeName){
                    // merge the lists
                    var i=0;
                    while(ps.childNodes.length){
                        l.insertBefore(ps.childNodes[0], l.childNodes[i]);
                        i++;
                    }
                }
                var ps = l.nextSibling;
                if(ps != null && l.nodeName == ps.nodeName){
                    // merge the lists
                    while(ps.childNodes.length){
                        l.appendChild(ps.childNodes[0]);
                    }
                }
            }
        },

        execCommand : function(cmd, ui, val){
            var ed = tinyMCE.activeEditor;
            if(cmd.indexOf("mceOLListStyle") == 0){
                var index = parseInt(cmd.substr("mceOLListStyle".length));

                var list = ed.plugins.jivelists.ol_styles;
                var style = list[index];

                var n = tinyMCE.activeEditor.selection.getNode();
                var par = ed.dom.getParent(n, 'ol');

                par.style.listStyleType = style[1];

                return true;
            }
            if(cmd.indexOf("mceULListStyle") == 0){
                var index = parseInt(cmd.substr("mceOLListStyle".length));

                var list = ed.plugins.jivelists.ul_styles;
                var style = list[index];

                var n = tinyMCE.activeEditor.selection.getNode();
                var par = ed.dom.getParent(n, 'ul');

                par.style.listStyleType = style[1];

                return true;
            }

            function fixBlockQuote(ed){
                var n = ed.selection.getNode();
                n = ed.dom.getParent(n, "ol,ul");
                var quote = ed.dom.getParent(n, "blockquote");
                if(quote != null){
                    var newList = ed.getDoc().createElement(n.nodeName);
                    quote.parentNode.insertBefore(newList, quote);
                    while(quote.childNodes.length) newList.appendChild(quote.childNodes[0]);
                    quote.parentNode.removeChild(quote);
                    ed.selection.select(n);
                }
            }

            if(cmd.indexOf("mceOutdent") == 0){
                ed.execCommand("Outdent");
                this.fixLists(ed);
                return true;
            }
            if(cmd.indexOf("mceIndent") == 0){
                ed.execCommand("Indent");
                this.fixLists(ed);
                fixBlockQuote(ed);
                return true;
            }
            if(cmd.indexOf("mceInsertUnorderedList") == 0){
                ed.execCommand("InsertUnorderedList");
                this.fixLists(ed);
                return true;
            }
            if(cmd.indexOf("mceInsertOrderedList") == 0){
                ed.execCommand("InsertOrderedList");
                this.fixLists(ed);
                return true;
            }

            return false;
        },


        cleanList : function(ed, n){
            if(n.nodeType != 1) return;
            for(var i=0;i<n.childNodes.length;i++){
                var kid = n.childNodes[i];
                if(kid.nodeType != 1 && kid.nodeType != 3 ||
                        kid.nodeType == 1 && (kid.nodeName.toLowerCase() == "meta" || kid.nodeName.toLowerCase() == "style")){
                    n.removeChild(kid);
                    i--;
                }
                this.cleanList(ed, kid);
            }
        },


        init : function(ed, url){
            this.url = url;
            var t = this;
            this.index = 0;
            this.ol_styles = new Array();
            this.ol_styles.push(["default",""]);
            this.ol_styles.push(["none","none"]);
            this.ol_styles.push(["inherit","inherit"]);
            this.ol_styles.push(["d","decimal"]);
            this.ol_styles.push(["dz","decimal-leading-zero"]);
            this.ol_styles.push(["ur","upper-roman"]);
            this.ol_styles.push(["lr","lower-roman"]);
            this.ol_styles.push(["ua","upper-alpha"]);
            this.ol_styles.push(["la","lower-alpha"]);
            this.ol_styles.push(["lg","lower-greek"]);
            this.ol_styles.push(["ki","katakana-iroha"]);
            this.ol_styles.push(["k","katakana"]);
            this.ol_styles.push(["hii","hiragana-iroha"]);
            this.ol_styles.push(["hi","hiragana"]);
            this.ol_styles.push(["ci","cjk-ideographic"]);
            this.ol_styles.push(["g","georgian"]);
            this.ol_styles.push(["a","armenian"]);
            this.ol_styles.push(["he","hebrew"]);

            this.ul_styles = new Array();
            this.ul_styles.push(["default",""]);
            this.ul_styles.push(["none","none"]);
            this.ul_styles.push(["inherit","inherit"]);
            this.ul_styles.push(["s","square"]);
            this.ul_styles.push(["c","circle"]);
            this.ul_styles.push(["di","disc"]);


            ed.onNodeChange.add(function(ed){
                this.fixLists(ed);
                var node = ed.selection.getNode();
                var n = ed.dom.getParent(node, "ul,ol");
                if(n){
                    this.cleanList(ed, n);
                }

            }, this);

            ed.onInit.add(function() {
                if (ed && ed.plugins.contextmenu) {
                    ed.plugins.contextmenu.onContextMenu.add(function(th, m, e) {
                        var sm, se = ed.selection, el = se.getNode() || ed.getBody();

                        if (ed.dom.getParent(e, 'ol')){
                            var par = ed.dom.getParent(e, 'ol');
                            var last = ed.dom.getParent(e, function(x){
                                return $def(x.tagName) && x.tagName.toLowerCase() == "ol" && x != par;
                            });

                            m.addSeparator();
                            sm = m.addMenu({title : 'jivelists.list_style', max_height : "200", 'class' : 'mceDropDown defaultSkin mceMacroMenu mceListBoxMenu'});
                            var list = ed.plugins.jivelists.ol_styles;
                            for(var i=0;i<list.length;i++){
                                if(last != null || last == null && list[i][0] != "inherit"){
                                    var clz = "";
                                    if(par.style.listStyleType == list[i][1]){
                                        clz = "mceMenuItemSelected";
                                    }else{
                                        clz = "";
                                    }
                                    sm.add({title : 'jivelists.' + list[i][0], cmd : 'mceOLListStyle' + i, 'class' : clz});
                                }
                                if(i == 2){
                                    sm.addSeparator();
                                }
                            }

                        }else if(ed.dom.getParent(e, 'ul')){
                            var par = ed.dom.getParent(e, 'ul');
                            var last = ed.dom.getParent(e, function(x){
                                return $def(x.tagName) && x.tagName.toLowerCase() == "ul" && x != par;
                            });

                            m.addSeparator();
                            sm = m.addMenu({title : 'jivelists.list_style', max_height : "200", 'class' : 'mceDropDown defaultSkin mceMacroMenu mceListBoxMenu'});
                            var list = ed.plugins.jivelists.ul_styles;
                            for(var i=0;i<list.length;i++){
                                if(last != null || last == null && list[i][0] != "inherit"){
                                    var clz = "";
                                    if(par.style.listStyleType == list[i][1]){
                                        clz = "mceMenuItemSelected";
                                    }else{
                                        clz = "";
                                    }
                                    sm.add({title : 'jivelists.' + list[i][0], cmd : 'mceULListStyle' + i, 'class' : clz});
                                }
                                if(i == 2){
                                    sm.addSeparator();
                                }
                            }

                        }
                    });
                }
            });


            this.prepForEnter = false;
            this.prepForDel = false;

            ed.onKeyDown.addToTop(function(ed, e) {
                this.prepForEnter = false;
                this.prepForDel = false;
                if(e.keyCode == 8 && ed.selection.isCollapsed()){ // delete key
                    var li = ed.dom.getParent(ed.selection.getNode(), 'li');
                    var list = ed.dom.getParent(ed.selection.getNode(), 'ul,ol');
                    var sel = ed.selection;
                    var isFrontOfLi = sel.getBookmark().start == 0 || sel.getRng().startOffset == 0;
                    if(li != null && li.nodeType == 1 && li.previousSibling== null && tinymce.isGecko){            // first li in list
                        var selMe = li.childNodes.length ? li.childNodes[0] : null;
                        var b = sel.getBookmark();
                        if(isFrontOfLi){
                            this.prepForDel = true;
                            tinymce.dom.Event.cancel(e);
                            while(li.childNodes.length){
                                var kid = li.childNodes[0];
                                if(kid.nodeType == 1 && kid.nodeName.toLowerCase() == "br"){
                                    var p = ed.getDoc().createElement('P');
                                    p.appendChild(kid);
                                    kid = p;
                                }
                                list.parentNode.insertBefore(kid, list);
                            }
                            list.removeChild(li);
                            if(selMe){
                                ed.selection.moveToBookmark(b);
//                                ed.selection.select(selMe);
//                                ed.selection.collapse(true);
                            }
                        }
                    }else if(li != null && li.nodeType == 1 && isFrontOfLi){                                   // not first li
                        this.prepForDel = true;
                        tinymce.dom.Event.cancel(e);
                        ed.execCommand("mceOutdent");
                        return false;
                    }
                }else if(e.keyCode == 13 && !e.shiftKey){ // enter key
                    var li = ed.dom.getParent(ed.selection.getNode(), 'li');
                    var list = ed.dom.getParent(ed.selection.getNode(), 'ul,ol');
                    if(li != null &&
                       li.nodeType == 1 &&
                       li.nextSibling == null &&
                       li.childNodes.length == 1 &&
                       $def(li.childNodes[0].nodeName.toLowerCase()) &&
                       li.childNodes[0].nodeName.toLowerCase() == "br"){
                        this.prepForEnter = true;
                        tinymce.dom.Event.cancel(e);

                        var par = list.parentNode;
                        if(par.nodeName.toLowerCase() == "ol" || par.nodeName.toLowerCase() == "ul"){
                            ed.execCommand("mceOutdent");
                        }else{
                            var p = ed.plugins.jivemacros.createEmptyPara(ed.getDoc());
                            if(par.childNodes[par.childNodes.length-1] == list){
                                par.appendChild(p);
                            }else{
                                par.insertBefore(p, list.nextSibling);
                            }
                            list.removeChild(li);
                            if(list.childNodes.length == 0){
                                list.parentNode.removeChild(list);
                            }
                            ed.selection.select(p.childNodes[0]);
                            ed.selection.collapse(true);
                        }
                    }
                }else if(e.keyCode == 13 && e.shiftKey){
                    window.breakNow = true;
                    // shift enter, so put in a <br>
                    var li = ed.dom.getParent(ed.selection.getNode(), 'li');
                    var list = ed.dom.getParent(ed.selection.getNode(), 'ul,ol');
                    var sel = ed.selection;
                    var mac = ed.plugins.jivemacros.isMacro(sel.getNode()) || ed.plugins.jivemacros.isLink(sel.getNode());
                    var node = sel.getNode();
                    var isEndOfBlock = sel.getRng().startOffset == (sel.getNode().childNodes[sel.getNode().childNodes.length-1].nodeValue.length) &&
                                       node.childNodes.length > 0 &&
                                        node.childNodes[node.childNodes.length-1].nodeType == 3 &&
                                        sel.getRng().startContainer == node.childNodes[node.childNodes.length-1];
                    if(li != null && isEndOfBlock){
                        this.prepForEnter = true;
                        tinymce.dom.Event.cancel(e);

                        var p = ed.getDoc().createElement('BR');
                        li.appendChild(p);
                        ed.selection.select(p);
                        ed.selection.collapse();
                    }
                }
                if(e.keyCode == 9 && !e.ctrlKey && !e.altKey){
                    var p = ed.dom.getParent(ed.selection.getNode(), 'ul,ol');
                    if(p != null){
                        tinymce.dom.Event.cancel(e);
                        return false;
                    }
                }
            }, this);
            ed.onKeyPress.add(function(ed, e) {
                if(e.keyCode == 8 && this.prepForDel){
                    tinymce.dom.Event.cancel(e);
                    return false;
                }
                if(e.keyCode == 13 && this.prepForEnter){
                    tinymce.dom.Event.cancel(e);
                }
                if(e.keyCode == 9 && !e.ctrlKey && !e.altKey){
                    var p = ed.dom.getParent(ed.selection.getNode(), 'ul,ol');
                    if(p != null){
                        tinymce.dom.Event.cancel(e);
                        return false;
                    }
                }
            }, this);
            ed.onKeyUp.add(function(ed, e) {
                if(e.keyCode == 8 && this.prepForDel){
                    tinymce.dom.Event.cancel(e);
                    return false;
                }
                if(e.keyCode == 13 && this.prepForEnter){
                    tinymce.dom.Event.cancel(e);
                }
                if(e.keyCode == 9 && !e.ctrlKey && !e.altKey){
                    var p = ed.dom.getParent(ed.selection.getNode(), 'ul,ol');
                    if(p != null){
                        if(e.shiftKey){
                            ed.execCommand("mceOutdent");
                        }else{
                            ed.execCommand("mceIndent");
                        }
                        tinymce.dom.Event.cancel(e);
                        return false;
                    }
                }
            }, this);

            
        },

        getInfo : function() {
            return {
                longname : 'Jive Lists',
                author : 'Jive Software',
                authorurl : 'http://jivesoftware.com',
                infourl : 'http://jivesoftware.com',
                version : tinyMCE.majorVersion + "." + tinyMCE.minorVersion
            };
        },


		/**
		 * Creates control instances based in the incomming name. This method is normally not
		 * needed since the addButton method of the tinymce.Editor class is a more easy way of adding buttons
		 * but you sometimes need to create more complex controls like listboxes, split buttons etc then this
		 * method can be used to create those.
		 *
		 * @param {String} n Name of the control to create.
		 * @param {tinymce.ControlManager} cm Control manager to use inorder to create new control.
		 * @return {tinymce.ui.Control} New control instance or null if no control was created.
		 */
		createControl: function(n, cm) {
			return null;
		}


    });
	// Register plugin
	tinymce.PluginManager.add('jivelists', tinymce.plugins.JiveListsPlugin);
})();
