text: /* <copyright>
  Copyright (c) 2012, Motorola Mobility LLC.
  All Rights Reserved.
  
  Redistribution and use in source and binary forms, with or without
  modification, are permitted provided that the following conditions are met:
  
  * Redistributions of source code must retain the above copyright notice,
    this list of conditions and the following disclaimer.
  
  * Redistributions in binary form must reproduce the above copyright notice,
    this list of conditions and the following disclaimer in the documentation
    and/or other materials provided with the distribution.
  
  * Neither the name of Motorola Mobility LLC nor the names of its
    contributors may be used to endorse or promote products derived from this
    software without specific prior written permission.
  
  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  POSSIBILITY OF SUCH DAMAGE.
  </copyright> */
  /**
      @module montage/ui/composer/key-composer
      @requires montage
      @requires montage/ui/composer/composer
  */
  var Montage = require("montage").Montage,
      Composer = require("ui/composer/composer").Composer;
  
  
  /**
   @module montage/ui/composer/key-composer
   */
  
  
  /* Event type dispatched by KeyComposer */
  var KEYPRESS_EVENT_TYPE = "keyPress",
      LONGKEYPRESS_EVENT_TYPE = "longKeyPress",
      KEYRELEASE_EVENT_TYPE = "keyRelease";
  
  
  /**
   @class module:montage/ui/composer/key-composer.KeyComposer
   @classdesc Create a virtual key composed of none or several key modifiers (shift, control, alt and meta) and one native key.
   @extends module:montage/ui/composer/composer.Composer
   */
  var KeyComposer = exports.KeyComposer = Montage.create(Composer, /** @lends module:montage/ui/composer/key-composer.KeyComposer# */ {
  
      /**
      * @private
      */
      _isLoaded: {
          value: false
      },
  
      /**
      * @private
      */
      _shouldDispatchEvent: {
          value: false
      },
  
      /**
      * @private
      */
      shouldDispatchLongPress: {
          value: false
      },
  
      /**
        @private
      */
      _longPressTimeout: {
          value: null
      },
  
      /**
      * @private
      */
      _keyRegistered: {
          value: false
      },
  
      /**
      * @private
      */
      _keys:{
          value: null
      },
  
      /**
        The sequence of keys to compose.
        @type {string}
        @default null
      */
      keys: {
          get: function() {
              return this._keys;
          },
          set: function(keys) {
              if (this._keyRegistered) {
                  KeyManagerProxy.defaultKeyManager.unregisterKey(this);
                  this._keys = keys;
                  KeyManagerProxy.defaultKeyManager.registerKey(this);
              } else {
                  this._keys = keys;
              }
          }
      },
  
      /**
      * @private
      */
      _identifier: { value: null },
  
      /**
        The keyComposer's identifier.
        @type {string}
        @default null
      */
      identifier: {
         get: function() {
             return this._identifier;
         },
          set: function(identifier) {
              this._identifier = identifier;
          }
      },
  
      /**
        Create a ComposerKey.
        The key will only dispatch events when the component's element is in the native key event target path.
        If no identifier is provided, the keys and component's identifier will be used to generate an identifier.
        Note: You do not have to call KeyComposer.create() before calling this method.
        @function
        @param {Object} component. The component to attach the keyComposer to.
        @param {Object} keys. The key sequence.
        @param {Object} identifier. The identifier.
        @returns {Object} the newly created KeyComposer Object
      */
      createKey: {
          value: function(component, keys, identifier) {
              var key = this;
  
              if (this === KeyComposer) {
                  // This function has been called without creating a new instance of KeyComposer first
                  key = KeyComposer.create();
              }
  
              if (!identifier) {
                  if (component.identifier) {
                      identifier = component.identifier + keys.toLowerCase().replace(/[ +]/g).toCapitalized();
                  } else {
                      identifier = keys.toLowerCase().replace(/[ +]/g);
                  }
              }
              key.keys = keys;
              key.identifier = identifier;
  
              // console.log("CREATING KEY:", component, key, key.identifier);
  
              component.addComposer(key);
  
              return key;
          }
      },
  
      /**
        Create a global composerKey.
        A global key will dispatch events without requiring the component's element be in the native key event target path
        If no identifier is provided, the keys and component's identifier will be used to generate an identifier.
        Note: You do not have to call KeyComposer.create() before calling this method.
        @function
        @param {Object} component. The component to attach the keyComposer to.
        @param {Object} keys. The key sequence.
        @param {Object} identifier. The identifier.
        @returns {Object} the newly created KeyComposer Object
      */
      createGlobalKey: {
          value: function(component, keys, identifier) {
              var key = this;
  
              if (this === KeyComposer) {
                  // This function has been called without creating a new instance of KeyComposer first
                  key = KeyComposer.create();
              }
  
              key.keys = keys;
              key.identifier = identifier;
              // console.log("CREATING GLOBAL KEY:", component, key);
  
              component.addComposerForElement(key, window);
  
              return key;
          }
      },
  
      /**
        load method
        @private
      */
      load: {
          value: function() {
              // Only register the key if somebody is listening for, else let do it later
              // console.log("--- load", this.identifier);
              this._isLoaded = true;
              if (this._shouldDispatchEvent && !this._keyRegistered) {
                  KeyManagerProxy.defaultKeyManager.registerKey(this);
                  this._keyRegistered = true;
              }
          }
      },
  
      /**
        unload method
        @private
      */
      unload: {
          value: function() {
              this._isLoaded = false;
              KeyManagerProxy.defaultKeyManager.unregisterKey(this);
              this._keyRegistered = false;
          }
      },
  
      /**
        Add an event listener to the composerKey.
        @function
        @param {string} type. Any of the following types: keyPress, longKeyPress and keyRelease.
        @param {Object|function} listener. The listener object or function to call when dispatching the event.
        @param {boolean} useCapture. Specify if the listener want to be called during the capture phase of the event.
      */
      addEventListener: {
          value: function(type, listener, useCapture) {
              // Optimisation so that we don't dispatch an event if we do not need to
              // console.log("--- addEventListener", this.identifier);
              var component = this.component;
  
              Composer.addEventListener.call(this, type, listener, useCapture);
  
              if (type == KEYPRESS_EVENT_TYPE || type == LONGKEYPRESS_EVENT_TYPE || type == KEYRELEASE_EVENT_TYPE) {
                  this._shouldDispatchEvent = true;
                  if (type == LONGKEYPRESS_EVENT_TYPE) {
                      this._shouldDispatchLongPress = true;
                  }
  
                  if (this._isLoaded) {
                      if (!this._keyRegistered) {
                          KeyManagerProxy.defaultKeyManager.registerKey(this);
                          this._keyRegistered = true;
                      }
                  } else if (component && typeof component.addComposer !== "function") {
                      // this keyComposer is not associated with an element, let's make it a global key
                      if (!this.element) {
                          this.element = window;
                      }
                      // this keyComposer is not attached to a UI Component, let's load it manually
                      this.load();
                  }
              }
          }
      },
  
      /**
        didCreate method
        @private
      */
      didCreate: {
          value: function() {
              // console.log("KEY CREATED")
          }
      },
  
      /**
        Called when a composer is part of a template serialization.  It's responsible for calling addComposer on
        the component or call load on the composer.
        @private
      */
      deserializedFromTemplate: {
          value: function() {
              var component = this.component;
  
              if (this.identifier === null) {
                  this.identifier = Montage.getInfoForObject(this).label;
              }
  
              if (component) {
                  if (typeof component.addComposer == "function") {
                      component.addComposer(this);
                  } else if (!this._isLoaded) {
                      // this keyComposer is not associated with an element, let's make it a global key
                      if (!this.element) {
                          this.element = window;
                      }
                      // this keyComposer is not attached to a UI Component, let's load it manually
                      this.load();
                  }
              }
          }
      }
  });
  
  
  /**
   @class KeyManagerProxy
   @classdesc Provide a proxy for lazy load of module:montage/core/event/key-manager.KeyManager.
   @extends module:montage/core/core.Montage
   @private
   */
  var _keyManagerProxy= null;
  
  var KeyManagerProxy = Montage.create(Montage,  {
  
      /**
        @private
      */
      _defaultKeyManager: {
          value: null
      },
  
      /**
        @private
      */
      _loadingDefaultKeyManager: {
          value: false
      },
  
      /**
        didCreate method
        @private
      */
      _keysToRegister : {
          value: []
      },
  
      /**
        didCreate method
        @private
      */
      didCreate: {
          value: function() {
              // console.log("PROXY CREATED")
          }
      },
  
      /**
        Register a composerKey with the default KeyManager.
        @function
        @param {Object} keyComposer. A key composer object.
      */
      registerKey: {
          value: function(keyComposer) {
              var thisRef = this;
  
              if (!this._defaultKeyManager) {
                  this._keysToRegister.push(keyComposer);
                  if (!this._loadingDefaultKeyManager) {
                      this._loadingDefaultKeyManager = true;
  
                      require.async("core/event/key-manager", function(module) {
                          var keyManager = thisRef._defaultKeyManager = module.defaultKeyManager;
                          thisRef._keysToRegister.forEach(function(keyComposer) {
                              keyManager.registerKey(keyComposer);
                          });
                          thisRef._keysToRegister.length = 0;
                      });
                  }
              } else {
                  // This will happend only if somebody uses a cached return value from KeyManagerProxy.defaultKeyManager
                  this._defaultKeyManager.registerKey(keyComposer);
              }
          }
      },
  
      /**
        Unregister a composerKey with the default KeyManager.
        @function
        @param {Object} keyComposer. A key composer object.
      */
      unregisterKey: {
          value: function(keyComposer) {
              if (this._defaultKeyManager) {
                  this._defaultKeyManager.unregisterKey(keyComposer);
              }
          }
      },
  
      /**
        Return either the default KeyManager or its KeyManagerProxy.
        @function
        @returns {Object} KeyManager or KeyManagerProxy.
      */
      defaultKeyManager: {
         get: function() {
             if (!_keyManagerProxy) {
                 _keyManagerProxy = KeyManagerProxy.create();
             }
             if (this._defaultKeyManager) {
                 return this._defaultKeyManager;
             } else {
                 return _keyManagerProxy;
             }
         }
      }
  });
  