var Dom = YAHOO.util.Dom,
    Event = YAHOO.util.Event;

var statusInd;

// the feed currently displayed
var feed = '';
var contextPath = '';

var linkDialog = null;

var moveDialog = null;

/*
 * Initalize page controls
 */
Event.onDOMReady(function () {
    // the XSLT passes some metadata in META tags,
    // including feed and context path
    Dom.getElementsBy(function (element) {
        var name = element.getAttribute('name');
        switch (name) {
            case 'feed':
                feed = element.getAttribute('content');
                break;
            case 'context':
                contextPath = element.getAttribute('content');
                break;
        }
    }, 'meta', document);

    initActivityIndicator();
    
    // Init controls for editing a feed
    if (document.getElementById('e_title')) {
        new Editable('e_title').change.subscribe(modifyFeed);
        new Editable('e_subtitle').change.subscribe(modifyFeed);

        Event.addListener('upload-images', 'click', function() { new ImageUpload().show(); });

        Event.addListener(Dom.getElementsByClassName('del_entry', 'a', document.getElementById('weblog')), 'click', confirmDelete);

        Event.addListener('delete-feed', 'click', confirmDelete);

        Event.addListener('create-feed-form', 'submit', function () {
            window.location = location.pathname + '/' + document.forms['create-feed'].elements['add-feed'].value;
        });
    }

	if (document.getElementById('feedback-block')) {
		Event.addListener('feedback-close', 'click', function (ev) {
			Dom.setStyle('feedback-block', 'display', 'none');
		});
		setTimeout(function () {
		    Dom.setStyle('feedback-block', 'display', 'none');
		}, 3000);
	}

    // In edit mode, initialize the main editor
    if (document.getElementById('edit-tabs'))
        new BlogEditor();
    
    // Encapsulate all entries in a BlogEntry object
    var entries = Dom.getElementsByClassName('entry', 'div', document.getElementById('weblog'));
    for (var i = 0; i < entries.length; i++) {
        new BlogEntry(feed, entries[i]);
    }

    YAHOO.widget.Logger.enableBrowserConsole();

    SyntaxHighlighter.defaults['auto-links'] = false;
    SyntaxHighlighter.all();
    
	initToc();

	if (document.getElementById('edit-tabs'))
    	linkDialog = new LinkEditor();
	moveDialog = new MoveDialog();
});

function modifyFeed(type, args) {
    reportActivity('Changing feed title');
    var callback = {
        success: function (response) {
            endActivity();
            if (response.status != 204) {
                reportError("Server reported an error while changing feed title: " + response.status);
            }
        },
        failure: function (response) {
            endActivity();
            if (response.status == 401) {
                reportError("Permission denied. You are not authorized to change this feed.");
            } else
                reportError("Server reported an error while changing feed title: " + response.responseText);
            this.resetValue();
        },
        scope: this
    };
    var path = location.pathname;
    if (path.charAt(path.length - 1) != '/')
        path = path.replace(/^(.*)\/[^\/]+/, '$1/');
    var params = 'action=edit-feed&quiet=true&title=' + document.getElementById('e_title').value +
            '&subtitle=' + document.getElementById('e_subtitle').value;
    YAHOO.util.Connect.asyncRequest('POST', path, callback, params);
}

function toggleBox(ev) {
    Event.stopEvent(ev);
    var link = Event.getTarget(ev);
    var body = Dom.getElementsByClassName('body', 'div', link.parentNode.parentNode)[0];
    if (Dom.getStyle(body, 'display') != 'none') {
        var animOut = new YAHOO.util.Anim(body, { opacity: { to: 0 } }, 0.5, YAHOO.util.Easing.easeNone);
        animOut.onComplete.subscribe(function () {
            Dom.setStyle(body, 'display', 'none');
            link.innerHTML = 'show';
        });
        animOut.animate();
    } else {
        Dom.setStyle(body, 'display', '');
        var animIn = new YAHOO.util.Anim( body, { opacity: { to: 1 } }, 0.5, YAHOO.util.Easing.easeNone);
        animIn.animate();
        link.innerHTML = 'hide';
    }
}

function initActivityIndicator() {
    statusInd = document.createElement('div');
    statusInd.className = 'status-indicator';
    statusInd.style.position = 'absolute';
    statusInd.style.top = '0';
    statusInd.style.right = '0';
    statusInd.style.display = 'none';
    document.body.appendChild(statusInd);
}

function reportActivity(message) {
    Dom.setStyle(statusInd, 'display', '');
    statusInd.innerHTML = message;
}

function endActivity() {
    Dom.setStyle(statusInd, 'display', 'none');
    statusInd.innerHTML = '';
}

function confirmDelete(ev) {
    Event.stopEvent(ev);
    var link = Event.getTarget(ev);
    var href = link.href;
    var msg;
    if (link.id == 'delete-feed')
        msg = 'Are you sure you want to delete the entire feed, including all ' +
              'entries it contains?';
    else
        msg = 'Are you sure you want to delete this entry?';
    var dialog = new YAHOO.widget.SimpleDialog(Dom.generateId(), {
        width: '20em',
        fixedcenter: true,
        effect: { effect:YAHOO.widget.ContainerEffect.FADE, duration: 0.25},
        modal: true,
        visible: false,
        draggable: false
    });
    var buttons = [
        { text: 'Yes', handler: function () { dialog.hide(); dialog.destroy(); window.location = href; } },
        { text: 'No', handler: function () { dialog.hide(); dialog.destroy(); } }
    ];
    dialog.cfg.queueProperty("buttons", buttons);
    dialog.setHeader('Confirm Delete');
    dialog.setBody(msg);
    dialog.cfg.setProperty("icon",YAHOO.widget.SimpleDialog.ICON_WARN);
    dialog.render(document.body);
    dialog.show();
}

function initToc() {
    YAHOO.log('Initializing ToC');
    var toc = document.getElementById('toc');
    if (toc) {
        new YAHOO.util.DDTarget('toc');
        var trl = toc.getElementsByTagName('tr');
        for (var i = 0; i < trl.length; i++) {
            if (trl[i].id)
                new YAHOO.example.DDList(trl[i].id);
        }
        var form = document.forms['reorder-form'];
        Event.addListener(form, 'submit', changeEntryOrder);
    }
}

function changeEntryOrder() {
    YAHOO.log('Saving entry order ...');
    var xml = '<order>\n';
    var toc = document.getElementById('toc');
    var trl = toc.getElementsByTagName('tr');
    for (var i = 0; i < trl.length; i++) {
        if (trl[i].id)
          xml += '<entry id="' + trl[i].id.substring(1) + '"/>';
    }
    xml += '</order>';
    
    document.forms['reorder-form'].elements['data'].value = xml;
    return true;
}

function loadBoxAsync(id, feed, entryId) {
	var callback = {
		success: function (response) {
			document.getElementById(id).innerHTML = response.responseText;
		},
		failure: function (response) {
			YAHOO.log("Loading box failed: " + response.responseText);
		}
	};
	var params = 'feed=' + encodeURIComponent(feed) + '&id=' + 
		encodeURIComponent(entryId);
	YAHOO.log('Loading async box: ' + feed + '#' + id);
	YAHOO.util.Connect.asyncRequest('POST', 'async-box.xql', callback, params);
}

function BlogEntry(feed, element) {
    if (feed.charAt(feed.length - 1) != '/')
        feed = feed.replace(/^(.*)\/[^\/]+/, '$1');
    this.feed = feed;
    this.path = location.pathname;
    if (this.path.charAt(this.path.length - 1) != '/')
        this.path = this.path.replace(/^(.*)\/[^\/]+/, '$1');
    this.id = element.id;

	var moveLinks = Dom.getElementsByClassName('move_entry', 'a', element);
	for (var i = 0; i < moveLinks.length; i++) {
		Event.addListener(moveLinks[i], 'click', this.move, this, true);
	}

    this.comments = Dom.getElementsByClassName('comment-panel', 'div', document.getElementById(this.id))[0];

    var addComments = Dom.getElementsByClassName('add-comment', 'a', element);
    for (var i = 0; i < addComments.length; i++) {
        Event.addListener(addComments[i], 'click', this.addComment, this, true);
    }

    var displayComments = Dom.getElementsByClassName('display-comment', 'a', element);
    for (var i = 0; i < displayComments.length; i++) {
        Event.addListener(displayComments[i], 'click', this.loadComments, this, true);
    }

    var commentForm = Dom.getElementsByClassName('comment-form', 'div', element);
    if (commentForm.length > 0) {
        var button = Dom.getElementsByClassName('comment-send', 'button', commentForm[0])[0];
        Event.addListener(button, 'click', this.storeComment, this, true);
        button = Dom.getElementsByClassName('comment-cancel', 'button', commentForm[0])[0];
        Event.addListener(button, 'click', this.toggleCommentForm, this, true);
    }
}

BlogEntry.prototype.move = function (ev) {
	Event.stopEvent(ev);
	var link = Event.getTarget(ev);
	if (!moveDialog)
		moveDialog = new MoveDialog();
	moveDialog.move.subscribe(function (type, args) {
		document.getElementById('mid').value = this.id;
		document.forms['moveForm'].submit();
	}, this, true);
	moveDialog.show();
};

BlogEntry.prototype.loadComments = function (ev) {
    if (ev)
        Event.stopEvent(ev);

    if (Dom.getStyle(this.comments, 'display') != 'none') {
        var animOut = new YAHOO.util.Anim(this.comments, { opacity: { to: 0 } }, 0.5, YAHOO.util.Easing.easeNone);
        var comments = this.comments;
        animOut.onComplete.subscribe(function () { Dom.setStyle(comments, 'display', 'none'); });
        animOut.animate();
        return;
    }
    if (!this.comments.hasChildNodes()) {
        var callback = {
            success: this.commentLoaded,
            failure: this.commentLoaded,
            scope: this
        };
        var params = 'action=load-comment&id=' + encodeURIComponent(this.id);
        YAHOO.log('Loading comments: ' + params);
        YAHOO.util.Connect.asyncRequest('POST', this.path, callback, params);
    } else
        this.toggleComments();
};

BlogEntry.prototype.reloadComments = function () {
    this.comments.innerHTML = '';
    this.loadComments(null);
};

BlogEntry.prototype.commentLoaded = function (response) {
    if (response.status != 200) {
        reportError("Server reported an error while loading comments: " + response.responseText);
        return;
    }
    this.comments.innerHTML = response.responseText;
    this.toggleComments();
};

BlogEntry.prototype.toggleComments = function () {
    Dom.setStyle(this.comments, 'display', '');
    var animIn = new YAHOO.util.Anim( this.comments, { opacity: { to: 1 } }, 0.5, YAHOO.util.Easing.easeNone);
    animIn.animate();
};

BlogEntry.prototype.addComment = function (ev) {
    Event.stopEvent(ev);
    var element = document.getElementById(this.id);
    var commentForm = Dom.getElementsByClassName('comment-form', 'div', element);
    if (commentForm.length > 0) {
        if (!commentForm[0].editor) {
            var editor = Dom.getElementsByClassName('comment-editor', 'div', commentForm[0]);
            commentForm[0].editor = new WikiEditor(editor[0]);
        }
        Dom.setStyle(commentForm[0], 'display', '');
        var animIn = new YAHOO.util.Anim( commentForm[0], { opacity: { to: 1 } }, 0.25, YAHOO.util.Easing.easeOut);
        animIn.animate();
    }
};

BlogEntry.prototype.storeComment = function (ev) {
    Event.stopEvent(ev);
    
    var callback = {
        success: this.commentResponse,
        failure: this.commentResponse,
        scope: this
    };
    var form = document.forms['comment-form-' + this.id];
    var params = 'action=store-comment&id=' + this.id +
            '&name=' + form.elements['comment-name'].value +
            '&email=' + form.elements['comment-email'].value +
            '&content=' + form.elements['comment-text'].value;
    YAHOO.util.Connect.asyncRequest('POST', this.path, callback, params);
};

BlogEntry.prototype.commentResponse = function (response) {
    if (response.status != 200) {
        reportError("Server reported error while storing comment: " + response.responseText);
        return;
    }
    // hide comment form
    this.toggleCommentForm();
    // increase comment count
    var element = document.getElementById(this.id);
    var commentCount = Dom.getElementsByClassName('comment-count', 'span', element);
    if (commentCount.length > 0) {
        var count = commentCount[0].innerHTML;
        commentCount[0].innerHTML = ++count;
    }
    this.reloadComments();
};

BlogEntry.prototype.toggleCommentForm = function () {
    var element = document.getElementById(this.id);
    var commentForm = Dom.getElementsByClassName('comment-form', 'div', element);
    if (commentForm.length > 0) {
        var animOut = new YAHOO.util.Anim( commentForm[0], { opacity: { to: 0 } }, 0.25, YAHOO.util.Easing.easeOut);
        animOut.onComplete.subscribe(function () { Dom.setStyle(commentForm[0], 'display', 'none'); });
        animOut.animate();
    }
};

function BlogEditor() {
    this.tabs = new YAHOO.widget.TabView('edit-tabs');
    var previewTab = this.tabs.getTab(1);
    previewTab.on('click', this.preview, null, this);
    
    var textarea = document.getElementById('msgpost');
    this.mode = 'wiki';
    this.initWikiEditor();

    var btnStore = new YAHOO.widget.Button('msgstore');
    btnStore.on('click', this.store, null, this);
    var btnSave = new YAHOO.widget.Button('msgsave');
    btnSave.on('click', this.saveAndContinue, null, this);
    var btnCancel = new YAHOO.widget.Button('msgcancel');
    btnCancel.on('click', function () {
        window.location = window.location.pathname;
    }, null, this);

    this.title = new Editable('msgtitle');
    this.wikiId = new Editable('wikititle');

    Event.addListener('edit-tabs', 'keypress', this.keyPressed, this, true);
    Event.addListener('toggle-summary', 'click', function () {
    	var summary = document.getElementById('summaryeditor');
    	if (Dom.getStyle(summary, 'display') == 'none') {
    		Dom.setStyle(summary, 'display', '');
    		document.getElementById('toggle-summary').innerHTML = 'Hide Summary';
    	} else {
    		Dom.setStyle(summary, 'display', 'none');
    		document.getElementById('toggle-summary').innerHTML = 'Edit Summary';
    	}
    }, this, true);
}

BlogEditor.prototype.initWikiEditor = function () {
    new WikiEditor(document.getElementById('wikieditor'));
    new WikiEditor(document.getElementById('summaryeditor'));
};

BlogEditor.prototype.checkWikiLink = function () {
    var id = this.wikiId.getValue();
    if (id != '')
        return;
    var currentTitle = this.title.getValue();
    var words = currentTitle.split(/[\s.,:;!?'"]+/, 3);
    var newId = '';
    for (var i = 0; i < words.length; i++) {
        newId += words[i];
    }
    this.wikiId.setValue(newId);
};

BlogEditor.prototype.preview = function(ev) {
    Event.stopEvent(ev);
    this.checkAndPreview();
};

BlogEditor.prototype.store = function (ev) {
    Event.stopEvent(ev);
    this.post(false);
};

BlogEditor.prototype.checkAndPreview = function () {
    this.checkWikiLink();
    var callback = {
        success: this.previewResponse,
        failure: this.previewResponse,
        scope: this
    };
    var params = 'action=preview&' + this.encodeData();
    YAHOO.util.Connect.asyncRequest('POST', location.pathname, callback, params);
};

BlogEditor.prototype.saveAndContinue = function () {
    this.checkWikiLink();
    if (!this.checkForm())
        return;
    var action = document.forms['msgform'].elements['action'].value;
    var params = 'action=' + action + '&' + this.encodeData() + '&quiet=true';
    var callback = {
        success: function (response) {
            Dom.setStyle('save-status-ind', 'visibility', 'hidden');
            document.getElementById('save-status-text').innerHTML = '';
            document.forms['msgform'].elements['action'].value = 'update';
            document.forms['msgform'].elements['id'].value = response.responseText;
        },
        failure: function (response) {
            var previewTab = this.tabs.getTab(1);
            previewTab.get('contentEl').innerHTML =
                '<div class="entry snip last-entry">' +
                '   <div class="content error">' +
                '       <h2 class="entrytitle">An error occurred</h2>' +
                '       <div>' + response.responseText + '</div>' +
                '   </div>' +
                '</div';
              this.tabs.set('activeIndex', 1);
            Dom.setStyle('save-status-ind', 'visibility', 'hidden');
            document.getElementById('save-status-text').innerHTML = 'Error, not saved ...';
        },
        scope: this
    };
    Dom.setStyle('save-status-ind', 'visibility', 'visible');
    document.getElementById('save-status-text').innerHTML = 'Saving ...';
    YAHOO.util.Connect.asyncRequest('POST', location.pathname, callback, params);
};

BlogEditor.prototype.checkForm = function () {
    var title = document.getElementById('msgtitle').value;
    if (title == '') {
        reportError('You need to provide a title for the entry!');
        return false;
    }
    return true;
};

/**
 * Save the entry. To handle errors, the function first sends
 * a preview request. If that returns ok, the form will be
 * submitted.
 */
BlogEditor.prototype.post = function () {
    this.checkWikiLink();
    if (!this.checkForm())
        return;
    var params = 'action=preview&' + this.encodeData();
    var callback = {
        success: function () {
            // all ok, submit the form
            document.forms['msgform'].submit();
        },
        failure: function (response) {
            var previewTab = this.tabs.getTab(1);
            previewTab.get('contentEl').innerHTML =
                '<div class="entry snip last-entry">' +
                '   <div class="content error">' +
                '       <h2 class="entrytitle">An error occurred</h2>' +
                '       <div>' + response.responseText + '</div>' +
                '   </div>' +
                '</div';
              this.tabs.set('activeIndex', 1);
        },
        scope: this
    };
    YAHOO.util.Connect.asyncRequest('POST', location.pathname, callback, params);
};

BlogEditor.prototype.previewResponse = function (response) {
    var previewTab = this.tabs.getTab(1);
    YAHOO.log('Status ' + response.status + ': ' + response.statusText);
    if (response.status != 200) {
        previewTab.get('contentEl').innerHTML =
                '<div class="entry snip last-entry">' +
                '   <div class="content error">' +
                '       <h2 class="entrytitle">An error occurred</h2>' +
                '       <div>' + response.responseText + '</div>' +
                '   </div>' +
                '</div';
    } else {
        previewTab.get('contentEl').innerHTML = response.responseText;
        SyntaxHighlighter.all();
    }
};

BlogEditor.prototype.encodeData = function () {
    var title = document.getElementById('msgtitle').value;
    var wikiLink = document.forms['msgform'].elements['wikititle'].value;
    var content = document.getElementById('msgpost').value;
    var summary = document.getElementById('msgsummary').value;
    return 'id=' + document.forms['msgform'].elements['id'].value +
            '&content=' + encodeURIComponent(content) + 
            '&summary=' + encodeURIComponent(summary) + 
            '&title=' + encodeURIComponent(title) +
            '&wikititle=' + encodeURIComponent(wikiLink) +
            '&content-type=' + document.forms['msgform'].elements['content-type'].value;
};

BlogEditor.prototype.keyPressed = function (ev) {
    if (ev.ctrlKey) {
        var ch = Event.getCharCode(ev);
        if (ch == 115) {
            Event.stopEvent(ev);
            this.saveAndContinue();
        } else if (ch == 113) {
            this.store(ev);
        }
    }
};

function WikiEditor(container) {
    var interestingNodes = ['input', 'button', 'img', 'select'];
    var controls = new Array();
    for (var i = 0; i < interestingNodes.length; i++) {
        var nl = container.getElementsByTagName(interestingNodes[i]);
        for (var j = 0; j < nl.length; j++) {
            controls.push(nl[j]);
        }
    }
    for (var i = 0; i < controls.length; i++) {
        var node = controls[i];
        if (Dom.hasClass(node, 'wikiedit-bold')) {
            Event.addListener(node, 'click', function () {
                this.surroundWith('**');
            }, this, true);
        } else if (Dom.hasClass(node, 'wikiedit-em')) {
            Event.addListener(node, 'click', function () {
                this.surroundWith('__');
            }, this, true);
        } else if (Dom.hasClass(node, 'wikiedit-code')) {
            Event.addListener(node, 'click', function () {
                this.surroundWith('$$');
            }, this, true);
        } else if (Dom.hasClass(node, 'wikiedit-img')) {
        	Event.addListener(node, 'click', function () {
		        var dialog = new ImageSelect();
		        dialog.selected.subscribe(function (type, args) {
		            this.insertCode('$image(src=' + args[0] + ')');
		        }, this, true);
		        dialog.show();
        	}, this, true);
        } else if (Dom.hasClass(node, 'wikiedit-link')) {
    		Event.addListener(node, 'click', function () {
    			var sel = this.getSelection();
		        linkDialog.show(sel);
		        linkDialog.insert.subscribe(function (type, args) {
		            this.insertCode('[' + args[1] + '|' + args[0] + ']');
		        }, this, true);
    		}, this, true);
        } else if (Dom.hasClass(node, 'wikiedit-select-headers')) {
			Event.addListener(node, 'change', function (ev) {
				var select = Event.getTarget(ev);
        		var selected = select.options[select.selectedIndex].value;
        		if (selected != '')
            		this.formatHeader(selected);
        		select.selectedIndex = 0;
    		}, this, true);
        } else if (Dom.hasClass(node, 'wikiedit-select-code')) {
			Event.addListener(node, 'change', function (ev) {
		        var select = Event.getTarget(ev);
		        var selected = select.options[select.selectedIndex].value;
		        if (selected != '')
		            this.formatCode(selected);
		        select.selectedIndex = 0;
		    }, this, true);
    	}
    }
    this.input = container.getElementsByTagName('textarea')[0];
}

WikiEditor.prototype.getSelection = function () {
    this.input.focus();
    if (typeof document.selection != 'undefined') {
        var range = document.selection.createRange();
        return range.text;
    } else if (typeof this.input.selectionStart != undefined) {
        var start = this.input.selectionStart;
        var end = this.input.selectionEnd;
        return this.input.value.substring(start, end);
    }
};

WikiEditor.prototype.surroundWith = function(codeStart, codeEnd) {
    if (!codeEnd)
        codeEnd = codeStart;
    this.input.focus();
    if (typeof document.selection != 'undefined') {
        var range = document.selection.createRange();
        var insText = range.text;
        range.text = codeStart + insText + codeEnd;
        range = document.selection.createRange();
        if (insText.length == 0) {
            range.move('character', -codeStart.length);
        } else {
            range.moveStart('character', codeStart.length + insText.length + codeEnd.length);
        }
        range.select();
    } else if (typeof this.input.selectionStart != undefined) {
        var start = this.input.selectionStart;
        var end = this.input.selectionEnd;
        var insText = this.input.value.substring(start, end);
        this.input.value = this.input.value.substr(0, start) + codeStart + insText + codeEnd + this.input.value.substr(end);
        var pos;
        if (insText.length == 0) {
          pos = start + codeStart.length;
        } else {
          pos = start + codeStart.length + insText.length + codeEnd.length;
        }
        this.input.selectionStart = pos;
        this.input.selectionEnd = pos;
    }
};

WikiEditor.prototype.insertCode = function(code) {
    this.input.focus();
    if (typeof document.selection != 'undefined') {
        var range = document.selection.createRange();
        range.text = code;
        range = document.selection.createRange();
        range.move('character', -code.length);
        range.select();
    } else if (typeof this.input.selectionStart != undefined) {
        var start = this.input.selectionStart;
        var end = this.input.selectionEnd;
        this.input.value = this.input.value.substr(0, start) + code + this.input.value.substr(end);
        var pos = start + code.length;
        this.input.selectionStart = pos;
        this.input.selectionEnd = pos;
    }
};

WikiEditor.prototype.formatHeader = function (type) {
    switch (type) {
        case 'h1':
            this.surroundWith('=');
            break;
        case 'h2':
            this.surroundWith('==');
            break;
        case 'h3':
            this.surroundWith('===');
            break;
        case 'h4':
            this.surroundWith('====');
            break;
    }
};

WikiEditor.prototype.formatCode = function (type) {
    if (type.indexOf('--') > -1)
        return;
    if (type == 'other')
        this.surroundWith('{code}\n', '\n{/code}');
    else
        this.surroundWith('{code lang="' + type + '"}\n', '\n{/code}');
};

/**
 * Image upload dialog. This is a singleton object.
 * 
 * @param msg
 */
function ImageUpload() {

    var dialog = null;
    var imageList = null;
    var loadIndicator = null;
    
    this.startUpload = function() {
        Dom.setStyle(loadIndicator, 'visibility', 'visible');
        var uploadHandler = {
            upload: function () {
                Dom.setStyle(loadIndicator, 'visibility', 'hidden');
                imageList.load();
            },
            failure: function (response) {
                alert(response.responseText);
            }
        };
        YAHOO.util.Connect.setForm('uploadForm', true);
        YAHOO.util.Connect.asyncRequest('POST', 'upload.xql', uploadHandler);
    };

    this.show = function() {
        dialog.show();
    };

    dialog = new YAHOO.widget.Dialog(Dom.generateId(), {
        width: "500px",
        close: true,
        fixedcenter: true,
        draggable: true,
        visible: false,
        constraintoviewport: true,
        buttons: [ { text: "Done", handler: function () { this.hide(); this.destroy();}, isDefault: true } ]
    });
    dialog.setHeader('Upload Images');
    loadIndicator = Dom.generateId();
    var gallery = Dom.generateId();
    var uploadBtnId = Dom.generateId();
    dialog.setBody(
        '<form name="uploadForm" enctype="multipart/form-data" method="POST" action="upload.xql">' +
        '   <div class="upload-controls">' +
        '   <img id="' + loadIndicator + '" src="' + contextPath + '/images/loading.gif" style="visibility: hidden"/>' +
        '   <input class="fileupload" type="file" name="uploadedFile"/>' +
        '   <button type="button" id="' + uploadBtnId + '">Upload</button>' +
        '   <input type="hidden" name="feed" value="' + feed + '"/>' +
        '   </div>' +
        '   <div class="gallery" id="' + gallery + '">' +
        '</div>' +
        '</form>'
    );
    dialog.render(document.body);

    var uploadBtn = document.getElementById(uploadBtnId);
    Event.addListener(uploadBtn, 'click', this.startUpload, this);

    Dom.setStyle(gallery, 'height', '200px');
    imageList = new ImageList(gallery, feed);
    dialog.showEvent.subscribe(imageList.load, null, imageList);
};

function ImageSelect() {

    this.dialog = null;
    this.selectedImage = null;

    this.selected = new YAHOO.util.CustomEvent('insert image');

    this.show = function() {
        this.dialog.show();
    };

    this.insertImage = function () {
        if (this.selectedImage == null)
            return;
        this.dialog.hide();
        this.dialog.destroy();
        YAHOO.log('Fire selected event: ' + this.selected);
        this.selected.fire(this.selectedImage);
    };

    var dialogId = Dom.generateId();
     this.dialog = new YAHOO.widget.Dialog(dialogId, {
        width: "500px",
        close: true,
        fixedcenter: true,
        draggable: true,
        visible: false,
        constraintoviewport: true,
        buttons: [
            { text: "Insert", handler: { fn: this.insertImage, scope: this}, isDefault: true },
            { text: "Cancel", handler: function () { this.hide(); this.destroy(); }, isDefault: false }
        ]
    });
    var imageListId = Dom.generateId();
    this.dialog.setHeader('Insert Image');
    this.dialog.setBody('<div class="gallery" id="' + imageListId + '"></div>');
    this.dialog.render(document.body);

    var imageList = new ImageList(imageListId, feed);
    imageList.select.subscribe(function (type, args) { this.selectedImage = args[0]; }, null, this);
    Dom.setStyle(imageList.container, 'height', '200px');
    this.dialog.showEvent.subscribe(imageList.load, null, imageList);
};

/**
 * Queries the database for available images associated with this feed and
 * displays them as thumbnails in a div.
 * 
 * @param elem
 * @param feed
 */
function ImageList(elem, feed) {
    if (typeof elem == 'string') {
        this.container = document.getElementById(elem);
    } else {
        this.container = elem;
    }
    this.feed = feed;
    this.selected = null;
    this.select = new YAHOO.util.CustomEvent('image selected');
}

ImageList.MIME_TYPES = {
    'image': [ 'image/jpeg', 'image/gif' ]
};

ImageList.checkMimeType = function (mime) {
    for (var type in ImageList.MIME_TYPES) {
        var list = ImageList.MIME_TYPES[type];
        for (var i = 0; i < list.length; i++) {
            if (mime == list[i])
                return type;
        }
    }
    return 'unknown';
};

ImageList.prototype.load = function () {
    this.container.innerHTML = '';
    var callback = {
        success: this.loaded,
        failure: this.loaded,
        scope: this
    };
    var params = 'feed=' + encodeURIComponent(this.feed);
    YAHOO.log('Loading images: ' + params);
    YAHOO.util.Connect.asyncRequest('POST', 'list-resources.xql', callback, params);
};

ImageList.prototype.loaded = function (response) {
    var xml = response.responseXML;
    var root = xml.documentElement;
    var contextPath = root.getAttribute('context');
    var node = root.firstChild;
    while (node != null) {
        if (node.nodeName == 'resource') {
			var path = node.getAttribute('path');
            var p = path.lastIndexOf('/');
            var name = path.substring(p + 1);

            var img = document.createElement('img');
            Event.addListener(img, 'load', function () {
                if (this.height < 80)
                    this.style.paddingTop = ((80 - this.height) / 2) + 'px';
            }, img, true);
            img.setAttribute('title', path);
            YAHOO.log('thumbnail path = ' + path);
            if (ImageList.checkMimeType(node.getAttribute('mime')) == 'image')
                img.setAttribute('src', contextPath + '/thumbs?path=' + path + '&height=64');
            else
                img.setAttribute('src', contextPath + '/images/misc.png');
            img.name = name;
            var div = document.createElement('div');
            div.className = 'container';
            var innerDiv = document.createElement('div');
            innerDiv.className = 'thumb';
            div.appendChild(innerDiv);
            innerDiv.appendChild(img);
            var span = document.createElement('div');
            span.appendChild(document.createTextNode(name))
            innerDiv.appendChild(span);
            this.container.appendChild(div);

            Event.addListener(img, 'click', this.selectImage, this, true);
        }
        node = node.nextSibling;
    }
};

ImageList.prototype.selectImage = function(ev) {
    var img = Event.getTarget(ev);
    if (this.selected != null)
        Dom.removeClass(this.selected, 'selected');
    this.selected = img.parentNode;
    Dom.addClass(this.selected, 'selected');
    this.select.fire(img.name);
};

function LinkEditor() {

    this.dialog = null;

    this.insert = new YAHOO.util.CustomEvent('insert link');

    this.show = function (selection) {
        document.forms['linkForm'].elements['text1'].value = selection;
        document.forms['linkForm'].elements['text2'].value = selection;
        this.dialog.show();
    };

    this.insertLink = function () {
        this.dialog.hide();
        var tab = this.tabs.get('activeIndex');
        if (tab == 0) {
            var select = document.forms['linkForm'].elements['page-select'];
            this.insert.fire(document.forms['linkForm'].elements['text1'].value,
                    select.options[select.selectedIndex].value);
        } else {
            this.insert.fire(document.forms['linkForm'].elements['text2'].value,
                    document.forms['linkForm'].elements['url'].value);
        }
		this.insert.unsubscribeAll();
    };

    this.tabs = new YAHOO.widget.TabView('insert-link-tabs');

    this.dialog = new YAHOO.widget.Dialog('insertLink', {
        width: "500px",
        close: true,
        fixedcenter: true,
        draggable: true,
        visible: false,
        constraintoviewport: true,
        buttons: [
            { text: "Insert", handler: { fn: this.insertLink, scope: this}, isDefault: true },
            { text: "Cancel", handler: function () { this.hide(); }, isDefault: false }
        ]
    });
    this.dialog.render();

    var callback = {
        success: function (response) {
            var select = document.getElementById('page-select');
            select.parentNode.innerHTML = response.responseText;
        }
    };
    YAHOO.util.Connect.asyncRequest('GET', 'list-entries.xql', callback);
};

function MoveDialog() {

    this.dialog = null;

    this.move = new YAHOO.util.CustomEvent('move entry');

    this.show = function () {
		if (!this.loaded)
			this.load();
        this.dialog.show();
    };

    this.doMove = function () {
		var select = document.getElementById('destination-select');
		this.move.fire(select.options[select.selectedIndex].value);
		this.move.unsubscribeAll();
        this.dialog.hide();
    };

	this.loaded = false;

	this.load = function () {
		this.loaded = true;
		var callback = {
			success: function (response) {
				var select = document.getElementById('destination-select');
				select.parentNode.innerHTML = response.responseText;
			}
		};
		YAHOO.util.Connect.asyncRequest('GET', 'list-feeds.xql', callback);
	};

    this.dialog = new YAHOO.widget.Dialog('move-dialog', {
        width: "500px",
        close: true,
        fixedcenter: true,
        draggable: true,
        visible: false,
        constraintoviewport: true,
        buttons: [
            { text: "Move", handler: { fn: this.doMove, scope: this}, isDefault: true },
            { text: "Cancel", handler: function () { this.hide(); }, isDefault: false }
        ]
    });
    this.dialog.render();
};

function Editable(input) {
    this.input = typeof input == 'string' ? document.getElementById(input) : input;
    Dom.setStyle(this.input, 'display', 'none');

    var div = document.createElement('div');
    div.className = this.input.className;
    this.input.parentNode.replaceChild(div, this.input);
    
    this.span = document.createElement('span');
    var txt = document.createTextNode(this.input.value.length == 0 ? 'Click to edit' : this.input.value);
    this.span.appendChild(txt);

    this.toggle = document.createElement('a');
    this.toggle.href = '#';
    this.toggle.className = 'editable-toggle';
    txt = document.createTextNode('edit');
    this.toggle.appendChild(txt);

    div.appendChild(this.input);
    div.appendChild(this.span);
    div.appendChild(this.toggle);

    Event.addListener(this.span, 'click', this.toggleEditable, this, true);
    Event.addListener(this.toggle, 'click', this.toggleEditable, this, true);
    Event.addListener(this.input, 'keypress', this.keyPressed, this, true);

    this.value = this.input.value;

    this.change = new YAHOO.util.CustomEvent('content changed', this);
}

Editable.prototype.setValue = function (value) {
    this.span.innerHTML = value;
    this.input.value = value;
};

Editable.prototype.getValue = function () {
    return this.input.value;
};

Editable.prototype.resetValue = function () {
    this.setValue(this.value);
};

Editable.prototype.keyPressed = function (ev) {
    var ch = Event.getCharCode(ev);
    if (ch == 27 || ch == 10 || ch == 13) {
        Event.stopEvent(ev);
        this.toggleEditable();
    }
};

Editable.prototype.toggleEditable = function () {
    if (Dom.getStyle(this.input, 'display') == 'none') {
        Dom.setStyle(this.span, 'display', 'none');
        Dom.setStyle(this.input, 'display', '');
        this.toggle.innerHTML = 'close';
        this.input.focus();
        this.value = this.input.value;
    } else {
        this.span.innerHTML = this.input.value.length == 0 ? 'Click to edit' : this.input.value;
        Dom.setStyle(this.span, 'display', '');
        Dom.setStyle(this.input, 'display', 'none');
        this.toggle.innerHTML = 'edit';
        YAHOO.log(this.input.value + ' -> ' + this.value);
        if (this.input.value != this.value) {
            YAHOO.log('Firing...');
            this.change.fire(this.input.value);
        }
    }
};

function reportError(msg) {
    YAHOO.log('error: ' + msg);
    var dialog = new YAHOO.widget.SimpleDialog(Dom.generateId(), {
        width: '300px',
        fixedcenter: true,
        effect: { effect:YAHOO.widget.ContainerEffect.FADE, duration: 0.25},
        modal: true,
        visible: false,
        draggable: false
    });
    var buttons = [
        { text: 'Ok', handler: function () { dialog.hide(); dialog.destroy(); } }
    ];
    dialog.cfg.queueProperty("buttons", buttons);
    dialog.cfg.setProperty("icon",YAHOO.widget.SimpleDialog.ICON_WARN);
    dialog.setHeader('Error');
    dialog.setBody(msg);
    dialog.render(document.body);
    dialog.show();
}

function checkId(id) {
    if (id.charAt(0) == '?')
        return id.substring(1);
    else
        return id;
}

var DDM = YAHOO.util.DragDropMgr;

YAHOO.example.DDList = function(id, sGroup, config) {

    YAHOO.example.DDList.superclass.constructor.call(this, id, sGroup, config);

    this.logger = this.logger || YAHOO;
    var el = this.getDragEl();
    Dom.setStyle(el, "opacity", 0.67); // The proxy is slightly transparent

    this.goingUp = false;
    this.lastY = 0;
};

YAHOO.extend(YAHOO.example.DDList, YAHOO.util.DDProxy, {

    startDrag: function(x, y) {
        this.logger.log(this.id + " startDrag");

        // make the proxy look like the source element
        var dragEl = this.getDragEl();
        var clickEl = this.getEl();
        Dom.setStyle(clickEl, "visibility", "hidden");

        dragEl.innerHTML = clickEl.innerHTML;

        Dom.setStyle(dragEl, "color", Dom.getStyle(clickEl, "color"));
        Dom.setStyle(dragEl, "backgroundColor", Dom.getStyle(clickEl, "backgroundColor"));
        Dom.setStyle(dragEl, "border", "2px solid gray");
    },

    endDrag: function(e) {

        var srcEl = this.getEl();
        var proxy = this.getDragEl();

        // Show the proxy element and animate it to the src element's location
        Dom.setStyle(proxy, "visibility", "");
        var a = new YAHOO.util.Motion( 
            proxy, { 
                points: { 
                    to: Dom.getXY(srcEl)
                }
            }, 
            0.2, 
            YAHOO.util.Easing.easeOut 
        )
        var proxyid = proxy.id;
        var thisid = this.id;

        // Hide the proxy and show the source element when finished with the animation
        a.onComplete.subscribe(function() {
                Dom.setStyle(proxyid, "visibility", "hidden");
                Dom.setStyle(thisid, "visibility", "");
            });
        a.animate();
    },

    onDragDrop: function(e, id) {

        // If there is one drop interaction, the li was dropped either on the list,
        // or it was dropped on the current location of the source element.
        if (DDM.interactionInfo.drop.length === 1) {

            // The position of the cursor at the time of the drop (YAHOO.util.Point)
            var pt = DDM.interactionInfo.point; 

            // The region occupied by the source element at the time of the drop
            var region = DDM.interactionInfo.sourceRegion; 

            // Check to see if we are over the source element's location.  We will
            // append to the bottom of the list once we are sure it was a drop in
            // the negative space (the area of the list without any list items)
            if (!region.intersect(pt)) {
                var destEl = Dom.get(id);
                var destDD = DDM.getDDById(id);
                destEl.appendChild(this.getEl());
                destDD.isEmpty = false;
                DDM.refreshCache();
            }

        }
    },

    onDrag: function(e) {

        // Keep track of the direction of the drag for use during onDragOver
        var y = Event.getPageY(e);

        if (y < this.lastY) {
            this.goingUp = true;
        } else if (y > this.lastY) {
            this.goingUp = false;
        }

        this.lastY = y;
    },

    onDragOver: function(e, id) {
    
        var srcEl = this.getEl();
        var destEl = Dom.get(id);

        // We are only concerned with list items, we ignore the dragover
        // notifications for the list.
        if (destEl.nodeName.toLowerCase() == "tr") {
            var orig_p = srcEl.parentNode;
            var p = destEl.parentNode;

            if (this.goingUp) {
                p.insertBefore(srcEl, destEl); // insert above
            } else {
                p.insertBefore(srcEl, destEl.nextSibling); // insert below
            }

            DDM.refreshCache();
        }
    }
});
