
/*
 * StringBuffer: Constructor
 */
function StringBuffer() {
    this.buffer = [];
}

/*
 * StringBuffer: Returns the result string created using the buffer
 */
StringBuffer.prototype.toString = function toString() {
   return this.buffer.join('');
};

/*
 * StringBuffer: Append a string to the end of the buffer
 */
StringBuffer.prototype.append = function append(string) {
   this.buffer.push(string);
   return this;
};

/*
 * Init function. Called before any content is rendered, so we can hide the
 * textual header elements (h1 and h2) and avoid flickering.
 */
function init() {
    $$('h1 span')[0].className = 'accesible_hide';
    var h2_spans = $$('h2 span');

    for (var i=0; i < h2_spans.length; i++) {
        var span = h2_spans[i];
        span.className = 'accesible_hide';
    }
}

/*
 * Header images
 */
var header_images = {
    /*
     * Font server config
     */
    _font_server : {
        host : urls.imagesServerTextURL,
        text_param : 'texto',
        size_param : 'tamano',
        color_param : 'color',
        background_param : 'fondo'
    },

    /*
     * Replacement script
     */
    do_replacement : function(h) {
      var text = h.innerHTML.stripTags().toLowerCase();

      // Ensure R is in uppercase
      text = text.gsub(/^r\s/, 'R ').gsub(/\sr$/, ' R').gsub(/\sr\s/, ' R ')
      var img = document.createElement('img');

      if (h.title) {
        img.alt = img.title = h.title;
      } else {
        img.alt = img.title = text;
      }

      var src = new StringBuffer();

      src.append(this._font_server.host);
      src.append('?');
      src.append(this._font_server.text_param);
      src.append('=');
      src.append(text);
      if (h.style.fontSize) {
        src.append('&');
        src.append(this._font_server.size_param);
        src.append('=');
        src.append(h.style.fontSize.replace('px',''));
      }

      if (h.style.color) {
        src.append('&');
        src.append(this._font_server.color_param);
        src.append('=');
        var color = this._format_color(h.style.color);
        src.append(color);
      }

      if (h.style.backgroundColor) {
        src.append('&');
        src.append(this._font_server.background_param);
        src.append('=');
        var color = this._format_color(h.style.backgroundColor);
        src.append(color);
      }

      img.src = src.toString();
      h.innerHTML = '';
      h.appendChild(img);
    },

    /*
     * Color formatting
     */
    _format_color: function(c) {
        if (/#.*/) {
            return c.gsub('#', '%23');
        } else {
            return c;
        }
    }

};

/*
 * Button images
 */
var button_images = {
	/*
     * Button server config
     */
    _button_server : {
        host : urls.imagesServerButtonURL,
        text_param : 'texto',
        type_param : 'tipo'
    },

	/*
	 * Return the src for a image button with the specified +text+ and +type+
	 */
	get_image_src: function(text, type) {
		if (!type) {
			type = 1; //default to type 1
		}
		var sb = new StringBuffer();
		sb.append(this._button_server.host);
		sb.append("?");
		sb.append(this._button_server.text_param);
		sb.append("=");
		sb.append(text);
		sb.append("&");
		sb.append(this._button_server.type_param);
		sb.append("=");
		sb.append(type);

		return sb.toString();
	},

	/*
	 * Return the html for a image button with the specified +text+ and +type+
	 */
	get_image_tag: function(text, type) {
		var sb = new StringBuffer();
        sb.append("<img src='");
        sb.append(this.get_image_src(text, type));
        sb.append("' alt='");
        sb.append(text);
        sb.append("' />");

        return sb.toString();
	}
};

/*
 * Popup handling: wrpas the multimediaPopUp functionallity
 */
var popups = {

    /*
     * Multimedia Pop Up
     */
    _popup_options : {
      width : 760,
      height : 0
    },

    /*
     * Setups a link that needs a popup to be opened
     */
    setup : function(a) {
      Event.observe(a, 'click',
          this._click_event_handler.bindAsEventListener(a));
    },

    /*
     * Click event handler. Using the original URL of the link opens a
     * multimediaPopUp adding a "layout=false" param to the request to
     * allow the server side to send the ready-for-popup version of the
     * page
     */
    _click_event_handler : function(ev) {
      Event.stop(ev);

      var src = new StringBuffer();
      src.append(this.href);
      src.append(this.href.indexOf('?') == -1 ? '?' : '&' );
      src.append("layout=false");

      abrirPopUpMultimedia(popups._popup_options.width,
          popups._popup_options.height ,'iframe', src.toString());
    }
};

/*
 * Schedule management
 */
var schedule = {
    _channel_lis_cache: [],
    _genre_lis_cache: [],

    /*
     * A reference to the currently selected time slot (<li> element)
     */
    selected_time_slot: null,

    /*
     * Get the time slot param from the currently selected time slot
     */
    selected_time_slot_to_query_param: function() {
        if (schedule.selected_time_slot != null) {
            var url = schedule.selected_time_slot.firstChild.href;
            return url.match(/time_slot=(\d*)/)[0];
        } else {
            return '';
        }
    },

    /*
     * Cache list items and count channels per genre
     */
    _init_lis_caches: function() {
        var channels_select = $('channels_select');
        schedule._genre_lis_cache = channels_select.getElementsBySelector('li.genre_channels');

        for (var i = 0; i < schedule._genre_lis_cache.length; i++) {
            var li = schedule._genre_lis_cache[i];
            var channel_lis = li.getElementsBySelector('li');

            li.channels_count = channel_lis.length;
            li.visible_channels_count = channel_lis.length;

            for (var j=0; j < channel_lis.length; j++) {
                var channel_li = channel_lis[j];
                channel_li.genre_li = li;
                schedule._channel_lis_cache.push(channel_li);

                // Add check observer to highlight the li
                var cb = channel_li.childNodes[0].childNodes[1];
                schedule._set_channel_checked_state(cb);
                // OMG! Blur on focus for IE7 pleasure only
                Event.observe(cb, 'click', (function(){this.blur()}).bind(cb));
                Event.observe(cb, 'change', schedule._checkbox_change_event_handler.bind(cb));
            }
        }
    },

    /*
     * Checkbox change event listener
     */
    _checkbox_change_event_handler: function() {
        schedule._set_channel_checked_state(this);
    },

    _set_channel_checked_state: function(cb) {
        if (cb.checked) {
            Element.addClassName(cb.parentNode.parentNode, 'checked');
        } else {
            Element.removeClassName(cb.parentNode.parentNode, 'checked');
        }
    },

    /*
     * Create the 'clear filter' link
     */
    _create_clear_filter_link: function() {
        var form = $('channels_select_filter');
        var sb = new StringBuffer();
        sb.append("&nbsp;<a id='clear_filter_link' href='#'>");
        sb.append(button_images.get_image_tag(js_messages.clear_filter, 2));
        sb.append("</a>");

		var link_html = sb.toString();
        new Insertion.Bottom(form, link_html);
        var link = $('clear_filter_link');
        Event.observe(link, 'click', schedule.clear_filter.bindAsEventListener());
    },

    /*
     * Clear the filter
     */
    clear_filter: function(ev) {
        Event.stop(ev);
        $('channels_filter_text').value = '';
        schedule._show_all_genres();
        schedule._update_genres_count_and_visibility();
    },

    /*
     * Initialize the schedule filter
     */
    init_channels_filter: function() {
        schedule._init_lis_caches();
        schedule._create_clear_filter_link();
    },

    /*
     * Handle the event genre selection change
     */
    selected_genre_change_event_handler: function(ev) {
        Event.stop(ev);

        schedule._highlight_events_by_selected_genre(this);
    },

    /*
     * Highlight events in the schedule when their genre matches the one
     * selected by the user. +select+ is the html <select> element containing
     * the currently selected event genre
     */
    _highlight_events_by_selected_genre: function(select) {
        var selected_genre_id = select.options[select.selectedIndex].value;
        if (selected_genre_id == '') {
            selected_genre_id = 'no_genre'
        }
        var selected_class_name = 'event_genre_' + selected_genre_id;
		var regexp_string = selected_class_name + '\\s+|' + selected_class_name + '$';
		var r = new RegExp(regexp_string);
        $$('.event').each(
            function(it) {
                if (r.match(it.className))  {
                    it.addClassName('event_hl');
                } else {
                    it.removeClassName('event_hl');
                }
            }
        );
    },

    /*
     * Show or hide channels in the channel listing
     */
    toggle_channels: function(ev) {
        Element.toggle(this.list);
        this.list_visible = !this.list_visible;
        this.innerHTML = this.list_visible ? js_messages.hide : js_messages.show;
        Event.stop(ev);
    },

    /*
     * Filter the channels in the list by name
     */
    filter_channels: function(ev) {
        Event.stop(ev);

        var name = $('channels_filter_text').value.strip();

        schedule._reset_visible_channels_count();

        var show_channels = true;
        if (name.length == 0) {
            schedule._show_all_genres();
            show_channels = false;
        } else {
            schedule._filter_channels_by(name);
        }

        schedule._update_genres_count_and_visibility(show_channels);
    },

    /*
     * Reset values for visible channels count
     */
    _reset_visible_channels_count: function() {
        var genre_lis = schedule._genre_lis_cache;
        for(var i = 0; i < genre_lis.length; i++) {
            var genre_li = genre_lis[i];
            genre_li.visible_channels_count = genre_li.channels_count;
        }
    },

    /*
     * Shows all the genres, reseting the visibility state and counters
     */
    _show_all_genres: function() {
        var channel_lis = schedule._channel_lis_cache;
        for(var i = 0; i < channel_lis.length; i++) {
            var channel_li = channel_lis[i];

            if (!channel_li.visible()) {
                Element.show(channel_li);
            }
        }

        var genre_lis = schedule._genre_lis_cache;
        for(var i = 0; i < genre_lis.length; i++) {
            var genre_li = genre_lis[i];
            genre_li.visible_channels_count = genre_li.channels_count;
            Element.show(genre_li);
            var ul_to_hide = Element.down(genre_li, 'ul');
            if (ul_to_hide) {
	            Element.hide(ul_to_hide);
	        }
        }
    },

    /*
     * Filter channels by +name+, using a regular expression.
     */
    _filter_channels_by: function(name) {
        var lis = schedule._channel_lis_cache;
        var re = new RegExp(name, 'i');
        for(var i = 0; i < lis.length; i++) {
            var li = lis[i];
            var channel_name = li.firstChild.lastChild.innerHTML;
            if (!re.test(channel_name)) {
                Element.hide(li);
                li.genre_li.visible_channels_count--;
            } else {
                Element.show(li);
            }
        }
    },

    /*
     * Update visual counters for every genre and reset visibility state for genres
     * and events.
     * When +show_channels+ param is +false+, channel lists will be hidden,
     * returning to the original (unfiltered) state.
     */
    _update_genres_count_and_visibility: function(show_channels) {
        var genre_lis = schedule._genre_lis_cache;

        var empty = true;

        for(var i = 0; i < genre_lis.length; i++) {
            var genre_li = genre_lis[i];
            if (genre_li.visible_channels_count == 0) {
                Element.hide(genre_li);
            } else {
                var genre_li = genre_lis[i];
                var channels_number = Element.down(genre_li, 'em');
                channels_number.innerHTML = channels_number.innerHTML.gsub(
                    /\d+/, genre_li.visible_channels_count.toString());

                var toggle_link = Element.down(genre_li, 'a');
                if (show_channels) {
                    toggle_link.innerHTML = js_messages.hide;
                    schedule._show_genre_channels(genre_li);
                } else {
                    toggle_link.innerHTML = js_messages.show;
                }
                empty = false;
            }
        }

        var empty_message = $('channels_list_empty_message');
        if (empty) {
            Element.show(empty_message);
        } else {
            Element.hide(empty_message);
        }
    },

    /*
     * Show genre channels list for the given +genre_li+ list item (<li>).
     */
    _show_genre_channels: function(genre_li) {
        // The genre_li is the element surrounding the genre name (h3) and the
        // channels list (ul)
        var channels_list = Element.down(genre_li, 'ul');
        Element.show(genre_li);
        Element.show(channels_list);
    },

    /*
     * Request new time slot schedule and draw it, stopping event propagation
     */
    time_slot_click_event_handler: function(ev) {
        Event.stop(ev);         // stop event propagation
        var url = this.href;    // get the url
        url += "&layout=false"; // set a custom AJAX flag

        // show the loader and proceed
        ajax_utils.show_loader();

        // configure and send the AJAX request
        ajax_utils.request(url,
            function(transport) {
                // set the new HTML
                var grid = $('grid');
                grid.innerHTML = transport.responseText;

                var select = $('genreId');

                // highlight events by genre
                schedule._highlight_events_by_selected_genre(select);

                // link popups
                var as = $$('a.popup');
                for(var i = 0; i < as.length; i++) {
                    var a = as[i];
                    popups.setup(a);
                }

                // hide loader
                ajax_utils.hide_notice();
            }
        );

        // update selected time slot
        var parent_li = this.parentNode;
        if (schedule.selected_time_slot != null) {
           Element.removeClassName(schedule.selected_time_slot, 'current');
        }
        Element.addClassName(parent_li, 'current');
        schedule.selected_time_slot = parent_li;
    }
};

/*
 * AJAX calls handler for the channels listing
 */
var channels = {

    /*
     * A reference to the currently selected channel link (<a> element)
     */
    selected: null,

    /*
     * Get the channel param from the currently selected channel
     */
    selected_channel_to_query_param: function() {
        if (channels.selected != null) {
            var url = channels.selected.href;
            return url.match(/channelId=(\d*)/)[0];
        } else {
            return '';
        }
    },

    /*
     * Request channel info and draw it, stopping the click event propagation
     */
    channel_click_event_handler: function(ev) {
        Event.stop(ev);         // stop event propagation
        var url = this.href;    // get the url
        url += "&layout=false"; // set a custom AJAX flag

        // create the "notice" div
        var channel_info = $('channel_info');
        channel_info.innerHTML = '<div id="notice" class="channels_notice"></div>';

        Element.scrollTo($('wrapper'))

        ajax_utils.request(url,
            function(transport) {
                var channel_container = $('channel_schedule');

                // set the new HTML
                channel_container.innerHTML = transport.responseText;

                // link and show filter
                var select = $('event_genre');
                Event.observe(select, 'change',
                        channels.selected_genre_change_event_handler.bindAsEventListener(select));

                // link popups
                var as = $$('a.popup');
                for(var i = 0; i < as.length; i++) {
                    var a = as[i];
                    popups.setup(a);
                }

                // hide loader
                ajax_utils.hide_notice();
            }
        );

        // update selected channel
        if (channels.selected != null) {
           Element.removeClassName(channels.selected, 'selected');
        }
        Element.addClassName(this, 'selected');
        channels.selected = this;
    },

    /*
     * Highlight events in the schedule when their genre matches the one
     * selected by the user
     */
    selected_genre_change_event_handler: function(ev) {
        var selected_genre_id = this.options[this.selectedIndex].value;

        var selected_class_name = 'event_genre_' + selected_genre_id;
        $$('.event').each(
            function(it) {
                if (selected_genre_id == '' || it.className.indexOf(selected_class_name) > 0) {
                    Element.removeClassName(it.parentNode, 'channel_event_attenuated');
                } else {
                    Element.addClassName(it.parentNode, 'channel_event_attenuated');
                }
            }
        );
        Event.stop(ev);
    }
};

/*
 * Some utility functions for AJAX calls
 */
var ajax_utils = {
    /*
     *
     */
    request: function(url, success_callback) {
        // show the loader and proceed
        ajax_utils.show_loader();

        // configure and send the AJAX request
        new Ajax.Request(url,
            {
                method: 'get',
                onFailure: ajax_utils.show_error_notice,
                on500: ajax_utils.show_error_notice,
                on404: ajax_utils.show_error_notice,
                onSuccess: success_callback
            }
        );
    },

    /*
     * Show the loader
     */
    show_loader: function() {
        var notice = $('notice');
        notice.innerHTML = '<img src="img/loader.gif" /> <br />' +
            js_messages.loading;
        Element.show(notice);
    },

    /*
     * Show the notice area
     */
    show_error_notice: function() {
        var notice = $('notice');
        var html = '<p class="error">' +
            js_messages.connection_error + "</p>";
        notice.innerHTML = html;
        Element.show(notice);
    },

    /*
     * Hide the notice area
     */
    hide_notice: function() {
        var notice = $('notice');
        notice.innerHTML = '';
        Element.hide(notice);
    }
};

