/* TraceManager Class by Christopher J. Rock http://blog.sokay.net modified: 10.04.2007 8:35PM PST The TraceManager can be used to control the depth of trace outputs from a given function as well as the organization of those trace outputs. Each function that uses the TraceManager passes a number to the TraceChecker function. If the number is less than 0, the function will not trace out data. If that number is greater than 0, the function will trace out data, then submit the same number minus 1 to all of the functions within it. 0 will output no traces. 1 will only output a trace for the function that 1 was submitted to. 2 will output traces for the function it was submitted to and any functions nested in that function. 3 will output traces for the function it was submitted to, any functions nested in that function, and any functions nested in those functions. etc. In other words, you can have many levels of nested functions, but only trace out the depth of data that you are interested in. Implement the TraceManager into your functions in this form: ---------------------------------------------------- //Import the TraceManager class. import TraceManager //Initialize the TraceManager at the _root level. var traceManager:TraceManager = new TraceManager(~name~ , ~boolean~ , ~number1~ , ~number2~ , getTimer() / 1000) //Define a function. function Name (input , traceDepth:Number){ //Run TraceCheck at the start of your function. Save the returned number to a traceDepth variable. //-- If you run any nested functions, submit the traceDepth variable to those functions in the constructor. Nested functions must also use the TraceManager functions. var traceDepth:Number = _root.traceManager.TraceCheck("Name" , input , traceDepth) //Run the function operations. var output = ~~operate~on~input~~ //Run TraceResult at the end of your function. _root.traceManager.TraceResult(output , traceDepth) return output } //Run the function with given input and traceDepth values. _root.Name(input , traceDepth) ---------------------------------------------------- Here is an example of its usage in test functions: ---------------------------------------------------- //Importing and initializing TraceManager at the _root level. import TraceManager var traceManager:TraceManager = new TraceManager("TraceManager1" , true , 0 , 2 , getTimer() / 1000) //Defining new functions. ////////////////////////////////////////////////// function function1(input , traceDepth){ var traceDepth:Number = _root.traceManager.TraceCheck("function1" , input , traceDepth) var output = input + " 1" //This nested function is passed the traceDepth variable. output = function2(output , traceDepth) _root.traceManager.TraceResult(output , traceDepth) return output } function function2(input , traceDepth){ _root.traceManager.TraceCheck("function2" , input , traceDepth) var output = input + " 2" //This nested function is passed the traceDepth variable. output = function3(output , traceDepth) _root.traceManager.TraceResult(output , traceDepth) return output } //This is the last function, with no nested functions in it. function function3(input , traceDepth){ _root.traceManager.TraceCheck("function3" , input , traceDepth) var output = input + " 3" _root.traceManager.TraceResult(output , traceDepth) return output } //Running functions function1("test1" , 2) function1("test2" , 1) function1("test3" , 0) //This function can be run at any time to print out traceData. Use it to avoid slow down due to tracing. //If the TraceManager is turned on, but the tracesUNIVERSAL value is 0, no tracing will occur while the trace data builds. //When this program is run, all trace data will be traced out at the same time. //_root.traceManager.TracePrint(2) //You can also trace specific functions by accessing the functionDirectory array manually. //In this case, the traceOut element was set to false so TracePrint will not trace any data, but it will still return a tracable string. //_root.traceManager.TracePrint(2 , _root.traceManager.functionDirectory[1] , false) ---------------------------------------------------- Run this code for a demonstration of the TraceManager. Set the 2 , 1 and 0 values to whatever you want to see the effects. These functions are easier to understand after you see them in action. To change the formatting of your trace outputs; modify the traceHeader variable below or the TraceOpen, TraceClose and NumberString functions at the bottom of this text. */ class TraceManager { public var name:String public var onSwitch:Boolean //Turns functions on or off (true or false; default is false). public var startTime:Number //This is the time at which recording begins. public var tracesTOP:Number //This sets the trace depth for all functions with an undefined trace depth value. public var tracesUNIVERSAL:Number //This sets the trace depth for all functions. public var functionDirectory:Array = [] //The directory array for all function traces. public var currentAddress:Array = functionDirectory //The currently selected function within the directory. public var parentAddress:Array //The parent of the currently selected function within the directory. var depthDigits:Number = 4 //The number of digit spaces allowed for depth values in the trace formatting. If this number is too small, large depth values may disturb alignments of data. var timeDigits:Number = 20//The number of digit spaces allowed for time values in the trace formatting. If this number is too small, large time values may disturb alignments of data. ////////////FORMATTING: This variable can change trace formatting. Everything else related to formatting is at the bottom. //This defines the header that will go before all trace outs created by the TracePrint function. public var traceHeader:String = newline + "_________________________________________" + newline + "Time(seconds): Depth: Function:" + newline + "-----------------------------------------" /////////////////////// //Creates the TraceManager and sets values for traces that will apply to all TraceCheck uses under this manager. //onSwitch: This turns all TraceManager functions on or off (true or false, respectively). //tracesTOP: All undefined traceDepths will take this value. //tracesUNIVERSAL: All unnested traceDepths will take this value. //startTime: This is the time at which the TraceManager began. This number of seconds will be subtracted from all future time measurements, setting this time equal to zero. //depthDigits: The max number of digit spaces allowed for depth numbers (if the digits in a depth number go beyond this value, trace formatting will be augmented). //timeDigits: The max number of digit spaces allowed for time numbers (if the digits in a time number go beyond this value, trace formatting will be augmented). public function TraceManager(p_name:String , p_onSwitch:Boolean , p_tracesTOP:Number , p_tracesUNIVERSAL:Number , p_startTime:Number , p_depthDigits:Number , p_timeDigits:Number){ if (p_name == undefined){ this.name = "untitled" }else{ this.name = p_name } if (p_onSwitch == undefined){ this.onSwitch = false }else{ this.onSwitch = p_onSwitch } if (!isNaN(p_startTime)){ this.startTime = p_startTime }else{ this.startTime = getTimer() / 1000 } if (p_depthDigits != undefined){ this.depthDigits = p_depthDigits } if (p_timeDigits != undefined){ this.timeDigits = p_timeDigits } this.tracesTOP = p_tracesTOP this.tracesUNIVERSAL = p_tracesUNIVERSAL if (this.tracesTOP > 0 || this.tracesUNIVERSAL > 0){ trace(">>>>>>TraceManager: name = " + this.name + ", tracesTOP = " + this.tracesTOP + ", tracesUNIVERSAL = " + this.tracesUNIVERSAL + ", startTime = " + this.startTime + ", depthDigits = " + this.depthDigits + ", timeDigits = " + this.timeDigits) } } //This must be placed at the start of a function. This must be paired with TraceResult (see the next function: TraceResult). //Checks the local trace depth of a function. //traceDepth: The max depth of nested functions that will be traced. public function TraceCheck(functionName:String , functionInput:String , p_traceDepth:Number):Number{ if (this.onSwitch == true){ var time:Number = getTimer() / 1000 - this.startTime //tracesUNIVERSAL gets 1st priority, then the current p_traceDepth value, then the tracesTOP value. var traceDepth:Number if (this.tracesUNIVERSAL != undefined && this.currentAddress.parent == undefined){ traceDepth = this.tracesUNIVERSAL }else if (p_traceDepth != undefined){ traceDepth = p_traceDepth }else if (this.tracesTOP != undefined && this.currentAddress.parent == undefined){ traceDepth = this.tracesTOP }else{ traceDepth = 0 } //Updating functionDirectory array via the currentAddress array. Since a new TraceCheck is running, a new address must be created within the current one. this.currentAddress.push([]) //The currentAddress is copied to the parentAddress array. this.parentAddress = this.currentAddress //Updating the currentAddress so it is always equal to the last function address created. this.currentAddress = this.currentAddress[this.currentAddress.length - 1] //The parentAddress is saved within the currentAddress as an associated "parent" value. this.currentAddress.parent = this.parentAddress this.currentAddress.name = functionName this.currentAddress.input = functionInput this.currentAddress.startTime = time return traceDepth } } //This is placed at the end of a function to recognize its finish. The functionInput value will be ignored if undefined, but otherwise it will overwrite the previous input value. public function TraceResult(functionOutput:String , traceDepth:Number , functionInput:String){ if (this.onSwitch == true){ //Updating output data (and maybe input data too). this.currentAddress.output = functionOutput if (functionInput != undefined){ this.currentAddress.input = functionInput } this.currentAddress.endTime = getTimer() / 1000 - this.startTime this.parentAddress = this.currentAddress.parent.parent this.currentAddress = this.currentAddress.parent this.currentAddress.parent = this.parentAddress if (this.currentAddress.parent == undefined){ this.TracePrint(traceDepth , this.currentAddress) } } } //This traces out data saved in the directory array. //The data is arranged for visual clarity. //Set traceOut to stop the function from tracing, but still allow it to return traceData values. public function TracePrint(traceDepth:Number , directory:Array , traceOut:Boolean){ var traceData:String = "" var traceAddress:Array = directory if (traceAddress == undefined){ traceAddress = this.functionDirectory } if (traceAddress.height == undefined){ traceAddress.height = 0 } var depth:Number = 0 //This adds a neat title bar to the traced data. if (traceDepth > 0 && traceAddress.height == 0){ traceData = newline + newline + "TraceManager: " + this.name + this.traceHeader } //This phase selects the latest height within the latest depth. while (traceAddress.height < traceAddress.length && depth < traceDepth){ if (traceAddress.height > 0){ traceData += newline } //Add a new introductory function trace. traceData += this.TraceOpen(traceAddress[traceAddress.height] , depth) //This phase increases the depth until it can go no deeper. while (traceAddress[traceAddress.height].length > 0 && depth < traceDepth){ traceAddress = traceAddress[traceAddress.height] traceAddress.height = 0 depth++ //Add a new introductory function trace. traceData += this.TraceOpen(traceAddress[0] , depth) } //This phase decreases the depth until there is room to increase the height. while (traceAddress.height >= traceAddress.length - 1 && depth != 0){ //Add a new closing function trace. traceData += this.TraceClose(traceAddress[traceAddress.height] , depth) if (traceAddress.parent != undefined){ traceAddress = traceAddress.parent depth-- }else{ break } } traceData += this.TraceClose(traceAddress[traceAddress.height] , depth) //This phase increases the height before restarting the process. traceAddress.height++ } //Finally, after the data has been successfully arranged in an array and then converted into a neatly ordered string, the string is traced out. if (traceData.length > 0 && traceOut != false){ trace(traceData) } return traceData } //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// //////////!!!!!!!------------------------------------THESE FUNCTIONS DETERMINE TRACE FORMATTING. //////////////////////////////////////////////////////////////////////////////////////////////// //These last functions are for adding to a string for tracing. public function TraceOpen(functionAddress:Array , depth:Number):String{ var traceData:String = "" var timeString:String = this.NumberString(functionAddress.startTime , this.timeDigits) var depthString:String = this.NumberString(depth , this.depthDigits) //This is added to the beginning of all traced lines. var newLine:String = newline + timeString + " +" + depthString + " " //for loops var d:Number //Start newLine and add indentations to indicate nesting. traceData += newLine for (d = 0 ; d < depth ; d++){ traceData += " " } //Add function name and input data to trace. traceData += functionAddress.name + " (" + functionAddress.input + "){" return traceData } public function TraceClose(functionAddress:Array , depth:Number):String{ var traceData:String = "" //Converts numbers to strings and maintains alignments. var timeString:String = this.NumberString(functionAddress.endTime , this.timeDigits) var depthString:String = this.NumberString(depth , this.depthDigits) //This is added to the beginning of all traced lines. var newLine:String = newline + timeString + " -" + depthString + " " //for loops var d:Number //Start newLine and add indentations to indicate nesting. traceData += newLine for (d = 0 ; d < depth ; d++){ traceData += " " } //Add function name and input data to trace. traceData += "} " + functionAddress.name + "---RESULT( " + functionAddress.output + " )" return traceData } //This function controls the string presentation of numbers to ensure the proper alignment of data. function NumberString(number , length:Number):String{ var numberString:String = "" + number while (numberString.length < length){ numberString += " " } return numberString } }