Array.prototype.unique = function(){
    var vals = this;
    var uniques = [];
    for(var i=0 ; i < vals.length; i++){
        var val = vals[i];
        if($.inArray( val, uniques )==-1){
            uniques.unshift(val);
        }
    }
    return uniques;
}
Array.prototype.compact = function(){
    var vals = this;
    var compact_vals = [];
    for(var i=0 ; i < vals.length; i++){
        if( vals[i] ){
            compact_vals.push( vals[i] );
        }
    }
    return compact_vals;
}
function str_repeat(i, m) { for (var o = []; m > 0; o[--m] = i); return(o.join('')); }

function sprintf () {
  var i = 0, a, f = arguments[i++], o = [], m, p, c, x;
  while (f) {
    if (m = /^[^\x25]+/.exec(f)) o.push(m[0]);
    else if (m = /^\x25{2}/.exec(f)) o.push('%');
    else if (m = /^\x25(?:(\d+)\$)?(\+)?(0|'[^$])?(-)?(\d+)?(?:\.(\d+))?([b-fosuxX])/.exec(f)) {
      if (((a = arguments[m[1] || i++]) == null) || (a == undefined)) throw("Too few arguments.");
      if (/[^s]/.test(m[7]) && (typeof(a) != 'number'))
        throw("Expecting number but found " + typeof(a));
      switch (m[7]) {
        case 'b': a = a.toString(2); break;
        case 'c': a = String.fromCharCode(a); break;
        case 'd': a = parseInt(a); break;
        case 'e': a = m[6] ? a.toExponential(m[6]) : a.toExponential(); break;
        case 'f': a = m[6] ? parseFloat(a).toFixed(m[6]) : parseFloat(a); break;
        case 'o': a = a.toString(8); break;
        case 's': a = ((a = String(a)) && m[6] ? a.substring(0, m[6]) : a); break;
        case 'u': a = Math.abs(a); break;
        case 'x': a = a.toString(16); break;
        case 'X': a = a.toString(16).toUpperCase(); break;
      }
      a = (/[def]/.test(m[7]) && m[2] && a > 0 ? '+' + a : a);
      c = m[3] ? m[3] == '0' ? '0' : m[3].charAt(1) : ' ';
      x = m[5] - String(a).length;
      p = m[5] ? str_repeat(c, x) : '';
      o.push(m[4] ? a + p : p + a);
    }
    else throw ("Huh ?!");
    f = f.substring(m[0].length);
  }
  return o.join('');
}

function ajax_request(url, options)
{
    /* jquery fixed */
    if( !options )
        options = {};
    if( !$.string(url).startsWith('http://') )
    url = location.protocol + '//' + location.host + url;
    options['url'] = url;
    $.ajax(options);
}

function ajax_updater(target, url, options)
{
    if( !options )
        options = {};
    if( options.waiter )
        options.waiter.html(sprintf('Working...<img src="%s">', loading_image_path)).show();

    var success_orig = options.success;
    var error_orig = options.error;
    target = $(target);
    var opts = {
        success: function( data ) {
            target.replaceWith( data );
            if( success_orig )
                success_orig( data );
            if( options.waiter )
                options.waiter.html('Complete').fadeOut( "slow" );
        },
        error: function( data ) {
            if( options.waiter )
                options.waiter.html( data.responseText );
            if( error_orig )
                error_orig( data );
        }
    };
    $.extend( options, opts );
    ajax_request(url, options);
}

function vote(direction, oid, model, elem, carousal_type)
{
    elem = $(elem);
    ajax_updater(elem, '/record/vote/', {
        type: 'post',
        data: {
            model: model,
            obj_id: oid,
            direction: direction,
            car_type: carousal_type
        }
    });
}//function

function record_view(model, object_id)
{
    ajax_request(sprintf('/record/view/%s/%s/', model, object_id));
}

function update_msg(url, obj, event)
{
    obj = $(obj);
    obj.parents('.toggle').children('.ui-toggle-content').slideToggle("fast");
    obj.siblings().show();
    obj.hide();

    ajax_request(url);
}
function SimplePreloader(container, img_src, on_load, on_abort, on_error)
{
    var img = new Image();

    if( on_load != null )
        img.onload  = function() { on_load(img);  }

    if( on_error != null )
        img.onerror = function() { on_error(img); }

    if( on_abort != null )
        img.onabort = function() { on_abort(img); }

    img.src = img_src;
}
function init_audio_player(audio_id, target, audio_url, options)
{
    var def_options = { };
    var controls = {
            buttonColor:        '#919191',
            backgroundColor:    '#a2a0a0',
            buttonOverColor:    '#a8a8a8',
            bufferColor:        '#828282',
            timeColor:          '#eeddd8',
            progressGradient:   'medium',
            borderRadius:       0,
            sliderGradient:     'none',
            progressColor:      '#dbd8d7',
            backgroundGradient: 'medium',
            bufferGradient:     'none',
            durationColor:      '#ffffff',
            sliderColor:        '#d7ddc0',
            opacity:            1.0,
            play:               true,
            volume:             true,
            mute:               true,
            time:               true,
            stop:               true,
            fullscreen:         false,
            scrubber:           true
    };
    $.extend(controls, options.controls );
    $.extend(def_options, options );

    var fp = $f(target, {
        src: "/js/FlowPlayer/flowplayer-3.1.5.swf",
        width: options.width,
        height: options.height,
        wmode: 'transparent'
    },
    {
        play: { replayLabel:'Replay' },
        plugins: {
            controls: controls,
            audio: { url: '/js/FlowPlayer/flowplayer.audio-3.1.2.swf'  }
        },
        canvas: { backgroundColor: "#dbd8d7" },
        playlist: [
            {
                url:          audio_url,
                autoPlay:     false,
                autoBuffering: false,
                image: false,
                onBegin: function() { record_view('picture', audio_id); }
            }
        ]
    });
    if( options.playlist )
        fp.playlist(options.playlist);
}
function init_flow_player(target, video_url, splash_image, width, height, options)
{
    if( !options )
        options = {};
    var fsettings = {
        url:      video_url,
        autoPlay: false,
        autoBuffering: $.string( splash_image ).empty(),
        onBegin: function() { }
    };
    $.extend( fsettings, options);
    var playlist_settings = new Array();
    if( splash_image )
    {
        playlist_settings.push( {auto_play:false, autoBuffering:true, url:splash_image } );
    }
    playlist_settings.push( fsettings );

    var controls =
    {
        url: location.protocol + '//' + location.host + '/js/FlowPlayer/flowplayer.controls-3.1.5.swf',
        buttonColor: '#919191',
        backgroundColor: '#a2a0a0',
        buttonOverColor: '#a8a8a8',
        bufferColor: '#828282',
        timeColor: '#eeddd8',
        progressGradient: 'medium',
        borderRadius: '0',
        sliderGradient: 'none',
        progressColor: '#dbd8d7',
        backgroundGradient: 'medium',
        bufferGradient: 'none',
        durationColor: '#ffffff',
        sliderColor: '#d7ddc0',
        opacity: 1.0,
        play: true,
        volume: true,
        mute: true,
        time: true,
        stop: true,
        playlist: false,
        fullscreen: true,
        scrubber: true
    };
    if( options.inline )
    {
        controls['volume'] = false;
        controls['mute'] = false,
        controls['stop'] = false;
    }

    return $f(target, {
        src: location.protocol + '//' + location.host + "/js/FlowPlayer/flowplayer-3.1.5.swf",
        width: width,
        height: height,
        wmode: 'transparent'
    },
    {
        play: { replayLabel:'Replay' },
        plugins: {
            controls: controls
        },
        canvas: { backgroundColor: "#dbd8d7" },
        playlist: playlist_settings
    });
}
function mark_active(url, target, container)
{
    ajax_updater(target, url, {success:function(){ $(container).effect.highlight(); }});
}
function mark_inactive(url, target, container)
{
    ajax_updater(target, url, {success:function(){ $(container).effect.highlight({color:'#FFEBE8'}); }});
}
function pluralize(n)
{
    if( n > 1 )
        return "s";
    return "";
}
function handle_menu_click(menu, event)
{
    if( !menu.find(".menu_action_links").is(':visible') )
        open_menu(menu, event);
    else
        close_menu(menu, event);
    event.preventDefault();
}
function open_menu(menu, event)
{
    menu.find(".menu_action_links").show();
    menu.find('.menu_command a').addClass('open');
}
function close_menu(menu)
{
    menu.find('.menu_command a').removeClass('open');
    menu.find(".menu_action_links").hide();
}
function update_activity_box(box)
{
    var n, n_content;
    box = $( box );

    ajax_request(ACTIVITY_UPDATE_URL, { success: function(data){
        data = $.evalJSON(data);
        if( !data.n )
            return;

        n = data.n;
        var elem;
        var to_show  = data.content.reverse();
        var to_remove = box.find(".activity");

        if( box.find(".activity").size() > n )
            to_remove = box.find(".activity").slice(box.find(".activity").size()-n);

        jQuery.map(to_show, function(a){
            box.prepend(sprintf('<div style="padding: 6px 4px; display:none" class="activity">%s</div>', a));
        });
        to_show = box.find('.activity:'+n);

        to_remove.hide("drop", {direction:"down"}, 400, function(){
            to_remove.remove();
            to_show.fadeIn();
            /* ui.effects adds an invisible wrapper, do clean up */
            box.find('.ui-effects-wrapper').remove();
        });
        return;
    }});
}
function focus_first_element(form_elem)
{
    form_elem.find('input:visible:enabled:first').focus();
}
function init_location_controls()
{
    $('#id_city').autocomplete( {source:CITY_LIST_URL + '?country='+$('#id_country').val() });
    $('#id_country').bind('change', function(){
        $('#id_city').val("");
        $('#id_city').autocomplete( {source:CITY_LIST_URL + '?country='+$('#id_country').val() });
    });
}
function init_menu( jmenu )
{
    jmenu.find('.trigger').hover(function(){
			$(this).addClass('ui-state-hover');

		}, function(){
			$(this).removeClass('ui-state-hover');
		}
	);
	jmenu.find('trigger').hover(function(){
			$(this).addClass('ui-arrow-down-hover');
		}, function(){
			$(this).removeClass('ui-arrow-down-hover');
		}
	);

	jmenu.mouseover(function(ev){
		if ($(ev.target).is('.ui-active-state')){
			return false;
		}
	});

	//jump menu
	jmenu.find('.menuContain .menu li a').hover(
		function(){
			$(this).addClass('ui-state-hover');
		}, function(){
			$(this).removeClass('ui-state-hover');
		}
	).click(function(){
        if( jmenu.find('.menu').is(':visible') )
        {
            if( $(this).attr('href') && $(this).attr('href') != '#' && $(this).attr('href') != 'javascript:void(0)')
                window.location = $(this).attr('href');
            jmenu.find('.trigger').trigger('click');
        }
        return false;
    });

	jmenu.find('a.trigger').click(function(){
        $(this).parent().find('.menu').slideToggle('fast');
        $(this).toggleClass('ui-state-active');
        return false;
    });
}
function city_marker_helper(cid, rid, name, gpoint, marker_options)
{
    var icon = new GIcon(G_DEFAULT_ICON);
    icon.image = MARKER_IMAGE;
    icon.iconSize = new GSize(24, 24);
    icon.iconAnchor = new GPoint(10, 20);
    icon.shadow = '';
    var opts = { icon:icon, title:name, draggable:false };
    $.extend( opts, marker_options );
    var marker = new GMarker( gpoint, opts );
    marker.rid = rid;
    marker.cid = cid;
    marker.cname = name;

    return marker;
}
function place_city_marker(cid, rid, name, longitude, latitude, force, marker_options)
{
    if( longitude && latitude )
    {
        return city_marker_helper(cid, rid, name, new google.maps.LatLng(latitude, longitude), marker_options);
    }
    else
    {
        if( force )
        {
            var geocoder = new GClientGeocoder();
            geocoder.getLatLng(name, function(point)
            {
                if( point )
                    return city_marker_helper(cid, rid, name, point, marker_options);
            });
        }
    }
}
function start_activity_feed()
{
    ACTIVITY_TIMER_ID = setInterval(update_activity_box, 60000);
}
function pause_activity_feed()
{
    clearInterval(ACTIVITY_TIMER_ID);
}
function init_buttons()
{
    $('.ui-button, .ui-widget-button, input:submit, button').button();
    $('.ui-widget-button-save').button({ icons:{primary:'ui-icon-disk'} });
    $('.ui-widget-button-add').button({ icons:{primary:'ui-icon-plus'} });
    $('.ui-widget-button-search').button({ icons:{primary:'ui-icon-search'} });
    $('.ui-widget-button-del').button({ icons:{primary:'ui-icon-closethick'} });
}