
/****************************************************************
by Peter Buchmann 2010_06
The essential construct is the class_slideshow. 
It is a class, with member variables and methods, and can be instantiated
The actual implementation of the class is done as a function
	This function has member variables, some of them are scalar, others array and some are "inner" functions serving as methods
	Despite the crude syntax, we successfully emulate a Java Class this way.
	For all practically thinking people, the naming is explicit
	Autistic people may CHANGE naming to their two character lingo at will
*****************************************************************/


// default values; change before instantiating
var def_slideshow_autostart=1;       //0 - user start, 1 - autostart
var def_img_path='http://www.mowitania.de/Ferienwohnung/pics_slides1/';
var def_max_pic_width=320;           //set this to the width of your widest pic, pics are centered inside stage
var def_max_pic_height=120; 

var def_stage_id="stage1";        //the id of the div container that will hold the slideshow
var def_stage_bg_color="#005066";    // hint: set to body-background-color if not all your pics fill out the stage
var def_stage_show_controls=0;       //0 - no; 1 - yes
var def_stage_control_pics_arr=new Array ('pics_control/bwd.png', 'pics_control/start.png', 'pics_control/stop.png', 'pics_control/fwd.png');  //into this array insert the paths of your stage_control_pics_arr ol-buttons or the text to display e.g. back,start,stop,fwrd.

var def_slide_duration=2.5;            //seconds to show a pic between fades in seconds
var def_transition_duration=0.5;       //seconds of a complete fade in seconds
var def_transition_steps=8;         //steps of a transition, steps to fade from on pic to the next

var def_do_fade_out=0;         // also decrease opacity of previous img?
// set this, for a smoother "blending" of pic1 into pic2...
// however there may be slight changes in brightness, in the identical parts of the blended pics.
// cause the alpha values do not always add up to 100%

var def_max_opac=100;         // maximale deckungskraft, von/bis zu der überblendet wird


//****************************************************************


function render_message(message, append){
	return;

	append = typeof(append) != 'undefined' ? append : false;
	window.status = message;
	var msg_area = document.getElementById('msg_area');
	if( msg_area ){
		if( append ){
			msg_area.innerHTML = '';
		}
		msg_area.innerHTML += message +  '<br>';
	} else {
		window.status += ' (msg_area is not defined or GET dbgjs is not set) ';
	}
}


// no.1 of two helpers, that COULD be moved inside the object 
//	if this emulation of object oriented programming with javascript WOULD support methods with parameters
function pad2(int_arg){
	padded = int_arg.toString();
	if(padded.length == 1) padded = "0"+padded;
	return padded; 
}

// no.2 of two helpers, that COULD be moved inside the object - Nr2.
function set_img_opacity(img, val,max_opac){
	if( val == max_opac ){
		// no idea what this is for
		try{img.style.removeAttribute("filter");} catch(err){}
	}
	img.style.filter="Alpha(Opacity="+(val.toString())+")";
	img.style.MozOpacity= Math.round(val)/100;
	img.style.opacity=Math.round(val)/100;
}

// addding a function call to the onload-event
// previously added function calls are preserved
function onload_queue_append(add_fct){
	if( window.onload ){
		var fcts_before=window.onload;
		window.onload=function(){
			fcts_before();
			add_fct();
		};
	}else{
		window.onload=function(){add_fct();};
	}
}

/*

	AND NOW THE CLASS

	essential merits:
		Images are not all loaded at once (time).
		Images are dynamically loaded, as long as they are sequentially named. No need to maintain a filename array.
		Synchronicity problems when rendering dynamic HTML (and the browser has not yet updated the DOM) are handled.

	drawbacks
		no shuffle or randomize of images sequence, as they are loaded only one at a time

	still questionable
		I adopted the innerHTML code from predecessor.
		We rely on the <img> Tag to automtically shink/epxand to whatever the loaded src-file dimensions are.
		We also rely on vertical alignment based on a huge line-height with the image tag positioned like a piece of TEXT.
			img:  vertical-align:middle;
			surrounding div: text-align:center;
		But this centering technique only works when the stage is higher/wider than the content.
		Also: In firefox it seems to be impossible to reset the stage width and height.

		=> Maybe an implementation with a CSS background-image of a DIV would be more appropriate.
			But then the "alpha blending" would have to be done with some overlaying element
	




	command flow:
		The javascript-file-include defines defaults and defines the class class_slideshow.

		The javascript-file-include creates an instance of class_slideshow(), 
			which attaches the method class_slideshow.init_slideshow() to the document.onload event.

		Then the web browser moves on with rendering the html page.

		We become active again, when document.load calls init_slideshow().

		load_image_into_memory() creates the first, or a further image object
			upon first time, load_image_into_memory() also sets up the innerHTML with two images
			who alternately will be used to fadeout and fadein succeeding images

		after first/further images have been LOADED by load_image_into_memory()
		show_next_slide() DISPLAYS the images and initiates fading ins and fading outs (transition).

		If a transition is complete, load_image_into_memory() is called.
		If load_image_into_memory() cannot find a further image, it resets the image counter


		show_next_slide()  sets up to objects img_fadeout and img_fade_in (image to fade out, image to fade in) 
			and calls exec_one_fading_step()
		exec_one_fading_step() sets up the next timer firing 
		 either to exec_one_fading_step() or to show_next_slide()

*/



function class_slideshow(
	 dummy
	,arg_slideshow_autostart   
	,arg_img_path
	,arg_max_pic_width
	,arg_max_pic_height
	,arg_stage_id
	,arg_stage_bg_color
	,arg_stage_show_controls
	,arg_stage_control_pics_arr
	,arg_slide_duration
	,arg_transition_duration
	,arg_transition_steps
	,arg_do_fade_out
	,arg_max_opac
	){

	/*
		The following is an ugly  mix of constructor, setters and defaults
		Each member variable takes its value either from the constructor argument (arg_xxx)
		 or from the default setting which is expected to be defined outside
		 kinda "java on crutches", but I leave it from my revered precessors
	*/

	var slideshow_autostart     =(arg_slideshow_autostart)     ?arg_slideshow_autostart     : def_slideshow_autostart;
	var img_path                =(arg_img_path)                ?arg_img_path:def_img_path;
	var max_pic_width           =(arg_max_pic_width)           ?arg_max_pic_width:def_max_pic_width;
	var max_pic_height          =(arg_max_pic_height)          ?arg_max_pic_height:def_max_pic_height;
	var stage_id                =(arg_stage_id)                ?arg_stage_id:def_stage_id;
	var stage_bg_color          =(arg_stage_bg_color)          ?arg_stage_bg_color:def_stage_bg_color;
	var stage_show_controls     =(arg_stage_show_controls)     ?arg_stage_show_controls:def_stage_show_controls;
	var stage_control_pics_arr  =(arg_stage_control_pics_arr)  ?arg_stage_control_pics_arr:def_stage_control_pics_arr;
	var slide_duration          =(arg_slide_duration)          ?arg_slide_duration:def_slide_duration;
	var transition_duration     =(arg_transition_duration)     ?arg_transition_duration:def_transition_duration;
	var transition_steps        =(arg_transition_steps)        ?arg_transition_steps:def_transition_steps;
	var do_fade_out             =(arg_do_fade_out)             ?arg_do_fade_out:def_do_fade_out;
	var max_opac                =(arg_max_opac)                ?arg_max_opac:def_max_opac;


	var self = this;	// in every method, this is set to some calling/parent object. here we memorize the class_slideshow into self
	var sig_stop=1;   // internal variable, signalling, that the stop button was clicked
	var sig_s11p=0;   // stop the fading; an odd concept from the predessor; not changed any longer


	var ms_fade_step=transition_duration*1000/transition_steps;
	var ms_slide_step=slide_duration*1000;
	var timer_id;	    // the id of the currently active timer function
	var images_assign_callbacks=0;

	var opacity_increment=max_opac/transition_steps;
	var cntr_fade=0;	 // counter to transition_steps

	var img_arr = new Array();		// the array with the dom image objects, over which we will iterate over
	var img_total=0;              // length of img_arr; maybe LONGER than the actual number of images; is iterated till the entry is 'does_not_exist'
	var cntr_slide=1;             // which slide is to be shown next

	var img1, img2;               // two visible image objects, holding revolving references to img_arr
	var wrapper1, wrapper2;       // the enveloping divs need their zIndex inverted

	// references to either img1 or img2, wrapper1, wrapper2; alternating
	var img_fadeout,img_fade_in;   
	img_fade_in='init';
	var wpr_fadeout,wpr_fade_in;   

	this.init_slideshow = function(){
		self.show_next_slide();
	}
	// append the "this.setup_stage" method to the document.onload method queue.
	onload_queue_append(this.init_slideshow);




	/*
		prepare current and next and trigger slide
			z-index of img_fade_in is set larger than img_fadeout
			then the opacity of img_fade_in is increased. 
			exec_one_fading_step() calls itself kinda recursively "transission-steps"-times.
	*/
	this.show_next_slide = function(){

		clearTimeout(timer_id);
		cntr_fade=0;

		//render_message('show_next_slide ' + cntr_slide + ' - start');

		if( cntr_slide > img_arr.length ){
			self.load_image_into_memory_start();
			return;
		}

		
		if( img_arr[cntr_slide-1] == 'not_loaded_yet' ){
			self.load_image_into_memory_start();
			return;
		}
		
		if( img_arr[cntr_slide-1] == 'does_not_exist' ){
			cntr_slide=1;
			self.show_next_slide();
			return;
		}
		
		// first image condition
		if(img_arr.length==1){
			self.setup_stage();  // only done once	
			img1.src = img_arr[0].src;  // no fadein, instead directly show first image
			if( max_opac != 100 ){
				set_img_opacity(img1,max_opac,max_opac);
			}
			cntr_slide=cntr_slide+1;

			if(slideshow_autostart){
				sig_stop=0;
				timer_id=setTimeout(function(){self.show_next_slide();},ms_slide_step);
			}
			return;
		}
		
		
		//render_message('show_next_slide ' + cntr_slide + ' - pos1');


		//if( (cntr_slide%2)== 0)
		if(  img_fade_in == img1 ||  img_fade_in == 'init'){
			//render_message('show_next_slide ' + cntr_slide + ' - alternate1');
			img_fadeout = img1;
			img_fade_in = img2;
			wpr_fadeout = wrapper1;
			wpr_fade_in = wrapper2;
		} else {
			//render_message('show_next_slide ' + cntr_slide + ' - alternate2');
			img_fadeout = img2;
			img_fade_in = img1;
			wpr_fadeout = wrapper2;
			wpr_fade_in = wrapper1;
		}

		wpr_fadeout.style.zIndex=1;
		wpr_fade_in.style.zIndex=2;

		img_fade_in.src = img_arr[cntr_slide-1].src;
		set_img_opacity(img_fade_in,1,max_opac);  // a tiny bit larger than null
		// set_img_opacity(img_fadeout,max_opac-1,max_opac);       // redundant

		img_fadeout.style.visibility="visible";     // seems redundant, but IE requires this
		wpr_fadeout.style.visibility="visible";     // seems redundant, but IE requires this


		img_fade_in.style.visibility="visible";      // bugfix for IE; IE sets visibility to invisble on itself
		wpr_fade_in.style.visibility="visible";


		if(sig_s11p==0){
			//this.exec_one_fading_step();
			timer_id=setTimeout(function(){self.exec_one_fading_step();},ms_fade_step);
		}
	}



	/*
		carries out ONE transitionstep
		at the end, either recalls itself for the next transitionstep
		or sets up the entire NEXT transition
	*/
	this.exec_one_fading_step = function(){
		var alpha_ist,alpha_max,alpha_soll;

		cntr_fade=cntr_fade+1;

		alpha_soll=max_opac-opacity_increment*(cntr_fade);
		if( alpha_soll < 1 ) alpha_soll=1; // catch calc errors
		if(do_fade_out){
			set_img_opacity(img_fadeout,alpha_soll,max_opac);
		}

		alpha_soll=opacity_increment*(cntr_fade);
		if( alpha_soll >(max_opac-1) ) alpha_soll=max_opac; // catch calc errors
		set_img_opacity(img_fade_in,alpha_soll,max_opac);

		if(cntr_fade<transition_steps){     
			//transition not finished, prepare another cntr_fade timer call 
			if(sig_s11p==0){
				timer_id=setTimeout(function(){self.exec_one_fading_step();},ms_fade_step);
			} else {
				self.show_next_slide();
			}
		}else{ 
			//transition finished
			set_img_opacity(img_fade_in,max_opac,max_opac);
			wpr_fadeout.style.visibility="hidden";
			cntr_fade=0;


			cntr_slide=cntr_slide+1;
			if(sig_stop==0){
				timer_id=setTimeout(function(){self.show_next_slide();},ms_slide_step);
			}

		}
	}


	/*
		inserts initial html into the stage
	*/
	this.setup_stage= function(){


		var stage_html="";
		var z_index1, visibility1, sub_id, init_img;
		var the_stage;
		var wrapper_bg_color;


		if(stage_show_controls){
			var cntr_img;
			for(cntr_img=1;cntr_img<=4;cntr_img++){
				var check=stage_control_pics_arr[cntr_img-1].substring(stage_control_pics_arr[cntr_img-1].length-3).toLowerCase(); //check for buttons
				stage_control_pics_arr[cntr_img-1]=(check=="jpg"||check=="gif"||check=="png")?("<img src='"+stage_control_pics_arr[cntr_img-1]+"' style='border:none;' alt=''/>"):(stage_control_pics_arr[cntr_img-1]);
			}
			stage_html+="<div style='display:block;position:absolute;left:0px;top:90%;width:"+max_pic_width+"px;text-align:right;z-index:10;'>";
			stage_html+="  <a href='javascript:slideshow_"+stage_id+".btn_slide_previous();'  style='text-decoration:none'>"+stage_control_pics_arr[0]+"</a>&nbsp;";
			stage_html+="  <a href='javascript:slideshow_"+stage_id+".btn_slideshow_start();' style='text-decoration:none' accesskey='t' >"+stage_control_pics_arr[1]+"</a>&nbsp;";
			stage_html+="  <a href='javascript:slideshow_"+stage_id+".btn_slideshow_stop();'  style='text-decoration:none' accesskey='p' >"+stage_control_pics_arr[2]+"</a>&nbsp;";
			stage_html+="  <a href='javascript:slideshow_"+stage_id+".btn_slide_next();'      style='text-decoration:none' >"+stage_control_pics_arr[3]+"</a>";
			stage_html+="  <br>";
			stage_html+="  <a href='javascript:slideshow_"+stage_id+".btn_set_max_opac(10);'  style='text-decoration:none' accesskey='1' >Opac 10</a>";
			stage_html+="  <a href='javascript:slideshow_"+stage_id+".btn_set_max_opac(50);'  style='text-decoration:none' accesskey='5' >Opac 50</a>";
			stage_html+="  <a href='javascript:slideshow_"+stage_id+".btn_set_max_opac(100);' style='text-decoration:none' accesskey='0' >Opac 100</a>";
			stage_html+="  <br>";
			stage_html+="  <a href='javascript:slideshow_"+stage_id+".btn_show_slide_x_start(2);' style='text-decoration:none' accesskey='2' >slide 2</a>";
			stage_html+="  <a href='javascript:slideshow_"+stage_id+".btn_show_slide_x_start(9);' style='text-decoration:none' accesskey='9' >slide 9</a>";
			stage_html+="</div>";
		}

		z_index1=2;
		visibility1='visible';
		sub_id=1;
		init_img = '';
		wrapper_bg_color = 'transparent';  // NOT stage bg_color

		stage_html+="      <div id='"+stage_id+"_wrapper_"+sub_id+"' style='font-size:0;line-height:"+max_pic_height+"px;margin:0;padding:0;text-align:center;visibility:"+visibility1+";z-index:"+z_index1+";position:absolute;left:0;top:0;width:"+max_pic_width+"px;height:"+max_pic_height+"px;background-color:"+wrapper_bg_color+";'>\n";
		stage_html+="         <img id='"+stage_id+"_img_"+sub_id+"' src='"+init_img+"' style='vertical-align:middle;border:0;' alt=''/>\n";
		stage_html+="      </div>\n";

		z_index1=1;
		visibility1='hidden';
		sub_id=2;

		stage_html+="      <div id='"+stage_id+"_wrapper_"+sub_id+"' style='font-size:0;line-height:"+max_pic_height+"px;margin:0;padding:0;text-align:center;visibility:"+visibility1+";z-index:"+z_index1+";position:absolute;left:0;top:0;width:"+max_pic_width+"px;height:"+max_pic_height+"px;background-color:"+wrapper_bg_color+";'>\n";
		stage_html+="         <img id='"+stage_id+"_img_"+sub_id+"' src='"+init_img+"' style='vertical-align:middle;border:0;' alt=''/>\n";
		stage_html+="      </div>\n";



		the_stage = document.getElementById(stage_id);
		if( ! the_stage) alert('set stage_id='+stage_id +' does not seem to exist');
		the_stage.style.width=max_pic_width;
		the_stage.style.height=max_pic_height;
		the_stage.style.backgroundColor=stage_bg_color;
		the_stage.innerHTML=stage_html;

		self.images_assign();

	}


	/*
		now I am not sure, whether this setup_stage.innerHTML call is always synchroneous in all browsers.
		therefore we cannot be sure, whether the following two variables are already rendered
		and instantly available.
		therefore we wait for a limited time:
	*/
	this.images_assign= function(){

		images_assign_callbacks=images_assign_callbacks+1;
		if( document.getElementById(stage_id + '_img_1') && document.getElementById(stage_id + '_img_2') ){
			render_message('img1 and img2 available for fading in and out');
			img1 = document.getElementById( stage_id + '_img_1');
			img2 = document.getElementById( stage_id + '_img_2'); 
			wrapper1 = document.getElementById( stage_id + '_wrapper_1');
			wrapper2 = document.getElementById( stage_id + '_wrapper_2');
		}else{
			render_message('img1 and img2 not rendered yet');
			if( images_assign_callbacks < 10 ){
				setTimeout(arguments.callee, 50);
			} else {
				render_message('img1 and/or img2 could not be rendered');	
			}
		}
	}























	/*
	*/
	this.load_image_into_memory_start = function(){
		var img_idx = cntr_slide;
		
		// make room in the shadow img array
		//render_message('making room start');
		if( img_idx > img_arr.length ){
			for (var i = (img_arr.length+1); i <= img_idx; i++) {
				//render_message(' &nbsp; extending shadow image array to '+i);
				var empty_img_placeholder='not_loaded_yet';
				var arr_for_push=new Array(empty_img_placeholder);  
				img_arr=img_arr.concat(arr_for_push);
			}
		}
		//render_message('making room stop');

		var img_try_to_load=new Image();
		img_try_to_load.onload=self.load_image_into_memory_success;
		img_try_to_load.onerror=self.load_image_into_memory_failure;
		var padded_img_idx = pad2(img_idx);
		img_try_to_load.src=img_path+'pic'+padded_img_idx+'.jpg';
	}


	this.load_image_into_memory_success = function(){
		this.id=stage_id+"_memory_img_"+(cntr_slide);  // "this" contains the img object
		//render_message('img exists<br>id '+this.id+'<br>url '+ this.src, false);
		img_arr[cntr_slide-1]=this;
		self.show_next_slide();
	}

	this.load_image_into_memory_failure = function(){
		render_message('img NOT exists<br>url '+ this.src, false);
		img_arr[cntr_slide-1]='does_not_exist';
		self.show_next_slide();
	}














	/*
		it follows the event handlers for the control buttons: start, stop, previous, next
		jump_to_slide_x, change_max_opacity
	*/

	this.btn_slideshow_start= function(){
		if(sig_stop==1){
			//alert(cntr_slide);
			clearTimeout(timer_id);
			sig_stop=0;
			this.show_next_slide();
 		}
	}

	this.btn_slideshow_stop= function(){
		if(cntr_fade==0){ 
			// pic is shown statically => just prevent next slide
			clearTimeout(timer_id);
			sig_stop=1;
		} else{ 
			//whilst sliding
			// => let transition finish
			sig_stop=1;
		}
	}


	// assumes slideshow is already stopped.
	// otherwise brusquely interrupts current transition
	// insert code of btn_slideshow_stop() at start, to let a current transition finish
	// calling btn_slideshow_stop() does not help, as it is async
	this.btn_slide_next = function(){
		clearTimeout(timer_id);
		sig_stop=1;
		self.show_next_slide();
	}


	// assumes slideshow is already stopped.
	// otherwise brusquely interrupts current transition
	// insert code of btn_slideshow_stop() at start, to let a current transition finish
	// calling btn_slideshow_stop() does not help, as it is async
	this.btn_slide_previous = function(){
		clearTimeout(timer_id);
		sig_stop=1;
		if(cntr_slide==1 || cntr_slide==2){
			var last_valid = 1;
			for (var i = 0; i< (img_arr.length) ; i++) {
				render_message(' img ' + i + ' is ' + img_arr[i] );
			}
			
			for (var i = 0; i< (img_arr.length) ; i++) {
				if( img_arr[i]== 'does_not_exist' ){
					break;
				}
				last_valid = i+1;
			}
			
			cntr_slide=last_valid;
			if(cntr_slide==1){
				cntr_slide = cntr_slide-1;
			}
		}
		else if(cntr_slide>2){
			cntr_slide=cntr_slide-2;
		}
		self.show_next_slide();
	}



	this.btn_show_slide_x_start = function(arg1,arg2){

		
		var remaining_time_current_transition;
		var markup = 200;  // small waiting time after current transition finish to desired slide trans start
		var independent_timer_id;
		var slide_x, opac_x;
		
		// remember desired slide
		if(arg1){
			slide_x=parseInt(arg1);	
		} else {
			slide_x=1;	
		}
		

		if(arg2){
			opac_x=parseInt(arg2);	
		} else {
			opac_x=max_opac;	
		}
		

		// let current transition stop (if pending)
		if(cntr_fade==0){ 
			// pic is shown statically => just prevent next slide
			clearTimeout(timer_id);
			sig_stop=1;

			//alert("dbg1; "+slide_x+"; "+opac_x);		
			independent_timer_id=setTimeout(function(){self.btn_show_slide_x_part2(slide_x,opac_x);},(markup));
		} else{ 
			//whilst sliding
			// => let transition finish
			sig_stop=1;
			remaining_time_current_transition = (transition_steps-cntr_fade)*ms_fade_step;
			//alert(remaining_time_current_transition);
			independent_timer_id=setTimeout(function(){self.btn_show_slide_x_part2(slide_x,opac_x);},(remaining_time_current_transition+markup));
		}
		//alert(sig_stop);

	}

	// invoked by timer after last transition has definitely completed
	this.btn_show_slide_x_part2 = function(arg1,arg2){
		//alert('next slide '+arg1);
		cntr_slide = arg1;					// only NOW set the desired next slide
		this.btn_set_max_opac(arg2);		// only NOW change max opac
		self.show_next_slide();
	}



	this.btn_set_max_opac = function(arg1){
		if(arg1){
			max_opac=parseInt(arg1);	
		} else {
			max_opac=100;
		}
		opacity_increment=max_opac/transition_steps;
	}

	this.btn_get_max_opac = function(){
		var old_val = max_opac;
		return old_val;
	}


} // end of class







/* now we create two instance of slideshows
	and register their init-methods to the document_onload event:
 */

var slideshow_stage1= new class_slideshow();  // object names should be "slideshow_"+stage_id for control methods to work


// before we create the second slideshow, we change some parameters
def_do_fade_out=1;
def_stage_id="stage2";
def_img_path='http://www.mowitania.de/Ferienwohnung/pics_slides2/';
def_max_pic_width=1040;
def_max_pic_height=560;
def_stage_bg_color="transparent"; 

def_slide_duration=3.8;            //seconds to show a pic between fades in seconds
def_transition_duration=0.9;       //seconds of a complete fade in seconds
def_transition_steps=8;         //steps of a transition, steps to fade from on pic to the next

def_max_opac=100;         
def_stage_show_controls=0;

var slideshow_stage2= new class_slideshow();  // object names should be "slideshow_"+stage_id for control methods to work





