﻿/*
	v2.1.1, 14.06.2011, dogan

	Content Shifter Animation h/v

	©2011 Tanyel Dogan, alle Rechte vorbehalten
*/
if(! Cms4d)var Cms4d = {};

Cms4d.AddEvent = function(obj_pointer, type_str, func_pointer)
{
	//BEACHTE: bei IE muss der event Typ mit 'on' beginnen. Zur Vereinheitlichung
	//wird der allgemeine String übergeben und für den IE 'on' vorangestellt
	if(obj_pointer.attachEvent)
	{
		//IE
		type_str = 'on' + type_str;
		obj_pointer.attachEvent(type_str, func_pointer);
	}
	else if(obj_pointer.addEventListener)
	{
		//andere
		obj_pointer.addEventListener(type_str, func_pointer, false);
	}
}

Cms4d.SelectElements = function(pnode, snn, sid, scln, deep)
{
	var r = new Array();
	Cms4d.SelectElementsRecurs(pnode, snn, sid, scln, deep, r, 0);
	return(r);
}
Cms4d.SelectElementsRecurs = function(pnode, snn, sid, scln, deep, ia, lcounter)
{
	lcounter++;
	for(var i = 0; i < pnode.childNodes.length; i++)
	{
		var cnode = pnode.childNodes[i];
		var nt = cnode.nodeType;
		//Nur Elemente
		if(nt == 1)
		{
			var nn = cnode.nodeName.toLowerCase();
			if(nn == snn)
			{
				if(sid == '' && scln == '')
				{
					ia.push(cnode);
				}
				else if((sid != '' && scln == '') && cnode.id == sid)
				{
					ia.push(cnode);
				}
				else if((sid == '' && scln != '') && cnode.className == scln)
				{
					ia.push(cnode);
				}
				else if((sid != '' && scln != '') && (cnode.id == sid && cnode.className == scln))
				{
					ia.push(cnode);
				}
			}

			//R E K U R S I O N
			if(deep == true && lcounter < 128)
			{
				Cms4d.SSlider.SelectElementsRecurs(cnode, snn, sid, scln, deep, ia, lcounter);
			}
		}
	}
	lcounter--;
}
Cms4d.CShifter = function(p_ctrlid, p_speedup, p_slowdown, p_autoplay, p_autodelay, p_draw_tbuttons_func, p_draw_cbuttons_func, p_controls_container_id)
{
	this.ctrlid = p_ctrlid;
	this.varname = 'cms4d_cshifter_' + this.ctrlid;
	this.varpointer = 'window.' + this.varname;

	this.ctrlok = false;
	this.container = document.getElementById(this.ctrlid);
	this.container_w = 0;
	this.container_h = 0;
	this.tabs = new Array();
	this.tmax = 0;

	this.isrest = false;

	this.act_tabid = 0;
	this.act_tab = null;
	this.act_tab_x = 0;
	this.next_tabid = 0;
	this.next_tab = null;
	this.tabcursor = 0;

	this.autoplay = p_autoplay;
	this.autotimerid = null;
	this.autodelay = p_autodelay;
	this.autocount = 0;

	//Wird eine ID für einen gültigen DIV übergeben, so schreibt das Control seine Standardbuttons in diesen DIV.
	//Das Zielelement muss im DOM/HTML-Code VOR dem Script stehen, welches das Controls erzeugt.
	this.controls_container_id = p_controls_container_id;
	this.controls_container = null;

	//Der Wert der Beschleunigung zu Beginn der Bewegung zwischen 1.1 und 2.5, wobei Werte
	//über 2 auf kurzen Strecken kaum noch Sinn machen.
	//Je höher der Wert ist, desto rasanter beschleunigt die Bewegung zu Beginn.
	//Typischer guter Wert ist 1.5
	this.speedup = p_speedup;
	if(this.speedup < 1.1)this.speedup = 1.1;
	if(this.speedup > 2.5)this.speedup = 2.5;

	//Faktor für das Abbremsen nach dem Mitte der Strecke zwischen 2 und 20.
	//Je höher der Wert, desto langsamer wird die Bewegung zum Schluß hin abgebremst.
	//Typischer guter Wert ist 5
	this.slowdown = p_slowdown;
	if(this.slowdown < 2)this.slowdown = 2;
	if(this.slowdown > 20)this.slowdown = 20;

	//BEACHTE: der IE8/7 verarbeitet im Gegensatz zu allen anderen Browsern die Bewegung langsamer.
	//Deshalb sollte die Bewegung so eingerichtet werden, dass sie im IE nicht zu langsam abläuft.
	//Die anderen Browser sind dann zügiger beim Tabwechsel.

	this.dir = -1;
	this.x1 = 0;
	this.y1 = 0;
	this.x2 = 0;
	this.y2 = 0;
	this.x_2 = 0;
	this.y_2 = 0;
	this.vx = 1;
	this.vy = 1;
	this.timerid = null;
	this.timerdelay = 20;
	

	this.TabItem = function(eid, elm, ex, ey, ew, eh)
	{
		this.id = eid;
		this.obj = elm;
		this.x = ex;
		this.y = ey;
		this.w = ew;
		this.h = eh;
		this.tbut = null;
		this.toString = function()
		{
			var t = this.id + ',' + this.obj + ',' + this.x + ',' + this.y + ',' + this.w + ',' + this.h + ',' + this.tbut + '\n';
			return(t);
		}
	}

	this.DoAutoplay = function()
	{
		clearTimeout(this.autotimerid);
		clearTimeout(this.timerid);
		this.MoveCursor(1);
	}
	this.ResetAutoplay = function()
	{
		//WICHTIG: ggf. laufenden autotimer gleich canceln, da sonst der erste Bildwechsel nicht unterbunden werden kann
		//auch wenn der Benutzer sofort ins Control geklickt hat.
		clearTimeout(this.autotimerid);
		this.autoplay = 0;
	}

	//BEACHTE: zwischen MoveCursor und GotoTab gibt es einen entscheidenden Unterschied.
	//MoveCursor wird für Autoplay oder den Klick auf einen der Pfeilbuttons ausgeführt.
	//Dabei erwartet der Benutzer, dass der next_tab aus der Richtung ins Blickfeld gezogen wird,
	//in die der Pfeilbutton zeigt. Also beim Klick auf den linken Pfeilbutton, sollte next_tab
	//von links ins Bild kommen. Deshalb wird die Bewegungsrichtung this.dir hier explizit gesetzt
	//und dann MoveTab direkt aufgerufen.
	//Die Funktion GotoTab hingegen springt zu einem bestimmten Tab. Dabei ist dann für die Bewegungsrichtung
	//entscheidend, ob der neue Tab in der Liste vor oder hinter act_tab steht. Deshalb muss dort
	//die Bewegungsrichtung anders festgelegt werden. s.u.
	this.MoveCursor = function(d)
	{
		if(this.isrest != true)return;

		clearTimeout(this.timerid);

		//nächster tab
		var n = this.tabcursor + d;
		if(n < 0)n = this.tmax;
		if(n > this.tmax)n = 0;
		this.tabcursor = n;

		this.next_tabid = this.tabcursor;
		this.next_tab = this.tabs[this.next_tabid];

		//Die Bewegungsrichtung ist umgekehrt zu cursorrichtung
		this.dir = d * -1;

		this.CalcBorders();

		//Tabbutton markieren
		this.MarkTab();

		this.isrest = false;
		this.MoveTabs();
	}
	//vereinfachte Funktionen für parameterlosen Aufruf
	this.MoveLeft = function()
	{
		this.ResetAutoplay();
		this.MoveCursor(-1);
	}
	this.MoveRight = function()
	{
		this.ResetAutoplay();
		this.MoveCursor(1);
	}


	//Tab-Buttons
	this.DrawTButtons = function()
	{
		var bc = document.createElement('div');
		bc.className = 'cms4d_cshifter_tbut_container';
		//Zweiter Container, i.d.R. als float right
		var bic = bc.appendChild(document.createElement('div'));
		bic.className = 'cms4d_cshifter_tbut_inner_container';
		var t = '';
		for(var i = 0; i < this.tabs.length; i++)
		{
			var idstr = this.ctrlid + '_tbut_' + i;
			var class_name = 'tbut';
			if(i == this.act_tabid)class_name += ' tbut_on';
			var funcstr = this.varpointer + '.ResetAutoplay()';
			funcstr += ';' + this.varpointer + '.GotoTab(' + i + ')';
			t += '<a href="#" id="' + idstr + '" class="' + class_name + '" onclick="' + funcstr + ';return(false);">';
				//t += 'Tab ' + i;
			t += '</a>';
		}
		bic.innerHTML = t;
		var target_container = this.controls_container == null ? this.container : this.controls_container;
		target_container.appendChild(bc);
	}
	this.MarkTab = function()
	{
		//BEACHTE: hier wird der nächste tab markiert, da act_tab bis zum erneuten Stillstand bestehen bleibt
		var mytab = this.next_tab;
		if(mytab.tbut == null)return;
		for(var i = 0;i < this.tabs.length; i++)
		{
			var class_name = i == this.next_tabid ? 'tbut tbut_on' : 'tbut';
			this.tabs[i].tbut.className = class_name;
		}
	}

	//Cursor-Buttons
	this.DrawCButtons = function()
	{
		var target_container = this.controls_container == null ? this.container : this.controls_container;
		var tc_w = target_container.offsetWidth;
		var tc_h = target_container.offsetHeight;

		eval('var f_l = function(){' + this.varpointer + '.MoveLeft();}');
		eval('var f_r = function(){' + this.varpointer + '.MoveRight();}');

		var b_l = document.createElement('a');
			b_l.id = this.ctrlid + 'cbut_l';
			b_l.className = 'cms4d_cshifter_cbut_l';
			Cms4d.AddEvent(b_l, 'click', f_l);
			target_container.appendChild(b_l);
		var b_r = document.createElement('a');
			b_r.id = this.ctrlid + 'cbut_r';
			b_r.className = 'cms4d_cshifter_cbut_r';
			Cms4d.AddEvent(b_r, 'click', f_r);
			target_container.appendChild(b_r);

		var b_l_x = 0;
		var b_l_y = (tc_h / 2) - (b_l.offsetHeight / 2);
		with(b_l.style)
		{
			left = b_l_x + 'px';
			top = b_l_y + 'px';
		}

		var b_r_x = tc_w - b_r.offsetWidth;
		var b_r_y = (tc_h / 2) - (b_r.offsetHeight / 2);
		with(b_r.style)
		{
			left = b_r_x + 'px';
			top = b_r_y + 'px';
		}
	}


	if(this.container != null)
	{
		this.container_w = this.container.offsetWidth;
		this.container_h = this.container.offsetHeight;

		//Tabs suchen und in Array sammeln
		ea = Cms4d.SelectElements(this.container, 'div', '', 'tab', false);
		if(ea.length > 0)
		{
			for(var i = 0; i < ea.length; i++)
			{
				var d = ea[i];
				var x = this.container_w * i;
				var y = 0;

				with(d.style)
				{
					position = 'absolute';
					left = x + 'px';
					top = y + 'px';
				}
				this.tabs.push(new this.TabItem(i, d, x, y, this.container_w, this.container_h));
			}
			this.act_tab = this.tabs[this.act_tabid];
			//Anzahl Tabs für weiteren Gebrauch speichern
			this.tmax = this.tabs.length - 1;

			//Grenzen
			this.sliderx1 = -(this.container_w * (this.tmax));
			this.slidery1 = -(this.container_h * (this.tmax));
			this.sliderx2 = 0;
			this.slidery2 = 0;

			//Im window einen Zeiger auf sich selbst setzen
			window[this.varname] = this;

			//Sobald ein klick auf einem Element im Slider stattfindet soll ein ggf. laufendes Autoplay abgebrochen werden.
			//Es besteht aber das Problem, dass zu diesem Zeitpunkt die obige Funktion keinen Verweis auf die
			//tatsächlich Objektinstanz enthält. Für addEventListener bzw. attach Event muss jedoch ein Zeiger auf eine
			//Funktion übergeben werden, kein Funktionsname als String.
			//Deshalb wird hier eine anonyme Funktion genutzt, die die eigentliche Funktion der Instanz aufruft.
			//Ein Zeiger auf diese Instanz des shifters wurde oben schon in window[this.varname] gespeichert.
			//Durch eval kann der anonyme Funktions-String so evaluiert werden, dass this.varpointer den Variablennamen
			//im window enthält. Die anonyme Funktion wird immer aufgerufen, sobal ein mousedown innerhalb des Containers stattfindet.
			eval('var f = function(){' + this.varpointer + '.ResetAutoplay();}');
			//Event-Handler hinzufügen
			if(this.container.addEventListener)
			{
				//Alle ausser IE
				this.container.addEventListener('mousedown', f, false);
			}
			else if(this.container.attachEvent)
			{
				this.container.attachEvent('onmousedown', f);
			}

			//Wenn bis hierhin fehlerfrei, dann ist das Control in Ordnung.
			//WICHTIG: es müssen mindestens 2 tabs vorhanden sein, sonst bleibt das Control inkorrekt.
			if(this.tabs.length > 1)
			{
				this.next_tabid = this.act_tabid + 1;
				this.next_tab = this.tabs[this.next_tabid];

				//Nach ggf. abweichendem DIV suchen, in den die Controls geschrieben werden sollen
				var ccid = this.controls_container_id;
				if(typeof(ccid) == 'string')
				{
					this.controls_container = document.getElementById(this.controls_container_id);
				}
//alert(this.controls_container);

				//Register Tab-Buttons Sprunglinks
				//Es kann ggf. eine Funktion übergeben werden, um die Darstellungsrountine mit der eigenen zu überschreiben.
				//Wird jedoch null übergeben, so werden standardmässige Sprungbuttons gezeichnet (s.o.).
				if(typeof(p_draw_tbuttons_func) == 'function')
				{
					this.DrawTButtons = p_draw_tbuttons_func;
				}
				this.DrawTButtons();

				//ggf. vorhandene Buttons parsen und in zugehörigem Listeneintrag für direkten Zugriff speichern (Markierung umschalten)
				for(var i = 0; i < this.tabs.length; i++)
				{
					var o = this.tabs[i];
					var tb = document.getElementById(this.ctrlid + '_tbut_' + i);
					if(tb != null)o.tbut = tb;
				}

				//Cursor Buttons vor/zurück
				if(typeof(p_draw_cbuttons_func) == 'function')
				{
					this.DrawCButtons = p_draw_cbuttons_func;
				}
				this.DrawCButtons();

				this.isrest = true;
				this.ctrlok = true;
			}
		}
	}


	this.GotoTab = function(idx)
	{
		if(this.isrest != true)return;
		if(idx == this.act_tabid)return;

		clearTimeout(this.timerid);
		this.ResetAutoplay();

		this.tabcursor = idx;

		//Funktionsweise des Tabwechsels/Animation
		//Die Funktion move_cursor bestimmt nur, welcher tab als nächstes ins Blickfeld gezogen werden soll.
		//Dabei bleibt act_tab so lange der aktuell zuletzt sichtbare DIV, bis das Verschieben der beiden DIVs
		//KOMPLETT abgeschlossen wurde. Während der Animation wird act_tab in Richtung this.dir bewegt und
		//next_tab folgt je nach Bewegungsrichtung an der linken oder rechten Kante.
		//Nach Erreichen der Ruheposition wird next_tab zu act_tab.
		//WICHTIG: während der Bewegung müssen alle Eingaben des Benutzers ignoriert werden. Andernfalls käme
		//zu einem ziemlichen Durcheinander, wenn auf  halber Strecke next_tab umgeschaltet würde.
		this.next_tabid = this.tabcursor;
		this.next_tab = this.tabs[this.next_tabid];

		//Je nachdem, ob der nächste Tab in der Liste vor oder hinter act_tab liegt,
		//muss die Bewegung nach links oder rechts erfolgen
		this.dir = this.next_tabid < this.act_tabid ? 1 : -1;

		this.CalcBorders();

		//Tabbutton markieren
		this.MarkTab();

		//--- Event ---
		this.OnGotoTab();

		this.isrest = false;
		this.MoveTabs();
	}

	this.CalcBorders = function()
	{
		//Grenzen für act_tab
		if(this.dir < 0)
		{
			this.x1 = 0 - this.container_w;
			this.y1 = 0;
			this.x2 = 0;
			this.y2 = this.container_h;
		}
		else
		{
			this.x1 = 0;
			this.y1 = 0;
			this.x2 = this.container_w;
			this.y2 = this.container_h;
		}

		//Halbe Breite/Höhe für Grenze Beschleunigung
		this.x_2 = Math.round(this.container_w / 2) * this.dir;
		this.y_2 = Math.round(this.container_h / 2);

		//Positionsvariable und Beschleunigung zurücksetzen zurücksetzen !
		this.act_tab_x = 0;
		this.vx = 1;
		this.vy = 1;
	}
	this.MoveTabs = function()
	{
		clearTimeout(this.timerid);
		var doloop = true;

		var fx = 1 * this.vx;
		if(fx < 1)fx = 1;
		var newx = Math.round(this.act_tab_x + (this.dir * fx));
		var newx2 = 0;
		if(this.dir < 0)
		{
			if(newx <= this.x1)
			{
				newx = this.x1;
				doloop = false;
			}
			//next_tab rechts nachziehen
			newx2 = newx + this.container_w;
		}
		else
		{
			if(newx >= this.x2)
			{
				newx = this.x2;
				doloop = false;
			}
			//next_tab links nachziehen
			newx2 = newx - this.container_w;
		}

		this.act_tab_x = newx;

		this.act_tab.obj.style.left = newx + 'px';
		this.next_tab.obj.style.left = newx2 + 'px';

		if(doloop == true)
		{
			var d = 0;

			//Beschleunigung bis Mitte der zurückzulegenden Strecke, dann abbremsen
			if(this.dir < 0)
			{
				d = Math.abs(this.x1 - this.act_tab_x);
				if(this.act_tab_x > this.x_2)
				{
					this.vx = this.vx * this.speedup;
				}
				else
				{
					this.vx = d / this.slowdown;
				}
			}
			else
			{
				d = this.x2 - this.act_tab_x;
				if(this.act_tab_x < this.x_2)
				{
					this.vx = this.vx * this.speedup;
				}
				else
				{
					this.vx = d / this.slowdown;
				}
			}

			//Begrenzung der Beschleunigung
			if(this.vx < 1)this.vx = 1;
			if(this.vx > 50)this.vx = 50;

			var funcstr = this.varpointer + '.MoveTabs()';
			this.timerid = setTimeout(funcstr, this.timerdelay);
		}
		else
		{
			//Endposition ist erreicht, jetzt wird der bisherige next_tab zum act_tab.
			//Ab jetzt werden auch wieder Benutzereingaben angenommen.
			this.act_tabid = this.next_tabid;
			this.act_tab = this.next_tab;

			this.isrest = true;

			//Wenn autoplay aktiv ist, wird ab jetzt zeitverzögert der folgende rechte tab angesprungen.
			//Sobald der Benutzer einmal selbst geklickt hatte wird autoplay sowieso deaktiviert.
			if(this.autoplay == 1)
			{
				var funcstr = this.varpointer + '.DoAutoplay()';
				this.autotimerid = setTimeout(funcstr, this.autodelay);
			}

			//--- Event ---
			this.OnRest();
		}
	}





	//--- Handler ---
	this.OnGotoTab = function(){};
	this.OnRest = function(){};

	this.toString = function()
	{
		var t = '';
		t += 'ctrlok: ' + this.ctrlok + '\n';
		t += 'ctrlid: ' + this.ctrlid + '\n';
		t += 'autoplay: ' + this.autoplay + '\n';
		t += 'varname: ' + this.varname + '\n';
		t += 'varpointer: ' + this.varpointer + '\n';
		t += 'container: ' + this.container + '\n';
		t += 'container_w / h: ' + this.container_w + ' / ' + this.container_h + '\n';
		t += 'tabs:\n' + this.tabs + '\n';

		t += 'dir: ' + this.dir + '\n';
		t += 'tabcursor: ' + this.tabcursor + '\n';
		t += 'act_tabid: ' + this.act_tabid + '\n';
		t += 'act_tab_x: ' + this.act_tab_x + '\n';
		t += 'act_tab: ' + this.act_tab + '\n';
		t += 'next_tabid: ' + this.next_tabid + '\n';
		t += 'next_tab: ' + this.next_tab + '\n';

		t += 'vx / vy: ' + this.vx + '/' + this.vy + '\n';
		t += 'x_2 / y_2: ' + this.x_2 + '/' + this.y_2 + '\n';
		t += 'x1/y1 x2/y2: ' + this.x1 + '/' + this.y1 + ' ' + this.x2 + '/' + this.y2 + '\n';
		return(t);
	}


	//ggf. ersten Bildwechsel einleiten
	if(this.autoplay == 1 && this.ctrlok == true)
	{
		var funcstr = this.varpointer + '.DoAutoplay()';
		this.autotimerid = setTimeout(funcstr, this.autodelay);
	}

}

