/*****************************************************
*  
*  Copyright 2009 Adobe Systems Incorporated.  All Rights Reserved.
*  
*****************************************************
*  The contents of this file are subject to the Mozilla Public License
*  Version 1.1 (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.mozilla.org/MPL/
*   
*  Software distributed under the License is distributed on an "AS IS"
*  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
*  License for the specific language governing rights and limitations
*  under the License.
*   
*  
*  The Initial Developer of the Original Code is Adobe Systems Incorporated.
*  Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems 
*  Incorporated. All Rights Reserved. 
*  
*****************************************************/
package org.osmf.elements.compositeClasses
{
	import flash.utils.Dictionary;
	
	import org.osmf.containers.IMediaContainer;
	import org.osmf.events.ContainerChangeEvent;
	import org.osmf.events.DisplayObjectEvent;
	import org.osmf.layout.MediaElementLayoutTarget;
	import org.osmf.media.MediaElement;
	import org.osmf.traits.DisplayObjectTrait;
	import org.osmf.traits.MediaTraitBase;
	import org.osmf.traits.MediaTraitType;

	/**
	 * The view property of the composite trait of a parallel composition refers to a
	 * DisplayObjectContainer implementing instance, that holds each of the composition's
	 * view children's DisplayObject.
	 * 
	 * The bounds of the container determine the size of the composition.
	 *  
	 *  @langversion 3.0
	 *  @playerversion Flash 10
	 *  @playerversion AIR 1.5
	 *  @productversion OSMF 1.0
	 */	
	internal class ParallelDisplayObjectTrait extends CompositeDisplayObjectTrait
	{
		/**
		 * Constructor
		 *  
		 *  @langversion 3.0
		 *  @playerversion Flash 10
		 *  @playerversion AIR 1.5
		 *  @productversion OSMF 1.0
		 */
		public function ParallelDisplayObjectTrait(traitAggregator:TraitAggregator, owner:MediaElement)
		{
			super(traitAggregator, owner);
			
			traitAggregationHelper = new TraitAggregationHelper
				( traitType
				, traitAggregator
				, processAggregatedChild
				, processUnaggregatedChild
				);

			// Add all of our children to the layout renderer:
			for (var i:int = 0; i < this.owner.numChildren; i++)
			{
				var child:MediaElement = this.owner.getChildAt(i);
				
				var target:MediaElementLayoutTarget = MediaElementLayoutTarget.getInstance(child);
				target.addEventListener
					( ContainerChangeEvent.CONTAINER_CHANGE
					, onLayoutTargetContainerChange
					);
				
				mediaElementLayoutTargets[child] = target;
				
				setupLayoutTarget(target);
			}
		}
		
		// Overrides
		//
		
		override public function dispose():void
		{
			traitAggregationHelper.detach();
			traitAggregationHelper = null;
			
			super.dispose();
		}
		
		// Internals
		//

		private function processAggregatedChild(childTrait:MediaTraitBase, child:MediaElement):void
		{
			childTrait.addEventListener(DisplayObjectEvent.MEDIA_SIZE_CHANGE, onMediaSizeChange, false, 0, true);
			
			var layoutTarget:MediaElementLayoutTarget = mediaElementLayoutTargets[child];
			
			if (layoutTarget == null)
			{
				var target:MediaElementLayoutTarget = MediaElementLayoutTarget.getInstance(child);
				
				child.addEventListener
					( ContainerChangeEvent.CONTAINER_CHANGE
					, onLayoutTargetContainerChange
					);
				
				mediaElementLayoutTargets[child] = target;
				
				setupLayoutTarget(target);
			}	
		}
		
		private function processUnaggregatedChild(childTrait:MediaTraitBase, child:MediaElement):void
		{
			childTrait.removeEventListener(DisplayObjectEvent.MEDIA_SIZE_CHANGE, onMediaSizeChange);
			
			var target:MediaElementLayoutTarget = mediaElementLayoutTargets[child];
				
			child.removeEventListener
				( ContainerChangeEvent.CONTAINER_CHANGE
				, onLayoutTargetContainerChange
				);
			
			if (layoutRenderer.hasTarget(target))
			{
				layoutRenderer.removeTarget(target);
			}
			
			delete mediaElementLayoutTargets[child];
		}
		
		private function setupLayoutTarget(target:MediaElementLayoutTarget):void
		{
			var container:IMediaContainer = target.mediaElement.container; 
			if (container && container != owner.container)
			{
				if (layoutRenderer.hasTarget(target))
				{
					layoutRenderer.removeTarget(target);	
				}
			}
			else
			{
				if (layoutRenderer.hasTarget(target) == false)
				{
					layoutRenderer.addTarget(target);
				}
			}
		}
		
		private function onLayoutTargetContainerChange(event:ContainerChangeEvent):void
		{
			var mediaElement:MediaElement = event.target as MediaElement;
			
			setupLayoutTarget(mediaElementLayoutTargets[mediaElement]);
		}
		
		private function onMediaSizeChange(event:DisplayObjectEvent):void
		{
			updateMediaSize();
		}
		
		private function updateMediaSize():void
		{
			var newMediaWidth:int = -1;
			var newMediaHeight:int = -1;
			
			traitAggregator.forEachChildTrait
				(	function(trait:DisplayObjectTrait):void
					{
						newMediaWidth = Math.max(newMediaWidth, trait.mediaWidth);
						newMediaHeight = Math.max(newMediaHeight, trait.mediaHeight);
					}
				,	MediaTraitType.DISPLAY_OBJECT
				);
					
			setMediaSize(newMediaWidth, newMediaHeight);
		}

		private var traitAggregationHelper:TraitAggregationHelper;
		private var mediaElementLayoutTargets:Dictionary = new Dictionary();
	}
}