////////////////////////////////////////////////////////////////////////////////
//
//  Licensed to the Apache Software Foundation (ASF) under one or more
//  contributor license agreements.  See the NOTICE file distributed with
//  this work for additional information regarding copyright ownership.
//  The ASF licenses this file to You under the Apache License, Version 2.0
//  (the "License"); you may not use this file except in compliance with
//  the License.  You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////

package spark.skins.ios7
{
	import flash.display.DisplayObject;
	import flash.events.TimerEvent;
	import flash.geom.Matrix;
	import flash.utils.Timer;
	
	import mx.core.DPIClassification;
	
	import spark.components.BusyIndicator;
	import spark.skins.ios7.assets.BusyIndicator;
	import spark.skins.mobile.supportClasses.MobileSkin;
	
	public class BusyIndicatorSkin extends MobileSkin
	{
		static private const DEFAULT_ROTATION_INTERVAL:Number = 30;
		private var busyIndicatorClass:Class;
		private var busyIndicator:DisplayObject;
		private var busyIndicatorBackground:DisplayObject;
		private var busyIndicatorDiameter:Number;
		private var rotationTimer:Timer;
		private var rotationInterval:Number;
		private var rotationSpeed:Number;
		/**
		 *  @private
		 * 
		 *  Current rotation of this component in degrees.
		 */   
		private var currentRotation:Number = 0;
		private var symbolColor:uint;
		private var symbolColorChanged:Boolean = false;
		
		public function BusyIndicatorSkin()
		{
			super();
			
			busyIndicatorClass = spark.skins.ios7.assets.BusyIndicator;
			rotationInterval = getStyle("rotationInterval");
			if (isNaN(rotationInterval))
				rotationInterval = DEFAULT_ROTATION_INTERVAL;
			if (rotationInterval < 30) //Spokes are at 30 degree angle to each other. 
				rotationInterval = 30;
			rotationSpeed = 60;
			
			switch(applicationDPI) 
			{	
				case DPIClassification.DPI_640:
				{
					busyIndicatorDiameter = 104;
					break;
				}
				case DPIClassification.DPI_480:
				{
					busyIndicatorDiameter = 80;
					break;
				}		
				case DPIClassification.DPI_320:
				{
					busyIndicatorDiameter = 52;
					break;
				}
				case DPIClassification.DPI_240:
				{
					busyIndicatorDiameter = 40;
					break;
				}
				case DPIClassification.DPI_120:
				{
					busyIndicatorDiameter = 20;
					break;
				}
				default://160 DPI
				{
					busyIndicatorDiameter = 20;
					break;
				}
			}
		}
		
		private var _hostComponent:spark.components.BusyIndicator;
		
		public function get hostComponent():spark.components.BusyIndicator
		{
			return _hostComponent;
		}
		
		public function set hostComponent(value:spark.components.BusyIndicator):void 
		{
			_hostComponent = value;
		}
		
		override protected function createChildren():void
		{
			//This layer stays still in the background
			busyIndicatorBackground = new busyIndicatorClass();
			busyIndicatorBackground.width = busyIndicatorBackground.height = busyIndicatorDiameter;
			addChild(busyIndicatorBackground);
			//This layer rotates in the foreground to give the required effect
			busyIndicator = new busyIndicatorClass();
			busyIndicator.alpha = 0.3;
			busyIndicator.width = busyIndicator.height = busyIndicatorDiameter;
			addChild(busyIndicator);
		}
		
		override protected function measure():void
		{
			measuredWidth = busyIndicatorDiameter;
			measuredHeight = busyIndicatorDiameter;
			
			measuredMinHeight = busyIndicatorDiameter;
			measuredMinWidth = busyIndicatorDiameter
		}
		
		override protected function commitCurrentState():void
		{
			super.commitCurrentState();
			if(currentState == "rotatingState")
			{
				startRotation();
			}
			else
			{
				stopRotation();
			}
		}
		
		override public function styleChanged(styleProp:String):void
		{
			var allStyles:Boolean = !styleProp || styleProp == "styleName";
			
			if (allStyles || styleProp == "symbolColor")
			{
				symbolColor = getStyle("symbolColor");
				symbolColorChanged = true;
				invalidateDisplayList();
			}
			if (styleProp == "styleName") {
				var value:String = getStyle("styleName");
				
				// We're being removed from the stage
				if (value == null) {
					stopRotation();
					busyIndicatorBackground = null;
					busyIndicator = null;
				}
			}
			super.styleChanged(styleProp);
		}
		
		override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
		{
			super.updateDisplayList(unscaledWidth,unscaledHeight);
			if(symbolColorChanged)
			{
				colorizeSymbol();	
				symbolColorChanged = false;
			}
		}
		
		private function colorizeSymbol():void
		{
			super.applyColorTransform(this.busyIndicator, 0x000000, symbolColor);
		}
		
		private function startRotation():void
		{
			rotationTimer = new Timer(rotationSpeed);
			if (!rotationTimer.hasEventListener(TimerEvent.TIMER))
			{
				rotationTimer.addEventListener(TimerEvent.TIMER, timerHandler);
				rotationTimer.start();
			}
		}
		
		private function stopRotation():void
		{
			if (rotationTimer)
			{
				rotationTimer.removeEventListener(TimerEvent.TIMER, timerHandler);
				rotationTimer.stop();
				rotationTimer = null;
			}
		}
		
		/**
		 *  @private
		 * 
		 *  Rotate the spinner once for each timer event.
		 */
		private function timerHandler(event:TimerEvent):void
		{
			currentRotation += rotationInterval;
			if (currentRotation >= 360)
				currentRotation = 0;
			
			rotate(busyIndicator,currentRotation,width/2,height/2);
			event.updateAfterEvent();
		}
		
		private function rotate(obj:DisplayObject, angle:Number, aroundX:Number, aroundY:Number):void
		{
			var center:Number = Math.min(aroundX, aroundY); // stop wobbling if not square
			var rotationMatrix:Matrix = new Matrix();
			rotationMatrix.translate(-center,-center);
			rotationMatrix.rotate(Math.PI*angle/180);
			rotationMatrix.translate(center,center);
			obj.transform.matrix = rotationMatrix;
		}
		
	}
}
