/**
 * VERSION: 1.3
 * DATE: 2010-08-09
 * AS3
 * UPDATES AND DOCS AT: http://www.greensock.com/loadermax/
 **/
package com.greensock.loading {
    import com.greensock.loading.core.LoaderItem;
    import com.greensock.loading.LoaderStatus;
    
    import flash.events.Event;
    import flash.events.ProgressEvent;
    import flash.net.URLLoader;
    
    /** Dispatched when the loader's <code>httpStatus</code> value changes. **/
    [Event("httpStatus", type="com.greensock.events.LoaderEvent")]
    /** Dispatched when the loader experiences a SECURITY_ERROR while loading or auditing its size. **/
    [Event("securityError", type="com.greensock.events.LoaderEvent")]
/**
 * Loads generic data which can be text (the default), binary data, or URL-encoded variables. <br /><br />
 * 
 * If the <code>format</code> vars property is "text", the <code>content</code> will be a String containing the text of the loaded file.<br /><br />
 * If the <code>format</code> vars property is "binary", the <code>content</code> will be a <code>ByteArray</code> object containing the raw binary data.<br /><br />
 * If the <code>format</code> vars property is "variables", the <code>content</code> will be a <code>URLVariables</code> object containing the URL-encoded variables<br /><br />
 * 
 * <strong>OPTIONAL VARS PROPERTIES</strong><br />
 * The following special properties can be passed into the DataLoader constructor via its <code>vars</code> parameter:<br />
 * <ul>
 *         <li><strong> name : String</strong> - A name that is used to identify the loader instance. This name can be fed to the <code>LoaderMax.getLoader()</code> or <code>LoaderMax.getContent()</code> methods or traced at any time. Each loader's name should be unique. If you don't define one, a unique name will be created automatically, like "loader21".</li>
 *         <li><strong> format : String</strong> - Controls whether the downloaded data is received as text (<code>"text"</code>), raw binary data (<code>"binary"</code>), or URL-encoded variables (<code>"variables"</code>). </li>
 *         <li><strong> alternateURL : String</strong> - If you define an <code>alternateURL</code>, the loader will initially try to load from its original <code>url</code> and if it fails, it will automatically (and permanently) change the loader's <code>url</code> to the <code>alternateURL</code> and try again. Think of it as a fallback or backup <code>url</code>. It is perfectly acceptable to use the same <code>alternateURL</code> for multiple loaders (maybe a default image for various ImageLoaders for example).</li>
 *         <li><strong> noCache : Boolean</strong> - If <code>true</code>, a "cacheBusterID" parameter will be appended to the url with a random set of numbers to prevent caching (don't worry, this info is ignored when you <code>LoaderMax.getLoader()</code> or <code>LoaderMax.getContent()</code> by <code>url</code> or when you're running locally)</li>
 *         <li><strong> estimatedBytes : uint</strong> - Initially, the loader's <code>bytesTotal</code> is set to the <code>estimatedBytes</code> value (or <code>LoaderMax.defaultEstimatedBytes</code> if one isn't defined). Then, when the loader begins loading and it can accurately determine the bytesTotal, it will do so. Setting <code>estimatedBytes</code> is optional, but the more accurate the value, the more accurate your loaders' overall progress will be initially. If the loader is inserted into a LoaderMax instance (for queue management), its <code>auditSize</code> feature can attempt to automatically determine the <code>bytesTotal</code> at runtime (there is a slight performance penalty for this, however - see LoaderMax's documentation for details).</li>
 *         <li><strong> requireWithRoot : DisplayObject</strong> - LoaderMax supports <i>subloading</i>, where an object can be factored into a parent's loading progress. If you want LoaderMax to require this DataLoader as part of its parent SWFLoader's progress, you must set the <code>requireWithRoot</code> property to your swf's <code>root</code>. For example, <code>var loader:DataLoader = new DataLoader("text.txt", {name:"myText", requireWithRoot:this.root});</code></li>
 *         <li><strong> autoDispose : Boolean</strong> - When <code>autoDispose</code> is <code>true</code>, the loader will be disposed immediately after it completes (it calls the <code>dispose()</code> method internally after dispatching its <code>COMPLETE</code> event). This will remove any listeners that were defined in the vars object (like onComplete, onProgress, onError, onInit). Once a loader is disposed, it can no longer be found with <code>LoaderMax.getLoader()</code> or <code>LoaderMax.getContent()</code> - it is essentially destroyed but its content is not unloaded (you must call <code>unload()</code> or <code>dispose(true)</code> to unload its content). The default <code>autoDispose</code> value is <code>false</code>.
 *         
 *         <br /><br />----EVENT HANDLER SHORTCUTS----</li>
 *         <li><strong> onOpen : Function</strong> - A handler function for <code>LoaderEvent.OPEN</code> events which are dispatched when the loader begins loading. Make sure your onOpen function accepts a single parameter of type <code>LoaderEvent</code> (<code>com.greensock.events.LoaderEvent</code>).</li>
 *         <li><strong> onProgress : Function</strong> - A handler function for <code>LoaderEvent.PROGRESS</code> events which are dispatched whenever the <code>bytesLoaded</code> changes. Make sure your onProgress function accepts a single parameter of type <code>LoaderEvent</code> (<code>com.greensock.events.LoaderEvent</code>). You can use the LoaderEvent's <code>target.progress</code> to get the loader's progress value or use its <code>target.bytesLoaded</code> and <code>target.bytesTotal</code>.</li>
 *         <li><strong> onComplete : Function</strong> - A handler function for <code>LoaderEvent.COMPLETE</code> events which are dispatched when the loader has finished loading successfully. Make sure your onComplete function accepts a single parameter of type <code>LoaderEvent</code> (<code>com.greensock.events.LoaderEvent</code>).</li>
 *         <li><strong> onCancel : Function</strong> - A handler function for <code>LoaderEvent.CANCEL</code> events which are dispatched when loading is aborted due to either a failure or because another loader was prioritized or <code>cancel()</code> was manually called. Make sure your onCancel function accepts a single parameter of type <code>LoaderEvent</code> (<code>com.greensock.events.LoaderEvent</code>).</li>
 *         <li><strong> onError : Function</strong> - A handler function for <code>LoaderEvent.ERROR</code> events which are dispatched whenever the loader experiences an error (typically an IO_ERROR or SECURITY_ERROR). An error doesn't necessarily mean the loader failed, however - to listen for when a loader fails, use the <code>onFail</code> special property. Make sure your onError function accepts a single parameter of type <code>LoaderEvent</code> (<code>com.greensock.events.LoaderEvent</code>).</li>
 *         <li><strong> onFail : Function</strong> - A handler function for <code>LoaderEvent.FAIL</code> events which are dispatched whenever the loader fails and its <code>status</code> changes to <code>LoaderStatus.FAILED</code>. Make sure your onFail function accepts a single parameter of type <code>LoaderEvent</code> (<code>com.greensock.events.LoaderEvent</code>).</li>
 *         <li><strong> onIOError : Function</strong> - A handler function for <code>LoaderEvent.IO_ERROR</code> events which will also call the onError handler, so you can use that as more of a catch-all whereas <code>onIOError</code> is specifically for LoaderEvent.IO_ERROR events. Make sure your onIOError function accepts a single parameter of type <code>LoaderEvent</code> (<code>com.greensock.events.LoaderEvent</code>).</li>
 *         <li><strong> onHTTPStatus : Function</strong> - A handler function for <code>LoaderEvent.HTTP_STATUS</code> events. Make sure your onHTTPStatus function accepts a single parameter of type <code>LoaderEvent</code> (<code>com.greensock.events.LoaderEvent</code>). You can determine the httpStatus code using the LoaderEvent's <code>target.httpStatus</code> (LoaderItems keep track of their <code>httpStatus</code> when possible, although certain environments prevent Flash from getting httpStatus information).</li>
 * </ul><br />
 * 
 * @example Example AS3 code:<listing version="3.0">
 import com.greensock.loading.~~;
 import com.greensock.events.LoaderEvent;
 import flash.utils.ByteArray;
 import flash.net.URLVariables;
 
//create a DataLoader for loading text (the default format)
var loader:DataLoader = new DataLoader("assets/data.txt", {name:"myText", requireWithRoot:this.root, estimatedBytes:900});

//start loading
loader.load();

//Or you could put the DataLoader into a LoaderMax. Create one first...
var queue:LoaderMax = new LoaderMax({name:"mainQueue", onProgress:progressHandler, onComplete:completeHandler, onError:errorHandler});

//append the DataLoader and several other loaders
queue.append( loader );
queue.append( new DataLoader("assets/variables.txt", {name:"myVariables", format:"variables"}) );
queue.append( new DataLoader("assets/image1.png", {name:"myBinary", format:"binary", estimatedBytes:3500}) );

//start loading the LoaderMax queue
queue.load();

function progressHandler(event:LoaderEvent):void {
    trace("progress: " + event.target.progress);
}

function completeHandler(event:LoaderEvent):void {
    var text:String = LoaderMax.getContent("myText");
    var variables:URLVariables = LoaderMax.getContent("myVariables");
    var binary:ByteArray = LoaderMax.getContent("myBinary");
    trace("complete. myText: " + text + ", myVariables.var1: " + variables.var1 + ", myBinary.length: " + binary.length);
}

function errorHandler(event:LoaderEvent):void {
    trace("error occured with " + event.target + ": " + event.text);
}
 </listing>
 * 
 * <b>Copyright 2010, GreenSock. All rights reserved.</b> This work is subject to the terms in <a href="http://www.greensock.com/terms_of_use.html">http://www.greensock.com/terms_of_use.html</a> or for corporate Club GreenSock members, the software agreement that was issued with the corporate membership.
 * 
 * @author Jack Doyle, jack@greensock.com
 */    
    public class DataLoader extends LoaderItem {
        /** @private **/
        private static var _classActivated:Boolean = _activateClass("DataLoader", DataLoader, "txt,js");
        /** @private **/
        protected var _loader:URLLoader;
        
        /**
         * Constructor
         * 
         * @param urlOrRequest The url (<code>String</code>) or <code>URLRequest</code> from which the loader should get its content.
         * @param vars An object containing optional configuration details. For example: <code>new DataLoader("text/data.txt", {name:"data", onComplete:completeHandler, onProgress:progressHandler})</code>.<br /><br />
         * 
         * The following special properties can be passed into the constructor via the <code>vars</code> parameter:<br />
         * <ul>
         *         <li><strong> name : String</strong> - A name that is used to identify the loader instance. This name can be fed to the <code>LoaderMax.getLoader()</code> or <code>LoaderMax.getContent()</code> methods or traced at any time. Each loader's name should be unique. If you don't define one, a unique name will be created automatically, like "loader21".</li>
         *         <li><strong> format : String</strong> - Controls whether the downloaded data is received as text (<code>"text"</code>), raw binary data (<code>"binary"</code>), or URL-encoded variables (<code>"variables"</code>). </li>
         *         <li><strong> alternateURL : String</strong> - If you define an <code>alternateURL</code>, the loader will initially try to load from its original <code>url</code> and if it fails, it will automatically (and permanently) change the loader's <code>url</code> to the <code>alternateURL</code> and try again. Think of it as a fallback or backup <code>url</code>. It is perfectly acceptable to use the same <code>alternateURL</code> for multiple loaders (maybe a default image for various ImageLoaders for example).</li>
         *         <li><strong> noCache : Boolean</strong> - If <code>true</code>, a "cacheBusterID" parameter will be appended to the url with a random set of numbers to prevent caching (don't worry, this info is ignored when you <code>LoaderMax.getLoader()</code> or <code>LoaderMax.getContent()</code> by <code>url</code> or when you're running locally)</li>
         *         <li><strong> estimatedBytes : uint</strong> - Initially, the loader's <code>bytesTotal</code> is set to the <code>estimatedBytes</code> value (or <code>LoaderMax.defaultEstimatedBytes</code> if one isn't defined). Then, when the loader begins loading and it can accurately determine the bytesTotal, it will do so. Setting <code>estimatedBytes</code> is optional, but the more accurate the value, the more accurate your loaders' overall progress will be initially. If the loader is inserted into a LoaderMax instance (for queue management), its <code>auditSize</code> feature can attempt to automatically determine the <code>bytesTotal</code> at runtime (there is a slight performance penalty for this, however - see LoaderMax's documentation for details).</li>
         *         <li><strong> requireWithRoot : DisplayObject</strong> - LoaderMax supports <i>subloading</i>, where an object can be factored into a parent's loading progress. If you want LoaderMax to require this DataLoader as part of its parent SWFLoader's progress, you must set the <code>requireWithRoot</code> property to your swf's <code>root</code>. For example, <code>var loader:DataLoader = new DataLoader("text.txt", {name:"myText", requireWithRoot:this.root});</code></li>
         *         <li><strong> autoDispose : Boolean</strong> - When <code>autoDispose</code> is <code>true</code>, the loader will be disposed immediately after it completes (it calls the <code>dispose()</code> method internally after dispatching its <code>COMPLETE</code> event). This will remove any listeners that were defined in the vars object (like onComplete, onProgress, onError, onInit). Once a loader is disposed, it can no longer be found with <code>LoaderMax.getLoader()</code> or <code>LoaderMax.getContent()</code> - it is essentially destroyed but its content is not unloaded (you must call <code>unload()</code> or <code>dispose(true)</code> to unload its content). The default <code>autoDispose</code> value is <code>false</code>.
         *         
         *         <br /><br />----EVENT HANDLER SHORTCUTS----</li>
         *         <li><strong> onOpen : Function</strong> - A handler function for <code>LoaderEvent.OPEN</code> events which are dispatched when the loader begins loading. Make sure your onOpen function accepts a single parameter of type <code>LoaderEvent</code> (<code>com.greensock.events.LoaderEvent</code>).</li>
         *         <li><strong> onProgress : Function</strong> - A handler function for <code>LoaderEvent.PROGRESS</code> events which are dispatched whenever the <code>bytesLoaded</code> changes. Make sure your onProgress function accepts a single parameter of type <code>LoaderEvent</code> (<code>com.greensock.events.LoaderEvent</code>). You can use the LoaderEvent's <code>target.progress</code> to get the loader's progress value or use its <code>target.bytesLoaded</code> and <code>target.bytesTotal</code>.</li>
         *         <li><strong> onComplete : Function</strong> - A handler function for <code>LoaderEvent.COMPLETE</code> events which are dispatched when the loader has finished loading successfully. Make sure your onComplete function accepts a single parameter of type <code>LoaderEvent</code> (<code>com.greensock.events.LoaderEvent</code>).</li>
         *         <li><strong> onCancel : Function</strong> - A handler function for <code>LoaderEvent.CANCEL</code> events which are dispatched when loading is aborted due to either a failure or because another loader was prioritized or <code>cancel()</code> was manually called. Make sure your onCancel function accepts a single parameter of type <code>LoaderEvent</code> (<code>com.greensock.events.LoaderEvent</code>).</li>
         *         <li><strong> onError : Function</strong> - A handler function for <code>LoaderEvent.ERROR</code> events which are dispatched whenever the loader experiences an error (typically an IO_ERROR or SECURITY_ERROR). An error doesn't necessarily mean the loader failed, however - to listen for when a loader fails, use the <code>onFail</code> special property. Make sure your onError function accepts a single parameter of type <code>LoaderEvent</code> (<code>com.greensock.events.LoaderEvent</code>).</li>
         *         <li><strong> onFail : Function</strong> - A handler function for <code>LoaderEvent.FAIL</code> events which are dispatched whenever the loader fails and its <code>status</code> changes to <code>LoaderStatus.FAILED</code>. Make sure your onFail function accepts a single parameter of type <code>LoaderEvent</code> (<code>com.greensock.events.LoaderEvent</code>).</li>
         *         <li><strong> onIOError : Function</strong> - A handler function for <code>LoaderEvent.IO_ERROR</code> events which will also call the onError handler, so you can use that as more of a catch-all whereas <code>onIOError</code> is specifically for LoaderEvent.IO_ERROR events. Make sure your onIOError function accepts a single parameter of type <code>LoaderEvent</code> (<code>com.greensock.events.LoaderEvent</code>).</li>
         *         <li><strong> onHTTPStatus : Function</strong> - A handler function for <code>LoaderEvent.HTTP_STATUS</code> events. Make sure your onHTTPStatus function accepts a single parameter of type <code>LoaderEvent</code> (<code>com.greensock.events.LoaderEvent</code>). You can determine the httpStatus code using the LoaderEvent's <code>target.httpStatus</code> (LoaderItems keep track of their <code>httpStatus</code> when possible, although certain environments prevent Flash from getting httpStatus information).</li>
         * </ul>
         */
        public function DataLoader(urlOrRequest:*, vars:Object=null) {
            super(urlOrRequest, vars);
            _type = "DataLoader";
            _loader = new URLLoader(null);
            if ("format" in this.vars) {
                _loader.dataFormat = String(this.vars.format);
            }
            _loader.addEventListener(ProgressEvent.PROGRESS, _progressHandler, false, 0, true);
            _loader.addEventListener(Event.COMPLETE, _receiveDataHandler, false, 0, true);
            _loader.addEventListener("ioError", _failHandler, false, 0, true);
            _loader.addEventListener("securityError", _failHandler, false, 0, true);
            _loader.addEventListener("httpStatus", _httpStatusHandler, false, 0, true);
        }
        
        /** @private **/
        override protected function _load():void {
            _prepRequest();
            _loader.load(_request);
        }
        
        /** @private scrubLevel: 0 = cancel, 1 = unload, 2 = dispose, 3 = flush **/
        override protected function _dump(scrubLevel:int=0, newStatus:int=0, suppressEvents:Boolean=false):void {
            if (_status == LoaderStatus.LOADING) {
                try {
                    _loader.close();
                } catch (error:Error) {
                    
                }
            }
            super._dump(scrubLevel, newStatus, suppressEvents);
        }
        
        
//---- EVENT HANDLERS ------------------------------------------------------------------------------------
        
        /** @private Don't use _completeHandler so that subclasses can set _content differently and still call super._completeHandler() (otherwise setting _content in the _completeHandler would always override the _content previously set in sublcasses). **/
        protected function _receiveDataHandler(event:Event):void {
            _content = _loader.data;
            super._completeHandler(event);
        }
        
//---- GETTERS / SETTERS -------------------------------------------------------------------------
        
        
        
    }
}