1 /* 2 * Copyright the original author or authors. 3 * 4 * Licensed under the MOZILLA PUBLIC LICENSE, Version 1.1 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.mozilla.org/MPL/MPL-1.1.html 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 import org.as2lib.env.event.EventSupport; 18 import org.as2lib.env.event.impulse.FrameImpulse; 19 import org.as2lib.env.event.impulse.FrameImpulseListener; 20 import org.as2lib.util.ArrayUtil; 21 import org.as2lib.app.exec.StepByStepProcess; 22 23 /** 24 * {@code Processor} executes any {@code StepByStepProcess} for step based code execution. 25 * 26 * <p>MM Flash Player has got a time limit for the execution of code. {@code Processor} 27 * allows to seperate code into steps. 28 * 29 * <p>It executes every step of a added {@code StepByStepProcess}. 30 * If the {@code StepByStepProcess} reaches the (@link #MAX_EXECUTION_TIME} 31 * limit during the exeuction, the {@code Processor} pauses for one frame as 32 * workaround for this time limitation. 33 * 34 * <p>Within the pause, anything may happen. It may require a complex implemnetation 35 * strategy within the {@code StepByStepProcess}. 36 * 37 * <p>{@code Processor} observes {@link FrameImpulse} if any {@code StepByStepProcess} 38 * has to be executed. It automatically removes itself as observer if all 39 * processes have finished. 40 * 41 * <p>{@code Processor} is built as singleton. It is possible to access it by 42 * {@code Processor.getInstance()}. 43 * 44 * @author Martin Heidegger 45 * @version 1.0 46 */ 47 class org.as2lib.app.exec.Processor extends EventSupport implements FrameImpulseListener { 48 49 /** Time until pause of the execution. */ 50 public static var MAX_EXECUTION_TIME:Number = 1500; 51 52 /** Instance of the used {@code Processor} in {@code getInstance}. */ 53 private static var instance:Processor; 54 55 /** 56 * Singleton - returns the default instance of the {@code Processor} 57 * 58 * @return instance of the {@code Processor} 59 */ 60 public static function getInstance(Void):Processor { 61 if (!instance) { 62 instance = new Processor(); 63 } 64 return instance; 65 } 66 67 /** Flag if the processor is running (connected to the FrameImpulseListener) */ 68 private var running:Boolean = false; 69 70 /** Current process to handle */ 71 private var current:Number; 72 73 /** List of all processes currently executing */ 74 private var processList:Array; 75 76 /** 77 * Constructs a new {@code Processor} instance. 78 */ 79 private function Processor(Void) { 80 processList = new Array(); 81 } 82 83 /** 84 * Adds a new {@code StepByStepProcess} to the execution list. 85 * 86 * <p>It is possible that a {@code StepByStepProcess} can be added twice. 87 * 88 * <p>The {@code Processor} will automatically awake from stand-by. 89 * 90 * @param p {@code StepByStepProcess} to be added 91 */ 92 public function addStepByStepProcess(p:StepByStepProcess):Void { 93 processList.push(p); 94 awakeFromStandBy(); 95 } 96 97 /** 98 * Removes all occurances of {@code StepByStepProcess}. 99 * 100 * @param p {@code StepByStepProcess} to be removed 101 */ 102 public function removeStepByStepProcess(p:StepByStepProcess):Void { 103 var formerLength = processList.length; 104 var result:Array = ArrayUtil.removeElement(processList, p); 105 var i:Number = result.length; 106 // Shift the current cursor 107 // Backward processing to ensure the correct size. 108 while (--i-(-1)) { 109 if (current > result[i]) { 110 current --; 111 } 112 } 113 } 114 115 /** 116 * Restart listening to the {@code FrameImpulse} 117 */ 118 private function awakeFromStandBy(Void):Void { 119 if (!running) { 120 running = true; 121 current = 0; 122 FrameImpulse.getInstance().addFrameImpulseListener(this); 123 } 124 } 125 126 /** 127 * Stop listening to the {@code FrameImpulse}. 128 */ 129 private function gotoStandBy(Void):Void { 130 running = false; 131 FrameImpulse.getInstance().removeFrameImpulseListener(this); 132 } 133 134 /** 135 * Handling of the event of {@link FrameImpulse}. 136 * 137 * @param impulse {@code FrameImpulse} that executes the impulse 138 */ 139 public function onFrameImpulse(impulse:FrameImpulse):Void { 140 var startTime:Number = getTimer(); 141 while (current < processList.length) { 142 143 var currentProcessable:StepByStepProcess = processList[current]; 144 while (!currentProcessable.hasFinished()) { 145 146 if (startTime+MAX_EXECUTION_TIME < getTimer() || currentProcessable.isPaused()) { 147 return; 148 } 149 150 currentProcessable.nextStep(); 151 } 152 current ++; 153 } 154 processList = new Array(); 155 gotoStandBy(); 156 } 157 158 }