package sk.yoz.net { import __AS3__.vec.Vector; import flash.events.Event; import flash.events.EventDispatcher; import flash.events.IOErrorEvent; import flash.events.TimerEvent; import flash.net.URLRequest; import flash.utils.Timer; import sk.yoz.events.URLRequestBufferEvent; public class URLRequestBuffer extends EventDispatcher { private var maxRequests:uint = 2; private var timeout:uint; private var waitingList:Vector. = new Vector.(); private var activeList:Vector. = new Vector.(); private var nextID:uint = 0; public function URLRequestBuffer(maxRequests:uint, timeout:uint=3000) { super(); this.maxRequests = Math.max(1, maxRequests); this.timeout = timeout; } public function push(loader:EventDispatcher, request:URLRequest, priority:uint = 0, delay:uint = 0):URLRequestBufferItem { nextID++; var index:uint = getIndexForPriority(priority); var item:URLRequestBufferItem = new URLRequestBufferItem( this, nextID, loader, request, priority, delay) waitingList.splice(index, 0, item); var type:String = URLRequestBufferEvent.WAITING_REQUEST_ADDED; dispatchEvent(new URLRequestBufferEvent(type, false, false, item)); loadNext(); return item; } public function get countWaiting():uint { return waitingList.length; } public function get countActive():uint { return activeList.length; } public function getWaitingItem(index:uint):URLRequestBufferItem { return waitingList[index]; } public function getActiveItem(index:uint):URLRequestBufferItem { return activeList[index]; } protected function getIndexForPriority(priority:uint):uint { var length:uint = countWaiting; for(var i:uint = 0; i < length; i++) if(priority > waitingList[i].priority) return i; return length; } protected function get firstWaitingReadyItem():URLRequestBufferItem { var item:URLRequestBufferItem; var length:uint = countWaiting; for(var i:uint = 0; i < length; i++) { item = waitingList[i]; if(item.ready) return item; } return null; } public function loadNext():void { if(countActive >= maxRequests || !countWaiting) return; var item:URLRequestBufferItem = firstWaitingReadyItem; if(!item) return; removeWaitingById(item.id); createListeners(item.dispatcher); item.load(); activeList.push(item); var timer:Timer = new Timer(timeout, 1); timer.addEventListener(TimerEvent.TIMER_COMPLETE, function(event:TimerEvent):void { EventDispatcher(event.currentTarget) .removeEventListener(event.type, arguments.callee); onTimeout(event, item.id); }); timer.start(); var type:String = URLRequestBufferEvent.ACTIVE_REQUEST_ADDED; dispatchEvent(new URLRequestBufferEvent(type, false, false, item)); loadNext(); } protected function createListeners(dispatcher:EventDispatcher):void { dispatcher.addEventListener(Event.COMPLETE, onComplete); dispatcher.addEventListener(IOErrorEvent.IO_ERROR, onIOError); } protected function removeListeners(dispatcher:EventDispatcher):void { dispatcher.removeEventListener(Event.COMPLETE, onComplete); dispatcher.removeEventListener(IOErrorEvent.IO_ERROR, onIOError); } protected function onComplete(event:Event):void { var loader:EventDispatcher = URLRequestBufferItem.getLoader(event); var item:URLRequestBufferItem = getActiveByLoader(loader); if(item) removeActiveById(item.id); loadNext(); } protected function onIOError(event:IOErrorEvent):void { var loader:EventDispatcher = URLRequestBufferItem.getLoader(event); var item:URLRequestBufferItem = getActiveByLoader(loader); if(item) removeActiveById(item.id); loadNext(); } protected function onTimeout(event:TimerEvent, id:uint):void { var item:URLRequestBufferItem = getActiveById(id); if(!item) return; removeActiveById(id); var type:String = URLRequestBufferEvent.REQUEST_TIMEOUT; dispatchEvent(new URLRequestBufferEvent(type, false, false, item)); } public function getWaitingById(id:uint):URLRequestBufferItem { var length:uint = countWaiting; for(var i:uint = 0; i < length; i++) if(waitingList[i].id == id) return waitingList[i]; return null; } public function getWaitingByLoader(loader:EventDispatcher) :URLRequestBufferItem { var length:uint = countWaiting; for(var i:uint = 0; i < length; i++) if(waitingList[i].loader == loader) return waitingList[i]; return null; } public function removeWaitingById(id:uint):URLRequestBufferItem { var item:URLRequestBufferItem = getWaitingById(id); if(!item) return null; waitingList.splice(waitingList.indexOf(item), 1); var type:String = URLRequestBufferEvent.WAITING_REQUEST_REMOVED; dispatchEvent(new URLRequestBufferEvent(type, false, false, item)); return item; } public function getActiveById(id:uint):URLRequestBufferItem { var length:uint = countActive; for(var i:uint = 0; i < length; i++) if(activeList[i].id == id) return activeList[i]; return null; } public function getActiveByLoader(loader:EventDispatcher):URLRequestBufferItem { var length:uint = countActive; for(var i:uint = 0; i < length; i++) if(activeList[i].loader == loader) return activeList[i]; return null; } public function removeActiveById(id:uint):URLRequestBufferItem { var item:URLRequestBufferItem = getActiveById(id); if(!item) return null; removeListeners(item.dispatcher); item.close(); activeList.splice(activeList.indexOf(item), 1); var type:String = URLRequestBufferEvent.ACTIVE_REQUEST_REMOVED; dispatchEvent(new URLRequestBufferEvent(type, false, false, item)); loadNext(); return item; } } }