text: /*
   * Copyright (c) 2012 Adobe Systems Incorporated. All rights reserved.
   * 
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   * 
   *     http://www.apache.org/licenses/LICENSE-2.0
   * 
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  (function() {
  
      function ActiveObject(source, delegate) {
          ActiveObject.$super.call(this);
          this.delegate = delegate;
          this.properties = {};
          if (source)
              this.loadFromJSON(source);
      }
  
      function ActiveCollection(source, delegate) {
          ActiveCollection.$super.call(this, source, delegate);
      }
  
      Global.Utils.extend(ActiveObject).from(Global.EventDispatcher);
      Global.Utils.extend(ActiveCollection).from(ActiveObject);
  
      $.extend(ActiveObject.prototype, {
          loadFromJSON: function(source) {
              var self = this;
              $.each(source, function(key, val) {
                  if (!self.properties.hasOwnProperty(key))
                      self.injectSetterMethod(key);
                  self.properties[key] = self.wrapValue(val);
              });
          },
  
          injectSetterMethod: function(key) {
              Object.defineProperty(this, key, {
                  get: this.get.bind(this, key),
                  set: this.set.bind(this, key),
                  enumerable: true,
                  configurable: true
              });
          },
  
          wrapValue: function(val) {
              if (val !== null && typeof(val) == "object") {
                  if (val instanceof Array)
                      val = new ActiveCollection(val, this);
                  else if (!(val instanceof ActiveObject))
                      val = new ActiveObject(val, this);
              } 
              return val;
          },
  
          toJSON: function() {
              var result = {};
              $.each(this.properties, function(key, value) {
                  if (value && value instanceof ActiveObject)
                      value = value.toJSON();
                  result[key] = value;
              });
              return result;
          },
  
          fireRootValueChanged: function() {
              var root = this;
              while (root.delegate)
                  root = root.delegate;
              root.fire("rootValueChanged");
          },
  
          set: function(key, newValue) {
              var oldValue = this.properties[key],
                  hadValue = this.properties.hasOwnProperty(key);
              if (!hadValue)
                  this.injectSetterMethod(key);
              this.properties[key] = newValue = this.wrapValue(newValue);
              this.fire("propertyChanged." + key, [newValue, oldValue]);
              this.fire("propertyChanged", [key, newValue, oldValue]);
              if (!hadValue)
                  this.fire("propertyAdded", [key, newValue]);
              this.fireRootValueChanged();
              return newValue;
          },
  
          get: function(key) {
              return this.properties[key];
          },
  
          remove: function(key) {
              var oldValue = this.properties[key],
                  hadValue = this.properties.hasOwnProperty(key);
              if (!hadValue)
                  return;
              delete this.properties[key];
              this.fire("propertyChanged." + key, [null, oldValue]);
              this.fire("propertyChanged", [key, null, oldValue]);
              this.fire("propertyRemoved", [key, oldValue]);
              this.fireRootValueChanged();
              return oldValue;
          },
  
          bind: function(key, fn) {
              fn(this.get(key), null);
              return this.on("propertyChanged." + key, fn);
          },
  
          unbind: function(key, fn) {
              return this.off("propertyChanged." + key, fn);
          },
  
          oneWayBind: function(key, el, fn) {
              this.bind(key, function(newValue, oldValue) {
                  var value = el[fn].call(el);
                  if (oldValue != null && value == newValue)
                      return;
                  el[fn].call(el, newValue);
              });
              return this;
          },
  
          twoWayBind: function(key, el, fn, events) {
              var self = this;
              this.oneWayBind(key, el, fn);
              el.bind(events, function() {
                  var value = el[fn].call(el);
                  self.set(key, value);
              });
              return this;
          },
  
          bindToTextInput: function(key, el) {
              return this.twoWayBind(key, el, "val", "change keyup blur");
          },
  
          bindToSelectInput: function(key, el) {
              return this.twoWayBind(key, el, "val", "change keyup click blur");
          }
      });
  
      $.extend(ActiveCollection.prototype, {
          loadFromJSON: function(source) {
              this.$super.loadFromJSON.call(this, source);
              this.set("length", source.length);
          },
  
          toJSON: function() {
              var result = [];
              $.each(this.properties, function(key, value) {
                  if (value && value instanceof ActiveObject)
                      value = value.toJSON();
                  result.push(value);
              });
              return result;
          }
      });
  
      Global.ActiveObject = ActiveObject;
      Global.ActiveCollection = ActiveCollection;
  
  })();