function ce(s) { return document.createElement(s); }
function ge_i(s) { return document.getElementById(s); }

function instanceOf(object, constructor) { while (object != null) { if (object == constructor.prototype) return true; object = object.__proto__; } return false; }

function State()
{
    this.showURLs = false;
    this.loggedIn = false;
    this.blocks = new Array();
    this.user = '';
    this.floatBlock = null;
    this.floatItem = null;
}

// Block functionality
function Block(xmlDoc, bReadOnly)
{
    if (!xmlDoc) return;

	this.id = xmlDoc.attributes.getNamedItem('id').value;
	this.name = unescape(xmlDoc.attributes.getNamedItem('name').value);
	this.desc = unescape(xmlDoc.attributes.getNamedItem('desc').value);
    var collapsed = (xmlDoc.attributes.getNamedItem('collapsed').value == 1);

	this.node = ce('div');
	this.node.className = 'mf_block' + (bReadOnly ? 'sys' : '');

	this.elemTop = ce('div');
	this.elemTop.className = 'mf_blocktop' + (bReadOnly ? 'sys' : '');
	this.elemTop.id = 'blocktop:' + this.id;
    if (!bReadOnly) this.elemTop.onmousedown = function(evnt) { if (((document.all && event.srcElement.id) || (!document.all && evnt.target.id)) && !state.EditBox) MoveBlock(getBlockFromId('blocktop:', this.id), evnt); }

    this.eCollapse = ce('div');
    this.eCollapse.className = 'mf_blockcollapse';
    this.eCollapse.onmousedown = function() { getBlockFromId('blocktop:', this.parentNode.id).ToggleCollapse(); }
    this.elemTop.appendChild(this.eCollapse);

	this.elemName = ce('div');
	this.elemName.className = 'mf_blockname';
	this.elemName.id = 'blockname:' + this.id;
    this.elemName.innerHTML = bReadOnly ? this.name : '<a href="javascript:void(0);" onclick="EditField(' + this.id + ', \'elemName\', \'name\', true, \'Request_BlockNameChange\');" title="Edit name">' + this.name + '</a>';

	this.elemTop.appendChild(this.elemName);

	this.elemDesc = ce('div');
	this.elemDesc.className = 'mf_blockdesc';
	this.elemDesc.id = 'blockdesc:' + this.id;
    this.elemDesc.innerHTML = bReadOnly ? this.desc : '<a href="javascript:void(0);" onclick="EditField(' + this.id + ', \'elemDesc\', \'desc\', true, \'Request_BlockDescChange\');" title="Edit description">' + this.desc + '</a>';
	this.elemTop.appendChild(this.elemDesc);
	this.node.appendChild(this.elemTop);

    this.content = ce('div');

    this.content.style.display = collapsed ? 'none' : 'block';
    this.eCollapse.innerHTML = collapsed ? '<a href="javascript:void(0);" title="Show block">&nbsp;&darr;&nbsp;</a>' : '<a href="javascript:void(0);" title="Hide block">&nbsp;&uarr;&nbsp;</a>';

    this.node.appendChild(this.content);

	this.node.id = 'block:' + this.id;
	state.blocks[this.id] = this;
}

Block.prototype.ToggleCollapse = function()
{
    var bHidden = !(this.content.style.display == 'none');

    this.content.style.display = bHidden ? 'none' : 'block';
    this.eCollapse.innerHTML = bHidden ?'<a href="javascript:void(0);" title="Show block">&nbsp;&darr;&nbsp;</a>' : '<a href="javascript:void(0);" title="Hide block">&nbsp;&uarr;&nbsp;</a>';

    Request_BlockState(this.id, bHidden);

    for (i in state.blocks)
    {
        state.blocks[i].UpdateLocationInfo();
    }
}

Block.prototype.UpdateLocationInfo = function()
{
    this.left = findPosX(this.node);
    this.top = findPosY(this.node);
}

Block.prototype.EditField = function(elemTarget, member, start, fn)
{
    var target = eval('this.' + elemTarget);
    var val = eval('this.' + member);

    if (start)
    {
        if (state.EditBox != undefined)
        {
            state.EditBox.onblur();
        }

        state.EditBox = ce('input');
        state.EditBox.className = 'mfinput';
        state.EditBox.id = 'edit:' + this.id;
        state.EditBox.type = 'text';
        state.EditBox.onkeypress = function() { if (window.event && window.event.keyCode == 13) state.EditBox.onblur(); }
        state.EditBox.onblur = function() { var block = getBlockFromId('edit:', this.id); block.EditField(elemTarget, member, false, fn); }
        state.EditBox.value = val;
        target.parentNode.replaceChild(state.EditBox, target);
        state.EditBox.select();
    }
    else
    {
        var newVal = state.EditBox.value;
        if (val != newVal)
        {
            eval('this.' + member + ' = newVal;');
            target.childNodes[0].innerHTML = newVal;
            eval(fn + '(this, newVal);');
        }

        state.EditBox.parentNode.replaceChild(target, state.EditBox);
        state.EditBox = undefined;
    }
}

function EditField(blockId, elemDst, member, start, fn)
{
	var block = state.blocks[blockId];
	block.EditField(elemDst, member, start, fn);
}

function ReallyDeleteBlock(blockId)
{
    Request_DeleteBlock(state.blocks[blockId]);
}

function DeleteBlock(blockId)
{
    ConfirmBox('Confirm block deletion', 'Are you sure you want to delete the block "' + state.blocks[blockId].name + '"?', 'ReallyDeleteBlock(' + blockId + ')');
}

Block.prototype.Update = function(xmlDoc)
{
	this.name = unescape(xmlDoc.attributes.getNamedItem('name').value);
	this.desc = unescape(xmlDoc.attributes.getNamedItem('desc').value);
    this.elemName.childNodes[0].innerHTML = this.name;
    this.elemDesc.childNodes[0].innerHTML = this.desc;
}

function AddItem(blockId)
{
    Request_NewItem(state.blocks[blockId]);
}

function ReallyDeleteItem(blockID, itemID)
{
    var block = state.blocks[blockID];
    var item = block.items[itemID];

    Request_DeleteItem(item);
}

function DeleteItem(blockID, itemID)
{
    var block = state.blocks[blockID];
    var item = block.items[itemID];

    ConfirmBox('Confirm item deletion', 'Are you sure you want to delete the item "' + item.title + '"?', 'ReallyDeleteItem(' + blockID + ', ' + itemID + ')');
}

// Block usage

// A block with links
function LinkBlock(xmlDoc, bReadOnly)
{
    if (!xmlDoc) return;

    this.base = Block;
    this.base(xmlDoc, bReadOnly);

	this.elemList = ce('ul');
	this.elemList.style.display = 'none';
	this.elemList.className = 'mf_blocklist';
	this.content.appendChild(this.elemList);

    // Add items
	this.items = new Array();
    var items = xmlDoc.getElementsByTagName('item');
    for (i = 0; i < items.length; ++i)
    {
        var item = new Item(items[i]);
        this.items[item.id] = item;

        this.elemList.style.display = 'block';
    }
}

LinkBlock.prototype = new Block;

function UserLinkBlock(xmlDoc, col)
{
    if (!xmlDoc) return;

    this.base = LinkBlock;
    this.base(xmlDoc, false);

    this.elemCtrl = ce('div');
    this.elemCtrl.className = 'mf_ctrls';
    this.elemCtrl.innerHTML = '<a href="javascript:void(0);" onclick="AddItem(' + this.id + ');" title="Add item">&nbsp;Add item&nbsp;</a>';

    this.elemCtrlRight = ce('div');
    this.elemCtrlRight.className = 'mf_ctrls_right';
    this.elemCtrlRight.innerHTML = '<a href="javascript:void(0);" onclick="DeleteBlock(' + this.id + ');" title="Delete block">&nbsp;Delete block&nbsp;</a>';

    this.content.appendChild(this.elemCtrlRight);
    this.content.appendChild(this.elemCtrl);

    var parent;
    if (col)
    {
        parent = col;
    }
    else
    {
        parent = ge_i('client-col1');
        var parent2 = ge_i('client-col2');
        if (parent.childNodes.length > parent2.childNodes.length)
        {
            parent = parent2;
        }
    }

    parent.appendChild(this.node);
}

UserLinkBlock.prototype = new LinkBlock;

function SystemLinkBlock(xmlDoc)
{
    if (!xmlDoc) return;

    this.base = LinkBlock;
    this.base(xmlDoc, true);
}

SystemLinkBlock.prototype = new LinkBlock;

// Item functionality
function Item(xmlDoc)
{
	this.id = xmlDoc.attributes.getNamedItem('id').value; 
	this.blockID = xmlDoc.attributes.getNamedItem('blockid').value;
	this.node = ce('li');
	this.node.id = createItemTagId(this);
	this.node.className = 'mf_item';

    this.node.innerHTML = '<a class="mf_item"></a>';
    this.nodeItem = this.node.childNodes[0];

    this.controls = ce('span');
    this.controls.className = 'mf_item_extra';
    this.controls.innerHTML = '<a href="javascript:void(0);" onclick="EditURLOrTitle(' + this.blockID + ', ' + this.id + ', true, true);" title="Edit url">&nbsp;url&nbsp;</a>|' +
                         '<a href="javascript:void(0);" onclick="EditURLOrTitle(' + this.blockID + ', ' + this.id + ', true, false);" title="Edit title">&nbsp;title&nbsp;</a>|'+
                         '<a href="javascript:void(0);" style="cursor: pointer; cursor: hand; color: #f44;" onclick="DeleteItem(' + this.blockID + ', ' + this.id + ');" title="Delete item">&nbsp;x&nbsp;</a>|' +
                         '<a href="javascript:void(0);" style="cursor: move; color: #44f;" title="Move item">&nbsp;#&nbsp;</a>';
    this.controls.lastChild.onmousedown = function(evnt) { MoveItem(getItemFromId(this.parentNode.parentNode.id), evnt); }
    this.node.appendChild(this.controls);

    this.Update(xmlDoc);

    var block = state.blocks[this.blockID];

	block.items[this.id] = this;
	block.elemList.appendChild(this.node);
	block.elemList.style.display = 'block';
}

Item.prototype.Update = function(xmlDoc)
{
    this.valid = (xmlDoc.attributes.getNamedItem('valid') != undefined);

    if (this.valid)
    {
        this.url = xmlDoc.attributes.getNamedItem('url').value;
        this.title = unescape(xmlDoc.attributes.getNamedItem('title').value);
        if (this.title == '')
        {
            this.title = this.url;
        }
    }
    else
    {
        this.url = undefined;
        this.title = undefined;
    }

    if (this.valid)
    {
        this.nodeItem.setAttribute('href', this.url);
        this.nodeItem.setAttribute('title', this.url);
        this.nodeItem.onmousedown = function(evnt)
        {
            if (IsLeftButton(evnt))
            {
                this.setAttribute('href', 'goto.php?hit=' + getItemFromId(this.parentNode.id).id);
            }
        }

        if (state.showURLs)
        {
            this.nodeItem.innerHTML = '&nbsp;' + this.url + '&nbsp;';
        }
        else
        {
            this.nodeItem.innerHTML = '&nbsp;' + this.title + '&nbsp;';
        }
    }
    else
    {
        this.nodeItem.setAttribute('href', 'javascript:EditURLOrTitle(' + this.blockID + ', ' + this.id + ', true, true);');
        this.nodeItem.setAttribute('title', 'Enter url');
        this.nodeItem.innerHTML = '&nbsp;Click here to enter url&nbsp;';
    }
}

Item.prototype.EditURLOrTitle = function(start, isurledit)
{
    if (!this.valid && !isurledit)
    {
        return;
    }

    if (start)
    {
        if (state.EditBox != undefined)
        {
            state.EditBox.onblur();
        }

        var target = this.nodeItem;

        state.EditBox = ce('input');
        state.EditBox.className = 'mfinput';
        state.EditBox.type = 'text';
        state.EditBox.id = createItemTagId(this);
        state.EditBox.onkeypress = function() { if (window.event && window.event.keyCode == 13) state.EditBox.onblur(); }
        state.EditBox.onblur = function() { var item = getItemFromId(this.id); item.EditURLOrTitle(false, isurledit); }
        if (isurledit)
        {
            if (this.url != undefined)
            {
                state.EditBox.value = this.url;
            }
        }
        else
        {
            if (this.title != undefined)
            {
                state.EditBox.value = this.title;
            }
        }
        target.parentNode.replaceChild(state.EditBox, target);
        state.EditBox.select();
    }
    else
    {
        var newVal = state.EditBox.value;
        if (isurledit)
        {
            if (newVal != '' && (this.url == undefined || this.url != newVal))
            {
                this.url = newVal;
                this.nodeItem.innerHTML = '&nbsp;' + newVal + '&nbsp;';
                Request_ItemURLChange(this, newVal);
            }
        }
        else
        {
            if (newVal != '' && (this.title == undefined || this.title != newVal))
            {
                this.title = newVal;
                this.nodeItem.innerHTML = '&nbsp;' + newVal + '&nbsp;';
                Request_ItemTitleChange(this, newVal);
            }
        }

        state.EditBox.parentNode.replaceChild(this.nodeItem, state.EditBox);
        state.EditBox = undefined;
    }
}

function EditURLOrTitle(blockID, itemID, start, isurledit)
{
    var block = state.blocks[blockID];
    var item = block.items[itemID];
    item.EditURLOrTitle(start, isurledit);
}

// Load content
function AddToCols(colInfo, blocks, colNode)
{
    var col = colInfo.split(':');

    for (var i = 0; i < col.length; ++i)
    {
        var id = col[i];
            
        var found = false;
        for (var j = 0; j < blocks.length && !found; ++j)
        {
            var xmlBlock = blocks[j];
            var blockid = xmlBlock.attributes.getNamedItem('id').value;
            if (blockid == id)
            {
                new UserLinkBlock(blocks[j], colNode);
                blocks[j].attributes.getNamedItem('id').value = '-1';
                found = true;
            }
        }
    }
}

function LoadAll(xml)
{
    Request_Misc();

	var blocksNode = xml.getElementsByTagName('blocks');
	var blocks = blocksNode[0].getElementsByTagName('block');
    var orderNode = xml.getElementsByTagName('blockorder');

    if (orderNode && orderNode.length)
    {
        var nodeCol1 = ge_i('client-col1');
        var nodeCol2 = ge_i('client-col2');

        var aCols = orderNode[0].firstChild.data.split(',');
        AddToCols(aCols[0], blocks, nodeCol1);
        AddToCols(aCols[1], blocks, nodeCol2);
    }

	for (var j = 0; j < blocks.length; ++j)
	{
        if (blocks[j].attributes.getNamedItem('id').value >= 0)
        {
            new UserLinkBlock(blocks[j], null);
        }
	}
}

function ToggleTabbed(which)
{
    switch (which) {
    case 0:
        ge_i('stats').style.display = 'block';
        ge_i('help').style.display = 'none';
        ge_i('changes').style.display = 'none';
        break;
    case 1:
        ge_i('stats').style.display = 'none';
        ge_i('help').style.display = 'block';
        ge_i('changes').style.display = 'none';
        break;
    case 2:
        ge_i('stats').style.display = 'none';
        ge_i('help').style.display = 'none';
        ge_i('changes').style.display = 'block';
        break;
    default:
        break;
    }
}

function BuildTop(xml)
{
    var sumNode = xml.getElementsByTagName('misc')[0].attributes;
    count_users = sumNode.getNamedItem('users').value;
    count_links = sumNode.getNamedItem('links').value;
    count_items = sumNode.getNamedItem('items').value;
    var pSum = ge_i('summary_info');
    pSum.innerHTML = count_users + ' registered users with ' + count_links + ' links, ' + count_items + ' of which are unique';

    var container = ge_i('stats');

    // Top clicked
    var nodeClicked = ce('div');
    nodeClicked.className = 'mf_blocksys';
    nodeClicked.innerHTML= '<div class="mf_blocktopsys"><div class="mf_blockname">Top Visited Links</div><div class="mf_blockdesc">The sites that users visit most.</div></div>';
    
    // Top clicked by user
    var nodeClickedUser = ce('div');
    nodeClickedUser.className = 'mf_blocksys';
    nodeClickedUser.innerHTML= '<div class="mf_blocktopsys"><div class="mf_blockname">Your Top Visited Links</div><div class="mf_blockdesc">The sites that you visit most.</div></div>';
    
    // Top ranked
    var nodeLinks = ce('div');
    nodeLinks.className = 'mf_blocksys';
    nodeLinks.innerHTML= '<div class="mf_blocktopsys"><div class="mf_blockname">Top Ranked Links</div><div class="mf_blockdesc">The sites linked to most by users.</div></div>';
    
    var nodes = new Array( nodeClicked, nodeClickedUser, nodeLinks );
    for (var i = 0; i < nodes.length; ++i)
    {
        var node = nodes[i];
        var topsNode = xml.getElementsByTagName(node == nodeLinks ? 'toplinks' : (node == nodeClicked ? 'tophits' : 'tophitsuser'));
        var tops = topsNode[0].getElementsByTagName('top');

        var elemList = ce('ul');
        elemList.className = 'mf_blocklist';
        node.appendChild(elemList);

        for (var j = 0; j < tops.length; ++j)
        {
            var top = tops[j];
            var url = top.attributes.getNamedItem('url').value;
            var title = unescape(top.attributes.getNamedItem('title').value);
            var count = top.attributes.getNamedItem('count').value;
            var by = null;
            if (by = top.attributes.getNamedItem('creator'))
            {
                by = by.value;
            }

            if (title == '')
            {
                title = url;
            }

            var nodeItem = ce('li');
            nodeItem.className = 'mf_item';
            nodeItem.innerHTML = '<a class="mf_item" href="' + url + '">' + title + '</a> <span class="mf_item_extra"> (' + count + ')' + (by ? (' by ' + by) : '') + '</span>';
            nodeItem.childNodes[0].id = ((node == nodeClickedUser) ? 'u' : 'i') + top.attributes.getNamedItem('id').value;
            nodeItem.childNodes[0].onmousedown = function(evnt)
            {
                if (IsLeftButton(evnt))
                {
                    var id = this.id.substring(1, this.id.length);
                    var isUser = (this.id.substring(0, 1) == 'u');
                    this.setAttribute('href', (isUser ? 'goto.php?hit=' : 'goto.php?hititem=') + id);
                }
            }

            elemList.appendChild(nodeItem);
        }

        container.appendChild(node);
	}
}

function BuildUncat(xml)
{
	var uncatNode = xml.getElementsByTagName('uncat');
	var uncats = uncatNode[0].getElementsByTagName('block');

    if (uncats.length < 1)
    {
        return;
    }

    var block = new SystemLinkBlock(uncats[0]);

    var container = ge_i('stats');
    container.insertBefore(block.node, container.childNodes[0]);
}

var arrHelp = new Array (
    'By dragging the link &#8220;<a href="javascript:location.href=%22http://www.memeflow.com/goto/goto.php?cmd=itemfromsc&url=%22 + encodeURIComponent(location.href)">Add to GoTo</a>&#8221; to your browser links area in Firefox, or right-clicking the link in Internet Explorer and adding it to your favourites, you can automatically add the current web site to your GoTo subscriptions. They will be added to a new block under the &#8220;Top Links&#8221; section, and you can drag the items to your normal blocks from there.',
    'Top Tip! Try dragging a block around by clicking on the title bar of the block.  You can also drag links between blocks by clicking on the &#8220;#&#8221; mark at the end of the link.',
    'You can give a url a title by clicking on the &#8220;title&#8221; link next to the item.  If you don\'t supply a title, the system will eventually get the title from the page you linked to (if it hadn\'t done so already)'
);

var arrChanges = new Array (
    '11/11/05 Fixed bug with adding a block under IE.',
    '10/30/05 Javascript code refactoring and the ability to hide/show blocks.',
    '10/22/05 Decouple loading of main block data from misc stats data.',
    '10/22/05 Big backend reorganization for performance improvements.',
    '10/22/05 Feeds moved to new location.  Redirects in place for old location.',
    '10/17/05 Fixed a bug where the code that pulled pages to get the title could screw up with certain international character sets.  Put in a check for valid utf-8',
    '10/15/05 Add changes RSS Feed for page.',
    '10/15/05 Add RSS Feed for page.',
    '10/15/05 Move feeds to top of page and tweak layout to take up less space.',
    '10/15/05 Make OPML compliant to v1.1.',
    '10/8/05 Fix a bug where clicking another mouse button while left-click dragging a block or item would cause wierd things to happen.',
    '10/8/05 Fix a bug which could cause multiple edit boxes to be open for edit and out of sync in page.',
    '10/5/05 Small pages adjustments.  Separated system blocks into tabs.',
    '10/1/05 Items could temporarily disappear if moved from blocks with only one item. Fixed.',
    '10/1/05 Fixed display of confirm box in IE.',
    '10/1/05 Deletion of items now requires confirmation.',
    '9/26/05 The increase in usage shows a bug where the default sites assigned to new users cause the stats for those sites to spike.  The fix was to not include sites that trial users link to in the &#8220;Top Ranked&#8221; stats.',
    '9/26/05 <a href="http://radio.weblogs.com/0001011/2005/09/26.html#a11262" title="Robert Scoble">Scoble</a> links to the site causing a flurry of trials and registrations.',
    '9/22/05 Added Lazy Registration so that people can try the service without registering.',
    '8/25/05 Now tracking stats when users click on links in the stats panels.',
    '8/24/05 User\'s click stats now use the title given to the link by the user if available.',
    '8/24/05 Elements now resize based on the browser window size.',
    '8/19/05 Many updates including the tracking of clicks on links, in order to give some interesting stats.  Hopefully soon I can give users an indication of what they haven\'t looked at recently.',
    'Fixed issue where xml entities in urls weren\'t getting encoded correctly, causing the returned xml to be invalid.',
    'Fixed a problem where item controls would become non-functional after moving the item.',
    'By dragging the link &#8220;<a href="javascript:location.href=%22http://www.memeflow.com/goto/goto.php?cmd=itemfromsc&url=%22 + encodeURIComponent(location.href)">Add to GoTo</a>&#8221; to your browser links area, you can automatically add the current web site to your GoTo subscriptions. They will be added to a new block under the &#8220;Top Links&#8221; section, and you can drag the items to your normal blocks from there.',
    'You can move items around between blocks by clicking on the &#8220;#&#8221 icon next to the item.',
    'Deletion of blocks now requires confirmation.',
    'Added the ability to reset your password.',
    'Now supports all URI schemes, not just http.',
    'Fixed bug in ranking (links linked to by the same user multiple times now only counted once).',
    'Editing an item now selects the contents rather than just giving focus.',
    'Fixed issues regarding slashes being displayed after text has been escaped for storage.',
    'Blocks and items are now sorted by creation time.',
    'If using Internet Explorer, you can now hit &#8220;Enter&#8221 in edit boxes to complete the operation.',
    'You can now delete a block by clicking on the &#8220;Delete block&#8221; link.'
);

function BuildHelp(xml)
{
    var container = ge_i('help');

    var nodeBlock = ce('div');
    nodeBlock.className = 'mf_blocksys';
    nodeBlock.innerHTML= '<div class="mf_blocktopsys"><div class="mf_blockname">Helpful Information</div><div class="mf_blockdesc">Items of information to help you get to grips with GoTo.</div></div>';

    var elemList = ce('ul');
    elemList.className = 'mf_blocklist';
    nodeBlock.appendChild(elemList);

    for (var i = 0; i < arrHelp.length; ++i)
    {
        var item = ce('li');
        item.className = 'mf_item';
        item.innerHTML = '<span class="mf_item_bullet">- ' + arrHelp[i] + '</span>';
        elemList.appendChild(item);
    }

    container.appendChild(nodeBlock);

    container = ge_i('changes');
    
    var nodeBlock = ce('div');
    nodeBlock.className = 'mf_blocksys';
    nodeBlock.innerHTML= '<div class="mf_blocktopsys"><div class="mf_blockname">Recent Changes</div><div class="mf_blockdesc">Recent changes to the system.</div></div>';

    var elemList = ce('ul');
    elemList.className = 'mf_blocklist';
    nodeBlock.appendChild(elemList);

    for (var i = 0; i < arrChanges.length; ++i)
    {
        var item = ce('li');
        item.className = 'mf_item';
        item.innerHTML = '<span class="mf_item_bullet">- ' + arrChanges[i] + '</span>';
        elemList.appendChild(item);
    }

    container.appendChild(nodeBlock);
}

// UI
function ToggleDebug()
{
	var info = ge_i("info");
	info.style.display = (info.style.display == 'none') ? 'block' : 'none';
}

function ToggleURLs()
{
    state.showURLs = !state.showURLs;

    for (var i in state.blocks)
    {
        block = state.blocks[i];
        for (var j in block.items)
        {
            var item = block.items[j];
            if (item.valid)
            {
                item.nodeItem.innerHTML = '&nbsp;' + (state.showURLs ? item.url : item.title) + '&nbsp;';
            }
        }
    }
}

function AddNewBlock()
{
    Request_NewBlock();
}

function ShowRegistration()
{
    var elem = ge_i('registerinfo');
    elem.innerHTML = '';
    elem.style.display = 'none';

    ge_i('login').style.display = 'none';
    ge_i('register').style.display = 'block';
    ge_i('forgot').style.display = 'none';
}

function ShowForgot()
{
    var elem = ge_i('forgotinfo');
    elem.innerHTML = '';
    elem.style.display = 'none';

    ge_i('login').style.display = 'none';
    ge_i('register').style.display = 'none';
    ge_i('forgot').style.display = 'block';
}

function TryNow()
{
    Request_TryNow();
}

function Register()
{
    var username = ge_i('reg_user').value;
    var password = ge_i('reg_pword').value;
    var remember = ge_i('reg_remember').checked;
    var email = ge_i('reg_email').value;

    Request_Register(username, password, remember, email);
}

function Forgot()
{
    var email = ge_i('forgot_email').value;

    Request_NewPassword(email);
}

function Login()
{
    var username = ge_i('login_user').value;
    var password = ge_i('login_pword').value;
    var remember = ge_i('login_remember').checked;
    
    Request_Login(username, password, remember);
}

function Logout()
{
    Request_Logout();
    state.loggedIn = false;
    DoTopLogin();
}

function DoTopLogin()
{
    var elem = ge_i('logininfo');
    elem.innerHTML = '';
    elem.style.display = 'none';

    DoLogin();
}

function DoRegisterFromTrial()
{
  ge_i('register').style.display = 'block';
  ge_i('tabbed').style.display = 'none';
}

function DoLogin()
{
    if (state.loggedIn)
    {
        var elem = ge_i('logininfo');
        elem.innerHTML = '';
        elem.style.display = 'none';

        ge_i('logout-user').innerHTML = state.user;
        ge_i('logout').style.display = 'inline';
        ge_i('login').style.display = 'none';
        ge_i('title-area-left').style.display = 'inline';
        ge_i('client-area-container').style.display = 'block';
        ge_i('title_login').style.display = 'none';
        ge_i('register').style.display = 'none';
        ge_i('forgot').style.display = 'none';
        ge_i('explanation').style.display = 'none';
        if (state.user != 'trial user')
        {
            ge_i('feeds').style.display = 'block';
            ge_i('opml').setAttribute('href', 'public/' + state.user + '/feed.opml');
            ge_i('rss').setAttribute('href', 'public/' + state.user + '/feed.xml');
            ge_i('rss-changes').setAttribute('href', 'public/' + state.user + '/changes.xml');
        }
        ge_i('tabbed').style.display = 'block';
        ge_i('trial_user').style.display = (state.user == 'trial user') ? 'block' : 'none';
    }
    else
    {
        InitState(false);
        ge_i('logout').style.display = 'none';
        ge_i('login').style.display = 'block';
        ge_i('title-area-left').style.display = 'none';
        ge_i('client-area-container').style.display = 'none';
        ge_i('title_login').style.display = 'inline';
        ge_i('register').style.display = 'none';
        ge_i('forgot').style.display = 'none';
        ge_i('feeds').style.display = 'none';
        ge_i('trial_user').style.display = 'none';

        var divExp = ge_i('explanation');
        divExp.style.display = 'block';
        if (divExp.childNodes.length == 0)
        {
            ImportXML("explanation.xml", function(xmlDoc) {
                var divExp = ge_i('explanation');
                var divNew = xmlDoc.getElementsByTagName('content')[0];
                divExp.innerHTML = divNew.firstChild.data;
            });
        }
    }
}

// Requests
function ImportXML(strDoc, fnDone)
{
    var xmlDoc = null;

    if (document.implementation && document.implementation.createDocument)
    {
        xmlDoc = document.implementation.createDocument("", "", null);
        xmlDoc.onload = function() { fnDone(xmlDoc); }
    }
    else if (window.ActiveXObject)
    {
        xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
        xmlDoc.onreadystatechange = function () {
            if (xmlDoc.readyState == 4) fnDone(xmlDoc);
        };
    }

    if (xmlDoc == null)
    {
        alert('Your browser can\'t handle this script');
        return;
    }
    
    xmlDoc.load(strDoc);
}

function createRequest() {
	var req = undefined;
	if (window.XMLHttpRequest)
	{
		try {
			req = new XMLHttpRequest();
		} catch (e) {
			req = undefined;
		}
	}
	else if (window.ActiveXObject)
	{
		try {
			req = new ActiveXObject("Msxml2.XMLHTTP");
		} catch (e) {
			try {
				req = new ActiveXObject("Microsoft.XMLHTTP");
			} catch (e) {
				req = undefined;
			}
		}
	}

	if (req == undefined)
	{
		Info('Failed to create request.');
	}
	return req;
}

function Request(fnResponse, postData, noDefaultAction)
{
    CloseModal();

    if (noDefaultAction == null) noDefaultAction = false;

	var req = createRequest();
	if (req != undefined)
	{
		req.onreadystatechange = function() {
			if (req.readyState == 4)
            {
				if (req.responseXML)
				{
                    if (!noDefaultAction)
                    {
                        var results;
                        results = req.responseXML.getElementsByTagName('user');

                        if (results && results.length > 0)
                        {
                            state.user = results[0].firstChild.data;
                            if (!state.loggedIn)
                            {
                                state.loggedIn = true;
                                DoLogin();
                            }
                        }
                        else
                        {
                            state.loggedIn = false;
                            if (!state.inRegister)
                            {
                                Info(req.responseText);
                                Info('Not logged in, attempting to login');
                                DoLogin();
                            }
                            state.inRegister = false;
                        }
                    }

                    fnResponse(req);
				}
                else
                {
                    Info(req.responseText);
                    Info('Invalid response from server');
                }
			}
		}

		req.open("POST", "goto.php", true);
		req.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
		req.send(postData);
        Info('Sent: ' + postData);
	}
}

function XMLResponse(xml)
{
    this.result = 4;
    this.text = '';
    this.content = undefined;

    if (xml)
    {
        var results = xml.getElementsByTagName('result');
        if (results && results.length > 0 && results[0].childNodes.length > 0)
        {
            this.result = results[0].firstChild.data;
        }
        var texts = xml.getElementsByTagName('text');
        if (texts && texts.length > 0 && texts[0].childNodes.length > 0)
        {
            this.text = texts[0].firstChild.data;
        }
        this.content = xml.getElementsByTagName('content')[0];
        if (this.content && this.content.childNodes.length > 0)
        {
            this.content = this.content.childNodes[0];
        }
    }

    if (this.result == 1)
    {
        Info('XMLReponse: Not logged in.');
    }
    else
    {
        Info('XMLResponse: ' + this.result);
    }
}

function Request_Login(user, pword, remember)
{
    Request(function(req) {
        var resp = new XMLResponse(req.responseXML.documentElement);
        if (resp.result == 0)
        {
            Info('Login succeded');
            Request_All();
        }
        else
        {
            var elem = ge_i('logininfo');
            elem.innerHTML = 'Login failed: <b>' + resp.text + '</b>';
            elem.style.display = 'block';
            Info('Login failed');
        }
    }, 'cmd=login&user=' + user + '&pword=' + pword + '&remember=' + remember);
}

function Request_TryNow()
{
    state.inRegister = true;
    Request(function(req) {
        var resp = new XMLResponse(req.responseXML.documentElement);
        if (resp.result == 0)
        {
            Info('TryNow succeded');
            Request_All();
        }
        else
        {
            var elem = ge_i('registerinfo');
            elem.innerHTML = 'Registration failed: <b>' + resp.text + '</b>';
            elem.style.display = 'block';
            Info('TryNow failed');
        }
    }, 'cmd=trynow');
}

function Request_Register(user, pword, remember, email)
{
    state.inRegister = true;

    var cmd = 'register';
    if (state.user == 'trial user')
    {
        cmd = 'registerfromtrial';
    }

    Info(cmd);

    Request(function(req) {
        var resp = new XMLResponse(req.responseXML.documentElement);
        if (resp.result == 0)
        {
            ge_i('trial_user').style.display = 'none';
            ge_i('register').style.display = 'none';
            ge_i('tabbed').style.display = 'block';
            
            InitState(true);
            Request_All();

            Info('Register succeded');
        }
        else
        {
            var elem = ge_i('registerinfo');
            elem.innerHTML = 'Registration failed: <b>' + resp.text + '</b>';
            elem.style.display = 'block';
            Info('Register failed');
        }
    }, 'cmd=' + cmd + '&user=' + user + '&pword=' + pword + '&remember=' + remember + '&email=' + email);
}

function Request_NewPassword(email)
{
    Request(function(req) {
        var xml = req.responseXML.documentElement;
        var result = 4;
        var text = '';

        var results = xml.getElementsByTagName('result');
        if (results && results.length > 0 && results[0].childNodes.length > 0)
        {
            result = results[0].firstChild.data;
        }
        var texts = xml.getElementsByTagName('text');
        if (texts && texts.length > 0 && texts[0].childNodes.length > 0)
        {
            text = texts[0].firstChild.data;
        }

        var elem = ge_i('forgotinfo');
        if (result == 0)
        {
            elem.innerHTML = 'A new password is on it\'s way to you.</b>';
            elem.style.display = 'block';
            Info('New password succeded');
        }
        else
        {
            elem.innerHTML = 'Sorry, the request failed: <b>' + text + '</b>';
            elem.style.display = 'block';
            Info('Request for new password failed');
        }
    }, 'cmd=newpword&email=' + email, true);
}

function Request_Logout()
{
    Request(function(req) {
        var resp = new XMLResponse(req.responseXML.documentElement);
    }, 'cmd=logout');
}

function Request_All()
{
    Request(function(req) {
        var resp = new XMLResponse(req.responseXML.documentElement);
        if (resp.result == 0)
        {
            LoadAll(resp.content);

            Info('Processed request for all data.');
        }
        else
        {
            Info('An error occured while processing request for all data.');
        }

    }, 'cmd=getall');
}

function Request_Misc()
{
    Request(function(req) {
        var resp = new XMLResponse(req.responseXML.documentElement);
        if (resp.result == 0)
        {
            BuildTop(resp.content);
            BuildUncat(resp.content);
            BuildHelp();

            Info('Processed request for misc data.');
        }
        else
        {
            Info('An error occured while processing request for misc data.');
        }

    }, 'cmd=getmisc');
}

function Request_NewBlock()
{
	Request(function(req) {
        var resp = new XMLResponse(req.responseXML.documentElement);
        if (resp.result == 0)
        {
            var block = new UserLinkBlock(resp.content, null);

            UpdateColsSendOrder();
            Info('Processed newblock ' + block.id + '.');
        }
        else
        {
            Info('An error occured while processing new block.');
        }
    }, 'cmd=newblock');
}

function Request_BlockNameChange(block, newName)
{
	Request(function(req) {
        var resp = new XMLResponse(req.responseXML.documentElement);
        if (resp.result == 0)
        {
            block.Update(resp.content);
            Info('Processed request to change name for block ' + block.id + '.');
        }
        else
        {
            Info('An error occured while changing name for block ' + block.id + '.');
        }
    }, 'cmd=blockname&id=' + block.id + '&name=' + escape(newName));
}

function Request_DeleteBlock(block)
{
	Request(function(req) {
        var resp = new XMLResponse(req.responseXML.documentElement);
        if (resp.result == 0)
        {
            state.blocks[block.id] = undefined;
            var parent = block.node.parentNode;
            parent.removeChild(block.node);

            UpdateColsSendOrder();
        
            Info('Processed request to delete block ' + block.id + '.');
        }
        else
        {
            Info('An error occured while deleting block ' + block.id + '.');
        }
    }, 'cmd=deleteblock&id=' + block.id);
}

function Request_BlockDescChange(block, newDesc)
{
	Request(function(req) {
        var resp = new XMLResponse(req.responseXML.documentElement);
        if (resp.result == 0)
        {
            block.Update(resp.content);
            Info('Processed request to change description for block ' + block.id + '.');
        }
        else
        {
            Info('An error occured while changing description for block ' + block.id + '.');
        }

    }, 'cmd=blockdesc&id=' + block.id + '&desc=' + escape(newDesc));
}

function Request_NewItem(block)
{
	Request(function(req) {
        var resp = new XMLResponse(req.responseXML.documentElement);
        if (resp.result == 0)
        {
            var item = new Item(resp.content);
            Info('Processed newitem ' + item.id + ' for block ' + block.id + '.');
        }
        else
        {
            Info('An error occured while processing new item for block ' + block.id + '.');
        }
    }, 'cmd=newitem&id=' + block.id);
}

function Request_MoveItem(item)
{
	Request(function(req) {
    }, 'cmd=itemmove&id=' + item.id + '&block=' + item.blockID);
}

function Request_ItemURLChange(item)
{
	Request(function(req) {
        var resp = new XMLResponse(req.responseXML.documentElement);
        if (resp.result == 0)
        {
            item.Update(resp.content);
            Info('Processed item url change to ' + item.url + ' for item ' + item.id + '.');
        }
        else
        {
            Info('An error occured while changing item url to ' + item.url + ' for item ' + item.id + '.');
        }
    }, 'cmd=itemurl&block=' + item.blockID + '&id=' + item.id + '&url=' + encodeURIComponent(item.url));
}

function Request_ItemTitleChange(item)
{
	Request(function(req) {
        var resp = new XMLResponse(req.responseXML.documentElement);
        if (resp.result == 0)
        {
            item.Update(resp.content);
            Info('Processed item title change to ' + item.title + ' for item ' + item.id + '.');
        }
        else
        {
            Info('An error occured while changing item title to ' + item.title + ' for item ' + item.id + '.');
        }
    }, 'cmd=itemtitle&block=' + item.blockID + '&id=' + item.id + '&title=' + escape(item.title));
}

function Request_DeleteItem(item)
{
    Request(function(req) {
    }, 'cmd=deleteitem&block=' + item.blockID + '&id=' + item.id);
    
    var block = state.blocks[item.blockID];
    block.elemList.removeChild(item.node);

	if (block.elemList.childNodes.length == 0)
	{
		block.elemList.style.display = 'none';
	}

    block.items[item.id] = undefined;
}

function Request_SendOrder(order)
{
    Request(function(req) {
    }, 'cmd=blockorder&order=' + order);
}

function Request_BlockState(blockID, state)
{
    Request(function(req) {
    }, 'cmd=blockstate&id=' + blockID + '&state=' + state);
}

function Request_ItemHit(itemID)
{
    Request(function(req) {
    }, 'cmd=itemhit&id=' + itemID);
}

// Movement
var xPos, yPos;
function MoveHandler(evnt)
{
    evnt = (evnt) ? evnt : event;
    if (evnt.pageX)
    {
        xPos = evnt.pageX;
        yPos = evnt.pageY;
    }
    else
    {
        xPos = evnt.clientX + document.documentElement.scrollLeft;
        yPos = evnt.clientY + document.documentElement.scrollTop;
    }

    DoFollow();

    var moved = false;
    for (i in state.blocks)
    {
        b = state.blocks[i];
        var pn = b.node.parentNode;
        if (b != state.floatBlock && !instanceOf(b, SystemLinkBlock))
        {
            if (xPos > b.left && xPos < b.left + b.node.clientWidth)
            {
                if (yPos > b.top && (yPos < b.top + b.node.clientHeight || (pn.childNodes.item(pn.childNodes.length - 1) == b.node)))
                {
                    if (yPos < b.top + (0.3 * b.node.clientHeight))
                    {
                        // Move in front of this one
                        pn.insertBefore(divReplacement, b.node);
                        moved = true;
                        break;
                    }
                    else if (yPos > b.top + (0.7 * b.node.clientHeight))
                    {
                        // Move after this one
                        var length = pn.childNodes.length;
                        var nodeBefore = null;
                        var which = null;
                        for (var j = 0; j < length; ++j)
                        {
                            if (pn.childNodes.item(j) == b.node)
                            {
                                which = j;
                                break;
                            }
                        }
                        
                        if (which == length - 1)
                        {
                            pn.appendChild(divReplacement);
                        }
                        else
                        {
                            pn.insertBefore(divReplacement, pn.childNodes.item(which + 1));
                        }

                        moved = true;
                        break;
                    }
                }
            }
        }
    }

    if (!moved)
    {
        // If we're on a column with no entries, move there
        var col1 = ge_i('client-col1');
        var col2 = ge_i('client-col2');

        if (col1.childNodes.length == 0)
        {
            if (xPos < findPosX(col2))
            {
                col1.appendChild(divReplacement);
                moved = true;
            }
        }

        if (!moved && col2.childNodes.length == 0)
        {
            if (xPos > findPosX(col2))
            {
                col2.appendChild(divReplacement);
                moved = true;
            }
        }
    }

    if (moved)
    {
        for (i in state.blocks)
        {
            state.blocks[i].UpdateLocationInfo();
        }
    }
}

var moveItemOver = null;
var moveItemOverClass = null;
function MoveItemHandler(evnt)
{
    evnt = (evnt) ? evnt : event;
    if (evnt.pageX)
    {
        xPos = evnt.pageX;
        yPos = evnt.pageY;
    }
    else
    {
        xPos = evnt.clientX + document.documentElement.scrollLeft;
        yPos = evnt.clientY + document.documentElement.scrollTop;
    }

    DoFollow();

    for (i in state.blocks)
    {
        b = state.blocks[i];
        if (xPos > b.left && xPos < b.left + b.node.clientWidth)
        {
            if (yPos > b.top && yPos < b.top + b.node.clientHeight)
            {
                if (moveItemOver != b)
                {
                    if (moveItemOver)
                    {
                        moveItemOver.node.className = moveItemOverClass;
                    }

                    moveItemOver = b;
                    moveItemOverClass = b.node.className;
                    moveItemOver.node.className = moveItemOverClass + '_itemover';
                }
            }
        }
    }
}

function DoFollow()
{
    divFloat.style.left = (xPos - offsetX) + 'px';
    divFloat.style.top = (yPos - offsetY) + 'px';
}

function IsLeftButton(evnt)
{
    var left = true;
    if ((evnt) && evnt.which)
    {
        if (evnt.which != 1)
        {
            left = false;
        }
    }
    else if (event && event.button)
    {
        if (event.button != 1)
        {
            left = false;
        }
    }

    return (left);
}

function MoveBlock(block, evnt)
{
    if (state.floatBlock != null)
    {
        // Prevent a move from occuring during a mousedown while moving
        return;
    }

    evnt = (evnt) ? evnt : event;
    var selectedObj = block.node;

    offsetX = evnt.clientX - findPosX(selectedObj) + document.documentElement.scrollLeft;
    offsetY = evnt.clientY - findPosY(selectedObj) + document.documentElement.scrollTop;

    state.floatBlock = block;

    divReplacement = ce('div');
    divReplacement.className = 'mf_block';
    divReplacement.style.width = block.node.clientWidth + 'px';
    divReplacement.style.height = block.node.clientHeight + 'px';

    state.floatBlock.node.parentNode.replaceChild(divReplacement, state.floatBlock.node);
    state.floatBlock.node.className = 'mf_block_move';

    divFloat = ge_i('block_float');
    divFloat.appendChild(block.node);
    divFloat.style.display = 'block';

    if (window.document.all)
    {
        window.document.onmousemove = MoveHandler;
        window.document.onmouseup = StopMoveBlock;
        window.document.onmousedown = StopMoveBlock;
    }
    else
    {
        document.captureEvents(Event.MOUSEMOVE | Event.MOUSEUP | Event.MOUSEDOWN);
        document.onmousemove = MoveHandler;
        document.onmouseup = StopMoveBlock;
        document.onmousedown = function(evnt) { if (!IsLeftButton(evnt)) StopMoveBlock(); }
    }

    for (i in state.blocks)
    {
        state.blocks[i].UpdateLocationInfo();
    }

    MoveHandler(evnt);
}

function StopMoveBlock()
{
    if (window.document.all)
    {
        window.document.onmousemove = null;
        window.document.onmouseup = null;
        window.document.onmousedown = null;
    }
    else
    {
        document.releaseEvents(Event.MOUSEMOVE | Event.MOUSEUP | Event.MOUSEDOWN);
        document.onmousemove = null;
        document.onmouseup = null;
        document.onmousedown = null;
    }

    divFloat.style.display = 'none';
    divFloat.removeChild(state.floatBlock.node);
    state.floatBlock.node.className = 'mf_block';
    divReplacement.parentNode.replaceChild(state.floatBlock.node, divReplacement);

    UpdateColsSendOrder();
        
    divFloat = null;
    state.floatBlock = null;
    divReplacement = null;
}

function MoveItem(item, evnt)
{
    if (state.floatItem != null)
    {
        // Prevent a move from occuring during a mousedown while moving
        return;
    }

    evnt = (evnt) ? evnt : event;
    var selectedObj = item.node;

    offsetX = evnt.clientX - findPosX(selectedObj) + document.documentElement.scrollLeft;
    offsetY = evnt.clientY - findPosY(selectedObj) + document.documentElement.scrollTop;

    state.floatItem = item;

    divReplacement = ce('div');
    divReplacement.className = 'mf_item';
    divReplacement.style.width = item.node.clientWidth + 'px';
    divReplacement.style.height = item.node.clientHeight + 'px';

    state.floatItem.node.className = 'mf_item_move';

    if (item.node.parentNode.childNodes.length == 1)
    {
        item.node.parentNode.style.display = 'none';
    }

    divFloat = ge_i('block_float');
    divFloat.appendChild(item.node);
    divFloat.style.display = 'block';
    
    if (window.document.all)
    {
        window.document.onmousemove = MoveItemHandler;
        window.document.onmouseup = StopMoveItem;
        window.document.onmousedown = StopMoveItem;
    }
    else
    {
        document.captureEvents(Event.MOUSEMOVE | Event.MOUSEUP | Event.MOUSEDOWN);
        document.onmousemove = MoveItemHandler;
        document.onmouseup = StopMoveItem;
        document.onmousedown = function(evnt) { if (!IsLeftButton(evnt)) StopMoveItem(); }
    }

    for (i in state.blocks)
    {
        state.blocks[i].UpdateLocationInfo();
    }

    moveItemOver = state.blocks[item.blockID];
    moveItemOverClass = moveItemOver.node.className;
    moveItemOver.node.className = moveItemOverClass + '_itemover';

    MoveItemHandler(evnt);
}

function StopMoveItem()
{
    if (window.document.all)
    {
        window.document.onmousemove = null;
        window.document.onmouseup = null;
        window.document.onmousedown = null;
    }
    else
    {
        document.releaseEvents(Event.MOUSEMOVE | Event.MOUSEUP | Event.MOUSEDOWN);
        document.onmousemove = null;
        document.onmouseup = null;
        document.onmousedown = null;
    }

    divFloat.style.display = 'none';
    divFloat.removeChild(state.floatItem.node);
    state.floatItem.node.className = 'mf_item';

    moveItemOver.node.className = moveItemOverClass;

    state.blocks[state.floatItem.blockID].items[state.floatItem.id] = null;
    moveItemOver.items[state.floatItem.id] = state.floatItem;
    state.floatItem.blockID = moveItemOver.id;

    state.floatItem.node.removeChild(state.floatItem.controls);
    state.floatItem.node.id = createItemTagId(state.floatItem);
    moveItemOver.elemList.appendChild(state.floatItem.node);
    moveItemOver.elemList.style.display = 'block';

    state.floatItem.controls = ce('span');
    state.floatItem.controls.className = 'mf_item_extra';
    state.floatItem.controls.innerHTML = '<a href="javascript:void(0);" onclick="EditURLOrTitle(' + state.floatItem.blockID + ', ' + state.floatItem.id + ', true, true);" title="Edit url">&nbsp;url&nbsp;</a>|' +
                         '<a href="javascript:void(0);" onclick="EditURLOrTitle(' + state.floatItem.blockID + ', ' + state.floatItem.id + ', true, false);" title="Edit title">&nbsp;title&nbsp;</a>|'+
                         '<a href="javascript:void(0);" style="cursor: pointer; cursor: hand; color: #f44;" onclick="DeleteItem(' + state.floatItem.blockID + ', ' + state.floatItem.id + ');" title="Delete item">&nbsp;x&nbsp;</a>|' +
                         '<a href="javascript:void(0);" style="cursor: move; color: #44f;" title="Move item">&nbsp;#&nbsp;</a>';
    state.floatItem.controls.lastChild.onmousedown = function(evnt) { MoveItem(getItemFromId(this.parentNode.parentNode.id), evnt); }
    state.floatItem.node.appendChild(state.floatItem.controls);

    Request_MoveItem(state.floatItem);

    moveItemOver = null;
    divFloat = null;
    state.floatItem = null;
}

function UpdateColsSendOrder()
{
    var col1 = ge_i('client-col1');
    var col2 = ge_i('client-col2');
    if (col1.childNodes.length == 0)
    {
        while (col2.childNodes.length)
        {
            col1.appendChild(col2.childNodes.item(0));
        }
    }

    var order = '';
    for (i = 0; i < col1.childNodes.length; ++i)
    {
        Info(col1.childNodes.item(i).id);
        order += getBlockFromId('block:', col1.childNodes.item(i).id).id;
        if (i < (col1.childNodes.length - 1))
        {
            order += ':';
        }
    }

    order += ',';

    for (i = 0; i < col2.childNodes.length; ++i)
    {
        order += getBlockFromId('block:', col2.childNodes.item(i).id).id;
        if (i < col2.childNodes.length - 1)
        {
            order += ':';
        }
    }

    Request_SendOrder(order);
}

function findPosX(obj)
{
    var curleft = 0;
    if (obj.offsetParent)
    {
        while (obj.offsetParent)
        {
            curleft += obj.offsetLeft
                obj = obj.offsetParent;
        }
    }
    else if (obj.x)
        curleft += obj.x;
    return curleft;
}

function findPosY(obj)
{
    var curtop = 0;
    if (obj.offsetParent)
    {
        while (obj.offsetParent)
        {
            curtop += obj.offsetTop
                obj = obj.offsetParent;
        }
    }
    else if (obj.y)
        curtop += obj.y;
    return curtop;
}

// Util
function getBlockFromId(prefix, strId)
{
	var id = strId.substring(prefix.length, strId.length);
	return state.blocks[id];
}

function createItemTagId(item)
{
    return "item:" + item.blockID + ":" + item.id;
}

function getItemFromId(strId)
{
    var prefix = "item:";
	var ids = strId.substring(prefix.length, strId.length).split(':');
	return state.blocks[ids[0]].items[ids[1]];
}

// Dialog box
function ConfirmBox(title, text, fnYes)
{
    CloseModal();

    var frameWidth, frameHeight;
    if (document.documentElement && document.documentElement.clientWidth)
    {
        frameWidth = document.documentElement.clientWidth;
        frameHeight = document.documentElement.clientHeight;
    }
    else if (document.body)
    {
        frameWidth = document.body.clientWidth;
        frameHeight = document.body.clientHeight;
    }
    else
    {
        fnYes();
    }

    var divConfirm = ce('div');
    divConfirm.className = 'mf_block';
    divConfirm.id = 'modal';
    
	var elemTop = ce('div');
	elemTop.className = 'mf_blocktop';
    elemTop.innerHTML = title;
    divConfirm.appendChild(elemTop);

    var elemDesc = ce('p');
    elemDesc.innerHTML = text;
    divConfirm.appendChild(elemDesc);

    var yesNo = ce('div');
    yesNo.className = 'yesNo';
    yesNo.innerHTML = '<input type="submit" onclick="CloseModal(); ' + fnYes + ';" value="Yes" /><input type="submit" onclick="CloseModal();" value="No" />';
    divConfirm.appendChild(yesNo);

    document.body.appendChild(divConfirm);

    x = frameWidth / 2;
    y = frameHeight / 3;
    x += document.documentElement.scrollLeft;
    y += document.documentElement.scrollTop;
    x -= divConfirm.clientWidth / 2;
    y -= divConfirm.clientHeight / 2;
    divConfirm.style.top = y + 'px';
    divConfirm.style.left = x + 'px';
}

function CloseModal()
{
    if (box = ge_i('modal')) box.parentNode.removeChild(box);
}

// Debug
function Info(sText)
{
	ge_i("info").innerHTML += "<br />" + sText;
}

// Startup 
function InitState(objonly)
{
    var ids = new Array('stats', 'help', 'changes', 'client-col1', 'client-col2');
    for (var id in ids)
    {
        var elem = ge_i(ids[id]);
        while (elem.childNodes.length)
        {
            elem.removeChild(elem.childNodes[0]);
        }
    }

    if (!objonly)
    {
        state = new State();
    }
}

function ResizeEnd(evnt)
{
    if (!document.styleSheets) return;
    var theRules = new Array();
    if (document.styleSheets[0].cssRules)
        theRules = document.styleSheets[0].cssRules;
    else if (document.styleSheets[0].rules)
        theRules = document.styleSheets[0].rules;
    else
        return;

    var sizeX = 0;
    if (self.innerWidth)
    {
        sizeX = self.innerWidth;
    }
    else if (document.documentElement && document.documentElement.clientWidth)
    {
        sizeX = document.documentElement.clientWidth;
    }
    else if (document.body)
    {
        sizeX = document.body.clientWidth
    }
    else return;

    // We're going to use 20% of the client area to account for all padding
    // 10 total units, 2 * 3 for blocks, 1 * 2 for sys
    var unit = Math.floor(sizeX / 10);
    var blockWidth = (unit * 3) + 'px';
    var sysWidth = (unit * 2) + 'px';
    theRules[0].style.width = blockWidth;
    theRules[1].style.width = blockWidth;
    theRules[2].style.width = blockWidth;
    theRules[3].style.width = sysWidth;
    theRules[4].style.width = sysWidth;
    theRules[5].style.width = sysWidth;
}

function Init()
{
    if (window.document.all)
    {
        window.onresize = ResizeEnd;
    }
    else
    {
        window.captureEvents(Event.RESIZE);
        window.onresize = ResizeEnd;
    }

    ResizeEnd();

	Info('Initializing&#8230;');
    InitState(false);
	Info('Requesting xml&#8230');
	Request_All();
}

