package com.exanimo.utils { import com.exanimo.utils.IEquatable; import flash.events.Event; import flash.events.EventDispatcher; import flash.events.IEventDispatcher; import flash.utils.Proxy; import flash.utils.flash_proxy; /** * */ dynamic public class XMLProxy extends Proxy implements IEventDispatcher, IEquatable { private var _dispatcher:EventDispatcher; private var _data:XML; private var _item:Object; private var _propertyList:Array; /** * * * */ public function XMLProxy(data:XML = null) { this._item = {}; this._dispatcher = new EventDispatcher(this); this.setData(data); } // // flash_proxy methods // /** * @private */ override flash_proxy function callProperty(methodName:*, ... args):* { var fn:Function = this[methodName] || this._item[methodName]; return fn.apply(this, args); } /** * @private */ override flash_proxy function deleteProperty(name:*):Boolean { var propertyDeleted:Boolean = false; if (name in this._data) { delete this._data[name]; propertyDeleted = true; } if (('@' + name) in this._data) { delete this._data['@' + name];; propertyDeleted = true; } if (name in this._item) { delete this._item[name]; propertyDeleted = true; } return propertyDeleted; } /** * @private */ override flash_proxy function getDescendants(name:*):* { throw new TypeError('Error #1016: Descendants operator (..) not supported on type XMLProxy.'); } /** * @private */ override flash_proxy function getProperty(name:*):* { return this.getProperty(name); } protected function getProperty(name:*):* { var value:*; if (name in this._item) { value = this._item[name]; } else { var list:XMLList = this._data[name]; if (list.length() == 0) { list = this._data['@' + name]; } value = list.length() == 0 ? null : list[0]; } return value; } /** * @private */ override flash_proxy function hasProperty(name:*):Boolean { return (name in this._item) || (name in this._data) || (('@' + name) in this._data); } /** * @private */ override flash_proxy function nextName(index:int):String { return this._propertyList[index - 1]; } /** * @private */ override flash_proxy function nextNameIndex(index:int):int { // initial call if (index == 0) { this._setupPropertyList(); } return index < this._propertyList.length ? index + 1 : 0; } /** * @private */ override flash_proxy function nextValue(index:int):* { // initial call if (index == 0) { this._setupPropertyList(); } return this._item[this._propertyList[index - 1]]; } /** * @private */ override flash_proxy function setProperty(name:*, value:*):void { this.setProperty(name, value); } protected function setProperty(name:*, value: *):void { this._item[name] = value; } // // private methods // /** * * * */ private function _setupPropertyList():void { this._propertyList = []; var p:*; for (p in this._item) { this._propertyList.push(p); } for each (p in this._data.* + this._data.attributes()) { p = String(p.localName()); if (this._propertyList.indexOf(p) == -1) { this._propertyList.push(p); } } } // // public methods // /** * @inheritDoc */ public function addEventListener(type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false):void { this._dispatcher.addEventListener(type, listener, useCapture, priority, useWeakReference); } /** * @inheritDoc */ public function dispatchEvent(event:Event):Boolean { return this._dispatcher.dispatchEvent(event); } /** * @inheritDoc */ public function hasEventListener(type:String):Boolean { return this._dispatcher.hasEventListener(type); } /** * @inheritDoc */ public function removeEventListener(type:String, listener:Function, useCapture:Boolean = false):void { return this._dispatcher.removeEventListener(type, listener, useCapture); } /** * @copy Object#toString() */ public function toString():String { return this._item.toString.call(this); } /** * @inheritDoc */ public function willTrigger(type:String):Boolean { return this._dispatcher.willTrigger(type); } // // internal methods // // TODO: Use namespace for these methods! public function getData():XML { return this._data; } public function setData(data:XML):void { this._data = data; } // // public methods // /** * @inheritDoc */ public function equals(obj:Object):Boolean { return this._propertiesAreEqual(this, obj) && this._propertiesAreEqual(obj, this); } /** * */ private function _propertiesAreEqual(a:Object, b:Object):Boolean { var propertiesAreEqual:Boolean = true; for (var prop:Object in a) { if (a[prop] != b[prop]) { propertiesAreEqual = false; break; } } return propertiesAreEqual; } } }