package com.fourD.core { import flash.events.IEventDispatcher; import flash.utils.Dictionary; import mx.core.Application; public class TectonMap2 extends EventMap { /** map of tectons to kanon (parent), tropon (child), and action (string) */ public var genericTectonMap:Dictionary; public var tectonMap:Dictionary; /** the tectons that are listening for tectons to start and whatnot */ public var tectonReceptors:Dictionary; public var activeReceptors:Dictionary; /** pathway of tectons to be run */ public var tectonPathway:Dictionary; private var _dispatcher:IEventDispatcher; private var firstTectonsInTree:Array; private var numLevelsUp:int; // how many levels we've climbed in the tree private var maxLevels:int; // max number of levels in the tree private var pathwayActive:Boolean; private var _presenter:SmartObject = new SmartObject(TectonScopeProperties.PRESENTER); [Bindable(event="propertyChange")] public function get presenter():* { return _presenter; } private var _tropon:SmartObject = new SmartObject(TectonScopeProperties.TROPON); [Bindable(event="propertyChange")] public function get tropon():* { return _tropon; } private var _kanon:SmartObject = new SmartObject(TectonScopeProperties.KANON); [Bindable(event="propertyChange")] public function get kanon():* { return _kanon; } /** holds our tecton objects from XML (easily done in RestfulX) */ private var _tectons:Array; [Bindable] public function get tectons():Array { return _tectons; } public function set tectons(value:Array):void { _tectons = value; trace("TECTONS SET"); if (_tectons) { initializeMaps(); } } public function TectonMap2() { tectonClassMap = new Dictionary(true); tectonMap = new Dictionary(true); tectonReceptors = new Dictionary(true); tectonPathway = new Dictionary(true); activeReceptors = new Dictionary(true); _dispatcher = this.getDispatcher(); _dispatcher.addEventListener(PathwayEvent.TRAVERSE, buildPathway); } // constructs the tectons required into a pathway object and then runs them in order... /** * 1) Find all Tectons that are assigned to the initialize of another Tecton * 2) Eliminate those Tectons that are already active or initialized * 3) Add event listener to the the current Tecton for each of the ones listening for it's initialize... * That is, addEventListener for super Tecton.COMPLETE * 4) Create a PathwayDictionary that has in there all the COMPLETE events the currentTecton is listening for * 5) Repeat * 6) For every COMPLETE the currentTecton hears, remove that one from the Dictionary * 7) Once all of them are removed from the Dictionary (by checking after every removal), * 8) Run the current Tecton. */ private function buildPathway(event:PathwayEvent):void { if (pathwayActive) { return; } trace("pathwayEvent"); var type:String = event.type; var url:Array = event.url; var tropon:*, action:String, tecton:Tecton, kanon:*; var fqnTropon:String, fqnKanon:String; var tectonName:String; var lastTecton:Tecton; // [{view:target, action:"show"}, {view:anotherTarget, action:"flip"}] // for loop is going from end to beginning! Provides space for initialization... if (url.tropon) { tropon = url.tropon; } if (url.action) { action = url.action; } if (url.kanon) { kanon = url.kanon; } // figure out what the tropon and action are: // 1) if it's multiple tropons, then must be part of the same kanon // to figure this out, chop the tropon off so we have the Sos.mainView, // then find a className based on that // that's where the tecton is sent. Tectons must know the parent "Kanon" //var className:String = getQualifiedClassName( event.target ).replace( "::", "." ); var path:String = tropon.toString(); kanonClass = RouterUtil.getClassKanonName((path); troponClass = RouterUtil.getClassTroponName(path); tectonName = RouterUtil.getTectonName(path, action); if (tropon.parent) { kanon = tropon.parent; } else if (url[i - 1].view) { kanon = url[i - 1].view; } else { kanon = "somethingElse"; } tectonName = tropon.toString() + "." + action; if (tectonMap[tectonName]) { tecton = tectonMap[tectonName]; } else { // create a new tecton for that tropon instance... fqnTropon = getQualifiedClassName(tropon); fqnKanon = (kanon is String) ? kanon : getQualifiedClassName(kanon); var appName:String = getQualifiedClassName(Application.application); var genericName:String = appName + "." + fqnKanon + "." + fqnTropon + "." + action; tecton = tectonClassMap[genericName]; // create a new one and then store it in the dictionary... tecton = TectonUtils.clone(tecton) as Tecton; tecton.tropon = tropon; tectonMap[tectonName] = tecton; // probably should add to the initialize and complete of other Tectons this // newly generated one... var baseName:String = "tecton" // split off the numbers from the instances in the class path var initializePheronType:String = baseName + Pheron2.INITIALIZE; var intializeTectons:Array = tectonPheronMap[initializePheronType]; var startPheronType:String = baseName + Pheron2.START; var startTectons:Array = tectonPheronMap[startPheronType]; var completePheronType:String = baseName + Pheron2.COMPLETE; var completeTectons:Array = tectonPheronMap[completePheronType]; // add the new tecton to all of the tecton listener handlers in the application // might be expensive? addTectonToHandlers(initializeTectons, Pheron2.INITIALIZE); addTectonToHandlers(startTectons, Pheron2.START); addTectonToHandlers(completeTectons, Pheron2.COMPLETE); } firstInTree = null; numLevelsUp = 0; maxLevels = 0; initialize(tecton); // this initialize function will create basically a preordered tree // and after tons of recursion, it will get here, // and we know the tree has been built. } pathwayActive = true; // finally, initialize the sequence and the rest will be handled by events! i=0, len = firstTectonsInTree.length; for (i; i < len; i++) { tecton = firstTectonsInTree[i]; tecton.runSequence(scope); } } private function addTectonToHandlers(handlerTectons:Array, phase:String):void { if (handlerTectons == null) { return; } var i:int=0, len:int = handlerTectons.length; for (i; i < len; i++) { var tect:Tecton = handlerTectons[i]; if (phase == Pheron2.INITIALIZE) { tect.initializeHandlers.push(tecton); } else if (phase == Pheron2.START) { tect.startHandlers.push(tecton); } else if (phase == Pheron2.COMPLETE) { tect.completeHandlers.push(tecton); } } } public function getTecton(fqnKanon:String, fqnTropon:String, action:String):Tecton { return TectonUtils.clone(tectonClassMap[fqnKanon][fqnTropon][action]) as Tecton } public function initialize(tecton:Tecton):void { if (!tecton) { return; } // throw error // 2) validate tecton conditions to see if it's viable var conditions:Array = tecton.conditions; if (conditions != null) { var value:Boolean = ConditionsUtil.validateConditions(conditions) if (!value) { return; } } tecton.isInitialized = true; var initializePheronType:String = tecton.toString() + Pheron2.INITIALIZE; // 4) Find tectons that are listening for this tecton to initialize initializeReceptorTectons(tecton, initializePheronType); } private function initializeReceptorTectons(tecton:Tecton, pheronType:String):Array { var receptorTectons:Array; if (pathwayMap[numLevelsUp] == undefined) { // then it's a new level! pathwayMap[numLevelsUp] = new Array(); numLevelsUp ++; pathwayMap[numLevelsUp].push(tecton); } if (tectonReceptors[pheronType] != undefined) { receptorTectons = tectonReceptors[pheronType]; } if (receptorTectons != null) { var i:int=0, len:int = receptorTectons.length; for (i; i < len; i++) { var receptorTecton:Tecton = receptorTectons[i]; // if it's already active, forget about it if (receptorTecton.isActive || receptorTecton.isInitialized) { continue; } var completePheronType:String = receptorTecton.toString() + Pheron2.COMPLETE; tecton.addEventListener(completePheronType, tecton.tectonate); initialize(receptorTecton); } } if (numLevelsUp > maxLevels) { // since the initialize() method will create another loop, // this value will only be calculated when it reaches the leaf of the tree. maxLevels = numLevelsUp; firstTectonsInTree = pathwayMap[maxLevels]; } } private function initializeMaps():void { var fqnTecton:String = getQualifiedClassName(tecton); registerClassAlias(fqnTecton.replace("::","."), Tecton); var i:int=0, len:int = tectons.length; trace("INITIALIZE MAPS!"); // 1) create map of tectonReceptors to tectons // 2) create map of tropons (from the troponTree) to tectons var tecton:Tecton, tropon:*, tropons:Array, action:String, kanon:*; for (i; i < len; i++) { tecton = tectons[i]; action = tecton.actionName; if (tecton.tropon) { trace("tecton exists"); tropon = tecton.tropon; if (!tropon is Class) { trace("tropon is displayObject"); trace(tropon); if (!tecton.kanon) { trace("kanon wasn't explicitly defined"); kanon = (tropon.parent) || null; } } else if (tropon is Class) { trace("tropon is class = " + tropon); if (!tecton.kanon) { trace("kanon doesn't exist for class"); //THROW ERROR, try to find it some other way, via the content map? } else { kanon = tecton.kanon; } } } else if (tecton.tropons) { tropons = tecton.tropons; } // doesn't matter if it's a Class or DisplayObject :) var fqnKanon:String = getQualifiedClassName(kanon); var fqnTropon:String = getQualifiedClassName(tropon); var fqnApp:String = getQualifiedClassName(Application.application); var genericName:String = fqnApp + "." + fqnKanon + "." + fqnTropon + "." + action; var baseName:String = "something" // figure out something like Sos.mainView.button.panel genericTectonMap[genericName] = tecton; genericTectonMap[baseName] = tecton; var j:int=0, lenj:int; trace(tropon); if (tropon != null) { trace("Tropon is not equal to null"); fqnTropon = getQualifiedClassName(tropon); if (tectonClassMap[fqnKanon] == undefined) { tectonClassMap[fqnKanon] = new Dictionary(true); trace("first dictionary"); } if (tectonClassMap[fqnKanon][fqnTropon] == undefined) { tectonClassMap[fqnKanon][fqnTropon] = new Dictionary(true); trace("second dictionary"); } if (action) { tectonClassMap[fqnKanon][fqnTropon][action] = tecton; trace("ALL OF IT: " + "\nKanon = " + fqnKanon + "\nTropon = " + fqnTropon + "\nAction = " + action); } } else if (tropons != null && tropon == null) { lenj = tropons.length; for (j; j < lenj; j++) { tropon = tropons[j]; fqnTropon = getQualifiedClassName(tropon); if (tectonClassMap[fqnKanon] == undefined) { tectonClassMap[fqnKanon] = new Dictionary(true); } if (tectonClassMap[fqnKanon][fqnTropon] == undefined) { tectonClassMap[fqnKanon][fqnTropon] = new Dictionary(true); } if (action) { tectonClassMap[fqnKanon][fqnTropon][action] = tecton; } } } } } } }