var UIPage = Class.create({
    initialize: function (cnf) {
        this.cnf = cnf || {};

        Prototype.Browser.IE7 = Prototype.Browser.IE && parseInt(navigator.userAgent.substring(navigator.userAgent.indexOf("MSIE")+5)) == 7;
        this.setup_view();
        if (!Prototype.Browser.IE) {
            Event.observe(window, 'resize', this.setup_view.bind(this));
        }
        this.menu = new UIMenu();

        this.image = new ImagePreloader(cnf);
        this.video_viewer = new VideoViewer();
        this.image.cache_images(['/images/over_item.png']);
        this.ui_extensions.bind(this).defer();
    },
    fetch: function (url, callback, params) {
        this.req = Utils.fetch(url, callback, params);
    },
    setup_view: function () {
        this.set_background();
        this.set_layout();
    },
    set_background: function () {
        return false; // no background today..
        var w = [1024, 1152, 1280, 1440, 1680].find(function (n) {
            return this < n;
        }.bind(document.viewport.getWidth())) || 1920;
        w = 'url(' + this.cnf.static_path + '/images/bg/'+w+'.jpg)';
        if (document.body.getStyle('backgroundImage') !== w) {
            document.body.setStyle({backgroundImage:w});
            Cookie.set('background', w);
        }
        return true;
    },
    set_layout: function () {
        (function () {
            $('content').removeClassName('clearfix').addClassName('clearfix');
            $('layout', 'content').invoke('setStyle', { height: 'auto' });
            var vh = document.viewport.getHeight();
            var lh = $('layout').getHeight();
            if (lh < vh) {
                $('layout').setStyle({ height: vh + 'px' });
                var no_content = lh - $('content').getHeight() + 50;
                $('content').setStyle({height: (vh - no_content) + 'px'});
            } else {
                $('content').setStyle({height:'auto'});
            }
        }).defer();
    },
    ui_extensions: function () {
        /* tabbed blocks */
        $$('div.b-tab-block').each(function (el) {
            new Control.Tabs(el.down('div.menu').identify(), {
                linkSelector: 'a'
            });
        });
        /* click button and inplace video */
        document.observe('click', function (e) {
            var el = e.findElement();
            var nel;
            if (el.tagName !== 'A' && (nel = e.findElement('.clicker')) && nel.down('a')) {
                e.stop();
                document.location.href = (nel.down('a.clicker_href') || nel.down('a')).href;
            } else if (el.tagName === 'A') {
                if (el.href.match(this.video_viewer.simple) && this.video_viewer.view(el.href)) {
                    e.stop();
                }
            }
        }.bindAsEventListener(this));
        /* action button */
        var a_btn = $('action_button');
        if (a_btn) {
            a_btn.setStyle({ width: a_btn.getWidth() + 4 + 'px' }); /* layout fix */
            if (a_btn.down('div.drop')) { /* drop down button */
                a_btn.down('div.drop').observe('click', function (e) {
                    if (this.hasClassName('press')) {
                        this.removeClassName('press');
                        $('action_options').addClassName('hide');
                    } else {
                        $('action_options').removeClassName('hide').down('table').setStyle({width: this.getWidth() + 'px'});
                        this.addClassName('press');
                    }
                }.bind(a_btn));
                Event.observe(document, 'click', function (e) {
                    if (this.hasClassName('press') && !e.findElement('div.b-action-button')) {
                        this.removeClassName('press');
                        $('action_options').addClassName('hide');
                    }
                }.bind(a_btn));
            }
        }
        /* show-hide trigger */
        $$('.hide').each(function (el) {
            if ($(el.id+'_trigger')) {
                $(el.id+'_trigger').observe('click', function (id, trigger) {
                    if ($(id).hasClassName('hide')) {
                        $(id).hide();
                        $(id).removeClassName('hide');
                        $(id).appear({duration:0.2, afterFinish: this.set_layout.bind(this)});
                        $(trigger).firstChild.nodeValue = $(trigger).firstChild.nodeValue.replace(/показать/ig, 'скрыть');
                        $(trigger).addClassName('triggered');
                    } else {
                        $(id).fade({duration:0.1, afterFinish: function (id, ef) {
                            $(id).addClassName('hide');
                            this.set_layout();
                        }.bind(this, id)});
                        $(trigger).firstChild.nodeValue = $(trigger).firstChild.nodeValue.replace(/скрыть/ig, 'показать');
                        $(trigger).removeClassName('triggered');
                    }
                }.bind(this, el.id, el.id+'_trigger'));
            }
        }.bind(this));
        /* collapsible blocks */
        $$('.collapse').invoke('observe', 'click', function (e) {
            e.findElement('div.collapsible').toggleClassName('collapsed');
            this.set_layout();
        }.bindAsEventListener(this));
        /* checkboxes extended click area */
        this._extended_check = function (e) {
            var box = e.findElement('div.checkbox.comment').down('input[type=checkbox]');
            if (box) {
                box.checked = !box.checked;
            }
        };
        $$('div.checkbox.comment span.comment').invoke('observe', 'click', this._extended_check.bindAsEventListener(this));
        $$('select.select_multiple').each(function (el) {
            new MultipleSelect(this, el);
        }.bind(this));
        /* show-hide tagged */
        $$('.tags').each(function (el) {
            el.observe('click', function (e) {
                var el = e.findElement('span');
                if (el) {
                    var off = el.hasClassName('hide_tag');
                    el[(off?'remove':'add')+'ClassName']('hide_tag');
                    el.up('.tags').up().down('.tagged').select('li').each(function (class_ids, el) {
                        el.removeClassName('hide');
                        if (class_ids.size() > 0) {
                            class_ids.each(function (class_id) {
                                if (this.hasClassName(class_id)) {
                                    this.addClassName('hide');
                                }
                            }.bind(el));
                        }
                    }.bind(
                        window,
                        el.up('.tags').childElements().select(function (s) {
                            return s.hasClassName('hide_tag');
                        }).map(function (el) {
                            return el.className.replace(new RegExp("\\s*hide_tag\\s*"), '');
                        })
                    ));
                }
            });
        });
        /* images with no placeholder */
        $$('img.nosize').invoke('observe', 'load', this.set_layout.bind(this));
        if ($('propose_ideas_switch')) {
            $('propose_ideas_switch').observe('click', function (e) {
                e.stop();
                Cookie[e.findElement('a').toggleClassName('bug').hasClassName('bug')?'set':'erase']('quiet', 1, 365, '/');
            });
        }
        /* quick search */
        if ($('do_qsearch')) {
            $('do_qsearch').observe('click', function (e) { e.findElement('form').sumbit() });
        }
        /* inline video player */
        $$('a.inline_video_player').each(function (el) {
            if (el.href.match(this.video_viewer.simple)) {
                var choosen = this.video_viewer.match(el.href);
                if (choosen) {
                    var w = 620, h = 400;
                    if (el.hasClassName('tiny')) { w = 500; h = 300; }
                    swfobject.embedSWF(this.video_viewer.vpath(choosen[0], choosen[1]), el.identify(), w, h, "10", null, null, { allowfullscreen: "true", allowscriptaccess: "always", wmode: "transparent" });
                    this.set_layout();
                }
            } else {
                el.update(el.href);
                el.target = "_blank";
            }
        }.bind(this));
        /* flash banners // should be automated */
        if ($('ays_hotel')) {
            swfobject.embedSWF('/static/upload/advert/ays_hotel_300x150.swf', 'ays_hotel', 285, 120, "9", null, null, { wmode: "transparent" });
        }
        /* adverts */
        $$('div.embed-flash').each(function (el) {
            var href = el.readAttribute('data-href');
            if (href) {
                el.insert({after: new Element('a', { href: href, target:'_blank', className: 'flash' }).setStyle({ width: el.readAttribute('data-width')+'px', height: el.readAttribute('data-height')+'px' })});
            }
            swfobject.embedSWF(el.readAttribute('data-url'), el.identify(), el.readAttribute('data-width'), el.readAttribute('data-height'), "9", null, null, { wmode: "transparent" });
        });
    }
});

var UIMenu = Class.create({
    select: function (id) {
        if ($(id)) {
            $(id).addClassName('select');
        }
    },
    subselect: function (id) {
        var el = $('sm_'+id);
        if (el) {
            el.addClassName('select');
        }
    }
});

// Cookie module
var Cookie = {
  set: function(name, value, daysToExpire, pathTo) {
    var expire = '';
    if (daysToExpire != undefined) {
      var d = new Date();
      d.setTime(d.getTime() + (86400000 * parseFloat(daysToExpire)));
      expire = '; expires=' + d.toGMTString();
    }
    var path = '';
    if (pathTo != undefined) {
        path = '; path='+escape(pathTo);
    }
    return (document.cookie = escape(name) + '=' + escape(value || '') + path + expire);
  },
  get: function(name) {
    var cookie = document.cookie.match(new RegExp('(^|;)\\s*' + escape(name) + '=([^;\\s]*)'));
    return (cookie ? unescape(cookie[2]) : null);
  },
  erase: function(name) {
    var cookie = Cookie.get(name) || true;
    Cookie.set(name, '', -1);
    return cookie;
  },
  accept: function() {
    if (typeof navigator.cookieEnabled  == 'boolean') {
      return navigator.cookieEnabled;
    }
    Cookie.set('_test', '1');
    return (Cookie.erase('_test') === '1');
  }
};

// Utils module
var Utils = {
    add_option: function (sel, opt, is_select) {
        sel.options[sel.options.length] = opt;
        if (is_select) {
            sel.options.selectedIndex = sel.options.length - 1;
        }
        return opt;
    },
    select: function (id, className) {
        $$('.'+className).invoke('removeClassName', className);
        $(id).addClassName(className);
    },
    mark: function (e, className) {
        e[(e.hasClassName(className)?'remove':'add')+'ClassName'](className);
    },
    swap_dom_siblings: function (foo, bar) {
        var clone = $(foo).cloneNode(true);
        var el = $(bar);
        $(foo).replace($(bar).cloneNode(true));
        el.replace(clone);
    },
    fetch: function (url, callback, params, error_callback) {
        return new Ajax.Request(url + '?' + Math.random(), {
            method: 'post',
            parameters: (params?params.toQueryString():null),
            onComplete: function (time, callback, error_callback, req) {
                if (req.status == '200' && ((req.responseText.charAt(0) == "{") || (req.responseText.charAt(0) == "["))) {
                    var json = req.responseText.evalJSON() || {'json':{}};
                    callback(json.json);
                } else {
                    if (error_callback) {
                        error_callback();
                    }
                }
            }.curry((new Date).getTime(), callback, error_callback)
        });
    },
    slide: function (left, slided) {
        if ((!left && slided.getWidth() > slided.up().getWidth()) || (left && parseInt(slided.style.marginLeft) < 0)) {
            var shift = (parseInt(slided.style.marginLeft) || 0) + (left?320:-320);
            if (left && shift > 0) {
                shift = 0;
            } else if (!left && shift < (slided.up().getWidth() - slided.getWidth())) {
                shift = slided.up().getWidth() - slided.getWidth();
            }
            new Effect.Tween(slided, (parseInt(slided.style.marginLeft) || 0), shift, { duration: 0.3 }, function (p) {
                this.setStyle({ marginLeft: p + 'px' });
            });
        }
    },
    growl: function (text, ops) {
        var g = new k.Growler();
        g.growl(text, ops);
    }
}

var ImagePreloader = Class.create({
    counter: new Hash({'total': 0, 'size':0 ,'loaded':0, 'time':0}),
    already_loaded: new Hash({}),
    initialize: function (cnf) {
        this.IMAGE_URL_BASE = cnf.static_path;
        document.body.appendChild(new Element('div', {'id':'preloaded_images_container'}).setStyle({'position':'fixed', 'width':'1px', 'height':'1px', 'bottom':0, 'right':0}));
    },
    cache_images: function (list) {
        list.each(function (item) {
            this.cache_image(this.IMAGE_URL_BASE + item);
        }.bind(this));
    },
    cache_image: function (src) {
        if (!this.already_loaded.get(src)) { this.already_loaded.set(src,1) } else { return true }
        var pic = new Element('img',{'src':src});
        if(pic.readyState === 'complete') { return true; }
        $('preloaded_images_container').appendChild(pic);
        var id = pic.identify();
        Event.observe(id,'load',this.image_loaded.bindAsEventListener(this, id, src));
        Event.observe(id,'error',this.image_loaded.bindAsEventListener(this, id, src));
        this.counter.set('total', this.counter.get('total')+1);
        delete pic;
        return true;
    },
    image_loaded: function (e, id, src) {
        Event.stopObserving(id);
        Event.stopObserving(id);
        $(id).remove();
        this.counter.set('loaded', this.counter.get('loaded')+1);
        if (this.counter.get('loaded') ===  this.counter.get('total')) {
            this.already_loaded.keys().each(function (key) {
                this.already_loaded.unset(key);
            }.bind(this));
        }
    },
    IMAGE_URL_BASE:''
});

var MultipleSelect = Class.create({
    initialize: function (host, el) {
        this.parent = host;
        this.original_length = $A(el.options).select(
            function (s){
                return !(s.value.match(this));
            }.bind(new RegExp(","))
        ).length;
        this.fix_up_visual(el);
        if (this.original_length > 1) {
            el.next('span.comment').observe('click', this.dialog.bindAsEventListener(this));
        }
    },
    dialog: function (e) {
        var el = e.findElement('span.comment');
        var container = el.up('div.select.comment');
        var select = container.down('select');
        this._selected = [];
        select.getValue().split(new RegExp(",")).each(function (v) {
            this._selected[v] = 1;
        }.bind(this));
        select.hide();
        el.hide();
        select.options.length = this.original_length;
        var dialog = Builder.node('div', {'class':'multi_select_dialog container'},
            [
                Builder.node('div', {}, [
                    Builder.node('table', [
                        $A(select.options).select(
                            function (option) {
                                return !!(parseInt(option.value));
                            }
                        ).map(
                            function (option, index) {
                                return Builder.node('tr', {className:(!(index % 2)?'odd':'even')+(option.value in this._selected?' select':'')}, [
                                    Builder.node('td', [
                                        new Element('span').update(option.text)
                                    ]),
                                    Builder.node('td', [
                                        new Element('input', {'type':'checkbox', 'value': option.value, 'checked':(option.value in this._selected)})
                                    ])
                                ])
                            }.bind(this)
                        )
                    ])
                ]),
                new Element('input', {type:'button', 'value':I18N.ready})
            ]
        );
        dialog.hide();
        container.appendChild(dialog);
        dialog.down('input[type=button]').observe('click', this.select.bindAsEventListener(this));
        dialog.observe('click', this.mark.bindAsEventListener(this));
        dialog.appear({duration:0.2});
    },
    mark: function (e) {
        var el = e.findElement();
        if (el.tagName === 'INPUT' && el.type === 'checkbox') {
            el.up('tr')[!el.checked?'removeClassName':'addClassName']('select');
        }
    },
    select: function (e) {
        var container = e.findElement('div.select.comment');
        var select = container.down('select');
        var el = container.down('span.comment');
        var dialog = container.down('div.multi_select_dialog');
        this._selected = [];
        var counter = 0;
        var single_check;
        dialog.select('input[type=checkbox]').each(function (el) {
            if (el.checked) {
                this._selected[el.value] = 1;
                single_check = el.value;
                counter++;
            }
        }.bind(this));
        if (counter > 1) {
            this._value = [];
            this._text = [];
            $A(select.options).each(function (o) {
                if (o.value in this._selected) {
                    this._value.push(o.value);
                    this._text.push(o.text);
                }
            }.bind(this));
            var option = new Option(this._text.join(', '), this._value.join(','), true, true);
            select.options[select.options.length] = option;
            Cookie.set(select.name+'_m', Object.toJSON($H({'t':option.text, 'v':option.value}).toObject()), 2, '/');
        } else if (counter == 1) {
            $A(select.options).each(function (single_check, o) {
                if (single_check === o.value) {
                    o.selected = true;
                    throw $break;
                }
            }.bind(this, single_check));
        } else {
            select.selectedIndex = 0;
        }
        dialog.stopObserving().down('input[type=button]').stopObserving();
        dialog.remove();
        select.appear({duration:0.2});
        select.fire('my:change');
        this.fix_up_visual(select);
        el.appear({duration:0.2});
        this.parent.set_layout();
        e.stop();
        return false;
    },
    fix_up_visual: function (select) {
        select.setStyle({'width':'auto'});
        if (select.getWidth() > 200) {
            select.setStyle({'width':'200px'});
        }
    }
});

var ProgressBar = Class.create({
    initialize: function (id, cnf) {
        $(id).update().appendChild(new Element('span').setStyle({'display':'inline-block','height':$(id).getHeight() + 'px','position':'absolute'}));
        $(id).appendChild(new Element('span').setStyle({'display':'inline-block','height':$(id).getHeight() + 'px','width':'100%','position':'absolute','textAlign':'center'}));
        this.cnf = cnf;
        this.id = id;
    },
    set: function (k) {
        $(this.id).down().setStyle({
            'width':Math.ceil($(this.id).getWidth()*k) + 'px',
            'backgroundColor':'rgb('+ this.color(k, 0) +','+this.color(k, 1)+','+this.color(k, 2)+')',
            'height':$(this.id).getHeight() + 'px'
        });
        if (!this.pe) {
            $(this.id).down().next().update((Math.round(k * 100)) + '%');
        }
    },
    color: function (koef, i) {
        return Math.ceil(this.cnf.end_color[i] * koef + this.cnf.start_color[i] * (1 - koef));
    },
    process: function (cnf) {
        this.k = 0;
        this.direction = 1;
        $(this.id).down().next().update('...');
        this.pe = new PeriodicalExecuter(function () {
            this.set(this.k);
            this.k += this.direction * 0.1;
            if (this.k > 1) {
                this.k = 1;
                this.direction = -1;
            } else if (this.k < 0) {
                this.k = 0;
                this.direction = 1;
            }
            return true;
        }.bind(this), 0.1);
    },
    stop: function () {
        if (this.pe) {
            this.pe.stop();
            delete this.pe;
        }
        return this;
    },
    show: function () {
        $(this.id).removeClassName('hide');
    },
    hide: function () {
        $(this.id).addClassName('hide');
    }
});

var NanoViewer = Class.create({
    chars: ['n_', 'i_'],
    initialize: function (cnf) {
        var parent = $(document.body);
        if (cnf) {
            if ('chars' in cnf) {
                this.chars = cnf.chars;
            }
            if (cnf.parent) {
                parent = cnf.parent;
            }
        }
        parent.select('img.view').invoke('observe', 'click', this.view_image.bindAsEventListener(this));
    },
    view_image: function (e) {
        var wnd = new Control.Modal(null, {
            overlayOpacity: 0.6,
            fade: true,
            closeOnClick: true
        });
        wnd.container.insert(new Element('img', {'src':e.findElement().src.replace(new RegExp(this.chars[0]), this.chars[1])}));
        wnd.open();
    }
});

var ImageViewer = Class.create({
    simple: function (e) {
        $$('img.view').invoke('observe', 'click', this.view.bindAsEventListener(this));
    },
    view: function (e, el) {
        if (!('img_wnd' in this)) {
            this.init_wnd();
        }
        this.image_from = el || e.findElement();
        this.set();
        this.img_wnd.open();
        this.img_wnd.container.down('table').setStyle({
            width: document.viewport.getWidth() + 'px',
            height: document.viewport.getHeight() -20  + 'px'
        });
        e.stop();
    },
    over: function (e) {
        e.findElement().addClassName('over');
    },
    out: function (e) {
        e.findElement().removeClassName('over');
    },
    next: function (e) {
        if (this.image_from && this.image_from.next()) {
            this.image_from = this.image_from.next();
            this.set();
            e.stop();
        }
    },
    prev: function (e) {
        if (this.image_from && this.image_from.previous()) {
            this.image_from = this.image_from.previous();
            this.set();
            e.stop();
        }
    },
    set: function () {
        this.img_wnd.container.down('img').writeAttribute({src:this.image_from.src.replace(new RegExp("nh?_"), 'i_')}).observe('load', function () {
            this.position();
        }.bind(this.img_wnd)).next().update(this.image_from.title || this.image_from.alt);
    },
    init_wnd: function () {
        this.img_wnd = new Control.Modal(null, {
            overlayOpacity: 0.6,
            fade: true,
            closeOnClick: true,
            width: document.viewport.getWidth,
            className: 'clean b-image-view'
        });
        this.img_wnd.container.insert(
            Builder.node('table', [
                Builder.node('tbody', [
                    Builder.node('tr', [
                        Builder.node('td', {className:'left btn'}, [
                            new Element('a')
                        ]),
                        Builder.node('td', [
                            new Element('div',{className:'close'}),
                            Builder.node('div', {className:'img'}, [
                                new Element('img'),
                                new Element('div',{className:'caption'})
                            ])
                        ]),
                        Builder.node('td', {className:'right btn'}, [
                            new Element('a')
                        ])
                    ])
                ])
            ])
        );
        this.img_wnd.container.down('td.left').observe('click', this.prev.bindAsEventListener(this)).observe('mouseenter', this.over).observe('mouseleave', this.out);
        this.img_wnd.container.down('td.right').observe('click', this.next.bindAsEventListener(this)).observe('mouseenter', this.over).observe('mouseleave', this.out);;
        this.img_wnd.container.down('div.close').observe('click', function () { this.img_wnd.close() }.bind(this));
        /* there is subclasses of imageviewer - so be careful when change it */
    }
});

var VideoViewer = Class.create({ /* used in PostPage */
    simple: new RegExp("http\\://.*?(vimeo|youtube)\\.com", "i"),
    provides: [
        {type: 'youtube', re: new RegExp("http\\://.*youtube\\.com/.*\\?v=([A-Za-z0-9_-]+)", "i")},
        {type: 'vimeo', re: new RegExp("http\\://.*vimeo\\.com/.*?(\\d{5,})", "i")}
    ],
    view: function (url) {
        if (!('wnd' in this)) {
            this.init_wnd();
        }
        var choosen = this.match(url);
        return choosen ? this.watch(choosen[0], choosen[1]) : false;
    },
    match: function (url) {
        this.choosen = null;
        this.provides.each(function (url, v) {
            var result;
            if ((result = v.re.exec(url)) != null) {
                this.choosen = [v.type, result[1]];
                return;
            }
        }.bind(this, url));
        return this.choosen;
    },
    watch: function (type, url) {
        var vpath = this.vpath(type, url);
        if (vpath) {
            if (this.swf) { swfobject.removeSWF('video_viewer') };
            this.swf = swfobject.embedSWF(vpath+'&autoplay=1', 'video_viewer', "750", "520", "10", null, null, { allowfullscreen: "true", allowscriptaccess: "always", wmode: "transparent" });
            this.wnd.open();
            return true;
        }
        return false;
    },
    vpath: function (type, url) {
        switch (type) {
            case 'youtube':
                return 'http://www.youtube.com/v/' + url + '&fs=1&color1=0x006699&color2=0x54abd6';
            case 'vimeo':
                return 'http://vimeo.com/moogaloop.swf?clip_id=' + url + '&server=vimeo.com&show_title=1&show_byline=1&show_portrait=0&color=0x006699&fullscreen=1';
        }
    },
    init_wnd: function () {
        this.wnd = new Control.Modal(null, {
            overlayOpacity: 0.6,
            fade: true,
            closeOnClick: true,
            width: document.viewport.getWidth,
            className: 'clean b-video-view'
        });
        this.wnd.container.appendChild($('video_viewer').show());
        return true;
    }
});

var StatusUpdater = Class.create({
    initialize: function () {
        this.pe = new PeriodicalExecuter(this.ping.bind(this), 45);
    },
    ping: function (pe) {
        Utils.fetch('/api/ping', function (json) {
            if ('messages' in json) {
                $('new_inbox')[json.messages?'show':'hide']().down('p').update(json.messages || 0)
            }
        })
    }
});

// Some extension
Array.prototype.swap_elements = function (foo, bar) {
    var copy = new Object(this[foo]);
    this[foo] = new Object(this[bar]);
    this[bar] = copy;
};

