if (!visual) var visual={};
if (!window.console) {window.console = {log:function(){}, debug:function(){}};}

Position.getWindowSize = function(w) {
    var width, height;
    w = w ? w : window;
    width = w.innerWidth || (w.document.documentElement.clientWidth || w.document.body.clientWidth);
    height = w.innerHeight || (w.document.documentElement.clientHeight || w.document.body.clientHeight);
    return {width:width, height:height};
}

function showSlideshow(src) {
    // Destroy old slideshow...
    if ($('__slideshow_iframe')) {var d = $('__slideshow_iframe'); d.parentNode.removeChild(d);}

    var ifrm = $(document.createElement('iframe'));
    var body = $$('body')[0];
    ifrm.setAttribute('id', '__slideshow_iframe'); ifrm.setAttribute('src', src); ifrm.setAttribute('frameborder', '0'); ifrm.setAttribute('border', '0');  ifrm.setAttribute('scrolling', 'no');

    windowSize = Position.getWindowSize();
    ifrm.setAttribute('width', windowSize.width-90); ifrm.setAttribute('height', windowSize.height-70);
    ifrm.setStyle({position:'absolute', top:(Position.realOffset(body)[1]+30)+'px', left:'30px', border:'8px solid #eee'});
    body.appendChild(ifrm);
}

function formatRating(rating,blockID) {return('(' + Math.floor(rating*10.0)/10.0 + ')');}
function rate(id,rating,numunits,blockID) {
    $$('#block'+blockID+' .object-rating-user-average').each(function(el){$(el).removeClassName('object-rating-user-average');});
    $$('#block'+blockID+' .object-rating-'+rating).each(function(el){$(el).addClassName('object-rating-user-average');});
    $$('#block'+blockID+' .object-rating').each(function(el){
            $(el).removeClassName('object-rating-no-user');
            $(el).addClassName('object-rating-user');
        });
    doAction('photo-rate', 'photo_id='+encodeURIComponent(id)+'&num_units='+encodeURIComponent(numunits)+'&rating='+encodeURIComponent(rating), {onSuccess:function(r){
                var avg_rating = r.responseText;
                if (!avg_rating.length) return;
                $$('#block'+blockID+' .object-rating-average-value').each(function(el){el.innerHTML = formatRating(avg_rating,blockID);});
                $$('#block'+blockID+' .object-rating-average').each(function(el){$(el).removeClassName('object-rating-average');});
                var int_rating = Math.floor(Math.round(avg_rating));
                $$('#block'+blockID+' .object-rating-'+int_rating).each(function(el){$(el).addClassName('object-rating-average');});
            }});

}

// Cookie object
var Cookie = {
    set: function(name, value, daysToExpire) {var expire = ''; if (daysToExpire != undefined) {var d = new Date();d.setTime(d.getTime() + (86400000 * parseFloat(daysToExpire)));expire = '; expires=' + d.toGMTString();} var path = '; path=/'; if (value.length) value=escape(value); else value='""'; return (document.cookie = escape(name) + '=' + value + expire + path);},
    get: function(name) {var cookie = document.cookie.match(new RegExp('(^|;)\\s*' + escape(name) + '=([^;\\s]*)')); return (cookie ? unescape(cookie[2]) : '');},
    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');}
};

function expandTA(ta) {if (ta.scrollHeight) {if ($(ta).rel!='fixedWidth') $(ta).setStyle({width:ta.getWidth()+'px'});$(ta).rel='fixedWidth';$(ta).setStyle({height:(ta.scrollHeight>350 ? 350 : (ta.scrollHeight<80 ? 80 : ta.scrollHeight))+'px'});}}
function resizeCssTable(id, className, force) {
    var o = document.getElementsByClassName(className);
    if (o.length==0) return;
    if (!o[0].offsetHeight) {
        $(id).style.visibility = 'hidden';
        window.setTimeout("resizeCssTable('" + id + "','" + className + "', " + force + ");", 100);
        return;
    }

    for (var i=0; i<o.length; i++) $(o[i]).removeClassName('margined-column');
    if (typeof(force)!=undefined && force) for (var i=0; i<o.length; i++) o[i].style.height = 'auto';
    var top = o[0].offsetTop;
    var cols = 1;
    while (o[cols] && o[cols].offsetTop==top) cols++;
    for (var rowStart=0; rowStart<(o.length-cols); rowStart+=cols) {
        var height = 0;
        for (var i=0; i<cols; i++) height = Math.max(height, o[rowStart+i].offsetHeight);
        for (var i=0; i<cols; i++) o[rowStart+i].style.height = height+'px';
    }

    for (var rowStart=0; rowStart<o.length; rowStart+=cols) {
        for (var i=0; i<cols; i++) if(o[rowStart+i]) $(o[rowStart+i]).addClassName(i<cols-1 ? 'margined-column' : 'non-margined-column');
    }
    $(id).style.visibility = 'visible';
}

function serializeObject(o) {var a = new Array(); for(i in o) a[a.length]=encodeURI(i)+'='+encodeURI(o[i]); return(a.join('&'));}
function doAction(action, params, opts) {if (typeof(opts)=='undefined' || opts.length==0) var opts = new Object();if (typeof(params)=='undefined' || params.length==0) {var params = 'action='+encodeURI(action);} else {params += '&action='+encodeURI(action);}var options = new Object();options.method = 'post';options.postBody = params;options.evalScripts=true;if (opts.onComplete) {options.onComplete=opts.onComplete;} else if (opts.indicator) {options.onComplete = function(){$(opts.indicator).hide();}}if (opts.onFailure) options.onComplete=opts.onFailure;if (opts.onSuccess) options.onComplete=opts.onSuccess;if (typeof(opts.asynchronous)!=undefined) options.asynchronous=opts.asynchronous;var url = '/actions';if (opts.container) {new Ajax.Updater(opts.container, url, options);} else {new Ajax.Request(url, options);}}
function rev(s) {var r=''; for (var i=s.length-1; i>=0; i--) r+=s.charAt(i); return r;}
function revmailto(e) {location.href = 'mailto:' + rev(e);}
function multiEdit() {if (visual && visual.page && visual.page.view_params.length) {var params = visual.page.view_params;} else {if (visual && visual.photos && visual.photos.length) {var a = []; for (var i=0; i<visual.photos.length; i++) a[a.length]='photos='+visual.photos[i].photo_id; var params = a.join('&');}} if (params.length) location.href='/organize?return_url='+encodeURI(visual.page.return_url)+'&show_search_form_p=f&'+params;}
function setFirstAndLast(o, childNodeName) {if (!$(o)) return; var nodes = $A($(o).getElementsByTagName(childNodeName)); nodes.each(function(node) {nodes.each(function(refNode) {if($(node).descendantOf(refNode)) {nodes = nodes.without(node);return;}});}); if(!nodes.length) return; $(nodes[0]).addClassName('first'); $(nodes[nodes.length-1]).addClassName('last');}
function setOddsAndEvens(o, childNodeName) {var odd=true; $A($(o).getElementsByTagName(childNodeName)).each(function(item) {$(item).addClassName((odd ? 'odd' : 'even')); odd=!odd;});}
function doJSON(endpoint, query, callback) {new Ajax.Request(endpoint, {parameters:query, onComplete:function(response){callback(eval('('+response.responseText+')'))}});}
function clearChildren(element) {while (element.firstChild) {element.removeChild(element.firstChild);}}
function indicate(c, text) {c=$(c); if(!c) return; clearChildren(c); var x=document.createElement('div'); x.className="jumptop center"; var d=document.createElement('div'); d.className='indicator'; d.style.display='inline'; d.innerHTML=text; x.appendChild(d); c.appendChild(x);}
function yellowFade(c) {new Effect.Highlight(c, {startcolor: '#FFFFCC', restorecolor:true, duration:3});}
/* Show inline help for all <div class="inlineHelp">...</div> */
function handleInlineHelp() {$$('div.inlineHelp').each(function(item) {if(item.hasClassName('__inlineHelpDone')) return; item.addClassName('__inlineHelpDone'); var icon=document.createElement('img'); icon.src='/resources/um/graphics/icons/info-icon.gif'; item.parentNode.insertBefore(icon, item); $$('body')[0].appendChild(item); Event.observe(icon, 'mouseover', function(){var pos=Position.cumulativeOffset(icon); item.addClassName('inlineHelpShow'); item.setStyle({left:pos[0]+'px',top:(25+pos[1])+'px'}); }); Event.observe(icon, 'mouseout', function(){item.removeClassName('inlineHelpShow');});});}
function preloadImage(src) {var img = new Image(); img.src=src;};

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('');}


visual.removeNodes = function(cssIdentifier) {if ($$(cssIdentifier)) $A($$(cssIdentifier)).each(function(node) {node.parentNode.removeChild(node);});}
visual.setText = function(cssIdentifier, text) {$A($$(cssIdentifier)).each(function(item) {item.innerHTML = text;});}
visual.contain = function(cssIdentifier, containerId) {var o = $$(cssIdentifier); if (o.length) {var e = o[0]; var c = document.createElement('div'); c.setAttribute('id', containerId); e.parentNode.insertBefore(c, e); c.appendChild(e);}}
visual.insert = function(actionElement, toElement, location, force) {
    actionElement=$(actionElement);toElement=$(toElement);
    if (!actionElement || !toElement) return;
    if (location!='top') location='bottom';
    if (!actionElement||!toElement) {return;}
    if(location=='bottom') toElement.appendChild(actionElement);
    else toElement.insertBefore(actionElement, toElement.firstChild);
}

visual.alert = function(message, onOK) {
    if (typeof(onOK)=='undefined') onOK = function(){};
    var container = $(document.createElement('div')); container.addClassName('visual-alert');
    var m = $(document.createElement('div')); m.addClassName('visual-alert-message'); m.appendChild(document.createTextNode(message));
    var buttons = $(document.createElement('div')); buttons.addClassName('visual-alert-buttons');
    var okButton = $(document.createElement('input')); okButton.setAttribute('type', 'button'); okButton.addClassName('button'); okButton.addClassName('visual-alert-ok-button'); okButton.setAttribute('value', 'OK');
    container.appendChild(m); buttons.appendChild(okButton); container.appendChild(buttons);
    var modal = new visual.modalDialog(container);
    Event.observe(okButton, 'click', function(){onOK(); modal.close();});
    this.modal = modal; this.onOK = onOK; return(this);
}
visual.confirm = function(question, onYes, onNo) {
    var container = $(document.createElement('div')); container.addClassName('visual-confirm');
    var q = $(document.createElement('div')); q.addClassName('visual-confirm-question'); q.appendChild(document.createTextNode(question));
    var buttons = $(document.createElement('div')); buttons.addClassName('visual-confirm-buttons');
    var yesButton = $(document.createElement('input')); yesButton.setAttribute('type', 'button'); yesButton.addClassName('button'); yesButton.addClassName('visual-confirm-yes-button'); yesButton.setAttribute('value', 'Yes');
    var noButton = $(document.createElement('input')); noButton.setAttribute('type', 'button'); noButton.addClassName('button'); noButton.addClassName('visual-confirm-no-button'); noButton.setAttribute('value', 'No');
    container.appendChild(q); buttons.appendChild(yesButton); buttons.appendChild(noButton); container.appendChild(buttons);
    var modal = new visual.modalDialog(container);
    Event.observe(yesButton, 'click', function(){onYes(); modal.close();});
    Event.observe(noButton, 'click', function(){onNo(); modal.close();});
    this.modal = modal; this.onYes = onYes; this.onNo = onNo; return(this);
}
visual.prompt = function(question, defaultValue, onOK, onCancel) {
    var container = $(document.createElement('div')); container.addClassName('visual-prompt');
    var q = $(document.createElement('div')); q.addClassName('visual-prompt-question'); q.appendChild(document.createTextNode(question));
    var text = $(document.createElement('div')); text.addClassName('visual-prompt-text');
    var input = $(document.createElement('input')); input.setAttribute('type', 'text'); input.addClassName('input'); input.addClassName('visual-prompt-text-input'); input.setAttribute('value', defaultValue);
    var buttons = $(document.createElement('div')); buttons.addClassName('visual-prompt-buttons');
    var okButton = $(document.createElement('input')); okButton.setAttribute('type', 'button'); okButton.addClassName('button'); okButton.addClassName('visual-prompt-ok-button'); okButton.setAttribute('value', 'Ok');
    var cancelButton = $(document.createElement('input')); cancelButton.setAttribute('type', 'button'); cancelButton.addClassName('button'); cancelButton.addClassName('visual-prompt-cancel-button'); cancelButton.setAttribute('value', 'Cancel');
    container.appendChild(q); text.appendChild(input); container.appendChild(text); buttons.appendChild(okButton); buttons.appendChild(cancelButton); container.appendChild(buttons);
    var modal = new visual.modalDialog(container);
    Event.observe(okButton, 'click', function(){onOK(input.value); modal.close();});
    Event.observe(cancelButton, 'click', function(){onCancel(); modal.close();});
    this.modal = modal; this.input = input; this.onOK = onOK; this.onCancel = onCancel; return(this);
}

visual.modalDialog = function(contentDOMNode) {
    var body = $$('body')[0]; var bodyOffset=Position.realOffset(body); bodyDimensions=Element.getDimensions(body);
    // Overall dialog div
    var dialog = $(document.createElement('div')); dialog.setStyle({visibility:'hidden'}); dialog.addClassName('visual-modal-dialog'); dialog.appendChild(contentDOMNode);
    // Screen body from clicks
    var screen = $(document.createElement('div')); screen.addClassName('visual-modal-screen'); screen.setStyle({height:bodyDimensions.height+'px', width:bodyDimensions.width+'px'}); body.appendChild(screen);
    Event.observe(screen, 'click', Event.stop); Event.observe(dialog, 'click', Event.stop);
    // Place it & Calculate it
    body.appendChild(dialog); dialogDimensions=Element.getDimensions(dialog);
    dialog.setStyle({top:(bodyOffset[1]+50)+'px', left:((bodyDimensions.width-dialogDimensions.width)/2)+'px', visibility:'visible'});
    // Prepare return object
    this.dialog=dialog; this.screen=screen; this.close = function() {try {body.removeChild(screen); body.removeChild(dialog);} catch(e){};}
    return(this);
}

visual.dialog = function(url, opts) {
    if (typeof(opts)=='undefined') opts = {};
    var body = document.getElementsByTagName('body')[0];

    // Body overlay?
    if(opts.overlay) {
        var dim = Element.getDimensions(body);
        var fade = new Element('div', {id:'dialogFade'}).addClassName('visual-dialog-fade').setStyle({width:dim.width+'px', height:dim.height+'px'});
        body.appendChild(fade);
    }

    // Overall dialog div
    var dialog = $(document.createElement('div'));
    dialog.addClassName('visual-dialog');
    dialog.setStyle({visibility:'hidden'});
    if(opts.id) dialog.setAttribute("id", opts.id);
    if(opts.height) dialog.setStyle({height:opts.height+'px'});
    if(opts.width) dialog.setStyle({width:opts.width+'px'});


    if(opts.noscroll) {
        dialog.setStyle({overflow:'hidden'});
    }

    // Container
    var dialogContainer = $(document.createElement('div'));
    dialogContainer.addClassName('visual-dialog-container');
    indicate(dialogContainer, 'Loading...');
    dialog.appendChild(dialogContainer);
    body.appendChild(dialog);

    // Prepare return object
    var closebox = $(document.createElement('div'));
    this.dialog=dialog;
    this.dialogContainer=dialogContainer;
    this.close = function() {try {body.removeChild(dialog); body.removeChild(closebox); body.removeChild(fade);} catch(e){};}

    // Position the dialog
    var bodyWidth = Element.getDimensions(body).width;
    var dialogWidth = Element.getDimensions(dialog).width;
    if (typeof(opts.top)=='undefined') opts.top=50;
    dialog.setStyle({top:(Position.realOffset(body)[1]+opts.top)+'px', left:((bodyWidth-dialogWidth)/2)+'px', visibility:'visible'});

    // Close button
    closebox.addClassName('visual-close');
    closebox.setStyle({top:(dialog.cumulativeOffset().top-15)+'px', left:(dialog.cumulativeOffset().left+dialog.getWidth()-15)+'px'});
    Event.observe(closebox, 'click', function(){this.close();}.bind(this));
    body.appendChild(closebox);

    // Close when clicking on body
    Event.observe(dialog, 'click', function(event){Event.stop(event);});
    if(opts.overlay) {Event.observe(fade, 'click', this.close);}

    // And give it some content
    if (typeof(opts.method)=='undefined') opts.method = 'GET';
    if (typeof(opts.evalScripts)=='undefined') opts.evalScripts = true;
    var requestOptions = {method:opts.method, evalScripts:opts.evalScripts, parameters:opts.parameters, postBody:opts.postBody, onComplete:opts.onComplete};
    new Ajax.Updater(dialogContainer, url, requestOptions);

    return(this);
}

// Make div fields editable
visual.editableHelper = {has_replaced:false, has_clicked:false, replacedHTML:'', ta:null};
function makeEditable(o) {
    if (typeof(o.defaultText)=='undefined' || o.defaultText.length==0) o.defaultText='';
    if (typeof(o.parameterName)=='undefined' || o.parameterName.length==0) o.parameterName='text';
    if (typeof(o.extraParams)=='undefined' || o.extraParams.length==0) o.extraParams=new Object();
    if (typeof(o.message)=='undefined' || o.message.length==0) o.message = 'Click here to edit';
    if (typeof(o.widget)=='undefined' || o.widget.length==0) o.widget = 'textarea';
    if (typeof(o.persistent)=='undefined') o.persistent=false;

    var c = $(o.containerName);
    var h = visual.editableHelper;
    var f = null;
    if (c.empty()) {
        if (o.persistent) {c.addClassName('editablePersistent'); c.innerHTML = o.message;} else {if (c.getHeight()<10) {c.setStyle({height:'20px'});}}
    } else {
        if (!c.getElementsByClassName('editableEditLabel').length) {var editLabel = $(document.createElement('span')); editLabel.addClassName('editableEditLabel'); editLabel.appendChild(document.createTextNode('Edit')); c.appendChild(editLabel, c.firstChild);}
    }
    var click = function(e){
        if (h.has_clicked) return; h.has_clicked = true;
        if (!h.has_replaced) {h.replacedHTML = c.innerHTML;} h.has_replaced = true; c.innerHTML=''; c.setStyle({height:''});
        f = document.createElement('form'); $(f).addClassName('editableForm');
        f.setAttribute('onsubmit', 'return(false);');
        Event.observe(f, 'submit', function(e){
                o.defaultText = (h.ta ? h.ta.value : f[o.parameterName].value);
                doAction(o.action, Form.serialize(f)+'&'+serializeObject(o.extraParams), {onSuccess:function(r){
                            c.innerHTML=r.responseText;
                            h.has_clicked=false; h.has_replaced=false; c.removeClassName('editable'); c.removeClassName('editableText'); c.removeClassName('editablePersistent');
                            Event.stopObserving(c, 'click', click); Event.stopObserving(c, 'mouseover', mouseover); Event.stopObserving(c, 'mouseout', mouseout);
                            makeEditable(o);
                        }});
                Event.stop(e);
                return(false);
            });
        Event.observe(f, 'reset', function(e){
                c.innerHTML=h.replacedHTML;
                h.has_clicked=false; h.has_replaced=false; c.removeClassName('editable'); c.removeClassName('editableText');
                Event.stopObserving(c, 'click', click); Event.stopObserving(c, 'mouseover', mouseover); Event.stopObserving(c, 'mouseout', mouseout);
                makeEditable(o);
                return(false);
            });
        var d = document.createElement('div');
        if (o.widget=='text') {
            var ta = document.createElement('input'); ta.setAttribute('type', 'text'); ta.setAttribute('name', o.parameterName); ta.className = 'input'; ta.value=o.defaultText;
            if (typeof(o.maxlength)!='undefined') ta.setAttribute('maxlength', o.maxlength);
        } else if (o.widget=='select') {
            var ta = document.createElement('select'); ta.setAttribute('name', o.parameterName); ta.className = 'small discrete';
            for (i in o.selectOptions) {var option = document.createElement('option'); option.value=i; option.innerHTML=o.selectOptions[i]; if (o.defaultText==i) option.setAttribute('selected', 'selected'); ta.appendChild(option);}
        } else {
            var ta = document.createElement('textarea'); ta.setAttribute('name', o.parameterName); ta.setAttribute('rows', '4'); ta.value=o.defaultText;
            Event.observe(ta, 'keyup', function(e){expandTA(ta);}); Event.observe(ta, 'click', function(e){expandTA(ta);}); Event.observe(ta, 'focus', function(e){expandTA(ta);});
            if (typeof(o.maxlength)!='undefined') {ta.setAttribute('onkeyup', 'if(this.value.length>'+o.maxlength+') this.value=this.value.substring(0,'+o.maxlength+');');}
        }
        h.ta = ta; d.appendChild(ta); f.appendChild(d);
        var d = document.createElement('div');
        var submit = document.createElement('input'); submit.setAttribute('type', 'submit'); submit.setAttribute('value', 'Save'); submit.className='button';  d.appendChild(submit);
        d.appendChild(document.createTextNode(' or '));
        var cancel = document.createElement('input'); cancel.setAttribute('type', 'reset'); cancel.setAttribute('value', 'Cancel'); cancel.className='discrete'; d.appendChild(cancel);
        // Opera didn't play nice with cancel from a link; had to do it with a form reset button. Don't know why.
        //var cancel = document.createElement('a'); cancel.setAttribute('href', '#'); cancel.setAttribute('onclick', 'return(false);'); cancel.appendChild(document.createTextNode('Cancel')); d.appendChild(cancel);
        //Event.observe(cancel, 'click', function(e){c.innerHTML=''; h.has_clicked=h.has_replaced=false; c.removeClassName('editable'); c.removeClassName('editableText');});
        f.appendChild(d); c.appendChild(f);  ta.focus();
    }
    var mouseover = function(e){
        if (h.has_clicked) return;
        h.replacedHTML = c.innerHTML;
        h.has_replaced = (o.defaultText.length==0);
        if (o.defaultText.length==0) {c.innerHTML=o.message; c.addClassName('editableText');}
        c.addClassName('editable');
    }
    var mouseout = function(e){
        if (h.has_clicked) return;
        if (h.has_replaced) c.innerHTML = h.replacedHTML;
        h.has_replaced = false;
        c.removeClassName('editable'); c.removeClassName('editableText');
    }
    Event.observe(c, 'click', click); Event.observe(c, 'mouseover', mouseover); Event.observe(c, 'mouseout', mouseout);
}

visual.browse = {
    dialog:null,
    selection:[],
    begin: function(params, clear) {
	visual.browse.selection = (Cookie.get('browseSelection').length>0 ? $A(Cookie.get('browseSelection').split(',')).uniq() : []);
	if(typeof(params)=='undefined') params={};
	if(typeof(clear)!='undefined' && clear) visual.browse.clearSelection();
	if (!params.return_url) params.return_url=location.href;
	params = $H(params).toQueryString();
	visual.browse.dialog = new visual.dialog('/photos/browse', {method:'POST',postBody:params,width:910,height:500,overlay:true});
    },
    search: function() {
	var f = $('browseForm');
	// IE 5.5 doesn't support $F() for selects, so we're doing it the hard way
	params = (typeof(f.params.selectedIndex)!='undefined' ? f.params[f.params.selectedIndex].value : f.params.value);
	//params = $F(f.params);
	params += '&search_string='+encodeURI($F(f.search_string));
	indicate('browsePhotos', 'Fetching photos, please wait...');
	new Ajax.Updater('browsePhotos', '/photos/browse/include', {method:'post',postBody:params,evalScripts:true});
	if($('browseSelectAllLink')) $('browseSelectAllLink').hide();
	if($('browseUnselectAllLink')) $('browseUnselectAllLink').hide();
    },
    saving:function(){
	// Maybe the box has been closed?
	if (!$('browseCancel')) return;

	$('browseCancel').hide();
	indicate('browseSaving', 'Performing actions, please wait...');
	$$('.browse-action-button').each(function(button) {$(button).addClassName('disabled');});
    },
    notSaving:function(){
	if (!$('browseCancel')) return;
	$('browseCancel').show(); $('browseSaving').hide();
	$$('.browse-action-button').each(function(button) {$(button).removeClassName('disabled');});
    },
    select: function(img, photo_id, doUnselect) {
        if(typeof(doUnselect)=='undefined') doUnselect=true;
	var img = $(img);
	img.addClassName('opaque');

	if (visual.browse.selection.indexOf(photo_id.toString())>=0 || visual.browse.selection.indexOf(photo_id)>=0) {if (doUnselect) visual.browse.unselect($('browseSelectedImg'+photo_id), photo_id); return;}
	visual.browse.selection[visual.browse.selection.length] = photo_id.toString();
	visual.browse.selection = visual.browse.selection.uniq();
	visual.browse.saveSelection();

	var newImg = $(document.createElement('img'));
	newImg.src = img.src;
	newImg.setAttribute('id', 'browseSelectedImg'+img.getAttribute('rel'));
	newImg.setAttribute('rel', img.getAttribute('rel'));
	newImg.setStyle({width:'30px', height:'30px', padding:'1px'});
	Event.observe(newImg, 'click', function(){visual.browse.unselect(newImg, photo_id);});
	$('browseSelection').appendChild(newImg);

	visual.browse.maintainUIState();
    },
    selectAll: function() {$$('#browsePhotos img').each(function(img) {var id = img.getAttribute('rel'); visual.browse.select(img, id, false);});},
    unselect: function(img, photo_id) {
	visual.browse.selection = visual.browse.selection.without(photo_id);
	visual.browse.saveSelection();
	if ($('browseImg'+photo_id)) $('browseImg'+photo_id).removeClassName('opaque');
	img.remove();

	visual.browse.maintainUIState();
    },
    unselectAll: function() {$$('#browseSelection img').each(function(img) {var id = img.getAttribute('rel'); visual.browse.unselect(img, id);});},
    saveSelection: function() {
	if(visual.browse.selection.length)
	    Cookie.set('browseSelection', visual.browse.selection.join(','), 1);
	else
	    Cookie.erase('browseSelection');
    },
    clearSelection: function() {
	Cookie.erase('browseSelection');
	visual.browse.selection = new Array();
	visual.browse.saveSelection();
	visual.browse.maintainUIState();
    },
    maintainUIState: function() {
	// Show, hide and disable based on state

	// Unselect all & Action buttons disabled?
	if ($('browseUnselectAllLink')) {
	    if (visual.browse.selection.length) {
		$$('.browse-action-button').each(function(button) {$(button).removeClassName('disabled');});
		$('browseUnselectAllLink').show();
	    } else {
		$$('.browse-action-button').each(function(button) {$(button).addClassName('disabled');});
		$('browseUnselectAllLink').hide();
	    }
	}

	// Select all
	if ($('browseSelectAllLink')) {
	    $('browseSelectAllLink').hide();
	    $$('#browsePhotos img').each(function(img) {if (!img.hasClassName('opaque')) {$('browseSelectAllLink').show(); throw $break;}});
	}
    }
}

visual.setSelectValue = function(select, value) {for(var i=0; i<select.options.length; i++) {if(select.options[i].value==value) {select.options[i].selected=true; return;}}}
visual.handlePreview=function(){
    $A($$('input.preview')).each(function(element) {
            Event.observe(element, 'focus', function(){if(element.hasClassName('preview')) {element.removeClassName('preview'); element.value='';}});
            element.up('form').observe('submit', function(e){if(element.hasClassName('preview')) {element.removeClassName('preview'); element.value='';}});
        });
}
visual.handleEmbed=function(){
    $A($$('input.embed,textarea.embed')).each(function(element) {
            Event.observe(element, 'click', function(){element.select(); element.focus();});
        });
}
visual.addHoverClass = function(cssIdentifier, hoverClassName) {
    $A($$(cssIdentifier)).each(function(element) {
	    Event.observe(element, 'mouseover', function(){$(element).addClassName(hoverClassName);});
	    Event.observe(element, 'mouseout', function(){$(element).removeClassName(hoverClassName);});
	});
    }
visual.addSingleHoverClass = function(cssIdentifier, hoverClassName) {
    $A($$(cssIdentifier)).each(function(element) {
	    Event.observe(element, 'mouseover', function(e){$(element).addClassName(hoverClassName); Event.stop(e);});
	    Event.observe(element, 'mouseout', function(){$(element).removeClassName(hoverClassName);});
	});
    }
document.observe('dom:loaded', function(){
        visual.handlePreview();
        visual.handleEmbed();
        visual.addHoverClass('#admintabs li, #adminsubtabs li', 'hover');
        visual.addHoverClass('#contextnav li', 'hover');
        visual.addHoverClass('.context-links a.iconbutton', 'hover');
        visual.addHoverClass('.view-item div, .view-item img', 'hover');
        visual.addHoverClass('.hoverable', 'hover');
        visual.addSingleHoverClass('.object-rating-hoverable', 'object-rating-hover');
    });


function fbs_click() {u=location.href;t=document.title;window.open('http://www.facebook.com/sharer.php?u='+encodeURIComponent(u)+'&t='+encodeURIComponent(t),'sharer','toolbar=0,status=0,width=626,height=436');return false;}


function getFlexApp(appName) {return(document[appName] ? document[appName] : window[appName]);}
Event.observe(window, 'beforeunload', function(){
        try {$$('object').each(function(o){o.unloadVideoPlayer();});} catch(e){}
    });


document.observe('dom:loaded', function(){
  if(typeof(Calendar)!=='undefined'&&Calendar&&Calendar.setup) {
      $$('form.autoform input[name$=_date]').each(function(el){
          Calendar.setup({dateField: el});
        });
    }
  });

document.observe('dom:loaded', function(){
    var translatorGrid = {};
    $$('.translator-mode-translated, .translator-mode-untranslated').each(function(el){
        el.absolutize();
        var o = el.cumulativeOffset();
        while ( translatorGrid[index = [Math.floor(o.left/10), Math.floor(o.top/10)].join(',')] ) {
          o.left += 10;
          el.setStyle({left:o.left+'px'});
        }
        translatorGrid[index] = true;
        el.addClassName('translator-mode-absolutized');
        el.observe('click', function(e){
            location.href = '/manage/translate/batch?message_key='+el.getAttribute('rel')+'&return_url='+encodeURIComponent(location.href);
            e.stop();
          }.bind(el));
      });
  });


function possiblyShowAdminOptions(manage_label, video_label, design_label){
  if (Cookie.get('untrusted_user_p')=='1') {
      try {
	  var c = new Element('div', {id:'adminlinks_container'});
	  var l = new Element('div', {id:'adminlinks'}).update();
	  if (Cookie.get('untrusted_admin_p')==='1')
	      l.appendChild(new Element('a', {href:'/presentation/layout?page_key='+encodeURIComponent(visual.page.name)}).update(design_label));
	  if (visual.page.name=='video-one' && visual.photo && visual.photo.photo_id)
	      l.appendChild(new Element('a', {href:'/manage/video/'+ visual.photo.photo_id}).update(video_label));
	  l.appendChild(new Element('a', {href:'/manage'}).update(manage_label));
	  c.appendChild(l);
	  $$('body').each(function(el){el.appendChild(c);});
      }catch(e){}
  }
}

function playVideoFromSecond(sec, playerName){
  playerName = playerName||'videoplayer';
  var v = getFlexApp(playerName);
  if (v) {
    var state = v.getPlayState; 
    v.playVideo();
    window.setTimeout(function(){v.setPlayheadTime(sec);}, (state==='playing' ? 0 : 1000));
    return(false);
  } else {
    return(true);
  }
  //$(playerName).scrollTo();
};

// Component-specific functions and event-handlers
function formatTime(time) {
  time = Math.round(time) || 0;

  var hour = Math.floor(time/3600);
  time = time - (hour*3600);
  var min = Math.floor(time/60).toString();
  var sec = Math.round(time%60).toString();
  
  var t = [];
  if (hour>0) t.push(hour);
  t.push(min.length==1 ? '0'+min : min);
  t.push(sec.length==1 ? '0'+sec : sec);
  return(t.join(':'));
}

function watchIntervals(selector){
  new PeriodicalExecuter(function(){
      $$(selector).each(function(int){
          int.innerHTML = formatTime((+(new Date)/1000.0) - new Number(int.getAttribute('rel')));
        });
    }, .05);
}



function lookupAddress(address) {
  var results = [];
  doAction('coordinate-lookup', $H({address:address, limit:10}).toQueryString(), {asynchronous:false, onSuccess:function(r){
        results = eval(r.responseText);
      }});
  return(results);
}
function lookupAddressForBlock() {
  var address = prompt("Which address do you want to center on?");
  if(!address || !address.length) return(false);
  var r = lookupAddress(address); 
  if(r.length>0){
    document.forms.block.center_latitude.value=r[0].latitude; 
    document.forms.block.center_longitude.value=r[0].longitude;
  } else {
    alert("The address was not found");
  } 
  return(false);
}

var CoordinateSelector = function(photo_id){
  var $this = this;
  $this.photo_id = photo_id;
  $this.map = null;
  $this.results = [];
  $this.markers = [];
  $this.marker = function(lat, lng, zoom, eventHandler) {
    // Clear existing markers
    $A($this.markers).each(function(m){m.setMap(null);})
    $this.markers = [];
    // Place a marker
    var point = new google.maps.LatLng(lat,lng);
    var image = new google.maps.MarkerImage('/resources/um/graphics/maps-add-marker.png', new google.maps.Size(133, 37),new google.maps.Point(0,0), new google.maps.Point(16, 37));
    var shadow = new google.maps.MarkerImage('/resources/um/graphics/maps-add-marker-shadow.png', new google.maps.Size(152, 37), new google.maps.Point(0, 0), new google.maps.Point(16, 37));
    var marker = new google.maps.Marker({position:point, map:$this.map, icon:image, shadow:shadow});
    google.maps.event.addListener(marker, 'click', eventHandler);;
    $this.markers.push(marker);
    // Possibly zoom and center to POI
    if(zoom) {
      $this.map.setCenter(point);
      $this.map.setZoom(14);
    }
    return(marker);
  };
  $this.select = function(index) {
    var o = $this.results[index];
    
    $this.marker(o.latitude, o.longitude, true, function(e){
        var params = o;
        o['photo_id'] = $this.photo_id;
        doAction('coordinate-add', $H(o).toQueryString(), {onSuccess:function(r){
              location.href = '?mode=maps';
            }});
      });
  };
  $this.search = function(address) {
    doAction('coordinate-lookup', $H({address:address, limit:5}).toQueryString(), {onSuccess:function(r){
          $this.results = eval(r.responseText);
          var container = $$('.visualmap-results')[0];
          container.innerHTML = '';
          if($this.results.length==0) {
            alert('No results to your search');
          }
          $A($this.results).each(function(res,index){
              var li = new Element('li');
              var a = new Element('a', {href:'#'});
              a.observe('click', function(e){
                  e.stop();
                  $this.select(index);
                });
              a.update(res.formatted_address);
              li.appendChild(a);
              container.appendChild(li);
            });
        }});
  };

  // Update maps on the currently selected list
  $$('.visualmap-list .visualmap-canvas').each(function(canvas){
      var coords = canvas.innerHTML.replace(/^\s+/,'').replace(/\s+$/,'');

      if(/^[0-9\-\.\,]+$/.test(coords)) {
        var latlng = new google.maps.LatLng(coords.split(',')[0], coords.split(',')[1]);
        var map = new google.maps.Map(canvas, {zoom:14, center:latlng, mapTypeId:google.maps.MapTypeId.ROADMAP, streetViewControl:false, mapTypeControl:false});
        var marker = new google.maps.Marker({position:latlng, map:map});
      }
    });

  // Place the map
  $$('.visualmap-select .visualmap-canvas').each(function(canvas){
      var newyork = new google.maps.LatLng(40.69847032728747, -73.9514422416687);
      $this.map = new google.maps.Map(canvas, {zoom:2, center:newyork, mapTypeId:google.maps.MapTypeId.ROADMAP, streetViewControl:false, mapTypeControl:true});
      // Listen to click events
      var dblclicked = false;
      google.maps.event.addListener($this.map, 'dblclick', function(e){dblclicked = true;});
      google.maps.event.addListener($this.map, 'click', function(e) {
          dblclicked = false;
          window.setTimeout(function(){
              if(!dblclicked) {
                var lat = e.latLng.lat();
                var lng = e.latLng.lng();
                $this.marker(lat, lng, false, function(){
                    doAction('coordinate-add', $H({photo_id:$this.photo_id, latitude:lat, longitude:lng}).toQueryString(), {onSuccess:function(r){
                          location.href = '?mode=maps';
                        }});
                  });
              }
              dblclicked = false;
            }, 300);
        });
    });

  return(this);
};

// Replace in editable html fields on each textarea.htmledit
document.observe('dom:loaded', function(){
    $$('textarea.htmledit').each(function(textarea){
        try {
          var editor = CodeMirror.fromTextArea(textarea, {
              height: "450px",
              parserfile: "parsexml.js",
              stylesheet: ["/resources/um/script/codemirror/css/xmlcolors.css", "/resources/um/style/codemirror.css"],
              path: "/resources/um/script/codemirror/js/",
              continuousScanning: 500,
              lineNumbers: true
            });
        }catch(e){console.debug(e);}
      });
  });

// Update maps in the front to be pretty
function buildVisualMap(){
  $$('.visualmap-canvas').each(function(canvas){
      // Read out settings
      if(!canvas.hasAttribute('rel')) return;
      var settings = canvas.getAttribute('rel').split(',');
      var centerLatitude = new Number(settings[0]||0)+0;
      var centerLongitude = new Number(settings[1]||0)+0;
      if(centerLatitude&&centerLongitude) {
        var center = new google.maps.LatLng(centerLatitude,centerLongitude);
      } else {
        var center = new google.maps.LatLng(40.69847032728747, -73.9514422416687);
      }
      var zoom = new Number(settings[2]||0)+0;
      var mapType = settings[3].toUpperCase();
        
      var mapTypeControl = (settings[4]=='1' || settings[4]=='t');
      var zoomControl = (settings[5]=='1' || settings[5]=='t');
      var overviewMapControl = (settings[6]=='1' || settings[6]=='t');
      var streetViewControl = (settings[7]=='1' || settings[7]=='t');
        
      // Create and show the map
      var mapContainer = new Element('div', {className:'visualmap-map'});
      mapContainer.setStyle({height:canvas.getHeight()+'px', width:canvas.getWidth()+'px'}); // We need this for IE
      canvas.appendChild(mapContainer);
      map = new google.maps.Map(mapContainer, {zoom:zoom, center:center, mapTypeControl:mapTypeControl, zoomControl:zoomControl, overviewMapControl:overviewMapControl, streetViewControl:streetViewControl, mapTypeId:google.maps.MapTypeId[mapType]});
        
      // Now, add some markers
      var bounds = new google.maps.LatLngBounds();
      canvas.select('.visualmap-marker').each(function(markerContent){
          var coords = markerContent.getAttribute('rel').split(',');
          var point = new google.maps.LatLng(coords[0], coords[1]);
          bounds.extend(point);
          var marker = new google.maps.Marker({position:point, map:map});
            
          if(markerContent.innerHTML.length>0) {
            // Show info window with a pop-up and thumbnail
            var info = new google.maps.InfoWindow({content:markerContent.innerHTML});
            google.maps.event.addListener(marker, 'click', function() {
                info.open(map,marker);
              });
          } else {
            // Just link the marker
            var href = markerContent.getAttribute('href');
            google.maps.event.addListener(marker, 'click', function() {
                location.href = href;
              });
          }
        });
      // Zoom and center the map
      if(zoom>0) {
        map.setZoom(zoom);
        if(!centerLatitude || !centerLongitude) map.setCenter(bounds.getCenter());
      } else {
        if(!centerLatitude || !centerLongitude) map.fitBounds(bounds);
      }
    });
}
Event.observe(window, 'load', function(){buildVisualMap()});
