/////////////////////////////////////////////////////////////////////////////////
//
// c) 2012 24/7 Real Media - A WPP Company  
// This source code is Confidential and Proprietary information of the company.
//
/////////////////////////////////////////////////////////////////////////////////
package com.panache.assets.renditions
{
	import com.panache.core.PanacheCreativeObject;
	import com.panache.debug.MediaServicesAdDebug;

	/**
	 * PanacheCreativeRenditionSelector is a class which uses for storage the pnachehe rendition object and selection a randition 
	 * using the parameters specified in the spec.
	 * 
	 * <p>
	 *This interfaces extends IPanacheObject.
	 * </p>
	 * 
 	 * @see		com.panache.core.PanacheCreativeObject							PanacheCreativeObject
     * @see 	com.panache.assets.renditions.IPanacheCreativeRenditionSelector	IPanacheCreativeRenditionSelector
	 */
	public class PanacheCreativeRenditionSelector extends PanacheCreativeObject implements IPanacheCreativeRenditionSelector
	{
		private static const DEBUG_SOURCE:String = "PanacheCreativeRenditionSelector";	

		private var _sName:String = "";
		private var _renditions:Array;
		private var _variationMgr:PanacheCreativeRenditionVariationManager;
		private var _selectedVariation:String = "";
		
		/**
		 * Creates a PanacheCreativeRenditionSelector object.
		 * 
		 * param	nodeName	the xml node name represents the renditions
		 */
		public function PanacheCreativeRenditionSelector(nodeName:String)
		{
			_sName = nodeName;
			_renditions = new Array();
			_variationMgr = new PanacheCreativeRenditionVariationManager(_sName);
		}

		/**
		 * This method adds a rendition to the list of renditions that the selector is managing.
		 * 
		 * @param	rendition	the panache rendition.
		 */
		public function addRendition( rendition:IPanacheCreativeRendition ) : void
		{
			// note a rendition MUST have a width and height parameter and url
			// so if it does not - do not add it
			// unless it is a simple spec - meaning it ONLY has a url
			
			if (rendition != null)
			{
				if (!rendition.hasUrl())
					MediaServicesAdDebug.reportErrorTrace("Cannot add rendition, no url: " + rendition.toString(), null, DEBUG_SOURCE, "addRendition");
				else if (rendition.isSimpleRendition())
					_renditions.push(rendition);	
				else if (isNaN(rendition.width))
					MediaServicesAdDebug.reportErrorTrace("Cannot add rendition, no width: " + rendition.toString(), null, DEBUG_SOURCE, "addRendition");
				else if (isNaN(rendition.height))
					MediaServicesAdDebug.reportErrorTrace("Cannot add rendition, no height: " + rendition.toString(), null, DEBUG_SOURCE, "addRendition");
				else
				{
					var duplicateSpec:Boolean = containsRenditionKey(rendition.key); 
					_renditions.push(rendition);
					if (!rendition.isSimpleRendition())
					{
						_variationMgr.addVariation(rendition);
					}
					else if (duplicateSpec)
					{
						_variationMgr.addOrphanVariation(rendition);
					}
				}	
			}
		}

		/**
		 * This method returns true if a rendition key exists (used in variation selection).
		 * 
		 * @param	key		the rendition key.
		 * 
		 * @return	true if a rendition key exists.
		 */
		public function containsRenditionKey( key:String ) : Boolean
		{
			var answer:Boolean = false;
			for (var i:int = 0; i < _renditions.length; i++)
			{
				var testRendition:IPanacheCreativeRendition = IPanacheCreativeRendition(_renditions[i]);
				if ((testRendition != null) && (testRendition.key == key))
				{
					answer = true;
					break;	
				}
			}
			
			return answer;
		}

		/**
		 * This method selects a "best fit" rendition using the parameters specified in the selection spec.
		 * 
		 * @param	selectionSpec	the selection spec.
		 * 
		 * @return	selected panache rendition interface or null if no rendition is selected.
		 */
		public function select( selectionSpec:IPanacheCreativeRendition) : IPanacheCreativeRendition
		{
			var rendition:IPanacheCreativeRendition;
			
			var n:uint = _renditions.length;
			switch(n)
			{
			case 0:
				rendition = null;
				break;
				
			case 1:
				rendition = _renditions[0];
				break;
				
			default :
				rendition = selectBestFit(selectionSpec);
			}
			
			if (rendition != null)
			{
				// now check to see if there are variations for this rendition
				if (_variationMgr.hasVariations(rendition))
					rendition = _variationMgr.selectVariation(rendition);
				_selectedVariation = rendition.variationName;
			}
			else
				_selectedVariation = "";
			
			return rendition;
		}

		/**
		 * This method returns the name of the selected variation.
		 */
		public function get selectedVariation() : String
		{
			return _selectedVariation;
		}

		/**
		 * This method makes sure all unnamed variations are named.
		 */
		public function validateVariations() : void
		{
			for (var i:int = 0; i < _renditions.length; i++)
			{
				var spec:IPanacheCreativeRendition = _renditions[i];
				// check for spec that have no variation named themselves but 
				// have variations defined for the same key in the variation mananger
				if (spec != null && (spec.variationName == null || spec.variationName.length == 0) && _variationMgr.hasVariations(spec))
				{
					_variationMgr.addOrphanVariation(spec);	
				}
			}
		}

		private function selectBestFit(selectionSpec:IPanacheCreativeRendition) : IPanacheCreativeRendition
		{
			var n:uint = _renditions.length;
			var currentFit:PanacheCreativeRenditionSelectionFit = new PanacheCreativeRenditionSelectionFit(selectionSpec);
			var bestRendition:IPanacheCreativeRendition = null;
			for (var i:int = 0; i < n; i++)
			{
				var rendition:IPanacheCreativeRendition = _renditions[i];	
				if (currentFit.isBetterFit(rendition))
				{
					bestRendition = rendition;
					MediaServicesAdDebug.reportTrace("Temp best rendition = " + bestRendition.url, 
													 DEBUG_SOURCE, "selectBestFit");
				}
			}
			
			MediaServicesAdDebug.reportTrace("Final best rendition = " + bestRendition.url, DEBUG_SOURCE, "selectBestFit");
			return bestRendition;	
		}
		
	}
}