/*
 * General functions and classes for toostis UI
 * 
 * TODO: cleanup, compress
 */

/* 
 * textCounter is used for limiting textarea fields
 * parameters: text field, the count field (can be omitted), max length
 * the number of left character is printed in count field (if any)
 */
function textCounter(field, countfield, maxlimit) {
    if (field.value.length > maxlimit)
        field.value = field.value.substring(0, maxlimit);
    else if (countfield)
        countfield.value = maxlimit - field.value.length;
}

/*
 * getElementById shortcut, should be used instead of everywhere creating a new jQuery object
 */
function gId(element_id) {
    return document.getElementById(element_id);
}

// Detect the browser version (currently detects IE)
function is_ie() {
    var ua = navigator.userAgent.toLowerCase();

    // Browser version
    var is_ie = ((ua.indexOf("msie") != -1) && (ua.indexOf("opera") == -1));

    return is_ie;
}

/*
 * Utility functions
 */

// Bind
function bind(f, context) {
    // Binds function to a context
    return function () {
        return f.apply(context, arguments);
    }
}

// Content dimensions including the area
//  where user can scroll.
function content_area() {
    var horizontal, vertical;
    if (window.innerHeight && window.scrollMaxY) {
        horizontal = document.body.scrollWidth;
        vertical = window.innerHeight + window.scrollMaxY;
    } else if (document.body.scrollHeight > document.body.offsetHeight){ 
        horizontal = document.body.scrollWidth;
        vertical = document.body.scrollHeight;
    } else { 
        horizontal = document.body.offsetWidth;
        vertical = document.body.offsetHeight;
    }
    return new Array(horizontal, vertical);
}

// Currently visible content area.
function visible_area() {
    var width, height;
    if (self.innerHeight) { // Mozilla and friends
        width = self.innerWidth;
        height = self.innerHeight;
    } else if (document.documentElement && document.documentElement.clientHeight) { // Explorer
        width = document.documentElement.clientWidth;
        height = document.documentElement.clientHeight;
    } else if (document.body) { // Other Explorers
        width = document.body.clientWidth;
        height = document.body.clientHeight;
    } 
    return new Array(width, height); 
}

// Position where user window is scrolled.
function scrolled_position() {
    var vertical = 0;
    if (self.pageYOffset) { // Mozilla and friends
        vertical = self.pageYOffset;
    } else if (document.documentElement && document.documentElement.scrollTop) {
        vertical = document.documentElement.scrollTop;
    } else if (document.body) { // Explorer
        vertical = document.body.scrollTop;
    }
    return new Array(0, vertical);
}

// Display an overlay
function show_overlay(name) {
    if ($('#overlay').is(':hidden')) {
        if (name) {
            $('#overlay-content').attr('class', name);
        }
        gId('overlay-background').style.height = content_area()[1] + "px";
        $('#overlay').show();
    }
    // Set top margin in any case
    gId('overlay-content').style.top = scrolled_position()[1] + 
                                              (visible_area()[1] - $('#overlay-content').height()) / 2 + "px";
    // Allow it to receive keystrokes
    $('#overlay-content').focus();
}

// Hide the overlay
function hide_overlay() {
    $('#overlay').hide();
    $('#overlay-content').blur();
    $('#overlay-content').innerHTML = '';
}

/*
 * Dropdown class
 * 
 * Represents a general dropdown list of items: select box,
 * autosuggest etc.
 *
 * Box - dom element for storing dropdown elements. Should
 * have .dropdown class set.
 * Box contains list in form <ul> <li>1</li> ... </ul>,
 * which represents the elements in dropdown list.
 *
 * .select(item) method is called when some item is selected.
 * It should be overriden for each instance. Should return false.
 *
 * Note: uses jquery selectors.
 *
 */
var Dropdown = function(box) {
    // Properties
    this.box = box;
    this.marked = null;

    // Event bindings
    $(this.box).bind('keypress', {context: this}, this.keypress);
    $(this.box).find('li').bind('mouseover', {context: this}, this.mouseover);
    $(this.box).find('li').bind('click', {context: this}, this.click)
    $('body').bind('click', {context: this}, this.declick);
}
Dropdown.prototype = {
    loadContent: function(html) {
        this.box.innerHTML = html;
        if ($(this.box).find('li').length > 0) {
            $(this.box).show();
            $(this.box).find('li').bind('mouseover', {context: this}, this.mouseover);
            $(this.box).find('li').bind('click', {context: this}, this.click)
        } else {
            $(this.box).hide();
        }
    },
    mark: function(item) {
        $(this.box).find('li').removeClass('marked');
        this.marked = item; 
        $(this.marked).addClass('marked');
    },
    _select: function() {
        // Internal select method which calls user-modified select()
        this.select(this.marked);
        this.close();
    },
    select: function(item) {
        // Should be implemented separately for each instance
    },
    open: function() {
        // Only if list is not empty
        if ($(this.box).find('li').length > 0) {
            // Hide all before showing
            $('.dropdown').hide();
            $(this.box).show();
        }
    },
    close: function() {
        this.mark(null);
        $(this.box).hide();
    },
    toggle: function() {
        if ($(this.box).is(':visible')) {
            this.close();
        } else {
            this.open();
        }
    },
    click: function(event) {
        event.data.context._select();
    },
    declick: function(event) {
        event.data.context.close();
    },
    mouseover: function(event) {
        var context = event.data.context;
        context.mark($(event.target).closest('li')[0]);
    },
    keypress: function(event) {
        var context = event.data.context; 
        if (event.keyCode == 38 || event.keyCode == 40) {
            if (event.keyCode == 40) {  // Down arrow
                context.open();
                var next = $(context.marked).next()[0];
                var first = $(context.box).find('li')[0];
            } else if (event.keyCode == 38) {  // Up arrow
                var next = $(context.marked).prev()[0];
                var first = $(context.box).find('li:last')[0];
            }
            if (next && context.marked) {
                context.mark(next);
            } else {
                context.mark(first);
            }
            return false;
        } else if (event.keyCode == 13) {  // Enter key
            // Stop propagation if dropdown is active
            if (context.marked) {
                context._select();
                // Imitate stopImmediatePropagation for this event
                event.cancel = true;
                return false;
            }
        } else if (event.keyCode == 9) {  // Tab key
            context.close();
        }
    }
}

/*
 * Static class for managing concealable labels.
 */
var Concealable = function () {};
Concealable.prototype = {
    toggle_label: function(e) {
        value = $(this).val();
        if (value) {
            $(e.data.label).hide();
        } else {
            $(e.data.label).show();
        }
    },
    enable: function() {
        $('label.concealable').each(function(i, el) {
            var input = $('#' + $(el).attr('for'));
            input.bind('input keyup keydown focus blur click', {label: el}, Concealable.prototype.toggle_label);
            input.keyup();
        });
    }
}

$(document).bind('ready', function() {
    /*
     * Scripts for select-box dropdown widgets
     */
    enable_selectboxes();

    /*
     * For all dropdown widgets
     */
    $('.dropdown').click(function(event) {
        event.stopPropagation();
    });
    $('body').click(function() {
        // Declick
        $('.dropdown, .popup').hide();
    });

    /*
     * For dark overlay
     */
    $('#overlay-background').bind('click', hide_overlay);
    $('#overlay-content').keypress(function(e) {
        // If slideshow is open, navigate with keys
        if ($('#overlay-content').hasClass('slideshow')) {
            if (e.keyCode == 37 ||
                e.keyCode == 8) {
                var prev = $('#slideshow-prev-url').val();
                $('#overlay-content').load(prev);
            } else if (e.keyCode == 39 ||
                       e.charCode == 32) {
                var next = $('#slideshow-next-url').val();
                $('#overlay-content').load(next);
            }
        }
    });

    /*
     * For concealable input labels
     */
    Concealable.prototype.enable();

    /*
     * For timeline
     */
    if ($('#timeline').length > 0) {
        var url = '/util/get_timeline/';

        // Load jquery-ui for displaying a datepicker
        $.getScript('/jslib/jquery-ui.js', function() {
            // Activate datepicker
            var cal_properties = {
                dateFormat: 'yy-mm-dd',
                onSelect: function(date_str, inst) {
                    $('#timeline').load(url + date_str, function() {
                        $('#timeline .calendar').datepicker(cal_properties);
                    });
                }
            }

            // Datepicker button
            $('.calendar-button').live('click', function(e) {
                $('#timeline .calendar').datepicker(cal_properties);
                $('#timeline .calendar').click(function(e){e.stopPropagation()});
                $('#timeline .calendar').toggle();
                e.stopPropagation();
                return false;
            });

        });

        $('#timeline').bind('mouseleave click', function(e){
            $('#timeline .rollover').hide();
        })
    }

    /*
     * Refresh feed every 3 minutes
     */
    if ($('#box-feed').length) {
        setInterval(function() { $('#box-feed').load('/util/get_feed'); }, 180000);
    }

    /*
     * Invitation box
     */
    $('#invite-input').live('keydown',function(event) {
        if (event.keyCode == 13 && !event.cancel) {
            // The same as clicking "Invite" button
            // For event.cancel hack see Dropdown.keypressed
            $('#invite-button').click();
        }
        // Resize
        per_row = 15;
        event.target.rows = $(event.target).val().length / per_row;
    });

    /*
     * Esc key pressed
     */
    $(document).bind('keypress', function(e) {
        if (e.keyCode == 27) {
            hide_overlay(); 
        }
    });
});

/*
 * Autosuggest
 *
 * id_input -- input element
 * id_box   -- box for suggestions
 * list     -- whether input contains a list of items
 */
function enable_autosuggest(id_input, id_box, url, is_list) {
    var is_list = is_list;
    var url = url;
    var d = new Dropdown(gId(id_box));

    // Unbind keypress from the box (bound by Dropdown)
    $('#' + id_box).unbind('keypress', {context: d}, d.keypress);
    // Rebind it to input field
    $('#' + id_input).bind('keydown', {context: d}, d.keypress);

    // List
    if (is_list === undefined) {
        is_list = false;
    }

    d.select = function(item) {
        if ($(item).find('.value').length > 0) {
            item = $(item).find('.value')[0];
        }
        // Append new item in a comma-separated list
        input_field = $('#' + id_input);
        input_value = input_field.val().split(',')
        input_value.pop();
        if (input_value.length > 0) {
            input_value.push(' ' + item.innerHTML);
        } else {
            input_value.push(item.innerHTML);
        }
        if (is_list) {
            input_value.push(' ');
        }
        input_value = input_value.join(',');
        input_field.val(input_value);
    }

    ev_input = 'input';
    if (is_ie()) {
        // IE does not support 'input' event
        ev_input = 'keyup'
    }
    $('#' + id_input).bind(ev_input, function(event){
        if (event.keyCode < 48) {
            // IE hack - not to disturb arrow keys
            // Since IE is on keyup, it reloads the content
            // and thus removes marking
            return;
        }
        if (is_list) {
            name = event.target.value.split(',').pop()
        } else {
            name = event.target.value;
        }
        if (event.target.value != "") {
            $.ajax({
                url: url,
                data: {name: name},
                success: function (html) {
                    d.loadContent(html);
                }
            });
        } else {
            d.close();
        }
    });
}

/*
 * Enable tinyMCE editor
 *
 * ids -- array of textarea element ids
 */
function enable_tinymce(ids) {
    ids_string = ids.join(',');
    tinyMCE.init({
        strict_loading_mode: 1,
        mode: "exact",
        elements: ids_string,
        theme: "simple",
        height: "140",
        skin: "newt",
        init_instance_callback: function(ed) {
            // This hack is for styling
            // Actually there are two textareas: one for degradation (with simulated padding)
            // and other for tinyMCE (without simulated padding)
            $('textarea[name=' + ed.id + ']').hide();
            $('#' + ed.id + '_container').show();
            $('textarea[name=' + ed.id + ']').attr('name', '');
            $('textarea[id=' + ed.id + ']').attr('name', ed.id);

            // For concealable labels
            var label = $('label[for=' + ed.id + '-input]');
            function toggle_label(ed, l) {
                if (ed.getContent()) { $(label).hide(); }
                else { $(label).show(); }
            }
            ed.onKeyUp.add(toggle_label);
        }
    });
}

/*
 * Make decorated select boxes functional
 */
function enable_selectboxes() {
    $('.select-box').each(function(index, element) {
        var element = element;
        var d = new Dropdown($(element).find('.dropdown')[0]);
        $(element).find('.current').bind('keydown', {context: d}, d.keypress);
        $(element).find('.current').bind('click', function(event) {
            d.toggle();
            event.stopPropagation();
        });
        d.select = function(item) {
            $(element).find('.current span').text($(item).find('.title').text());
            $(element).find('select').val($(item).find('.value').text());
        }
    });
}

/* Special serializing function for using post over ajax load method */
jQuery.fn.extend({
    toObject: function () {
        var param_object = {};
		var param_array = this.map(function(){
			return this.elements ? jQuery.makeArray(this.elements) : this;
		})
		.filter(function(){
			return this.name && !this.disabled &&
				(this.checked || /select|textarea/i.test(this.nodeName) ||
					/text|hidden|password|search/i.test(this.type));
		});
        $.each(param_array, function(i, elem) {
            var val = jQuery(this).val();
            if (val != null) {
                param_object[elem.name] = val;
            }
        });
        return param_object;
    }
})

/*
 * Process data received after submiting a link to video
 */
function process_video_upload(response) {
    if (response.status == 'ok') {
        $('.media').html(response.html);
    } else {
        $('#video-upload-form .field').addClass('error');
        $('#video-upload-form .field').removeClass('no-error');
        $('#video-upload-form .field .notice span').text(response.message);
    }
}

/*
 * Load css file
 */
function load_style(color) {
    css_path = '/css/' + color + '.css';
    $('<link rel="stylesheet" type="text/css" href="' + css_path + '" >')
       .appendTo("head");
    
    $.get('/util/set_theme/' + color);
}

/*
 * Timeline rollover management
 */
function show_timeline_rollover(id) {
    $('#timeline .rollover').hide();
    $('#tl-rollover-' + id).show();
}
