1////////////////////////////////////////////////////////////////////////////////
2//
3//  ADOBE SYSTEMS INCORPORATED
4//  Copyright 2005-2007 Adobe Systems Incorporated
5//  All Rights Reserved.
6//
7//  NOTICE: Adobe permits you to use, modify, and distribute this file
8//  in accordance with the terms of the license agreement accompanying it.
9//
10////////////////////////////////////////////////////////////////////////////////
11
12package mx.core
13{
14
15import flash.display.LoaderInfo;
16import flash.display.MovieClip;
17import flash.events.ErrorEvent;
18import flash.events.Event;
19import flash.events.IOErrorEvent;
20import flash.events.SecurityErrorEvent;
21import flash.events.TimerEvent;
22import flash.system.ApplicationDomain;
23import flash.text.TextField;
24import flash.text.TextFieldAutoSize;
25import flash.utils.Dictionary;
26import flash.utils.Timer;
27import flash.utils.getDefinitionByName;
28import mx.core.RSLItem;
29import mx.core.RSLListLoader;
30import mx.events.ModuleEvent;
31import mx.resources.IResourceManager;
32import mx.resources.ResourceManager;
33
34[ExcludeClass]
35
36/**
37 *  @private
38 */
39public class FlexModuleFactory extends MovieClip implements IFlexModuleFactory
40{
41	include "../core/Version.as";
42
43	//--------------------------------------------------------------------------
44	//
45	//  Class constants
46	//
47	//--------------------------------------------------------------------------
48
49    /**
50	 *  @private
51	 */
52    private static const INIT_STATE:int = 0;
53
54    /**
55	 *  @private
56	 */
57	private static const RSL_START_LOAD_STATE:int = 1;
58
59    /**
60	 *  @private
61	 */
62	private static const APP_LOAD_STATE:int = 2;
63
64    /**
65	 *  @private
66	 */
67	private static const APP_START_STATE:int = 3;
68
69    /**
70	 *  @private
71	 */
72	private static const APP_RUNNING_STATE:int = 4;
73
74    /**
75	 *  @private
76	 */
77	private static const ERROR_STATE:int = 5;
78
79    /**
80	 *  @private
81	 */
82	private static const RSL_LOADING_STATE:int = 6;
83
84
85	//--------------------------------------------------------------------------
86	//
87	//  Constructor
88	//
89	//--------------------------------------------------------------------------
90
91    /**
92	 *  @private
93	 */
94	public function FlexModuleFactory()
95    {
96		super();
97
98		var rsls:Array = info()["rsls"];
99		var cdRsls:Array = info()["cdRsls"];
100
101		// Put cross-domain RSL information in the RSL list.
102        var rslList:Array = [];
103        var n:int;
104        var i:int;
105		if (cdRsls && cdRsls.length > 0)
106		{
107			var crossDomainRSLItem:Class = Class(getDefinitionByName("mx.core::CrossDomainRSLItem"));
108			n = cdRsls.length;
109			for (i = 0; i < n; i++)
110			{
111				// If crossDomainRSLItem is null, then this is a compiler error. It should not be null.
112				var cdNode:Object = new crossDomainRSLItem(
113					cdRsls[i]["rsls"],
114					cdRsls[i]["policyFiles"],
115					cdRsls[i]["digests"],
116					cdRsls[i]["types"],
117					cdRsls[i]["isSigned"]);
118
119				rslList.push(cdNode);
120			}
121
122		}
123
124		// Append RSL information in the RSL list.
125		if (rsls != null && rsls.length > 0)
126		{
127			n = rsls.length;
128			for (i = 0; i < n; i++)
129			{
130			    var node:RSLItem = new RSLItem(rsls[i].url);
131				rslList.push(node);
132			}
133		}
134
135        rslListLoader = new RSLListLoader(rslList);
136
137		mixinList = info()["mixins"];
138
139		stop(); // Make sure to stop the playhead on the currentframe
140
141		loaderInfo.addEventListener(Event.COMPLETE, moduleCompleteHandler);
142
143	    var docFrame:int = totalFrames == 1 ? 0 : 1;
144
145        addEventListener(Event.ENTER_FRAME, docFrameListener);
146
147		timer = new Timer(100);
148		timer.addEventListener(TimerEvent.TIMER, timerHandler);
149		timer.start();
150
151        update();
152    }
153
154    private function docFrameListener(event:Event):void
155    {
156        if (currentFrame == 2)
157        {
158            removeEventListener(Event.ENTER_FRAME, docFrameListener);
159            if (totalFrames > 2)
160                addEventListener(Event.ENTER_FRAME, extraFrameListener);
161
162            docFrameHandler();
163        }
164    }
165
166    private function extraFrameListener(event:Event):void
167    {
168        if (lastFrame == currentFrame)
169            return;
170
171        lastFrame = currentFrame;
172
173        if (currentFrame + 1 > totalFrames)
174            removeEventListener(Event.ENTER_FRAME, extraFrameListener);
175
176        extraFrameHandler();
177    }
178
179	//--------------------------------------------------------------------------
180	//
181	//  Variables
182	//
183	//--------------------------------------------------------------------------
184
185  	/**
186	 *  @private
187	 */
188	private var rslListLoader:RSLListLoader;
189
190    /**
191	 *  @private
192	 */
193	private var mixinList:Array;
194
195    /**
196	 *  @private
197	 */
198    private var state:int = INIT_STATE;
199
200    /**
201	 *  @private
202	 */
203	private var appReady:Boolean = false;
204
205    /**
206	 *  @private
207	 */
208	private var appLoaded:Boolean = false;
209
210    /**
211	 *  @private
212	 */
213	private var timer:Timer = null;
214
215    /**
216     *  @private
217     *  Track which frame was last processed
218     */
219    private var lastFrame:int;
220
221    /**
222	 *  @private
223	 */
224	private var nextFrameTimer:Timer = null;
225
226    /**
227	 *  @private
228	 */
229	private var errorMessage:String = null;
230
231    //----------------------------------
232    //  preloadedRSLs
233    //----------------------------------
234
235    /**
236     *  The RSLs loaded by this FlexModuleFactory before the application
237     *  starts. RSLs loaded by the application are not included in this list.
238     *
239     *  Information about preloadedRSLs is stored in a Dictionary. The key is
240     *  the RSL's LoaderInfo. The value is the url the RSL was loaded from.
241     */
242    public function  get preloadedRSLs():Dictionary
243    {
244       // Overriden by compiler generate code.
245        return null;
246    }
247
248	//--------------------------------------------------------------------------
249	//
250	//  Methods
251	//
252	//--------------------------------------------------------------------------
253
254  	/**
255   	 *  @private
256	 *  This method is overridden in the autogenerated subclass.
257   	 */
258    public function create(... params):Object
259    {
260	    var mainClassName:String = info()["mainClassName"];
261
262		if (mainClassName == null)
263	    {
264            var url:String = loaderInfo.loaderURL;
265            var dot:Number = url.lastIndexOf(".");
266            var slash:Number = url.lastIndexOf("/");
267            mainClassName = url.substring(slash + 1, dot);
268	    }
269
270        var mainClass:Class = Class(getDefinitionByName(mainClassName));
271
272        return mainClass? new mainClass() : null;
273    }
274
275  	/**
276   	 *  @private
277   	 */
278    public function info():Object
279    {
280        return {};
281    }
282
283    /**
284     *  Calls Security.allowDomain() for the SWF associated with this FlexModuleFactory.
285     *  plus all the SWFs assocatiated with RSLs preloaded by this FlexModuleFactory.
286     *
287     */
288    public function allowDomain(... domains):void
289    {
290       // Overridden by compiler generated code.
291    }
292
293    /**
294     *  Calls Security.allowInsecureDomain() for the SWF associated with this FlexModuleFactory
295     *  plus all the SWFs assocatiated with RSLs preloaded by this FlexModuleFactory.
296     *
297     */
298    public function allowInsecureDomain(... domains):void
299    {
300       // Overridden by compiler generated code.
301    }
302
303   /**
304    *  @inheritDoc
305    */
306    public function getDefinitionByName(name:String):Object
307    {
308       const domain:ApplicationDomain =
309		info()["currentDomain"] as ApplicationDomain;
310
311       var definition:Object;
312       if (domain.hasDefinition(name))
313          definition = domain.getDefinition(name);
314
315       return definition;
316    }
317
318    /**
319	 *  @private
320	 */
321    private function update():void
322    {
323        switch (state)
324        {
325            case INIT_STATE:
326			{
327                if (rslListLoader.isDone())
328                    state = APP_LOAD_STATE;
329                else
330                    state = RSL_START_LOAD_STATE;
331				break;
332			}
333
334            case RSL_START_LOAD_STATE:
335			{
336			    // start loading all the rsls
337                rslListLoader.load(null,
338                				   rslCompleteHandler,
339                				   rslErrorHandler,
340                				   rslErrorHandler,
341                				   rslErrorHandler);
342                state = RSL_LOADING_STATE;
343                break;
344            }
345            case RSL_LOADING_STATE:
346            {
347                if (rslListLoader.isDone())
348                {
349                    state = APP_LOAD_STATE;
350                }
351                break;
352			}
353
354            case APP_LOAD_STATE:
355			{
356                if (appLoaded)
357                {
358                    deferredNextFrame();
359                    state = APP_START_STATE;
360                }
361                break;
362			}
363
364            case APP_START_STATE:
365			{
366                if (appReady)
367                {
368            		if (mixinList && mixinList.length > 0)
369            		{
370            		    var n:int = mixinList.length;
371            			for (var i:int = 0; i < n; i++)
372            		    {
373            		        var c:Class;
374            		        try
375            		        {
376            		           c =	Class(getDefinitionByName(mixinList[i]));
377            		           c["init"](this);
378            		        }
379            		        catch(e:Error)
380            		        {
381							}
382            		    }
383                    }
384
385                    state = APP_RUNNING_STATE;
386        			timer.removeEventListener(TimerEvent.TIMER, timerHandler);
387        			// Stop the timer.
388        			timer.reset();
389
390                    dispatchEvent(new Event("ready"));
391
392                    loaderInfo.removeEventListener(Event.COMPLETE, moduleCompleteHandler);
393                }
394                break;
395			}
396
397            case ERROR_STATE:
398			{
399                if (timer != null)
400                {
401        			timer.removeEventListener(TimerEvent.TIMER, timerHandler);
402        			// stop the timer
403        			timer.reset();
404                }
405
406                var tf:TextField = new TextField();
407                tf.text = errorMessage;
408                tf.x = 0;
409                tf.y = 0;
410                tf.autoSize = TextFieldAutoSize.LEFT;
411                addChild(tf);
412
413                dispatchEvent(new ModuleEvent(ModuleEvent.ERROR, false, false,
414                              0, 0, errorMessage));
415
416                loaderInfo.removeEventListener(Event.COMPLETE, moduleCompleteHandler);
417                break;
418			}
419        }
420    }
421
422    /**
423	 *  @private
424	 */
425    public function autorun():Boolean
426    {
427        return true;
428    }
429
430    /**
431	 *  @private
432	 */
433    private function displayError(msg:String):void
434    {
435        errorMessage = msg;
436        state = ERROR_STATE;
437        update();
438    }
439
440    /**
441	 *  @private
442	 */
443	private function docFrameHandler(event:Event = null):void
444	{
445		// Register singleton classes.
446		// Note: getDefinitionByName() will return null
447		// if the class can't be found.
448
449		Singleton.registerClass("mx.managers::IBrowserManager",
450			Class(getDefinitionByName("mx.managers::BrowserManagerImpl")));
451
452        Singleton.registerClass("mx.managers::ICursorManager",
453			Class(getDefinitionByName("mx.managers::CursorManagerImpl")));
454
455        Singleton.registerClass("mx.managers::IDragManager",
456			Class(getDefinitionByName("mx.managers::DragManagerImpl")));
457
458        Singleton.registerClass("mx.managers::IHistoryManager",
459			Class(getDefinitionByName("mx.managers::HistoryManagerImpl")));
460
461        Singleton.registerClass("mx.managers::ILayoutManager",
462			Class(getDefinitionByName("mx.managers::LayoutManager")));
463
464        Singleton.registerClass("mx.managers::IPopUpManager",
465			Class(getDefinitionByName("mx.managers::PopUpManagerImpl")));
466
467		Singleton.registerClass("mx.resources::IResourceManager",
468			Class(getDefinitionByName("mx.resources::ResourceManagerImpl")));
469
470        Singleton.registerClass("mx.styles::IStyleManager",
471			Class(getDefinitionByName("mx.styles::StyleManagerImpl")));
472
473        Singleton.registerClass("mx.styles::IStyleManager2",
474			Class(getDefinitionByName("mx.styles::StyleManagerImpl")));
475
476        Singleton.registerClass("mx.managers::IToolTipManager2",
477			Class(getDefinitionByName("mx.managers::ToolTipManagerImpl")));
478
479		appReady = true;
480
481        // The resources must be installed before update() creates components
482		// (such as DateChooswer) that might need them immediately.
483		installCompiledResourceBundles();
484
485		update();
486
487		if (currentFrame < totalFrames)
488            deferredNextFrame();
489    }
490
491    /**
492	 *  @private
493	 */
494	private function installCompiledResourceBundles():void
495	{
496		//trace("FlexModuleFactory.installCompiledResourceBundles");
497
498		var info:Object = this.info();
499
500		var applicationDomain:ApplicationDomain =
501            info["currentDomain"];
502
503		var compiledLocales:Array /* of String */ =
504			info["compiledLocales"];
505
506		var compiledResourceBundleNames:Array /* of String */ =
507			info["compiledResourceBundleNames"];
508
509		var resourceManager:IResourceManager =
510			ResourceManager.getInstance();
511
512		resourceManager.installCompiledResourceBundles(
513			applicationDomain, compiledLocales, compiledResourceBundleNames);
514
515		// If the localeChain wasn't specified in the FlashVars of the SWF's
516		// HTML wrapper, or in the query parameters of the SWF URL,
517		// then initialize it to the list of compiled locales,
518        // sorted according to the system's preferred locales as reported by
519        // Capabilities.languages or Capabilities.language.
520		// For example, if the applications was compiled with, say,
521		// -locale=en_US,ja_JP and Capabilities.languages reports [ "ja-JP" ],
522        // set the localeChain to [ "ja_JP" "en_US" ].
523		if (!resourceManager.localeChain)
524			resourceManager.initializeLocaleChain(compiledLocales);
525	}
526
527    /**
528	 *  @private
529	 */
530    private function deferredNextFrame():void
531    {
532        if (currentFrame + 1 <= framesLoaded)
533		{
534            nextFrame();
535		}
536        else
537        {
538            // Next frame isn't baked yet, we'll check back...
539    		nextFrameTimer = new Timer(100);
540		    nextFrameTimer.addEventListener(TimerEvent.TIMER,
541											nextFrameTimerHandler);
542		    nextFrameTimer.start();
543        }
544    }
545    /**
546	 *  @private
547	 */
548	private function extraFrameHandler(event:Event = null):void
549	{
550	    var frameList:Object = info()["frames"];
551
552	    if (frameList && frameList[currentLabel])
553	    {
554	        var c:Class;
555	        try
556	        {
557	            c = Class(getDefinitionByName(frameList[currentLabel]));
558	            c["frame"](this);
559	        }
560	        catch(e:Error)
561	        {
562			}
563	    }
564
565	    if (currentFrame < totalFrames)
566            deferredNextFrame();
567	}
568
569	//--------------------------------------------------------------------------
570	//
571	//  Event handlers
572	//
573	//--------------------------------------------------------------------------
574
575    /**
576	 *  @private
577	 */
578    private function rslCompleteHandler(event:Event):void
579    {
580        var rsl:RSLItem = rslListLoader.getItem(rslListLoader.getIndex());
581        if (event.target is LoaderInfo)
582            preloadedRSLs[event.target] = rsl.urlRequest.url;
583        update();
584    }
585
586    /**
587	 *  @private
588	 */
589    private function rslErrorHandler(event:Event):void
590    {
591        var rsl:RSLItem = rslListLoader.getItem(rslListLoader.getIndex());
592        var detailedError:String;
593        var message:String;
594
595        if (event is ErrorEvent)
596            detailedError = ErrorEvent(event).text;
597
598        if (!detailedError)
599            detailedError = "";
600
601        message = "RSL " + rsl.urlRequest.url + " failed to load. " + detailedError;
602        trace(message);
603        displayError(message);
604    }
605
606    /**
607	 *  @private
608	 */
609    private function moduleCompleteHandler(event:Event):void
610    {
611        appLoaded = true;
612		update();
613    }
614
615    /**
616	 *  @private
617	 */
618	private function timerHandler(event:TimerEvent):void
619	{
620	    if (totalFrames > 2 && framesLoaded >= 2 ||
621			framesLoaded == totalFrames)
622		{
623            appLoaded = true;
624		}
625
626		update();
627    }
628
629    /**
630	 *  @private
631	 */
632	private function nextFrameTimerHandler(event:TimerEvent):void
633	{
634	    if (currentFrame + 1 <= framesLoaded)
635	    {
636	        nextFrame();
637            nextFrameTimer.removeEventListener(TimerEvent.TIMER,
638											   nextFrameTimerHandler);
639        	// stop the timer
640        	nextFrameTimer.reset();
641        }
642    }
643}
644
645}
646