window.OnDomLoaded = Class.create();
window.OnDomLoaded.prototype = {
    initialize : function()
    {
        if (!document.onDomLoadedCallbacks) {
            document.onDomLoadedCallbacks = [];

            var script;

            if (document.addEventListener) {
                document.addEventListener('DOMContentLoaded', this.doOnLoad, false);
            }
            else if (null != $('init_js')) {
                script = $('init_js');
                var self = this;
                script.onreadystatechange = function() {
                    if ('complete' == this.readyState) {
                        self.doOnLoad();
                    }
                };

                script.onreadystatechange();
                script = null;
            }
            else {
                script = document.createElement('script');
                script.setAttribute('defer', true);
                script.setAttribute('src', "javascript:'window.OnDomLoaded.doOnLoad();'");
                $$('head')[0].appendChild(script);
            }

            Event.observe(window, 'load', this.doOnLoad);
        }
    },

    register : function(callback)
    {
        document.onDomLoadedCallbacks.push(callback);
    },

    doOnLoad : function()
    {
        if (arguments.callee.done) {
            return;
        }

        arguments.callee.done = true;

        $A(document.onDomLoadedCallbacks).each(
            function(callback)
            {
                try {
                    callback();
                }
                catch (e) {
                    alert(e);
                }
            }
        );

        document.onDomLoadedCallbacks = [];
    }
};

var odl = new window.OnDomLoaded();
var Cookie = {
    set : function(name, value, expires, path, domain, secure)
    {
        if (expires) {
            var now = new Date();
            now.setTime(now.getTime() + expires*1000);
            expires = '; expires=' + now.toGMTString();
        }
        else {
            expires = '';
        }

        document.cookie = name + '=' + escape(value) +
                          expires +
                          ((path) ? '; path=' + path : '') +
                          ((domain) ? '; domain=' + domain : '') +
                          ((secure) ? '; secure' : '');
    },

    get : function(name)
    {
        var start = document.cookie.indexOf(name + '=');
        var len   = start + name.length + 1;
        if (-1 == start || !start && name != document.cookie.substring(0, name.length)) {
            return null;
        }

        var end = document.cookie.indexOf(';', len);
        if (-1 == end) {
            end = document.cookie.length;
        }

        return unescape(document.cookie.substring(len, end));
    },

    erase : function(name, path, domain, secure)
    {
        return this.set(name, '', -36000, path, domain, secure);
    }
};
window.Toolbox = Class.create();
window.Toolbox.prototype = {
    initialize : function()
    {
        $$('.toolbox').each(
            function(node)
            {
                new Draggable(node, { handle : 'title' });
                node.select('.close').invoke('observe', 'click', this._closeBox.bindAsEventListener(this, node));
            }.bind(this)
        );
    },
    _closeBox : function(e, box)
    {
        this.closeBox(box);
    },
    closeBox : function(box)
    {
        $(box).hide();
        var f = $(box).select('form')[0];
    	if (f) {
    	    f.reset();
    	}
    }
};

window.InfoBar = Class.create();
window.InfoBar.prototype = {
    initialize : function(id)
    {
        if (null == $(id)) {
            var ctr = $(Builder.node('div', { 'class' : 'infobar' }, [
                Builder.node('div', { 'id' : id })
            ]));

            this.infobar = ctr.down();

            var body = document.getElementsByTagName('body')[0];
            body.insertBefore(ctr, body.firstChild);
            this.infobar.observe('click', this.hide.bindAsEventListener(this));
        }

        this.paused = false;
    },
    hide : function()
    {
        Effect.Queues.get('infobar').invoke('cancel');
        this.infobar.style.display = 'none';
    },
    show : function(cls, html)
    {
        this.hide();
        this.infobar.update('<div>' + html + '</div>');

        this.infobar.addClassName(cls);

        this.infobar.style.display = 'block';
        new Effect.Fade(
            this.infobar,
            {
                queue: {
                    position : 'end',
                    scope    : 'infobar',
                    limit    : 2
                },
                duration : 8,
                from     : 1.0,
                to       : 0.0
            }
        );

        if (Prototype.Browser.IE) {
            function onScroll()
            {
                var x = this.infobar;
                x.top = parseInt(document.documentElement.scrollTop, 10);
                x.style.top = parseInt(document.documentElement.scrollTop, 10) + 'px';

                if ('none' == x.style.display) {
                    Event.stopObserving(window, 'scroll', this.boundOnScroll);
                }
            }

            this.boundOnScroll = onScroll.bindAsEventListener(this);
            Event.observe(window, 'scroll', this.boundOnScroll);
            onScroll();
        }
    }
};

var Validator = {
    email : function(email)
    {
        var re = /^[_\-\w]+(\.[_\-\w]+)*@[_\-\w]+(\.[_\-\w]+)*$/i;
        return re.test(email) ? true : false;
    },
    url : function(url)
    {
        var re = /^([a-z]+\:\/\/)?[a-z0-9_~\-]+(\.[a-z0-9_~\-]+)+(:\d+)?(\/.*)?$/i;
        return re.test(url.strip()) ? true : false;
    },
    notEmpty : function(s)
    {
        return !s.strip().empty();
    }
};

var Ajaxer = {
    done     : 0,
    requests : 0,
    pool     : $H({}),
    killAll  : function()
    {
        Ajaxer.done = 1;
        try {
            Ajaxer.pool.pluck('value').invoke('abort');
        }
        catch (e) {
        }

        delete Ajaxer.pool;
        return true;
    }
};

Ajax.Responders.register(
    {
        onCreate : function(requester, xhr)
        {
            if (1 == Ajaxer.done) {
                throw '';
            }

            var date = new Date();
            ++Ajaxer.requests;
            xhr.customMark = date.getTime() + '_' + Math.random();
            Ajaxer.pool.set(xhr.customMark, xhr);
        },

        /**
         * @param requester Ajax.Request
         * @param xhr XMLHttpRequest
         * @param json mixed    X-JSON
         */
        onComplete : function(requester, xhr, json)
        {
            --Ajaxer.requests;
            Ajaxer.pool.unset(xhr.customMark);
        },

        /**
         * @param requester Ajax.Request
         * @param exception Exception
         */
        onException : function(requester, exception)
        {
        }
    }
);

window.Engine = Class.create();
window.Engine.prototype = {
    initialize : function()
    {
        var base = $$('head base');
        if (base && base[0]) {
            base = base[0];
            this.base_url = base.getAttribute('href')
        }

        if ($('logout')) {
            $('logout').observe('click', this.logOut);
        }
    },

    dpw : 400,
    dph : 400,

    logOut : function(e)
    {
        var res;
        var ovl = $('overlay');
        if (null != ovl) {
            ovl.style.display = 'block';
        }

        if (!confirm(_lang.logout)) {
            e.stop();
            if (null != ovl) {
                ovl.style.display = 'none';
            }
        }
    },

    confirmation : function(e)
    {
        if (!confirm(_lang.are_you_sure)) {
            e.stop();
        }
    },

    getAjaxHandler : function()
    {
        return this.base_url + 'ajax.php';
    },

    highlightError : function(field)
    {
        new Effect.Highlight($(field).activate(), { startcolor : '#FF0000' });
    },

    makeRequest : function(method, param, callback)
    {
        var querystring;
        if ('string' == typeof param) {
            if (0 != param.length) {
                param += '&';
            }

            param += 'method=' + encodeURIComponent(method);
            querystring = param;
        }
        else {
            if (!param) {
                param = {};
            }

            param.method = method;
            querystring  = Hash.toQueryString(param);
        }

        var options = {
            asynchronous :  true,
            method       :  'post',
            evalScripts  :  true,
            parameters   :  querystring,
            onLoading    :  function(request)
                            {
                                //$('indicator').show();
                            },
            onException  :  function(t, e)
                            {
                                //$('indicator').style.display = 'none';
                                //alert('Exception: ' + e.toSource() + "\n" + t.transport.responseText);
                            },
            onComplete   :  function(response, json)
                            {
                                //$('indicator').style.display = 'none';
                            },
            onSuccess    :  function(transport, json)
                            {
                                //$('indicator').style.display = 'none';
                                if (options['internal_onComplete']) {
                                    try {
                                        options['internal_onComplete'](transport, json);
                                    }
                                    catch(e) {
                                        //alert(e.toSource());
                                    }
                                }
                            },
            onFailure    :  function(request)
                            {
                                //$('indicator').style.display = 'none';
                                //alert(_lang.error_communicating_with_server);
                            }
        }

        if (callback) {
            options['internal_onComplete'] = callback;
        }

        new Ajax.Request(this.getAjaxHandler(), options);
    },

    saveSearch : function(field)
    {
        var value = $F(field);
        if (true == value.empty()) {
            this.highlightError(field);
            return;
        }

        this.makeRequest(
            'saveSearch',
            { name : value },
            function(response)
            {
                this.InfoBar.show('success', _lang.saved);
            }.bind(this)
        );

        return false;
    },

    deleteSearch : function(select)
    {
        select   = $(select);
        var name = $F(select);

        this.makeRequest('deleteSearch', { 'name' : name });
        select.select('option[value="' + name.replace(/"/, "\"") + '"]').invoke('remove');
        return false;
    },

    reportSpam : function(id, button)
    {
        this.makeRequest('reportSpam', { 'id' : id });
        this.InfoBar.show('success', _lang.spam_reported);
        if (window.opener && window.opener.Engine && window.opener.Engine.Inbox) {
            window.opener.Engine.Inbox.removeMessage(id);
        }

        if ($(button)) {
            $(button).disable();
        }
    },

    blockSender : function(name, button)
    {
        if ($(button)) {
            $(button).disable();
        }

        this.makeRequest(
            'addIgnored',
            { 'name' : name },
            function(response)
            {
                var json = response.headerJSON;
                if (null == json) {
                    return;
                }

                if ('undefined' != typeof(json.error)) {
                    if (2 == json.error) {
                        this.engine.InfoBar.show('error', _lang.user_not_found);
                    }
                    else if (3 == json.error) {
                        this.engine.InfoBar.show('success', _lang.already_ignored);
                    }
                    else {
                        this.engine.InfoBar.show('error', _lang.unknown_error);
                    }
                }
                else {
                    this.InfoBar.show('success', _lang.added_to_ignored);
                }
            }.bind(this)
        );
    },

    addToFriends : function(name)
    {
        this.makeRequest(
            'addFriend',
            { 'name' : name },
            function(response)
            {
                var json = response.headerJSON;
                if (null == json) {
                    return;
                }

                if ('undefined' != typeof(json.error)) {
                    if (2 == json.error) {
                        this.InfoBar.show('error', _lang.user_not_found);
                    }
                    else if (3 == json.error) {
                        this.InfoBar.show('success', _lang.already_friends);
                    }
                    else {
                        this.InfoBar.show('error', _lang.unknown_error);
                    }
                }
                else {
                    this.InfoBar.show('success', _lang.added_to_friends);
                }
            }.bind(this)
        );
    },

    readMessage : function(id)
    {
        if (window.opener && window.opener.Engine && window.opener.Engine.Inbox) {
            window.opener.Engine.Inbox.markRead(id);
        }
    },

    saveMessage : function(id)
    {
        this.makeRequest(
            'saveMessage',
            { 'id' : id },
            function(response)
            {
                $('message_' + id).remove();
                this.InfoBar.show('success', _lang.message_saved);
            }.bind(this)
        );
    }
};

window.Messenger = Class.create();
window.Messenger.prototype = {
    initialize : function(engine)
    {
        this.engine = engine;
        if (null != $('mref')) {
            this.enableRefresh($F('mref'), 1);
            $('mref').observe(
                'change',
                function(e)
                {
                    this.enableRefresh($F(e.element()));
                }.bindAsEventListener(this)
            );
        }

        if (null != $('cmn')) {
            $('cmn').observe(
                'click',
                function(e)
                {
                    e.stop();
                    this.engine.makeRequest('checkMessages', {}, this._refreshHandler.bind(this));
                }.bindAsEventListener(this)
            );
        }

        if ($('mrform')) {
            $('mrform').style.display = 'block';
        }
    },
    enableRefresh : function(enable, init)
    {
        this.refresh_enabled = (0 == enable) ? 0 : 1;
        if (1 != init) {
            this.engine.makeRequest('updateRefresh', { refresh : this.refresh_enabled });
        }

        if (1 == this.refresh_enabled) {
	    this.engine.makeRequest('checkMessages', {}, this._refreshHandler.bind(this));
            new PeriodicalExecuter(this.refreshMsgCount.bind(this), 45);
        }
    },
    refreshMsgCount : function(pe)
    {
        if (0 == this.refresh_enabled) {
            pe.stop();
            return;
        }

        this.engine.makeRequest('checkMessages', {}, this._refreshHandler.bind(this));
    },
    _refreshHandler : function(response, json)
    {
        if ($('unread_count')) {
            var cnt = parseInt(response.responseText, 10);
            $('unread_count').update(cnt);
            $('li_ur').style.fontWeight = (0 == cnt) ? 'normal' : 'bold';
        }

        var json = response.headerJSON;
        if (null == json) {
            return;
        }

        if (json.count > 0) {
            popupWH(this.engine.base_url + 'mail/ims', 'instantmessages', this.engine.dpw, this.engine.dph);
            $('im_note').style.display = 'block';
        }
        else {
            $('im_note').style.display = 'none';
        }
    }
};

window.QuickLinks = Class.create();
window.QuickLinks.prototype = {
    initialize : function(user_id, engine)
    {
        this.user_id = user_id;
        this.engine  = engine;
        this.id      = 'user_' + user_id;
        this.order   = [];

        if ($(this.id)) {
            $(this.id).select('li').each(
                function(node)
                {
                    var span = Builder.node('span', { 'class' : 'action del'});
                    var div  = Builder.node('div', { 'class' : 'dragme'});
                    node.appendChild(span);
                    node.insertBefore(div, node.firstChild);
                    span.observe('click', this._deleteLink.bindAsEventListener(this));
                    this.order.push(node.getAttribute('id'));
                }.bind(this)
            );

            this._createSortable.bind(this).defer();
        }
    },
    _createSortable : function()
    {
        Sortable.create(
            $(this.id),
            {
                handle      : 'dragme',
                dropOnEmpty : true,
                constraint  : false,
                onUpdate    : this._updateOrder.bind(this)
            }
        );
    },
    _updateOrder : function(container)
    {
        this.engine.makeRequest('updateQuickLinksOrder', Sortable.serialize(container));
        this._renumber();
    },
    _deleteLink : function(e)
    {
        if (confirm(_lang.are_you_sure)) {
            var li = e.findElement('li');
            var no = li.getAttribute('id').match(/\d+$/)[0];
            this.engine.makeRequest('deleteQuickLink', { id : no }, this._linkDeleted.bind(this, no));
            this.order = this.order.without(li.getAttribute('id'));
            this._renumber();
        }
    },
    _renumber : function()
    {
        var n = 0;
        $(this.id).select('li').each(
            function(node)
            {
                node.setAttribute('id', this.order[n]);
                ++n;
            }.bind(this)
        );
    },
    _linkDeleted : function(transport, json)
    {
        $('link_' + arguments[0]).remove();
    }
};

window.UsernameAutocompleter = Class.create();
window.UsernameAutocompleter.prototype = {
    initialize : function(engine)
    {
        this.engine = engine;
    },
    addTo : function(element, div)
    {
        var element = $(element);
        var div     = $(div);
        if (null != element && null != div) {
            new Ajax.Autocompleter(
                element,
                div,
                this.engine.getAjaxHandler(),
                {
                    minChars   : 2,
                    parameters : 'method=autocompleteUsername',
                    paramName  : 'value'
                }
            );
        }
    }
};

window.WhoIsOnline = Class.create();
window.WhoIsOnline.prototype = {
    initialize : function(engine, options)
    {
        this.engine = engine;
        this.options = Object.extend(
            {
                members_online : 'members_online',
                online_users   : 'online_users',
                friends_online : 'fo',
                span_friends   : 'friends_online',
                admired_online : 'ao',
                span_admired   : 'admired_online',
                li_prefix      : 'li_'
            },
            options || {}
        );

        if ($(this.options.members_online) && $(this.options.online_users)) {
            new PeriodicalExecuter(this.refreshOnline.bind(this), 47);
        }
    },
    refreshOnline : function()
    {
        this.engine.makeRequest('refreshOnline', {}, this._refreshHandler.bind(this));
    },
    _refreshHandler : function(response, json)
    {
		
        json = response.responseJSON;
        if (null == json) {
            return;
        }

        $(this.options.span_friends).update(json.friends);
        $(this.options.span_admired).update(json.admired);

        $(this.options.li_prefix + this.options.friends_online).style.fontWeight = (0 == json.friends) ? 'normal' : 'bold';
        $(this.options.li_prefix + this.options.admired_online).style.fontWeight = (0 == json.admired) ? 'normal' : 'bold';

        $(this.options.members_online).update(json.total);

        var ou = $(this.options.online_users);
        ou.select('*').invoke('remove');

        var df = (document.createDocumentFragment) ? document.createDocumentFragment() : null;

        for (var country_name in json.countries) {
            var country = json.countries[country_name];
            var li = document.createElement('li');
            var a  = document.createElement('a');
            var ul = document.createElement('ul');
            a.setAttribute('href', 'online/users/' + encodeURIComponent(country_name));
            a.appendChild(document.createTextNode(country.total + _lang.x_in_y + country_name));
            li.appendChild(a);
            li.appendChild(ul);

            if (df) {
                df.appendChild(li);
            }
            else {
                ou.appendChild(li);
            }

            for (var city_name in country.cities) {
                var city = country.cities[city_name];
			
                li = li.cloneNode(false);
                a  = a.cloneNode(false);
                a.setAttribute('href', 'online/users/' + encodeURIComponent(country_name) + '/' + encodeURIComponent(city_name).replace('%2F', '%252F'));
                a.appendChild(document.createTextNode(city.total + ' in ' + city_name));
                li.appendChild(a);
                ul.appendChild(li);
            }
        }

        if (df) {
            ou.appendChild(df);
        }
    }
};

window.ColExHandler = Class.create();
window.ColExHandler.prototype = {
    initialize : function()
    {
        this.cehandler = this._ce_click.bindAsEventListener(this);
        $$('.colex').each(
            function(node)
            {
                node.observe('click', this.cehandler);
                node.style.display = 'block';
            }.bind(this)
        )
    },
    _ce_click : function(e)
    {
        var el = e.findElement('span');
        if (el) {
            el.toggleClassName('collapsed');
        }
    }
};

window.FeedLoader = Class.create();
window.FeedLoader.prototype = {
    initialize : function(engine, container, options)
    {
        this.engine = engine;
        this.container = $(container);

        this.options = Object.extend(
            {
                feed_prefix : 'feed_',
                ce_prefix   : 'ce_',
                fc_prefix   : 'fc_',
                del_prefix  : 'del_',
                add_link    : 'addfeed_link',
                add_form    : 'addfeed_form'
            },
            options || {}
        );

        if (null != this.container) {
            this.feeds = [];
            this.container.select('ul').each(
                function(node)
                {
                    var item_id = node.getAttribute('id');
                    var feed_id = item_id.replace(/^[^_]+_/, '');
                    var entries = node.select('li').length;
                    this.feeds[feed_id] = {
                        'item_id'  : item_id,
                        'feed_id'  : feed_id,
                        'entries'  : entries,
                        'loaded'   : entries,
                        'complete' : false
                    };
                }.bind(this)
            );

            this.ce_click = this._feed_ce_click.bindAsEventListener(this);
            this.del_click = this._feed_del_click.bindAsEventListener(this);
            this.container.select('.colex').invoke('observe', 'click', this.ce_click);
            var dels = this.container.select('.del');
            dels.invoke('observe', 'click', this.del_click);

            this.addlink = $(this.options.add_link);
            this.addform = $(this.options.add_form);

            if (this.addlink && this.addform) {
                this.addlink.observe('click', this._toggleForm.bindAsEventListener(this));
                this.addform.observe('submit', this._submitForm.bindAsEventListener(this));
            }
        }
    },
    _submitForm : function(e)
    {
        e.stop();
        var url     = $F('feed_url');
        var maxnews = $F('max_news');

        if (false == Validator.url(url)) {
            this.engine.highlightError($('feed_url'));
            return;
        }

        new Effect.toggle(this.addform, 'appear');
        this.engine.makeRequest('addFeed', { 'url' : url, 'max' : maxnews }, this._feedAdded.bind(this));
    },
    _toggleForm : function(e)
    {
        e.stop();
        if ('none' == this.addform.style.display) {
            this.addform.reset();
        }

        new Effect.toggle(this.addform, 'appear');
    },
    _feed_ce_click : function(e)
    {
        var span    = e.findElement('span');
        var feed_id = span.getAttribute('id').replace(/^[^_]+_/, '');
        var entry   = this.feeds[feed_id];

        if (true == span.hasClassName('collapsed')) {
            this._collapseFeed(entry, feed_id);
        }
        else if (entry.entries < entry.loaded) {
            this._expandFeed(entry, feed_id);
        }
        else {
            if (0 != this.feeds[feed_id]['loaded']) {
                this.engine.makeRequest('loadNews', { 'feed_id' : feed_id }, this._onFeedLoaded.bind(this));
            }
        }
    },
    _expandFeed : function(entry, feed_id)
    {
        $R(entry.entries+1, entry.loaded, true).each(
            function(item)
            {
                if ($(this.options.feed_prefix + feed_id + '_' + item)) {
                    $(this.options.feed_prefix + feed_id + '_' + item).show();
                }
            }.bind(this)
        );
    },
    _collapseFeed : function(entry, feed_id)
    {
        $R(entry.entries+1, entry.loaded, true).each(
            function(item)
            {
                if ($(this.options.feed_prefix + feed_id + '_' + item)) {
                    $(this.options.feed_prefix + feed_id + '_' + item).hide();
                }
            }.bind(this)
        );
    },
    _onFeedLoaded : function(response)
    {
        var json = response.responseJSON;
        if (null != json && 'undefined' != typeof json.items) {
            this.feeds[json.id]['loaded'] = json.items.length;
            this.feeds[json.id]['complete'] = true;
            var entry = this.feeds[json.id];
            var ul    = $(this.options.feed_prefix + json.id);
            for (var i=entry.entries+1; i<entry.loaded; ++i) {
                var x = json.items[i];

                var li = Builder.node('li', { id : this.options.feed_prefix + json.id + '_' + i }, [
                    Builder.node('a', { href : x.link, target : '_blank' }, [
                        Builder.node('strong', [x.title])
                    ]),
                    '\u00A0\u2013 ',
                    Builder.node('em', [x.date]),
                    Builder.node('div', [x.description])
                ]);

                ul.appendChild(li);
            }
        }
    },
    _feedAdded : function(response)
    {
        var json = response.responseJSON;
        if (null != json) {
            this.feeds[json.id] = {
                'item_id'  : this.options.feed_prefix + json.id,
                'feed_id'  : json.id,
                'entries'  : 0,
                'loaded'   : 0,
                'complete' : true
            };

            var div = Builder.node('div', { id : this.options.fc_prefix + json.id }, [
                Builder.node('h4', [
                    Builder.node('span', { id : this.options.ce_prefix + json.id, 'class' : 'colex collapsed', style : 'display: block' }, [
                        Builder.node('img', { alt : '', src : images_url + '/icons/colex.gif' })
                    ]),
                    Builder.node('span', { 'class' : 'action del', id : this.options.del_prefix + json.id }),
                    Builder.node('a', { target : '_blank', href : json.link }, [json.title])
                ]),
                Builder.node('ul', { id : this.options.feed_prefix + json.id })
            ]);

            this.container.appendChild(div);
            var ce  = div.down().down();
            var del = ce.next();
            ce.observe('click', this.engine.ColExHandler.cehandler);
            ce.observe('click', this.ce_click);
            del.observe('click', this.del_click);
            this._onFeedLoaded(response);
            this.feeds[json.id]['entries'] = parseInt(json.maxnews, 10);
            this._collapseFeed(this.feeds[json.id], json.id);
        }
    },
    _feed_del_click : function(e)
    {
        e.stop();
        if (confirm(_lang.are_you_sure)) {
            var elt = $(e.element());
            var id  = elt.getAttribute('id').replace(/^[^_]+_/, '');
            var ctr = $(this.options.fc_prefix + id);
            elt.stopObserving('click', this.del_click);
            $(this.options.ce_prefix + id).stopObserving('click', this.ce_click);
            $(this.options.ce_prefix + id).stopObserving('click', this.engine.ColExHandler.cehandler);
            ctr.remove();
            this.engine.makeRequest('delFeed', { 'feed_id' : id });
        }
    }
};

window.QuickLinksManager = Class.create();
window.QuickLinksManager.prototype = {
    initialize : function(engine, options)
    {
        this.engine = engine;
        this.options = Object.extend(
            {
                links  : 'mylinks',
                button : 'doadd',
                prefix : 'link_',
                url    : 'url',
                name   : 'name',
                maxlen : 50,
                edit   : {
                    box    : 'ml_editbox',
                    id     : 'lid',
                    url    : 'lurl',
                    name   : 'lname',
                    button : 'doedit'
                }
            },
            options || {}
        );

        this.button = $(this.options.button);
        this.links  = $(this.options.links);
        this.name   = $(this.options.name);
        this.url    = $(this.options.url);
        this.box    = $(this.options.edit.box);
        this.order  = [];

        if (null != this.button && null != this.name && null != this.url) {
            this.button.observe('click', this._onBeforeSubmit.bindAsEventListener(this));
        }

        this.del_link  = this._deleteLink.bindAsEventListener(this);
        this.edit_link = this._editLink.bindAsEventListener(this);

        if (null != this.links) {
            this.links.select('.dragme').invoke('setStyle', { visibility : 'visible' });
            this.links.select('.del').invoke('observe', 'click', this.del_link);

            if (null != this.box) {
                this.links.select('.edit').invoke('observe', 'click', this.edit_link);
                $(this.options.edit.button).observe('click', this._onBeforeEdited.bindAsEventListener(this));
            }

            this.order = this.links.select('li.item').pluck('id');

            this._recreateSortable();
        }
    },
    _onBeforeSubmit : function(e)
    {
        e.stop();
        if (false == Validator.url($F(this.url))) {
            this.engine.highlightError(this.url);
            return;
        }

        if (false == Validator.notEmpty($F(this.name))) {
            this.engine.highlightError(this.name);
            return;
        }

        this.engine.makeRequest('addQuickLink', { name : $F(this.name), url : $F(this.url) }, this._onLinkAdded.bind(this));
    },
    _recreateSortable : function()
    {
        Sortable.create(
            this.links,
            {
                only     : 'item',
                handle   : 'dragme',
                onUpdate : this._updateOrder.bind(this)
            }
        );
    },
    _updateOrder : function(container)
    {
        var n = 0;
        this.engine.makeRequest('updateQuickLinksOrder', Sortable.serialize(container) + '&param=' + this.links.getAttribute('id'));
        this.links.select('li.item').each(
            function(node)
            {
                node.setAttribute('id', this.order[n]);
                ++n;
            }.bind(this)
        );
    },
    _onLinkAdded : function(response)
    {
        var json = response.headerJSON;
        if (null == json) {
            return;
        }

        if ('undefined' != typeof json.error) {
            if (2 == json.error) {
                this.engine.highlightError(this.url);
                this.engine.InfoBar.show('error', _lang.invalid_url);
                return;
            }

            if (1 == json.error) {
                this.engine.highlightError(this.name);
                this.engine.InfoBar.show('error', _lang.invalid_link_title);
                return;
            }

            this.engine.InfoBar.show('error', _lang.error_processing_request);
            return;
        }

        this.url.form.reset();

        var li = $(document.createElement('li'));
        li.setAttribute('id', this.prefix + json.id);
        li.addClassName('item');
        var div = $(document.createElement('div'));
        div.addClassName('dragme');
        div.style.visibility = 'visible';
        li.appendChild(div);
        div = $(document.createElement('div'));
        div.addClassName('col1');
        var a = document.createElement('a');
        a.setAttribute('href', json.url);
        a.setAttribute('title', json.name);
        a.setAttribute('target', '_blank');
        a.appendChild(document.createTextNode(json.name.truncate(this.maxlen)));
        div.appendChild(a);
        li.appendChild(div);
        div = $(document.createElement('div'));
        div.addClassName('col2');
        var span1 = $(document.createElement('span'));
        span1.addClassName('action');
        var span2 = $(span1.cloneNode(false));
        span1.addClassName('edit');
        div.appendChild(span1);
        span2.addClassName('del');
        div.appendChild(span2);
        li.appendChild(div);
        this.links.appendChild(li);
        span1.observe('click', this.edit_link);
        span2.observe('click', this.del_link);

        this.order.push(json.id);
        this._recreateSortable();
    },
    _deleteLink : function(e)
    {
        e.stop();
        if (confirm('Are you sure?')) {
            var li = e.findElement('li');
            var id = li.getAttribute('id').replace(/^[^_]+_/, '');
            this.engine.makeRequest('deleteQuickLink', { 'id' : id });
            this.order = this.order.without(li.getAttribute('id'));
            li.select('.del').invoke('stopObserving', 'click', this.del_link);
            li.select('.edit').invoke('stopObserving', 'click', this.edit_link);
            li.remove();
        }
    },
    _editLink : function(e)
    {
        e.stop();
        var li = e.findElement('li');
        var a  = li.select('.col1 a')[0];
        var id = li.getAttribute('id').replace(/^[^_]+_/, '');
        this.box.clonePosition(li, { setWidth : false, setHeight : false, offsetTop : li.offsetHeight, offsetLeft : 30 });
        this.box.show();
        this.box.select('form')[0].focusFirstElement();
        $(this.options.edit.id).value = id;
        $(this.options.edit.url).value = a.getAttribute('href');
        $(this.options.edit.name).value = a.getAttribute('title');
    },
    _onBeforeEdited : function(e)
    {
        e.stop();
        var id   = $F(this.options.edit.id);
        var url  = $F(this.options.edit.url);
        var name = $F(this.options.edit.name);

        if (false == Validator.notEmpty(name)) {
            this.engine.highlightError(this.options.edit.name);
            return;
        }

        if (false == Validator.url(url)) {
            this.engine.highlightError(this.options.edit.url);
            return;
        }

        $(this.options.edit.button).disabled = true;
        this.engine.makeRequest('editQuickLink', { 'id' : id, 'url' : url, 'name' : name }, this._onEdited.bind(this));
    },
    _onEdited : function(response)
    {
        $(this.options.edit.button).disabled = false;

        var json = response.headerJSON;
        if (null == json) {
            return;
        }

        if ('undefined' != typeof json.error) {
            if (2 == json.error) {
                this.engine.highlightError(this.url);
                this.engine.InfoBar.show('error', _lang.invalid_url);
                return;
            }

            if (1 == json.error) {
                this.engine.highlightError(this.name);
                this.engine.InfoBar.show('error', _lang.invalid_link_title);
                return;
            }

            this.engine.InfoBar.show('error', _lang.error_processing_request);
            return;
        }

        var li = $(this.options.prefix + json.id);
        if (null != li) {
            var a = li.select('.col1 a')[0];
            a.setAttribute('href', json.url);
            a.setAttribute('title', json.name);
            a.update(json.name.truncate(this.options.maxlen));
        }

        this.engine.Toolbox.closeBox(this.box);
    }
};

window.NewsfeedsManager = Class.create();
window.NewsfeedsManager.prototype = {
    initialize : function(engine, options)
    {
        this.engine = engine;
        this.options = Object.extend(
            {
                feeds     : 'myfeeds',
                button    : 'doadd',
                prefix    : 'feed_',
                url       : 'url',
                headlines : 'headlines',
                maxlen    : 37,
                edit      : {
                    box       : 'mf_editbox',
                    id        : 'fid',
                    url       : 'furl',
                    headlines : 'fheadlines',
                    button    : 'doedit'
                }
            },
            options || {}
        );

        this.button = $(this.options.button);
        this.feeds  = $(this.options.feeds);
        this.hlines = $(this.options.headlines);
        this.url    = $(this.options.url);
        this.box    = $(this.options.edit.box);
        this.order  = [];

        if (null != this.button && null != this.hlines && null != this.url) {
            this.button.observe('click', this._onBeforeSubmit.bindAsEventListener(this));
        }

        this.del_feed  = this._deleteFeed.bindAsEventListener(this);
        this.edit_feed = this._editFeed.bindAsEventListener(this);

        if (null != this.feeds) {
            this.feeds.select('.dragme').invoke('setStyle', { visibility : 'visible' });
            this.feeds.select('.del').invoke('observe', 'click', this.del_feed);

            if (null != this.box) {
                this.feeds.select('.edit').invoke('observe', 'click', this.edit_feed);
                $(this.options.edit.button).observe('click', this._onBeforeEdited.bindAsEventListener(this));
            }

            this.order = this.feeds.select('li.item').pluck('id');
            this._recreateSortable();
        }
    },
    _recreateSortable : function()
    {
        Sortable.create(
            this.feeds,
            {
                only     : 'item',
                handle   : 'dragme',
                onUpdate : this._updateOrder.bind(this)
            }
        );
    },
    _updateOrder : function(container)
    {
        var n = 0;
        this.engine.makeRequest('updateFeedsOrder', Sortable.serialize(container) + '&param=' + this.feeds.getAttribute('id'));
        this.feeds.select('li.item').each(
            function(node)
            {
                node.setAttribute('id', this.order[n]);
                ++n;
            }.bind(this)
        );
    },
    _onBeforeSubmit : function(e)
    {
        e.stop();
        var url = $F(this.url);
        var hls = $F(this.hlines);

        if (false == Validator.url(url)) {
            this.engine.highlightError(this.url);
            return;
        }

        this.engine.makeRequest('addFeed', { 'url' : url, 'max' : hls, refresh : 60, load : 0 }, this._onFeedAdded.bind(this));
    },
    _onFeedAdded : function(response)
    {
        var json = response.headerJSON;
        if (null == json) {
            return;
        }

        if ('undefined' != typeof json.error) {
            if (1 == json.error) {
                this.engine.highlightError(this.url);
                this.engine.InfoBar.show('error', _lang.invalid_url);
                return;
            }

            this.engine.InfoBar.show('error', _lang.error_processing_request);
            return;
        }

        this.url.form.reset();

        var li = $(document.createElement('li'));
        li.setAttribute('id', this.prefix + json.id);
        li.addClassName('item');
        var div = $(document.createElement('div'));
        div.addClassName('dragme');
        div.style.visibility = 'visible';
        li.appendChild(div);
        div = $(document.createElement('div'));
        div.addClassName('col1');
        var a = document.createElement('a');
        a.setAttribute('href', json.url);
        a.setAttribute('title', json.url);
        a.setAttribute('target', '_blank');
        a.appendChild(document.createTextNode(json.url.truncate(this.maxlen)));
        div.appendChild(a);
        li.appendChild(div);
        div = $(document.createElement('div'));
        div.addClassName('col2');
        div.appendChild(document.createTextNode(json.max));
        li.appendChild(div);
        div = $(document.createElement('div'));
        div.addClassName('col3');
        var span1 = $(document.createElement('span'));
        span1.addClassName('action');
        var span2 = $(span1.cloneNode(false));
        span1.addClassName('edit');
        div.appendChild(span1);
        span2.addClassName('del');
        div.appendChild(span2);
        li.appendChild(div);
        this.feeds.appendChild(li);
        span1.observe('click', this.edit_feed);
        span2.observe('click', this.del_feed);

        this.order.push(json.id);
        this._recreateSortable();
    },
    _deleteFeed : function(e)
    {
        e.stop();
        if (confirm('Are you sure?')) {
            var li = e.findElement('li');
            var id = li.getAttribute('id').replace(/^[^_]+_/, '');
            this.engine.makeRequest('delFeed', { 'feed_id' : id });
            this.order = this.order.without(li.getAttribute('id'));
            li.select('.del').invoke('stopObserving', 'click', this.del_feed);
            li.select('.edit').invoke('stopObserving', 'click', this.edit_feed);
            li.remove();
        }
    },
    _editFeed : function(e)
    {
        e.stop();
        var li = e.findElement('li');
        var a  = li.select('.col1 a')[0];
        var n  = li.select('.col2').innerHTML;
        var id = li.getAttribute('id').replace(/^[^_]+_/, '');
        this.box.clonePosition(li, { setWidth : false, setHeight : false, offsetTop : li.offsetHeight, offsetLeft : 30 });
        this.box.show();
        this.box.select('form')[0].focusFirstElement();
        $(this.options.edit.id).value = id;
        $(this.options.edit.url).value = a.getAttribute('href');
        $(this.options.edit.headlines).value = n;
    },
    _onBeforeEdited : function(e)
    {
        e.stop();
        var id  = $F(this.options.edit.id);
        var url = $F(this.options.edit.url);
        var hls = $F(this.options.edit.headlines);

        if (false == Validator.url(url)) {
            this.engine.highlightError(this.options.edit.url);
            return;
        }

        $(this.options.edit.button).disabled = true;
        this.engine.makeRequest('editFeed', { 'id' : id, 'url' : url, 'max' : hls }, this._onEdited.bind(this));
    },
    _onEdited : function(response)
    {
        $(this.options.edit.button).disabled = false;

        var json = response.headerJSON;
        if (null == json) {
            return;
        }

        if ('undefined' != typeof json.error) {
            if (1 == json.error) {
                this.engine.highlightError(this.url);
                this.engine.InfoBar.show('error', _lang.invalid_url);
                return;
            }

            this.engine.InfoBar.show('error', _lang.error_processing_request);
            return;
        }

        var li = $(this.options.prefix + json.id);
        if (null != li) {
            var a = li.select('.col1 a')[0];
            a.setAttribute('href', json.url);
            a.setAttribute('title', json.url);
            a.update(json.url.truncate(this.options.maxlen));
            li.select('.col2')[0].update(json.max);
        }

        this.engine.Toolbox.closeBox(this.box);
    }
};

var Engine;

function gcn_onDomLoaded()
{
    $$('.autocomplete').invoke('setStyle', { border : '1px solid #888' });

    var ctr = $$('body')[0];
    var ovl = $(Builder.node('div', { id : 'overlay', style : 'display: none' }));
    ovl.style.display = 'none';
    ctr.insertBefore(ovl, ctr.firstChild);

    Event.observe(window, 'unload', Ajaxer.killAll);

    Engine = new window.Engine();
    Engine.Messenger = new window.Messenger(Engine);
    Engine.UsernameAutocompleter = new window.UsernameAutocompleter(Engine);
    Engine.WhoIsOnline = new window.WhoIsOnline(Engine);
    Engine.ColExHandler = new window.ColExHandler();
    Engine.InfoBar = new window.InfoBar('infobar');
    Engine.Toolbox = new window.Toolbox();

    if ('undefined' != typeof initLightbox) {
        initLightbox(
            {
                overlay      : 'overlay',
                loading_img  : images_url + '/lightbox/loading.gif',
                close_img    : images_url + '/lightbox/closelabel.png',
                force_update : true,
                animate      : false
            }
        );
    }
}

odl.register(gcn_onDomLoaded);

function popup(url, target, options)
{
    var newWin;
    try {
        var now = new Date();
        newWin = window.open(url, target + now.getTime(), options);
        if (null == newWin || newWin.closed || !newWin.focus) {
            return true;
        }
        else {
            newWin.focus();
        }
    }
    catch (e) {
        alert('Failed to open a window!');
    }

    if (window.event) {
        window.event.returnValue = false;
        window.event.cancelBubble = true;
    }

    return false;
}

function popupWH(url, target, width, height)
{
    return popup(url, target, 'width=' + width +',height=' + height + ',resizable=yes,scrollbars=yes,status=yes');
}
