var Notice = {
	//if you set this to true then infinite notices can pile up on the screen
	//if false, then only one notice will show up (the last one set)
	enable_multiple_notices:false,
	last_notice:null,
	pulsate:function(id){
		new Effect.Pulsate(id, {pulses:1, duration:0.25});
	},
	pulsate2x:function(id){
		new Effect.Pulsate(id, {duration:1.0, pulses:2});
	},
	shake:function(id){
		new Effect.Shake(id, {duration:0.25});
	},
	flash_ok:function(id){
		new Effect.Highlight($(id), {startcolor:'#91e852', keepBackgroundImage:true, duration:0.5});
	},
	flash_text_ok:function(id){
		var end_color = $(id).style.color;
		
		//if the sender element does not have a specific color set we assume black othwise the second morph breaks
		if(end_color==null || end_color == undefined || end_color=='') end_color = '#000';
		
		new Effect.Morph(id, {style:{color:'#6bff00'}, duration:0.1});
		setTimeout(function(){
			new Effect.Morph(id, {style:{color:end_color}, duration:0.25});
		},200);
	},
	flash_error:function(id){
		new Effect.Highlight($(id), {startcolor:'#ec0000', keepBackgroundImage:true, duration:0.5});
	},
	flash_text_error:function(id){
		var end_color = $(id).style.color;
		
		//if the sender element does not have a specific color set we assume black othwise the second morph breaks
		if(end_color==null || end_color == undefined || end_color=='') end_color = '#000';
		
		new Effect.Morph(id, {style:{color:'#ff0000'}, duration:0.1});
		setTimeout(function(){
			new Effect.Morph(id, {style:{color:end_color}, duration:0.25});
		},200);
	},
	clear_all:function(){
		$$('a_bar_any').each(function(t){if(!t.hasClassName('a_bar_prototype')){t.remove()}});
	},
	/*responds to a server request's return object with a positive or negative UI feedback*/
	respond:function(r){
		if(r.ok){
			Notice.text(r.msg);
		}else{
			Notice.warn_text(r.msg);
		}
	},
	//syntactic sugar is Warn(m)
	warn_text:function(m){
		//pulse the screen red?
		if(m==undefined || m==null || m.length==0) return;
		Notice.create({text:m, is_error:true});
	},
	accept_text:function(m){
		//pulse the screen red?
		if(m==undefined || m==null || m.length==0) return;
		Notice.create({text:m, back_img_override:'accept'});
	},
	//calling from outer wrapper so you don't have to click on the colored portion of the bar to kill
	//the notice
	dismiss_outer:function(o){
		try{
			Notice.dismiss($(o).childElements()[1]);
		}catch(ex){}
	},
	dismiss:function(o){
		//IE will not recognize when the user clicks on the info bar, and when it recognizes
		//a click on the close X it does things oddly. so we process IE separately.
		if(BrowserDetect.ie7 || BrowserDetect.ie8){
			//in case the element is deleted already
			try{
				if(o.nodeName.toLowerCase()=='a'){
					$(o).up().up().remove();
				}else{
					$(o).remove();
				}
			}catch(ex){}
		}else{
			try{
				o=$(o);
				try{
					if(!o.hasClassName('a_bar_any')){
						o = o.up('div')[0].up();
					}
				}catch(ex){}//who cares--thrown if they click the x, not the bar.
				//new Effect.Fade(o, {duration:0.5});
				//setTimeout(function(){o.remove();},500);
				o.remove();
			}catch(ex){}//in case the element was deleted
		}
	},
	//syntactic sugar is Say(m)
	text:function(m){
		//do not show blank messages, this makes no sense to show nothing (regardless of the debug value...)
		if(m==undefined || m==null || m.length==0) return;
		Notice.create({text:m});
	},
	//does a text notify that does not auto-hide for 5 min
	warn_permanent:function(text){
		if(m==undefined || m==null || m.length==0) return;
		Notice.create({text:m,period:300000});
	},
	create:function(args){
		
		if(!this.enable_multiple_notices && this.last_notice != null){
			this.dismiss(this.last_notice);
			this.last_notice = null;
		}
		
		var style = 'a_bar_notification';
		var period=7000;
		
		if(args.is_error===true) style = 'a_bar_error';
		if(args.period>0) period = args.period;
		
		var back_img_override = '';
		
		//allow the icon to the left of the message to be changed
		if(args.back_img_override != null){
			back_img_override = ' style="background-image:url(/images/edit/' + args.back_img_override + '.png);" ';
		}
		
		var html = '<div class="not_content" ' + back_img_override + '>' + args.text + '</div>';
		
		
		
		var a = new Element('div', { 'class': 'a_bar_any', onclick: 'Notice.dismiss(this);' }).update(html);
		a.addClassName(style);
		
		this.last_notice = a;
		
		setTimeout(function(){
			Notice.dismiss(a);
			this.last_notice = null;
		}, period);
		
		
		$('notifications').childElements()[$('notifications').childElements().length-1].insert({after:a});
		
	}
}

//syntactic sugar
function Say(m){
	Notice.text(m);
}

//syntactic sugar
function Warn(m){
	Notice.warn_text(m);
}



//Sheet.show('yo');
//ONLY use these methods for temporary sheets--they delete the sheet div on close, so will mess up persisting sheets
var Sheet = {
	zindexbase:1001,
	count:0,
	
	// the main entry/exit points
	open:function(name){
		Sheet.show_this_one('sheet_static_'+name);
	},
	close:function(name){
		Sheet.hide_this_one('sheet_static_'+name);
	},
	
	show_this_one:function(id){
		Sheet.show_blur_check();
		$(id).style.zIndex = Sheet.zindexbase;//important--allows for seamless stacking
		$(id).show();
	},
	hide_this_one:function(id){
		$(id).hide();
		Sheet.hide_blur_check();
	},
	show:function(html){
		// $('infobox_html').update(html);
		Sheet.show_box(html);
	},
	show_box:function(msg){
		this.show_blur_check();
		
		var html = '<div class="infobox_hide"><a href="#" onclick="Sheet.hide(this);return false;"><img src="/images/ui/blank.gif" width="32" height="32"/></a></div><div id="infobox_html">'+msg+'</div>';
		
		var a = new Element('div', { 'class': 'infobox_sheet'}).update(html);
		a.style.zIndex = Sheet.zindexbase;
		
		$('infoboxes').childElements()[$('infoboxes').childElements().length-1].insert({after:a});
	},
	hide:function(o){
		o=$(o);
		o.up().up().remove();
		
		this.hide_blur_check();
	},
	//handles logic to keep page dimmer & zindices working
	show_blur_check:function(){
		Page.blur();
		Sheet.zindexbase += 1;
		Sheet.count += 1;
	},
	//handles logic to keep page dimmer & zindices working
	hide_blur_check:function(){
		Sheet.count -= 1;
		if(Sheet.count==0) Page.focus();
	}
}

//only for ok/cancel dialogues
//hmm this looks like it only supports a single ok/cancel at a time. should be
//ok though since you cannot spawn an action from these. or you could, but you
//shouldn't, logically
//however these should actually be queued up, because when you chain them together it sort of breaks in that
//you need to use setTimeout to keep from hiding the second sheet you just asked for.
var Dialogue = {
	text:function(m){
		Dialogue.show({html:m});
	},
	//if an array turns into nice html, otherwise returns as-is
	turn_array_into_html:function(a){
		if(a.constructor.toString().indexOf("Array") == -1){
			return a;
		}else{
			var h = '';
			if(a.length>0){
				h = '<h1>' + a[0] + '</h1>';
				for(i=1;i<a.length;i++){
					h += '<p>' + a[i] + '</p>';
				}
			}
			return h;
		}
	},
	//show:function(img,html,on_ok,on_cancel,ok_label,cancel_label){
	show:function(args){
		//check for empty callbacks
		if(args.on_ok==null) args.on_ok = function(){};
		if(args.on_cancel==null) args.on_cancel = function(){};
		
		//check for no labels
		if(args.ok_label==null) args.ok_label = "Ok";
		if(args.cancel_label==null) args.cancel_label = "Cancel";
		
		//update html
		var the_html = Dialogue.turn_array_into_html(args.html);
		$('vh_dialogue_content_holder').update(the_html);
		
		//assign generic or custom icon
		if(args.img!=null){
			$('vh_dialogue_content_holder').style.backgroundImage = 'url('+args.img+')';
		}else{
			$('vh_dialogue_content_holder').style.backgroundImage = 'url(/images/edit/info.png)';
		}
		
		//wire up cancel and ok buttons
		if(args.suppress_cancel_button){
		  $('dialogue_button_cancel').hide();
		}else{
		  $('dialogue_button_cancel').show();
		}
		
		$('dialogue_button_cancel').value = args.cancel_label;
		
		$('dialogue_button_cancel').onclick = function(){
			try{
				args.on_cancel();
			}catch(ex){
				Notice.text(ex);
			}
			Dialogue.hide_dialogue();
		};
		
		$('dialogue_button_ok').value = args.ok_label;
		
		$('dialogue_button_ok').onclick = function(){
			try{
				args.on_ok();
			}catch(ex){
				Notice.text(ex);
			}
			Dialogue.hide_dialogue();
		};
		
		//show the completed UI
		Dialogue.show_diaglogue();
	},
	resize_dialogue:function(){
		var d = $('dialogues');
		var inner = d.select('.vh_dialogue_content')[0];
		var h = inner.getHeight();
		
		var middle = d.select('.vh_dialogue_middle')[0];
		
		var middle_height = h - 131;
		if(middle_height < 1) middle_height = 1;	//keep a min height
		
		
		middle.style.height = middle_height.toString() + 'px';
		
		d.style.top = '50%';
		d.style.marginTop = '-' + (d.getHeight()/2).toString() + 'px';
	},
	hide:function(){
		Dialogue.hide_dialogue();
	},
	show_diaglogue:function(){
		Page.blur();
		
		if(BrowserDetect.ie6){
			$$('.content select').each(function(t){
				if($(t).visible()){
					t.addClassName('ie_only_hide');
				}
			});
		}
		
		$('dialogues').show();
		//resize to fit content
		Dialogue.resize_dialogue();
	},
	hide_dialogue:function(){
		$('dialogues').hide();
		if(Sheet.count==0){
			Page.focus();
		}
		if(BrowserDetect.ie6){
			$$('.ie_only_hide').each(function(t){t.removeClassName('ie_only_hide');});
		}
	},
	make_red:function(name){
		$(name).removeClassName('green_528_box');
		$(name).addClassName('red_528_box');
	},
	make_green:function(name){
		$(name).removeClassName('red_528_box');
		$(name).addClassName('green_528_box');
	},
	make_normal:function(name){
		$(name).removeClassName('red_528_box');
		$(name).removeClassName('green_528_box');
	}
}

//todo--track how many open items there are that require the page to be blurred, and only un-blur when that number is zero.
var Page = {
  spinny_timers:{},
  //under 200ms response time is instant
  start_spinning:function(o){
    Page.start_spinning_actual(o,Page.spinny_html);
  },
  start_spinning_small:function(o){
    Page.start_spinning_actual(o,Page.spinny_small_img);
  },
  //separated out because we have a few different spinners depending on where on the page the element is
  start_spinning_actual:function(o,spin_html){
    if(Page.spinny_timers[o] != null){
      clearTimeout(Page.spinny_timers[o]);
    }
    Page.spinny_timers[o] = setTimeout(function(){
      //not sure why but ff throws errors sometimes on this
			try{
				if($(o).innerHTML.strip()==''){
					$(o).update(spin_html);
				}else{
					$(o).setOpacity(0.2);
				}
			}catch(e){}
    }, 250);
  },
  stop_spinning:function(o){
    if(Page.spinny_timers[o] != null){
      clearTimeout(Page.spinny_timers[o]);
    }
		$(o).setOpacity(1);
  },
	spinny_html:'<div class="spinny_for_dialogues"></div>',
	black_spinny_html:'<div class="black_spinny_for_dialogues"></div>',
	spinny_small_img:'<img src="/images/ui/spinny_small.gif" />',
	blur:function(){
		$('page_dim').show();
	},
	white_out:function(){
		$('page_dim_2').show();
	},
	focus:function(){
		$('page_dim').hide();
	}
}





var Tooltip = {
	x:0,
	y:0,
	x_incr:10,
	y_incr:10,
	visible:false,
	show:function(m){
		Tooltip.y_incr = 10;
		Tooltip.visible=true;
		$('tooltip').update(m);
		$('tooltip').show();
	},
	show_up:function(m){
		Tooltip.y_incr = -20;
		Tooltip.visible=true;
		$('tooltip').update(m);
		$('tooltip').show();
	},
	hide:function(){
		Tooltip.visible=false;
		$('tooltip').hide();
	},
	mousemove:function(evt){
		if(Tooltip.visible){
			Tooltip.x=evt.pointerX();
			Tooltip.y=evt.pointerY();
			$('tooltip').style.left = Tooltip.x+Tooltip.x_incr+'px';
			$('tooltip').style.top = Tooltip.y+Tooltip.y_incr+'px';
		}
	}
}





var Help = {
	open:function(name){
		Sheet.show_this_one('sheet_about_'+name);
	},
	close:function(name){
		Sheet.hide_this_one('sheet_about_'+name);
	}
}




// variable height sheet
var Poster = {
	//if there is a javascript function in the div with class on_open then this
	//will spin the dialogue, hide the buttons in .poster_buttons and call that function. after it calls that function, it
	//will resize the dialogue appropriately and show the buttons in .poster_buttons
	//the function passed via the div MUST take two parameters, the callback that resizes
	//the div, passed first, and the object where content may be placed.
	//it is up to that function to draw html or whatever on the screen.
	//all this is async friendly, so you can load html from the server or whatever.
	show:function(name){
		var pname = 'poster_'+name;
		var js_open = $(pname).select('.on_open');
		Sheet.show_this_one(pname);
		if(js_open.length>0){
			//we open through a callback
			//first spin the content
			var the_content_area = Poster.find(name).select('.poster_content_holder')[0];
			Page.start_spinning(the_content_area);
			//fit to spinner to center on screen
			Poster.fit_poster_to_content(pname);
			
			//hide buttons
			var buttons = Poster.find(name).select('.poster_buttons')[0];
			if(buttons != null){
				buttons.hide();
			}
			
			var load_and_show = function(callback, the_content_area){
				eval(js_open[0].innerHTML);
			};
			
			load_and_show.apply(this, [function(ok, inspect_r, final_callback){
				if(final_callback != null){//never null for use from PosterController
					final_callback.apply(this, [inspect_r, function(){
						Poster.fit_poster_to_content(pname);
						if(buttons != null){
							buttons.show();
						}
						if(!ok) Poster.flash_error(the_content_area);
					}]);
				}else{
					Poster.fit_poster_to_content(pname);
					if(buttons != null){
						buttons.show();
					}
					if(!ok) Poster.flash_error(the_content_area);
				}
			}.bind(this), the_content_area]);
			
		}else{
			Poster.fit_poster_to_content(pname);
		}
	},
	//a sample function that you could place in the .on_open div that would
	//work.
	sample_on_open_called_function:function(callback, the_content_area){
		//do async here
		setTimeout(function(){
			$(the_content_area).update('<p>loaded via async</p><p>loaded via async</p>');
			Page.stop_spinning(the_content_area);
			callback();
		}.bind(this), 500);
	},
	hide:function(o){
		var pstr = this.find(o);
		
		//hide it
		Sheet.hide_this_one(pstr.id);
		
		if(BrowserDetect.ie6){
			$$('.ie_only_hide').each(function(t){t.removeClassName('ie_only_hide');});
		}
	},
	flash_ok:function(o){
		var pstr = this.find(o).select('.poster_content')[0];
		Notice.flash_ok(pstr);
	},
	flash_error:function(o){
		var pstr = this.find(o).select('.poster_content')[0];
		Notice.flash_error(pstr);
	},
	find:function(o){
		if(typeof o == 'string'){
			//a string name passed in
			return $('poster_'+o);
		}else{
			//an object reference passed in
			o=$(o);
			return o.up('.poster_sheet');
		}
	},
	fit_poster_to_content:function(o){
		var d = $(o);
		var inner = d.select('.poster_content')[0];
		var middle = d.select('.poster_middle')[0];
		var content_area = d.select('.poster_content_holder')[0];
		
		//since we set this later here we need to reset it first otherwise we get
		//an infinite loop of smaller and smaller ones
		content_area.style.height = 'auto';
		
		var h = inner.getHeight();
		
		//min height is 50 so that we have enough room for buttons, should they be there
		var middle_height = h - 90;
		if(middle_height < 50) middle_height = 50;	//keep a min height
		
		//defined by the screen
		var max_middle_height = document.viewport.getHeight() - 250;
		
		if(middle_height > max_middle_height) middle_height = max_middle_height
		
		middle.style.height = middle_height.toString() + 'px';
		content_area.style.height = (middle_height + 50).toString() + 'px';
		
		d.style.top = '50%';
		d.style.marginTop = '-' + (d.getHeight()/2).toString() + 'px';
		
		
		if(BrowserDetect.ie6){
			$$('.content select').each(function(t){
				t.addClassName('ie_only_hide');
			});
		}
	}
}































