//2013-04-15
//debug console.log("knob.js loaded");
(function( $ ){
	

function sett0r(prop,val)
			{
				if(typeof(val)==="undefined")	
				{
					// get
					return this.data("IBEknob").settings[prop];
				}
				else
				{
					// set
					this.data("IBEknob").settings[prop]=val;
					return this ;//seb this.each(function(){});
				}
			}
			

	var methods = {
    	init : function( options ) 
		{
				/*
				settings:
					- startStep
					- totalSteps
					- changeStep(->function)
					- turn (->function)
					
				options:
					- startStep
					- totalSteps
					- currentStep
					- currentPos
				*/
				
				var currentSettings = $.extend({}, options);
		
				var $this = this;
				
				function persistent0r() {
					if(typeof $this.data("IBEknob") !== "undefined") {
						if(typeof(currentSettings)!=="undefined") {
							for (key in currentSettings) {
								$this.data("IBEknob").settings[key]=currentSettings[key];
							}
						
						}
					}
				}
				
			
					
				var data = $this.data("IBEknob");
				
				//If the plugin hasn't been initialized yet
				if ( ! data ) 
				{
					//debug  console.log("1st init knob");
									
					//settings objekt wird erzeugt
					var settings={};
					$(this).data("IBEknob",
								 data={target : $this,settings : settings});
					
					// Eingaben werden dauerhaft gespeichert
					persistent0r();
					
					// Startbedingung:
					if(typeof(currentSettings.startStep)!=="undefined")
					{
						data.settings.currentStep=currentSettings.startStep;
					}
					else
					{
						data.settings.currentStep=1;
					}
					
					var pos=0;
					if(typeof(data.settings.totalSteps)!=="undefined")
					{
						var n=this.data("IBEknob").settings.totalSteps;
						var cf=this.data("IBEknob").settings.currentStep;
						pos=1/(n-1)*cf+1/(1-n);
					}
		
					if(typeof(data.settings.maxAngle)==="undefined")
					{
						data.settings.maxAngle=360;
					}
					var datset=data.settings;
					
					datset.currentPos=pos;
					datset.currentDeg=datset.currentPos*datset.maxAngle;
					datset.lastDeg=datset.currentPos*datset.maxAngle
					datset.rotation = datset.currentDeg
					if(typeof datset.turn==="function") 
						datset.turn(datset.currentPos);
				}
				
				// Nachträgliche Eingaben überschreiben bereits gespeicherte Daten
				persistent0r();
				
				// Plugin kann kaskadiert (?) werden
				return this.each(function()
				{
					/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
					var knob = $(this);
					var	$this=$(this);
					var data=$(this).data("IBEknob").settings;
					data.startDeg = -1;
					doc = $(document);
					
					
					knob.on('mousedown touchstart', function(e)
					{
						e.preventDefault();
					
						var offset = knob.offset();
						var center ={y : offset.top + knob.height()/2,x: offset.left + knob.width()/2};
						var a, b, deg, tmp,
						rad2deg = 180/Math.PI;
						
						//Position( in[0,1]) korrigieren in Abh. des Steps)
						if(typeof(data.totalSteps)!=="undefined") data.currentPos=(data.currentStep-1)/(data.totalSteps-1);
						$(document).on('mousemove.rem touchmove.rem',function(e)
						{
							e = (e.originalEvent.touches) ? e.originalEvent.touches[0] : e;
							a = center.y - e.pageY;
							b = center.x - e.pageX;
							deg = Math.atan2(a,b)*rad2deg;
							// we have to make sure that negative
							// angles are turned into positive:
							if(deg<0)
							{
								deg = 360 + deg;
							}
								
							//Save the starting position of the drag
							if(data.startDeg == -1)
							{
								data.startDeg = deg;
							}
								
							// Calculating the current rotation
							var tmp = ((deg-data.startDeg) + data.rotation);
							
							// Making sure the current rotation
							// stays between 0 and 359._9
							if(tmp < 0)
							{
								tmp = 360 + tmp;
							}
							else if(tmp >= 360)
							{
								tmp = tmp % 360;
							}
							
							
//seb 20160403							if(data.currentDeg>data.maxAngle && data.infinite!=="true")
							if(data.currentDeg>data.maxAngle && !data.infinite)
							{
								data.currentDeg = data.maxAngle;
								data.lastDeg = data.currentDeg;
							}
							
							// DEG -> POS -> STP
							//deg->pos
							data.currentPos=data.currentDeg/data.maxAngle;
							
							// pos->stp
							if(typeof(data.totalSteps)!=="undefined")
							{
								var turningStep=Math.floor(data.totalSteps*data.currentPos)+1
								if(turningStep>data.totalSteps) turningStep=data.totalSteps;
								if(turningStep!=data.currentStep)
								{
									data.currentStep=turningStep;
									if(typeof(data.changeStep)==="function")
									{
										data.changeStep(data.currentStep);
									}
									$this.trigger('changeStep', data.currentStep);	//seb
								}
							}
							
							
							if(typeof(data.turn)==="function")
							{
								data.turn(data.currentPos);
							}
							/*if(typeof(data.changeStep)==="function")
							{
								data.changeStep(data.currentStep);
							}
							$this.trigger('changeStep');*/

							
							// This would suggest we are at an end position;
							// we need to block further rotation.
//seb 20160403							if(Math.abs(tmp - data.lastDeg) > 180 && data.infinite!==true)
							if(Math.abs(tmp - data.lastDeg) > 180 && !data.infinite)
							{
								if(tmp<data.lastDeg)
								{
									data.currentDeg = data.maxAngle-0.00000000001;
									data.lastDeg = data.currentDeg;
								}
								else
								{
									data.currentDeg = 0;
									data.lastDeg = 0;
								}
								return false;
							}
							
							data.currentDeg = tmp;
							data.lastDeg = tmp;
							
						});
					
						doc.on('mouseup.rem touchend.rem',function()
						{
							doc.off('.rem');
							// Saving the current rotation
							data.rotation = data.currentDeg;
							
							// Marking the starting degree as invalid
							data.startDeg = -1;
							
							//Pos+Deg korrigieren, damit "voller" schritt für stepwechsel nötig ist
							if(typeof(data.totalSteps)!="undefined")
							{
								data.currentPos=(data.currentStep-1)/(data.totalSteps-1);
								data.currentDeg=data.currentPos*data.maxAngle;
								data.lastDeg=data.currentPos*data.maxAngle
								data.rotation = data.currentDeg
								if(typeof data.turn === "function") data.turn(data.currentPos);
							}
						});					
					
					});
					/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
				});
				

		},
	

        destroy : function( )
		{
			return this.each(function()
			{
				var $this = $(this);
				var data = $this.data('IBEknob');
		
				// Namespacing FTW
				$(window).unbind('.IBEknob');
				$(document).unbind('.IBEknob');
				$this.removeData('IBEknob');
				
			});

		},
	 
     
	 
	 totalSteps : function(val)
	 {
			return sett0r.call(this, 'totalSteps',val);
	 },


     startStep : function(val)
	 { 
			sett0r.call(this, 'startStep',val); // kein return, da noch gesnapt werden muss // CHECK seb
			return sett0r.call(this, 'startStep',val);
     },
	 

	currentStep : function(val)
	{
		if(typeof(val)!=="undefined" && val!=$(this).data('IBEknob').settings.currentStep)
		{
			data=$(this).data('IBEknob').settings;
			
			data.currentStep=val;
			data.currentPos=val/data.totalSteps;
			data.currentDeg=data.currentPos*data.maxAngle;
			
			data.changeStep.apply( this, arguments ); //seb use arguments, for custom additional arguments... (val);
			if(typeof data.turn === "function") data.turn(val/data.totalSteps);
		}
		return sett0r.call(this, 'currentStep',val);
    },
  };

  $.fn.IBEknob = function( method ) {
    
    if ( methods[method] ) {
      return methods[method].apply( this, Array.prototype.slice.call( arguments, 1 ));
    } else if ( typeof method === 'object' || ! method ) {
      return methods.init.apply( this, arguments );
    } else {
      $.error( 'Method ' +  method + ' does not exist on jQuery.IBEknob' );
    }    
  
  };

})( jQuery );
