//TODO exit links and formatting on the left as well as right (most importantly
//links)
//TODO error checking for urls on anchors and imgs - not sure if this is
//relevant since autostripping of site root, ie not all urls will have http://
//at the start
var Editor = function()
{
    var current_editable_div = null;

    var min_width = Config.editorMinWidth();
    var min_height = Config.editorMinHeight();

    var current_node = null;
    var editor_div = null;

    var resize_counter = 0;
    var resize_interval = 5;

    var finishedCallback = null;

    var left_blinker = null;
    var right_blinker = null;

    var _pub = {
        edit: function(node,callback)
        {
            if(node)
            {
                current_node = node;
                showEditor();
            }
            else
                Debug.log('lulwut');
            finishedCallback = callback;
        },

        editBefore: function(node,callback)
        {
            var new_node = document.createTextNode(' ');
            var a = null;
            if(node.parentNode.match('a'))
                a = node.parentNode;
            else if(tmp = node.parentNode.up('a'))
                a = tmp;
            node.parentNode.insertBefore(new_node,node);
            Editor.edit(new_node,callback);
        },

        editAfter: function(node,callback)
        {
            var new_node = document.createTextNode(' ');
            if(node.nextSibling)
                node.parentNode.insertBefore(new_node,node.nextSibling);
            else
                node.parentNode.appendChild(new_node);
            Editor.edit(new_node,callback);
        },

        addBlinkers: function(node)
        {
            //tried putting these inside the nodes block node so
            //they inherit font height but this breaks mouseover
            //behaviour
            if(!left_blinker)
            {
                left_blinker = new Element('div',{class:'marker left'});
                document.body.appendChild(left_blinker);
            }
            if(!right_blinker)
            {
                right_blinker = new Element('div',{class:'marker right'});
                document.body.appendChild(right_blinker);
            }

            var left,right;
            if(node.nodeType == 3)
            {
                left = TextNode.coordsFromOffset(node,0);
                right = TextNode.coordsFromOffset(node,node.data.length);
            }
            else
            {
                var pos = node.cumulativeOffset();
                left = {left:pos.left,top:pos.top + node.getHeight() - left_blinker.getHeight()};
                right = {left:pos.left + node.getWidth(),top:pos.top + node.getHeight() - right_blinker.getHeight()};
            }

            left_blinker.style.left = left.left + 'px';
            left_blinker.style.top = left.top + 'px';
            right_blinker.style.left = right.left + 'px';
            right_blinker.style.top = right.top + 'px';

            if(left_blinker.onclick_func)
                Event.stopObserving(left_blinker,'click',left_blinker.onclick_func);
            if(right_blinker.onclick_func)
                Event.stopObserving(right_blinker,'click',right_blinker.onclick_func);
            left_blinker.onclick_func = 
            function()
            {
                Editor.hideBlinkers();
                Editor.editBefore(node,RRMark2.finishEdit);
            };
            right_blinker.onclick_func =
            function()
            {
                Editor.hideBlinkers();
                Editor.editAfter(node,RRMark2.finishEdit);
            };
            Event.observe(left_blinker,'click',left_blinker.onclick_func);
            Event.observe(right_blinker,'click',right_blinker.onclick_func);
        },

        hideBlinkers: function()
        {
            if(left_blinker)
            {
                left_blinker.remove();
                right_blinker.remove();
                left_blinker = null;
                right_blinker = null;
            }
        }
    };

    var showEditor = function()
    {
        if(editor_div)
        {
            Debug.log('editor div is already active!');
            return;
        }
        Wrapper.free();

        createFader();

        if(current_node.nodeType == 3)
        {
            //TODO improve this
            if(current_node.parentNode.match('p.add_content'))
            {
                var new_text = document.createTextNode('');
                var new_p = new Element('p');
                new_p.appendChild(new_text);
                current_node.parentNode.insert({before:new_p});
                current_node = new_text;
            }

            createTextEditorDiv(current_node);
        }
        else if(current_node.tagName.toLowerCase() == 'a')
        {
            createAnchorEditorDiv(current_node);
        }
        else if(current_node.tagName.toLowerCase() == 'img')
        {
            createImageEditorDiv(current_node);
        }
        else
        {
            Debug.log('editor called on some unexpected node: ' + current_node);
            hideEditor();
        }
        //TODO add other types?

        current_editable_div = null;
        if(current_node.parentNode.match('div.editable'))
            current_editable_div = current_node.parentNode;
        else
            current_editable_div = current_node.parentNode.up('div.editable');
        if(!current_editable_div)
            Debug.log('uh oh youve somehow edited a node that isnt a descendant of an editable div');

        var type = null;
        if(current_node.nodeType == 3)
            type = 'text';
        else if(current_node.match('img'))
            type = 'image';
        else if(current_node.match('a'))
            type = 'link';
        else
            type = 'item';

        current_editable_div.history.push('edit ' + type);
    };

    var hideEditor = function()
    {
        if(editor_div)
            editor_div.remove();
        editor_div = null;
        hideFader();
    };

    //TODO only return the nodes resulting from the edited textarea, not the
    //adjacent nodes too
    var saveContent = function(new_content)
    {
        var modified_nodes = new Array();
        if(current_node)
        {
            if(current_node.nodeType == 3)
            {
                if(current_node.parentNode.match('a') ||
                    current_node.parentNode.up('a'))
                {
                    current_node.data = new_content.data.replace(/[ \n\t]+/g,' ');
                    modified_nodes.push(current_node);
                }
                else
                {
                    var top = TextNode.getBlockNode(current_node);

                    var block_type;
                    if(top.match('li'))
                        block_type = 'li';
                    else
                        block_type = top.tagName;

                    var blocks = decomposeText(new_content.data,current_node);

                    blocks.each(function(block){
                        var new_block = new Element(block_type);
                        block.each(function(node){
                            new_block.appendChild(node);
                        });
                        modified_nodes = modified_nodes.concat(TextNode.collectTextNodes(new_block));
                        top.parentNode.insertBefore(new_block,top);
                    });
                    top.remove();
                }
                if(new_content.list)
                    Format.listify(modified_nodes);
            }
            else if(current_node.tagName.toLowerCase() == 'img')
            {
                current_node.removeClassName('unsaved');
                current_node.src = new_content.src;
                current_node.alt = new_content.alt;
                modified_nodes.push(current_node);
            }
            else if(current_node.tagName.toLowerCase() == 'a')
            {
                current_node.removeClassName('unsaved');
                current_node.removeClassName('style1');
                current_node.removeClassName('style2');
                current_node.removeClassName('style3');
                current_node.href = new_content.href;
                current_node.title = new_content.title;
                current_node.target = new_content.target;
                current_node.addClassName(new_content.style);
                modified_nodes.push(current_node);
            }
        }
        else
            Debug.log('saving but no current node, how could this happen to me?!?');

        if(finishedCallback)
            finishedCallback(modified_nodes);
    };

    var createTextEditorDiv = function(content)
    {
        var textarea = new Element('textarea');

        textarea.value = content.data.replace(/[ \n\t]+/g,' ');
        //textarea.value = content.data;
        textarea.style.width = '100%';
        textarea.style.height = '100%';
        textarea.style.border = '1px inset';
        //TODO figure out a way to use oninput here
        Event.observe(textarea,'keypress',resizeTextEditorDiv);
        Event.observe(textarea,'keydown',checkPaste1);
        Event.observe(textarea,'keyup',checkPaste2);

        var list_checkbox = new Element('input',{'type':'checkbox'});

        var save_func = function(){
            return saveContent({
                data: textarea.value,
                list: list_checkbox.checked
            });
        };

        editor_div = createGenericEditorDiv({
                content:new Array(textarea),
                save_func:save_func,
                nav_buttons:true,
                nav_filter:'text,img'
        });

        var anchor;
        if(content.parentNode.match('a'))
            anchor = content.parentNode;
        if(!anchor)
            anchor = content.parentNode.up('a');
        if(anchor)
        {
            editor_div.appendChild(document.createTextNode(' '));
            editor_div.appendChild(Util.createButton(
                'Edit Link',
                'edit the url and title of the link that uses this text',
                function(){
                    editor_div.save();
                    editor_div.remove();
                    editor_div = null;
                    Editor.edit(anchor,finishedCallback);
                },
                1
            ));
            //inspect the next textnode and see if it is part of the same
            //anchor, if not provide an 'exit link' button
            if((!editor_div.nextToEdit ||
                (editor_div.nextToEdit.parentNode != anchor &&
                !editor_div.nextToEdit.parentNode.descendantOf(anchor))))
            {
                editor_div.appendChild(Util.createButton(
                    'Exit Link',
                    'insert text after this link',
                    function(){
                        editor_div.save();
                        editor_div.remove();
                        editor_div = null;
                        Format.disableIntegrity();
                        var tn = document.createTextNode(' ');
                        if(anchor.nextSibling)
                            anchor.parentNode.insertBefore(tn,anchor.nextSibling);
                        else
                            anchor.parentNode.appendChild(tn);
                        Editor.edit(tn,finishedCallback);
                        Format.enableIntegrity();
                    },
                    1,
                    'exit_link_right')
                );
            }
            else if((textarea.value.replace(/[\n\t ]*/,'') == '' && 
                (!editor_div.prevToEdit ||
                (editor_div.prevToEdit.parentNode != anchor &&
                !editor_div.prevToEdit.parentNode.descendantOf(anchor)))))
            {
                editor_div.appendChild(Util.createButton(
                    'Exit Link',
                    'insert text before this link',
                    function(){
                        editor_div.save();
                        editor_div.remove();
                        editor_div = null;
                        Format.disableIntegrity();
                        var tn = document.createTextNode(' ');
                        anchor.parentNode.insertBefore(tn,anchor);
                        Editor.edit(tn,finishedCallback);
                        Format.enableIntegrity();
                    },
                    1,
                    'exit_link_left')
                );
            }
        }

        //generate 'exit blah' buttons for formats
        var formats = Format.getFormats(content);
        if(formats.length)
            editor_div.appendChild(document.createTextNode(' '));
        formats.each(function(fm){
            editor_div.appendChild(Util.createButton(
                'Exit ' + fm,
                'insert non-' + fm + ' text after this text',
                function(){
                    Format.disableIntegrity();

                    //TODO -1 subscript doesnt work in ie?
                    if(editor_div.firstChild.value.substr(-1,1) == ' ')
                        new_content = '';
                    else
                        new_content = ' ';

                    //new_content = 'placeholder';
                        
                    var new_text = document.createTextNode(new_content);

                    var walker;
                    if(textarea.value.replace(/[ \n\t]*/,'') == '')
                    {
                        walker = Format.isolate(content).parentNode;
                        editor_div.remove();
                        editor_div = null;
                    }
                    else
                    {
                        editor_div.save();
                        var after = editor_div.nextToEdit;
                        editor_div.remove();
                        editor_div = null;
                        walker = TextNode.prevLeaf(after,null,
                            'text',{skip_brs: true,accept_empty: true}).parentNode;
                    }
                    if(walker.match(fm))
                        fm_to_escape = walker;
                    else
                        fm_to_escape = walker.up(fm);

                    var new_formats = formats.without(fm);
                    var placeholder = document.createTextNode('');

                    if(fm_to_escape.nextSibling)
                        fm_to_escape.parentNode.insertBefore(placeholder,fm_to_escape.nextSibling);
                    else
                        fm_to_escape.parentNode.appendChild(placeholder);

                    var formatted_node =
                        Format.formatNode(new_text,Format.getFormats(placeholder));

                    placeholder.parentNode.insertBefore(formatted_node,placeholder);
                    placeholder.parentNode.removeChild(placeholder);

                    Editor.edit(new_text,finishedCallback);
                    Format.enableIntegrity();
                },
                1,
                'exit_' + fm
            ));
        });

        /*
        if(!(content.parentNode.match('a') || content.parentNode.up('a')))
        {
            editor_div.appendChild(list_checkbox);
            editor_div.appendChild(new Element('label',
                {'class':'checkbox','for':list_checkbox.identify()}
            ).update('listify'));
        }
        */

        var pos_start = TextNode.coordsFromOffset(content,0);
        var pos_end = TextNode.coordsFromOffset(content,content.data.length);

        var height = min_height,width;
        var top,left;

        top = pos_start.top;
        if(pos_start.top == pos_end.top)
        {
            //single line
            left = pos_start.left;
        }
        else
        {
            //multi line
            var parent = TextNode.getBlockNode(current_node);
            var parent_pos = parent.cumulativeOffset();
            left = parent_pos.left;
        }

        if(top < window.pageYOffset + 5)
            window.scrollTo(window.pageXOffset,top-5);

        editor_div.style.left = (left-1 - window.pageXOffset) + 'px';
        editor_div.style.top = (top-1 - window.pageYOffset) + 'px';

        document.body.appendChild(editor_div);
        var editor_div_pos = editor_div.cumulativeOffset();

        var div= content.parentNode.up('div.editable');
        var walker = content.parentNode;
        while(1)
        {
            //Debug.log(walker.tagName);
            walker = walker.parentNode;
            if(!walker)
                break;
        }

        editor_div.max_width = div.getWidth();
        editor_div.max_height = window.innerHeight - editor_div_pos.top - 10;

        resizeTextEditorDiv(null,1);

        if(top + editor_div.getHeight() > window.pageYOffset + window.innerHeight + 5)
        {
            window.scrollTo(window.pageXOffset,top + editor_div.getHeight() - window.innerHeight + 5);
            editor_div.style.top = (top-1 - window.pageYOffset) + 'px';
            editor_div_pos = editor_div.cumulativeOffset();
            editor_div.max_height = window.innerHeight - editor_div_pos.top - 10;
        }

        textarea.focus();
    };

    var createImageEditorDiv = function(img)
    {
        var img_copy = new Element('img',{'src':img.src});
        img_copy.style.border = '1px solid #000';

        var url_box = new Element('input');
        var url_label = new
        Element('label',{'for':url_box.identify()}).update('Image URL:');
        url_box.addClassName('wide');

        url_box.value = stripRoot(img.src);
        url_box.title = 'enter the url of an image then press "enter" to refresh';

        var alt_box = new Element('input');
        var alt_label = new Element('label',{'for':alt_box.identify()}).update('Alt text:');
        alt_box.addClassName('wide');
        alt_box.value = img.alt;

        Event.observe(url_box,'keypress',function(e){
            if(e.keyCode == 13)
            {
                img_copy.src = url_box.value;
                resizeImageEditorDiv();
            }
        });
        Event.observe(url_box,'blur',function(e){
            img_copy.src = url_box.value;
            resizeImageEditorDiv();
        });

        var save_func = function(){
            return saveContent({src: img_copy.src,alt: alt_box.value});
        };

        var cancel_func = function(){
            if(img.hasClassName('unsaved'))
            {
                var div = img.up('div.editable');
                div.history.undo();
                div.history.undo();
                div.history.deleteFuture();
                Dropper.abortDrop();
            }
        };

        var nav_buttons;
        if(img.getStyle('float') == 'left' || img.getStyle('float') == 'right')
            nav_buttons = 0;
        else
            nav_buttons = 1;

        editor_div = createGenericEditorDiv({
            content:new Array(img_copy,url_label,url_box,alt_label,alt_box),
            save_func:save_func,
            cancel_func:cancel_func,
            nav_buttons:nav_buttons,
            nav_filter:'text,a,img'
        });

        document.body.appendChild(editor_div);

        resizeImageEditorDiv();
    };

    var createAnchorEditorDiv = function(a)
    {
        var url_box = new Element('input').addClassName('wide');
        var url_label = new
        Element('label',{'for':url_box.identify()}).update('Link URL:');
        url_box.value = stripRoot(a.href);

        var title_box = new Element('input').addClassName('wide');
        var title_label = new
        Element('label',{'for':title_box.identify()}).update('Link Title:');
        title_box.value = a.title;

        var style_box = new Element('select').addClassName('wide');
        var styles = 'style1,style2,style3'.split(',');
        for(var n = 0;n < styles.length; n++)
        {
            style_box.appendChild(new
            Element('option',{value:'style'+(n+1)}).update('style '+(n+1)));
            if(a.hasClassName(styles[n]))
                style_box.selectedIndex = n;
        }
        var style_label = new
        Element('label',{'for':style_box.identify()}).update('Link Style:');

        var target_box = new Element('select').addClassName('wide');
        var targets = new Array(
            new Array('_blank','new window'),
            new Array('_self','same window'));
        for(var n = 0;n < targets.length; n++)
        {
            target_box.appendChild(new Element('option',{value:targets[n][0]}).update(targets[n][1]));
            if(a.target == targets[n][0])
                target_box.selectedIndex = n;
        }
        var target_label = new Element('label',{'for':target_box.identify()}).update('Opens In:');

        var save_func = function(){
            return saveContent({href: url_box.value,title:
            title_box.value,style:style_box.value,target:target_box.value});
        };

        var cancel_func = function(){
            if(a.hasClassName('unsaved'))
            {
                var div = a.up('div.editable');
                div.history.undo();
                div.history.undo();
                div.history.deleteFuture();
            }
        };

        editor_div = createGenericEditorDiv({
            content:new
            Array(url_label,url_box,title_label,title_box,style_label,style_box,target_label,target_box),
            save_func:save_func,
            cancel_func:cancel_func,
            nav_buttons:false
        });

        editor_div.appendChild(document.createTextNode(' '));
        var to_edit = TextNode.nextLeaf(a,a,'text');
        if(to_edit)
        {
            editor_div.appendChild(Util.createButton(
                'Edit label',
                'Edit link text',
                function(){
                    Debug.log('fdsfdsafasd');
                    editor_div.save();
                    editor_div.remove();
                    editor_div = null;
                    Debug.log('to_edit: '+Debug.summarise(to_edit));
                    Editor.edit(to_edit,finishedCallback);
                },
                1)
            );
        }

        document.body.appendChild(editor_div);

        editor_div.style.width = '400px';
        editor_div.style.left = (window.innerWidth/2 + - 200) + 'px';
        editor_div.style.top = (window.innerHeight/2 + - 100) + 'px';

        url_box.focus();
    };

    var createGenericEditorDiv = function(properties)
    {
        var content = properties.content;
        var save_func = properties.save_func;
        var cancel_func = properties.cancel_func;
        var nav_buttons = properties.nav_buttons;
        var nav_filter = properties.nav_filter;

        editor_div = new Element('div');

        if(save_func)
            editor_div.save = save_func;
        else
            editor_div.save = function(){
                Debug.log('you havent written a save function for this editor!');
            };

        editor_div.id = 'editor';

        editor_div.content = content;
        content.each(function(c){
            editor_div.appendChild(c);
        });

        //editor_div.appendChild(new Element('br'));
        editor_div.appendChild(Util.createButton(
            'Save',
            'save your changes and close the editor',
            function(){
                editor_div.save();
                hideEditor();
            },
            1,
            'save'
        ));
        editor_div.appendChild(Util.createButton(
            'Cancel',
            'discard your changes and close the editor',
            function(){
                if(cancel_func)
                    cancel_func();
                //TODO
                hideEditor();
            },
            1,
            'cancel'
        ));

        if(nav_buttons)
        {
            editor_div.appendChild(document.createTextNode(' '));

            var up = current_node.parentNode.up('div.editable');
            editor_div.nextToEdit =
            TextNode.nextLeaf(current_node,up,nav_filter,{skip_brs:
                true,skip_floating: true});
            editor_div.prevToEdit =
            TextNode.prevLeaf(current_node,up,nav_filter,{skip_brs:
                true,skip_floating: true});

            /*
            Debug.log('prev: ' + Debug.summarise(editor_div.prevToEdit))
            Debug.log('next: ' + Debug.summarise(editor_div.nextToEdit))
            */

            editor_div.editNext = function(){
                if(!editor_div.nextToEdit)
                    return false;
                Format.disableIntegrity();
                editor_div.save();
                editor_div.remove();
                var to_edit = editor_div.nextToEdit;
                editor_div = null;
                Editor.edit(to_edit,finishedCallback);
                Format.enableIntegrity();
                return true;
            };

            editor_div.editPrev = function(){
                if(!editor_div.prevToEdit)
                    return false;
                Format.disableIntegrity();
                editor_div.save();
                editor_div.remove();
                var to_edit = editor_div.prevToEdit;
                editor_div = null;
                Editor.edit(to_edit,finishedCallback);
                Format.enableIntegrity();
                return true;
            };

            editor_div.appendChild(Util.createButton(
                'Previous',
                'save changes and edit the previous item',
                editor_div.editPrev,
                editor_div.prevToEdit ? 1 : 0,
                'previous'
            ));
            editor_div.appendChild(Util.createButton(
                'Next',
                'save changes and edit the next item',
                editor_div.editNext,
                editor_div.nextToEdit ? 1 : 0,
                'next'
            ));
        }

        return editor_div;
    };

    var paste = false;
    var checkPaste1 = function(e)
    {
        if(e && Util.ctrlKey(e) && (e.which == 86 || e.which == 118))
            paste = true;
    };

    var checkPaste2 = function(e)
    {
        if(paste && e && (e.which == 86 || e.which == 118))
        {
            resizeTextEditorDiv(null,1);
            paste = false;
        }
    };

    var resizeTextEditorDiv = function(e,force)
    {
        if(e && e.keyCode == 9)
        {
            e.preventDefault();
            var result = null;
            if(e.shiftKey)
                result = editor_div.editPrev();
            else
                result = editor_div.editNext();
            return;
        }

        resize_counter--;
        if(e && e.which == 13)
            force = 1;
        if(resize_counter <= 0 || force)
        {
            var textarea = editor_div.content[0];
            var new_char;
            if(e)
            {
                if (e.which >= 32 && e.which <= 126)
                    new_char = String.fromCharCode(e.which);
                else if(e.which == 13)
                    new_char = '\n';
                else
                    new_char = '';
            }
            else
                new_char = '';

            var new_dims =
            textSize(textarea.value+new_char,editor_div.max_width-6,editor_div.max_height-56,textarea.style);

            if(new_dims.width < min_width)
                new_dims.width = min_width;
            if(new_dims.height < min_height)
                new_dims.height = min_height;

            editor_div.style.width = new_dims.width + 'px';
            editor_div.style.height = (new_dims.height + 10) + 'px';

            textarea.style.width = new_dims.width + 'px';
            textarea.style.height = new_dims.height + 'px';

            editor_div.style.height = 'auto';
            //editor_div.style.height = (new_dims.height + 30) + 'px';

            resize_counter = resize_interval;
        }
    };

    var resizeImageEditorDiv = function()
    {
        editor_div.style.left = (window.innerWidth/2 - (editor_div.getWidth()/2)) + 'px';
        editor_div.style.top = (window.innerHeight/2 - (editor_div.getHeight()/2)) + 'px';
    };

    var textSize = function(content,maxwidth,maxheight,style)
    {
        var div = new Element('div');
        //Util.removeChildren(div);
        var parts = content.split('\n');
        for(var n = 0;n < parts.length;n++)
        {
            div.appendChild(document.createTextNode(parts[n]));
            div.appendChild(new Element('br'));
        }
        div.appendChild(document.createTextNode('.'));

        //div.appendChild(document.createTextNode(content));
        div.style.position = 'absolute';
        div.style.border = editor_div.firstChild.getStyle('border');
        //div.style.background = '#fff';
        div.style.left = '0px';
        div.style.top = '0px';
        div.style.width = '';
        div.style.height = '';
        div.style.fontFamily = style.fontFamily;
        div.style.fontSize = style.fontSize;
        document.body.appendChild(div);
        div.style.width = (50+div.getWidth()) + 'px';
        if(div.getWidth() > maxwidth)
            div.style.width = maxwidth + 'px';
        if(div.getHeight() > maxheight)
            div.style.height = maxheight + 'px';

        var ret = {width:div.getWidth(),height:div.getHeight()};
        div.remove();
        //Util.removeChildren(div);
        return ret;
    };

    var createFader = function()
    {
        if($('fader'))
            return;
        //todo figure out why cursor doesnt show in textarea when fader is shown
        var fader = new Element('div');
        fader.id = 'fader';
        document.body.appendChild(fader);
    };

    var hideFader = function()
    {
        var fader = $('fader');
        if(fader && fader.parentNode)
            fader.remove();
    };

    //TODO select only nodes that resulted from the textarea, not neighbouring
    //nodes
    var decomposeText = function(new_text,old_textnode)
    {
        var ret = new Array();

        var first = new Array();
        var mid = new Array();
        var last = new Array();

        var old_formats = Format.getFormats(old_textnode);

        var top = TextNode.getBlockNode(old_textnode);

        var walker;

        //within block, gather the nodes before and after textnode

        walker = TextNode.prevLeaf(old_textnode,top,
            'text,img,a,br,ul');
        while(walker)
        {
            var next_node = TextNode.prevLeaf(walker,top,
                'text,img,a,br,ul');
            if(walker.nodeType == 3)
            {
                var formats = Format.getFormats(walker);
                first.push(Format.formatNode(walker,formats));
            }
            else
                first.push(walker);
            walker = next_node;
        }
        first = first.reverse();

        walker = TextNode.nextLeaf(old_textnode,top,
            'text,img,a,br,ul');
        while(walker)
        {
            var next_node = TextNode.nextLeaf(walker,top,
                'text,img,a,br,ul');
            if(walker.nodeType == 3)
            {
                var formats = Format.getFormats(walker);
                last.push(Format.formatNode(walker,formats));
            }
            else
                last.push(walker);
            walker = next_node;
        }

        //now split the supplied text up by double newlines
        //anything from the first block is appended to first, if there is more
        //than one block everything from the last block is appended to last, if
        //there are more than 2 blocks, each block in between is turned into an
        //array of textnodes and br nodes, where a single newline causes a break

        var parts = new_text.split('\n\n');
        
        //start
        first = first.concat(textToBrs(parts.first(),old_formats));

        //middle
        if(parts.length > 2)
            for(var n = 1;n < parts.length-1;n++)
                mid.push(textToBrs(parts[n],old_formats));

        //end
        if(parts.length > 1)
            last = textToBrs(parts.last(),old_formats).concat(last);
        else
            first = first.concat(last);

        ret.push(first);
        if(parts.length > 2)
            ret = ret.concat(mid);
        if(parts.length > 1)
            ret.push(last);

        /*
        Debug.log('results of decomposetext:');
        ret.each(function(r){
            Debug.log('new top level node');
            r.each(function(n){
                if(n.nodeType == 3)
                    Debug.log('textnode: ' + Debug.summarise(n));
                else
                    Debug.log(n.tagName);
            });
            Debug.log('');
        });
        */

        return ret;
    };

    var textToBrs = function(text,formats)
    {
        var ret = new Array();
        parts = text.split('\n');
        parts.each(function(sp){
            if(sp.replace(/[ \n\t]*/g,'') != '')
            {
                ret.push(Format.formatNode(document.createTextNode(sp),formats));
                ret.push(new Element('br'));
            }
        });
        if(ret.length)
            ret.pop();
        return ret;
    };

    var stripRoot = function(url)
    {
        var absolute;
        var ret;
        var site_root = Config.siteRoot();

        //hax
        absolute = false;
        if(site_root.indexOf('http://') == 0)
        {
            absolute = true;
            site_root = site_root.substr(7);
        }
        site_root = site_root.replace('//','/');
        if(absolute)
            site_root = 'http://' + site_root;

        absolute = false;
        if(url.indexOf('http://') == 0)
        {
            absolute = true;
            url = url.substr(7);
        }
        url = url.replace('//','/');
        if(absolute)
            url = 'http://' + url;

        if(url.indexOf(site_root) == 0)
            ret = url.substr(site_root.length);
        else
            ret = url;
        
        return ret;
    }

    return _pub;
}();
