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.overload.Overload; 18 import org.as2lib.app.exec.AbstractProcess; 19 import org.as2lib.app.exec.Call; 20 import org.as2lib.app.exec.Executable; 21 import org.as2lib.app.exec.ForEachExecutable; 22 import org.as2lib.env.event.impulse.FrameImpulse; 23 24 /** 25 * {@code Timeout} works as delayed execution of a executable. 26 * 27 * <p>As {@code Timeout} implements {@link Executable} it works like a usual 28 * executable and can be started with {@link #execute}. 29 * 30 * <p>As {@code Timeout} implements {@link Process} its possible to handle it 31 * as process. 32 * 33 * <p>{@code Timeout} works framebased, that means you have to define the delay 34 * in number of frames. 35 * 36 * <p>Due to the definition of Call all arguments passed-in in {@link #execute} 37 * will be passed to the connected executable 38 * 39 * Example for a direct execution: 40 * <code> 41 * import org.as2lib.app.exec.Timeout; 42 * import org.as2lib.app.exec.Call; 43 * 44 * Timeout.timeout(new Call(myObj, myMethod), 20, ["1", "2"]); 45 * </code> 46 * 47 * Example for a controlable usage: 48 * <code> 49 * import org.as2lib.app.exec.Timeout; 50 * import org.as2lib.app.exec.Call; 51 * 52 * var call:Call = new Call(myObj, myMethod); 53 * var frames:Number = 20; 54 * var t:Timeout = new Timeout(call, frames); 55 * t.execute("argument 1", "argument 2"); 56 * </code> 57 * 58 * @author Martin Heidegger 59 * @version 1.0 60 * @see Executable#execute 61 */ 62 class org.as2lib.app.exec.Timeout extends AbstractProcess implements ForEachExecutable { 63 64 /** Connected Executable */ 65 private var exe:Executable; 66 67 /** Amount of frames until execution (delay) */ 68 private var frames:Number; 69 70 /** Amount of listened frames */ 71 private var executed:Number; 72 73 /** 74 * List of the targets (arguments) for the execution. 75 * used in {@link #forEach}. 76 */ 77 private var target:Array; 78 79 /** Call to the onEnterFrame listener */ 80 private var timeCall:Call; 81 82 /** 83 * Simplyfier for the execution of a timeout. 84 * 85 * <p>Allows creation and execution of a {@code Timeout} with one call. 86 * 87 * @param exe Executable to excute after a delay 88 * @param frames Amout of frames during the end of the execution 89 * @param args Arguments to be passed at execution 90 */ 91 public static function setTimeout(exe:Executable, frames:Number, args:Array) { 92 var t:Function = eval("th"+"is"); 93 var o = new t(exe, frames).execute(args); 94 } 95 96 /** 97 * Creates a new {@code Timeout} instance. 98 * 99 * @overload #setExecutable 100 * @overload #setExecutableByObjectAndFunction 101 */ 102 public function Timeout() { 103 timeCall = new Call(this, onEnterFrame); 104 var o:Overload = new Overload(this); 105 o.addHandler([Executable, Number], setExecutable); 106 o.addHandler([Object, Function, Number], setExecutableByObjectAndFunction); 107 o.forward(arguments); 108 } 109 110 /** 111 * Sets the connected executable. 112 * 113 * @param exe Executable to be executed after the delay 114 * @param frames Delay in frames until execution. 115 */ 116 public function setExecutable(exe:Executable, frames:Number):Void { 117 this.exe = exe; 118 this.frames = frames; 119 } 120 121 /** 122 * Sets the connected executable with a generated call. 123 * 124 * @param inObject Scope of the execution 125 * @param func Method to execute 126 * @param frames Delay in frames until execution. 127 */ 128 public function setExecutableByObjectAndFunction(inObject:Object, func:Function, frames:Number):Void { 129 setExecutable(new Call(inObject, func), frames); 130 } 131 132 /** 133 * Starts the delay until the execution of the connected Executable. 134 * 135 * @see #setExecutable 136 * @see #setExecutableByObjectAndFunction 137 * @see Executable#execute 138 */ 139 public function execute() { 140 executed = 1; 141 if (!target) target = new Array(); 142 target.push(arguments); 143 working = true; 144 FrameImpulse.getInstance().connectExecutable(timeCall); 145 return null; 146 } 147 148 /** 149 * Referes to execute. 150 * 151 * <p>Implementation of {@link AbstractProcess#run} for using it as a 152 * process. 153 */ 154 public function run(Void):Void { 155 execute.apply(this, arguments); 156 } 157 158 /** 159 * Executed the Timeout for all iterable objects. 160 * 161 * <p>If you execute .forEach to Timeout it will redirect content, name and 162 * the object to each execution of the connected call. 163 * 164 * Example: 165 * <code> 166 * import org.as2lib.app.exec.Timeout; 167 * 168 * function display(content, name, inObject) { 169 * trace("Executed: "+content+", "+name+", "+inObject+";"); 170 * } 171 * 172 * var t:Timeout = new Timeout(this, display, 40); 173 * t.forEach({a:"1", b:"2", c:"3"}); 174 * </code> 175 * 176 * Delays for 40 frames: 177 * <pre> 178 * Executed: 1, a, [Object object]; 179 * Executed: 2, b, [Object object]; 180 * Executed: 3, c, [Object object]; 181 * </pre> 182 * 183 * @param object Object to be iterated 184 * @return null as the result isn't available yet. 185 */ 186 public function forEach(object):Array { 187 executed = 0; 188 if (!target) target = new Array(); 189 var i:String; 190 for (i in object) { 191 target.push([object[i], i, object]); 192 } 193 execute(); 194 FrameImpulse.getInstance().connectExecutable(timeCall); 195 return null; 196 } 197 198 /** 199 * Executed on each interval execution. 200 */ 201 private function onEnterFrame(Void):Void { 202 if (executed++ > frames) { 203 finalExecution(); 204 } 205 } 206 207 /** 208 * Internal method to finish the execution. 209 */ 210 private function finalExecution(impulse:FrameImpulse):Void { 211 executed = 1; 212 var i:Number; 213 impulse.disconnectExecutable(timeCall); 214 var oldTarget = target.concat(); 215 target = new Array(); 216 217 // Applying the execution to multiple targets (foreach) 218 try { 219 for (i=0; i<oldTarget.length; i++) { 220 exe["execute"].apply(exe, oldTarget[i]); 221 } 222 finish(); 223 } catch(e) { 224 interrupt(e); 225 } 226 } 227 }