/* CASA Framework for ActionScript 3.0 Copyright (c) 2008, Contributors of CASA Framework All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - Neither the name of the CASA Framework nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.casaframework.load { import flash.events.Event; import flash.events.EventDispatcher; import flash.events.IOErrorEvent; import flash.events.ProgressEvent; import flash.net.URLRequest; import flash.utils.getTimer; import org.casaframework.errors.ArguementTypeError; import org.casaframework.events.LoadEvent; import org.casaframework.events.RetryEvent; import org.casaframework.load.BaseLoadItem; import org.casaframework.math.Percent; import org.casaframework.util.LoadUtil; [Event(name="complete", type="org.casaframework.events.LoadEvent")] [Event(name="ioError", type="flash.events.IOErrorEvent")] [Event(name="progress", type="org.casaframework.events.LoadEvent")] [Event(name="retry", type="org.casaframework.events.RetryEvent")] [Event(name="start", type="org.casaframework.events.LoadEvent")] [Event(name="stop", type="org.casaframework.events.LoadEvent")] /** Base class used by load classes. LoadItem is not designed to be used on its own and needs to be extended to function. @author Aaron Clinger @version 06/03/08 */ public class LoadItem extends BaseLoadItem { protected var _attempts:uint; protected var _baseUrl:String; protected var _loaded:Boolean; protected var _loading:Boolean; protected var _preventCache:Boolean; protected var _retries:uint = 2; protected var _dispatcher:EventDispatcher; protected var _Bps:int = -1; protected var _loadItem:*; protected var _progress:Percent = new Percent(); protected var _request:URLRequest; protected var _startTime:uint; /** Defines the load object and file location. @param load: The load object. @param request: A String or an URLRequest reference to the file you wish to load. @throws ArguementTypeError if you pass a value type other than a String or URLRequest to parameter {@code request}. */ public function LoadItem(load:*, request:*) { super(); if (request is String) { request = new URLRequest(request); } else if (!(request is URLRequest)) { throw new ArguementTypeError('request'); } this._baseUrl = request.url; this._loadItem = load; this._request = request; } /** Begins the loading process. @sends LoadEvent#START - Dispatched when a load is started. */ override public function start():void { if (this._loading) return; this._loading = true; this._loaded = false; this._startTime = getTimer(); this._attempts = 0; this._progress = new Percent(); this._Bps = -1; if (this._preventCache) { var cache:String = 'casaCache=' + int(1000 * Math.random()); if (this._baseUrl.indexOf('?') == -1) { this._request.url = this._baseUrl + '?' + cache; } else { this._request.url = this._baseUrl + '&' + cache; } } this._load(); this.dispatchEvent(this._createDefinedLoadEvent(LoadEvent.START)); } /** Cancels the currently loading file from completing. @sends LoadEvent#STOP - Dispatched if the load is stopped during the loading process. */ override public function stop():void { if (!this.loading) return; this._loadItem.close(); this.dispatchEvent(this._createDefinedLoadEvent(LoadEvent.STOP)); this._loading = false; } /** Specifies if a random value name/value pair should be appended to the query string to help prevent caching {@code true}, or not append {@code false}; defaults to {@code false}. */ override public function get preventCache():Boolean { return this._preventCache; } override public function set preventCache(cache:Boolean):void { this._preventCache = cache; } /** The total number of bytes of the requested file. */ public function get bytesTotal():uint { return this._loadItem.bytesTotal; } /** The number of bytes loaded of the requested file. */ public function get bytesLoaded():uint { return this._loadItem.bytesLoaded; } /** The percent that the requested file has loaded. */ override public function get progress():Percent { return this._progress.clone(); } /** The number of times the file has attempted to load after {@link #start start} was called. */ public function get attempts():uint { return this._attempts; } /** The number of additional load retires the class should attempt before failing; defaults to {@code 2} additional retries / {@code 3} total load attempts. */ public function get retries():uint { return this._retries; } public function set retries(amount:uint):void { this._retries = amount; } /** The URLRequest reference to the requested file. */ public function get urlRequest():URLRequest { return this._request; } /** Determines if the requested file is loading {@code true}, or if it isn't currently loading {@code false}. */ override public function get loading():Boolean { return this._loading; } /** Determines if the requested file has loaded {@code true}, or hasn't finished loading {@code false}. */ override public function get loaded():Boolean { return this._loaded; } /** The current download speed of the requested file in bytes per second. */ override public function get Bps():int { return this._Bps; } protected function _initListeners(dispatcher:EventDispatcher):void { dispatcher.addEventListener(Event.COMPLETE, this._onComplete, false, 0, true); dispatcher.addEventListener(IOErrorEvent.IO_ERROR, this._onLoadError, false, 0, true); dispatcher.addEventListener(ProgressEvent.PROGRESS, this._onProgress, false, 0, true); this._dispatcher = dispatcher; } protected function _load():void { this._loadItem.load(this._request); } /** @sends RetryEvent#RETRY - Dispatched if the download attempt failed and the class is going to attempt to download the file again. @sends IOErrorEvent#IO_ERROR - Dispatched if requested file cannot be loaded and the download terminates. */ protected function _onLoadError(error:Event):void { if (++this._attempts <= this._retries) { var retry:RetryEvent = new RetryEvent(RetryEvent.RETRY); retry.attempts = this._attempts; this.dispatchEvent(retry); this._load(); } else { this._loading = false; this.stop(); this.dispatchEvent(error); } } protected function _onProgress(progress:ProgressEvent):void { this._calculateLoadProgress(); } /** @sends LoadEvent#PROGRESS - Dispatched as data is recieved during the download process. */ protected function _calculateLoadProgress():void { this._Bps = LoadUtil.calculateBps(this.bytesLoaded, this._startTime, getTimer()); this._progress.decimalPercentage = this.bytesLoaded / this.bytesTotal; this.dispatchEvent(this._createDefinedLoadEvent(LoadEvent.PROGRESS)); } /** @sends LoadEvent#COMPLETE - Dispatched when file has completely loaded. */ protected function _onComplete(complete:Event):void { this._complete(); this.dispatchEvent(this._createDefinedLoadEvent(LoadEvent.COMPLETE)); } protected function _createDefinedLoadEvent(type:String):LoadEvent { var loadEvent:LoadEvent = new LoadEvent(type); loadEvent.bytesLoaded = this.bytesLoaded; loadEvent.bytesTotal = this.bytesTotal; loadEvent.progress = this.progress; loadEvent.Bps = this.Bps; return loadEvent; } protected function _complete():void { this._loading = false; this._loaded = true; this._Bps = LoadUtil.calculateBps(this.bytesTotal, this._startTime, getTimer()); this._progress.decimalPercentage = 1; } } }