(function() {

var H = H || {};
H.consts = {};

var _ = function(arg) {
    try { 
        console.log.apply( console, arguments ); 
    } catch(e) { 
        try { 
            opera.postError.apply( opera, arguments ); 
        } catch(er){ 
            try {
                //debugbar
                console.log(arg); 
            } catch(er){
                //fail silently
            }
        } 
    } 
};

var initializing = false,
    fnTest = /xyz/.test(function(){xyz;}) ? /\b__super\b/ : /.*/,
    window = this,
    Class = function(){};

Class.extend = function(prop) {
    var __super = this.prototype;
    initializing = true;
    var proto = new this();
    initializing = false;
    for (var name in prop) { 
        proto[name] = typeof prop[name] == "function" && 
            typeof __super[name] == "function" && fnTest.test(prop[name]) ? 
        (function(name, fn){ 
            return function() { 
                var tmp = this.__super; 
                this.__super = __super[name]; 
                var ret = fn.apply(this, arguments);       
                this.__super = tmp; 
                return ret; 
            }; 
        })(name, prop[name]) : 
        prop[name]; 
    } 
    
    function Class() {
        if ( !initializing && this.__constructor ) {
            this.__constructor.apply(this, arguments);
        }
    }
    Class.prototype = proto;
    Class.constructor = Class;
    Class.extend = arguments.callee;
    return Class;
};

var Base = Class.extend({
    loop : function( elem, fn ) {
        var scope = this;
        if (typeof elem == 'number') {
            elem = new Array(elem);
        }
        jQuery.each(elem, function() {
            fn.call(scope, this);
        });
        return elem;
    },
    create : function( elem, className ) {
        if (!arguments.length) {
            return document.createElement('div');
        }
        if (arguments.length == 1) {
            className = arguments[0];
            elem = 'div';
        }
        var el = document.createElement(elem);
        el.className = className;
        return el;
    },
    getElements : function( selector ) {
        var elems = {};
        elems.length = 0;
        this.loop( jQuery(selector), function(elem) {
            Array.prototype.push.call( elems, elem );
        });
        return elems;
    },
    setStyle : function( elem, css ) {
        jQuery(elem).css(css);
        return elem;
    },
    disappear : function( elem ) {
        this.setStyle(elem, {
            position: 'absolute',
            left: '-10000px'
        });
    },
    appear : function( elem ) {
        this.setStyle(elem, {
            position: 'static',
            left: '0'
        }); 
    },
    mix : function( obj, ext ) {
        return jQuery.extend(obj, ext);
    },
    proxy : function( fn, scope ) {
        if ( typeof fn !== 'function' ) {
            return function() {};
        }
        scope = scope || this;
        return function() {
            return fn.apply( scope, Array.prototype.slice.call(arguments) );
        };
    },
    cloneNode : function( elem, bool ) {
        bool = bool || false;
        return jQuery(elem).clone(bool)[0];
    },
    listen : function( elem, type, fn ) {
        jQuery(elem).bind( type, fn );
    },
    forget : function( elem, type ) {
        jQuery(elem).unbind(type);
    },
    dispatch : function( elem, type ) {
        jQuery(elem).trigger(type);
    },
    jsonp : function( url, params, success ) {
        return jQuery.ajax({
            dataType: 'jsonp',
            data: params,
            method: 'get',
            url: url,
            success: this.proxy(success),
            error: function() {
                _(arguments);
            }
        });
    },
    wait : function(fn, callback, max) {
        fn = this.proxy(fn);
        callback = this.proxy(callback);
        max = max || 3000;
        var m = 0;
        window.setTimeout(function() {
            m += 1;
            if (fn() || m >= max) {
                callback();
                return false;
            }
            window.setTimeout(arguments.callee, 10);
        }, 10);
        return this;
    }
});

var Picture = Base.extend({
    
    __constructor : function() {
        this.image = new Image();
        this.elem = this.create('image');
        this.loaded = false;
        this.setStyle( this.elem, {
            overflow: 'hidden'
        } );
        this.elem.appendChild( this.image );
    },
    
    cache: {},
    
    load: function(src, callback) {
        callback = this.proxy( callback );
        //if ( this.cache[src] ) {
        //    var newImage = document.createElement("img");
        //    newImage.src = this.cache[src].src;
        //    this.image = newImage;
        //    this.elem.innerHTML = '';
        //    this.image.removeAttribute('width');
        //    this.image.removeAttribute('height');
        //    this.image.removeAttribute('style');
        //    jQuery(this.elem).html(this.image);
        //    callback( {target: this.image, scope: this} );
        //} else {
        this.image.src = src;
        this.cache[src] = this.image;
        //}
        if (this.loaded) {
            callback( {target: this.image, scope: this} );
            return this.image;
        }
        this.wait(function() {
            return (this.image.complete && this.image.width);
        }, function() {
            this.loaded = true;
            callback({ target: this.image, scope: this });
        });
        return this.image;
    },
    
    scale: function( width, height, crop ) {
        
        //upscale = upscale === false ? false : true;
        var iw = jQuery(this.image).width() || this.image.width,
            ih = jQuery(this.image).height() || this.image.width,
            ratio = Math[ (crop ? 'max' : 'min') ](width / iw, height / ih);
            
        this.setStyle(this.elem, {
            width: width,
            height: height,
            background:'#c83'
        });
        
        this.image.width = Math.ceil(iw * ratio);
        this.image.height = Math.ceil(ih * ratio);

        this.setStyle(this.image, {
            position : 'relative',
            top :  Math.round(this.image.height * -1 / 2 + (height / 2)),
            left : Math.round(this.image.width * -1 / 2 + (width / 2))
        });
    },
    
    clear: function() {
        this.image.src = '';
    }
});

var App = window.kvApp = Base.extend({
    __constructor: function(options) {

        // save title
        this.orig_title = document.title;
        
        // options
        this.options = this.mix({
            groups_per_page: 1,
            domain: 'http://happening.aino.se',
            url_list: '/list/',
            url_detail: '/detail/',
            occasions_limit: 5,
            loaderImage: '/media/i/loader.gif',
            username: null,
            lang: 'sv',
            group_by: 'month',
            group_label: '%F',
            group_next_label: '+ Nästa månad',
            source_category: '',
            category: ''
        }, options);
        
        this.groups = [];
        this.target = null;
        this.cities = [];
        this.lists = this.create('event-lists');
        this.filter = null;
        this.overlay = jQuery('<div id="kv-app-modal-overlay">').hide()[0];
        this.modalwindow = jQuery('<div id="kv-app-modal-window">').hide()[0];
        this.modalcontent = jQuery('<div id="kv-app-modal-content">').appendTo(this.modalwindow)[0];
        this.select = document.createElement("select");
        this.container = this.create();
        this.container.id = 'kv-app';
        this.form = this.create('event-filter-form');
        this.current = this.options.groups_per_page;
        this.loader = this.create('loader');
        this.loader.id = 'kv-app-loader';
        var i = new Image();
        i.src = this.options.domain + this.options.loaderImage;
        this.loader.appendChild(i);
        jQuery(this.loader).hide();
    },
    getForm: function() {
        
        var addOption = this.proxy(function(value, key) {
            key = key || value;
            var o = jQuery('<option>').attr('value', value).text(key);
            jQuery(this.select).append(o);
            //this.select.options.appendChild(o);
            //Array.prototype.push.call(this.select.options, o);
        });

        addOption('all','Alla områden');
        this.loop(this.groups, this.proxy(function(events){
            this.loop(events.events, this.proxy(function(item) {
                this.cities.push(item.venue.city);
            }));
        }));
        this.cities.sort().reverse();
            var i = this.cities.length,
            prev;
        while(i--) {
            if(this.cities[i] != prev) {
                addOption(this.cities[i]);
                prev = this.cities[i];
            }
        }
        var cnt = document.createElement('div');
        cnt.appendChild(this.select);
        return cnt;
    },
    run: function(selector) {
        var run = this.proxy(function() {
            
            document.body.appendChild(this.overlay);
            document.body.appendChild(this.modalwindow);
            document.body.appendChild(this.loader);
            
            this.target = this.getElements( selector )[0];
            if (!selector || !this.target) {
                _('ERROR: Selector "'+selector+'" not found.');
                return;
            }
            this.target.appendChild(this.container);
            this.container.appendChild(this.form);
            this.container.appendChild(this.lists);
        
            var params = {
                username: this.options.username,
                lang: this.options.lang,
                group_by: this.options.group_by,
                group_label: this.options.group_label,
                source_category: this.options.source_category,
                category: this.options.category
            }
        
            this.jsonp(this.options.domain + this.options.url_list, params, function(data) {
            
                // put groups in this.groups
                this.groups = Array.prototype.slice.call(data.groups);
                H.consts.months = Array.prototype.slice.call(data.months);
                H.consts.weekdays = Array.prototype.slice.call(data.weekdays);
                
                // check for hash
                var current = window.location.hash.replace(/^#\//,'');
                var showing = false;
                
                if (current.length) {
                    this.loop(this.groups, function(item) {
                        this.loop(item.events, function(single) {
                            if(single['event'].id == current && !showing) {
                                this.showEvent(current);
                                showing = true;
                            }
                        });
                    });
                }
                
                // create pluslink
                var anchor = document.createElement('a');
                anchor.href = '#';
                anchor.className = 'morelink';
                this.container.appendChild(anchor);
                var height = 0;
                var update = this.proxy(function(items) {
                    if (!items) {
                        return;
                    }
                    var list = this.buildList( items );
                    this.lists.appendChild( list );
                    if (this.groups[this.current+1]) {
                        anchor.innerHTML = this.options.group_next_label;
                    } else {
                        anchor.innerHTML = 'Inga fler poster.';
                        this.forget(anchor, 'click');
                        anchor.removeAttribute('href');
                    }
                });
                for (var i=0; i < this.current; i++) {
                    update(this.groups[i]);
                }
                
                this.form.appendChild(this.getForm());
                this.listen(anchor, 'click', this.proxy(function(e) {
                    e.preventDefault();
                    this.current++;
                    update(this.groups[this.current-1]);
                }));
                
                // create city dropdown
                
                this.listen(this.select, 'change', this.proxy(function(e) {
                    this.filter = e.target.options[e.target.selectedIndex].value;
                    if (this.filter == 'all') {
                        this.filter = false;
                    }
                    this.current = this.options.groups_per_page;
                    this.lists.innerHTML = '';
                    for (var i=0; i < this.current; i++) {
                        update(this.groups[i]);
                    }
                }));
            });
        });
        if (document.expando) { // if IE
            jQuery(run);
        } else {
            run();
        }
    },
    // builds the actual list
    buildList: function( group ) {

        var list = this.create('event-list');
        var title = document.createElement('h2');
        title.innerHTML = group.label;
        list.appendChild(title);
        
        // loop the events
        this.loop( group.events, function(item) {
            //_(item)
            // check for city filter
            if (!this.filter || this.filter == item.venue.city) {
                var block = this.create('event');
                var body = this.create('body');
                var image = this.create('photo');
                
                if (item['event'].image != undefined) {
                    var img = new Picture();
                
                    jQuery(img.image).show();
                    //this.disappear( img.image );
                    image.appendChild(img.elem);
                    
                    img.load( this.options.domain + item['event'].image, function(e) {
                        
                        jQuery(e.target).show()
                        //this.appear( e.target );
                        //e.scope.scale(100,100,true);
                    });
                }

                var h3 = document.createElement('h3');
                var title = document.createElement('a');
                title.href = '#/'+item['event'].id;
                title.innerHTML = item['event'].title;
                this.listen(title, 'click', this.proxy(function(e) {
                    e.preventDefault();
                    this.showEvent(item['event'].id);
                }));
                
                h3.appendChild(title);

                // date & time formatting
                var formatDate = function(dt) {
                    var d = dt.split('-').splice(1, 2);
                    return d[1] + ' ' + H.consts.months[ parseInt(d[0], 10) -1 ];
                }
                var formatTime = function(t) {
                    return ' kl. ' + t.split(':').splice(0, 2).join(':');
                }
                var formatWhen = function(when) {
                    s = formatDate(when.start_date);
                    if (when.start_time) {
                        s += formatTime(when.start_time);
                    }
                    return s;
                };

                var bodystring = '<p class="desc">' + item['event'].short_description + '</p>' +
                    '<div class="meta">';
                    // control when
                    var dtstart = formatDate(item['event'].first_date.split(' ')[0]);
                    var dtend = formatDate(item['event'].last_date.split(' ')[0]);
                    if (dtstart != dtend) {
                        bodystring += '<span class="time">' + dtstart + ' - '  + dtend + '</span>';
                    } else {
                        bodystring += '<span class="time">' + formatWhen(item.when) + '</span>';
                    }
                    bodystring += '<span class="venue">' + item.venue.title + ', ' + item.venue.city + '</span>' +
                    '</div>';
                    
                body.innerHTML = bodystring;
                body.insertBefore(h3, body.firstChild);

                block.appendChild(image);
                block.appendChild(body);
            
                list.appendChild(block);
            }
        });
        
        return list;
    },
    showEvent: function(id) {
        
        if (typeof document.body.style.maxHeight === "undefined") { //if IE 6
        	jQuery("select").hide();
        }
        
        this.setStyle(this.overlay, { display: 'block' });
        this.setStyle(this.loader, { display: 'block' });
        
        var close = jQuery('<a href="#">Stäng</a>').addClass('close').bind('click', this.proxy(function(e) {
            e.preventDefault();
            this.hideEvent();
        })).appendTo(this.modalcontent);
        
        this.listen(document, 'keyup', function(e) {
            var key = e.keyCode || e.which;
            if (key == 27) {
                close.trigger('click');
            }
        });
        this.listen( this.overlay, 'click', function(e) {
            close.trigger('click');
        });
        
        this.displayEvent(id);
    },
    displayEvent: function(id) {
        this.jsonp(this.options.domain + this.options.url_detail + id + '/', {}, function(data) {
            window.location.hash = '/' + id;
            document.title = data.item['event'].title;
            this.buildEvent( data.item );
        });
    },
    hideEvent: function() {
        
        if (typeof document.body.style.maxHeight === "undefined") { //if IE 6
        	jQuery("select").show();
        }
        
        this.forget(document, 'keyup');
        this.forget(this.overlay, 'click');
        this.modalcontent.innerHTML = '';
        this.setStyle(this.overlay, { display: 'none' });
        this.setStyle(this.modalwindow, { display: 'none' });
        this.setStyle(this.loader, { display: 'none' });
        window.location.hash = '#/';
        document.title = this.orig_title;
    },
    buildEvent: function(item) {
        if (!item) {
            return;
        }
        var parseTime = function(time) {
            return time ? time.replace(/^([0-9:]{5}).*/,' kl.$1') : '';
        };
        var ul = document.createElement('ul');
        ul.className = 'event-dates';
        var index = 0;
        this.loop( item.when, this.proxy(function(ev) {
            var li = document.createElement('li');
            var ical = jQuery('<a class="ical" title="Ladda hem ical-fil för detta evenemang">iCal</a>').attr("href", this.options.domain + "/cal/" + ev.id + "/");
            li.innerHTML = ev.start_date + parseTime(ev.start_time);
            jQuery(li).append(ical);
            ul.appendChild(li);
            index++;
            if (index > this.options.occasions_limit) {
                this.setStyle( li, {
                    display: 'none'
                });
            }
        }));
        
        var anchor;
        if (item.when.length > this.options.occasions_limit) {
            anchor = jQuery('<a>').bind('click', function(e) {
                e.preventDefault();
                jQuery(ul).children('li:hidden').each(function(i, el) {
                    if (i > 5) { return false; }
                    jQuery(el).show();
                });
            }).attr('href','#').text('+ fler tillfällen').addClass('innermore');
        }
        
        var _event = item['event'];
        
        var desc = '<p><strong class="preamble">' + item['event'].short_description + '</strong></p>';
        desc += item['event'].description_html;

        var img;
        var src = item.images[1] || item.images[0] || null;
        if (src) {
            img = new Picture();
            img.load(this.options.domain + src, this.proxy(function() {
                this.setStyle(this.modalwindow, {
                    display: 'block',
                    top: jQuery(document).scrollTop() + 50
                });
            }));
        } else {
            this.setStyle(this.modalwindow, {
                display: 'block',
                top: jQuery(document).scrollTop() + 50
            });
        }
        this.setStyle(this.loader,{display:'none'});
        var body = jQuery('<div class="modal-body-col">');
        if (img) {
            body.append(img.elem);
        }
        body.append('<h2>' + item['event'].title + '</h2>' + desc);
        var sidebar = jQuery('<div class="modal-sidebar-col">');
        
        var content = {};
        var titles = {
            notes: 'Info',
            cost: 'Pris',
            open: 'Öppettider',
            conference: 'Konferens'
        };
        for (var i in titles) {
            var tar = item['event'][i] || (item['event'].extra && item['event'].extra[i]);
            if (tar) {
                sidebar.append('<h3>' + titles[i].toString() + '</h3><p>' + tar + '</p>');
            }
        }
        sidebar.append('<h3>Tillfällen</h3>');
        sidebar.append(ul);
        sidebar.append(anchor);
        
        var address = '<h3>Spelplats</h3><p>';
        if (item.venue.title) {
            address+='<strong>'+item.venue.title+'</strong><br>';
        }
        if (item.venue.address) {
            address+=item.venue.address+'<br>';
        }
        if (item.venue.city || item.venue.zip_code) {
            address+=item.venue.zip_code + ' ' + item.venue.city;
        }
        address+='</p>';
        if (item.venue.lon && item.venue.lat) {
            address+='<p><a href="http://maps.google.se/maps?q='+item.venue.lat+','+item.venue.lon+'" target="_blank">Karta</a></p>';
        }
        
        var directions = '';
        
        if(item['event'].extra) {
            if (item['event'].extra.directions) {
                directions = '<h3>Vägbeskrivning</h3><p>'+item['event'].extra.directions+'</p>';
            }
        }
        
        var contact = '<h3>Kontaktinformation</h3><p>';
        
        if (item['event'].phone) {
            contact+='<strong>Tel:</strong> '+item['event'].phone+'<br>';
        }
        if (item['event'].email) {
            contact+='<strong>Email:</strong> '+item['event'].email+'<br>';
        }
        if (item['event'].website) {
            var link = item['event'].website.match(/http:\/\//) ? item['event'].website : 'http://'+item['event'].website;
            contact+='<a href="'+link+'" target="_blank">'+item['event'].website+'</a><br>';
        }
        contact+='</p>';
        
        if (typeof(_gat) == 'object')
        { 
        var pageTracker = _gat._getTracker('UA-11912618-3');
        pageTracker._trackPageview('/events/'+item['event'].id+ '/'+document.title);
        }
        
        sharer = '<h3>Dela</h3><p class="addthis_toolbox addthis_default_style">'+
        '<a class="addthis_button_facebook"></a>'+
        '<a class="addthis_button_email"></a>'+
        '<a class="addthis_button_favorites"></a>'+
        '<a class="addthis_button_print"></a>'+
        '<span class="addthis_separator">|</span>'+
        '<a href="http://www.addthis.com/bookmark.php?v=250&amp;username=xa-4b7e98d12d239010" class="addthis_button_expanded">Mer</a>'+
        '</p>';
     
        sidebar.append(address + directions + contact + sharer);
        jQuery(this.modalcontent).append(body);
        jQuery(this.modalcontent).append(sidebar);
        addthis.toolbox('.addthis_toolbox');

    }
});

jQuery.fn.kvApp = function(options) {
    return this.each(function() {
        var app = new kvApp(options);
        app.run(this);
    });
};

})();
