text: /*
   * Copyright (c) 2014 Gwennael Buchet
   *
   * License/Terms of Use
   *
   * Permission is hereby granted, free of charge and for the term of intellectual property rights on the Software, to any
   * person obtaining a copy of this software and associated documentation files (the "Software"), to use, copy, modify
   * and propagate free of charge, anywhere in the world, all or part of the Software subject to the following mandatory conditions:
   *
   *   •    The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
   *
   *  Any failure to comply with the above shall automatically terminate the license and be construed as a breach of these
   *  Terms of Use causing significant harm to Gwennael Buchet.
   *
   *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
   *  WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
   *  OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
   *  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
   *
   *  Except as contained in this notice, the name of Gwennael Buchet shall not be used in advertising or otherwise to promote
   *  the use or other dealings in this Software without prior written authorization from Gwennael Buchet.
   *
   *  These Terms of Use are subject to French law.
   */
  
  /**
   * A CGSGNodeImage represent an image node
   *
   * @class CGSGNodeImage
   * @extends CGSGNode
   * @module Node
   * @constructor
   * @param {Number} x Relative position on X
   * @param {Number} y Relative position on Y
   * @param {String} urlImage URL of the src image. Can be null tobe loaded later.
   * @type {CGSGNodeImage}
   * @author Gwennael Buchet (gwennael.buchet@gmail.com)
   */
  var CGSGNodeImage = CGSGNode.extend(
      {
          initialize: function (x, y, urlImage) {
              this._super(x, y);
  
              /**
               * @property classType
               * @type {String}
               */
              this.classType = "CGSGNodeImage";
  
              /**
               * the selected effect to be applied
               * @property effect
               * @default null
               * @type {CGSGEffect}
               */
              this.effect = null;
              /**
               * URL of the image
               * @property _urlImage
               * @type {String}
               * @private
               */
              this._urlImage = urlImage;
  
              /**
               * @property isProportionalResize
               * @default true
               * @type {Boolean}
               */
              this.isProportionalResize = true;
              /**
               * the image object itself
               * @property _img
               * @type {Image}
               * @private
               */
              this._img = new Image();
              /**
               * the region on the image to render
               * @property slice
               * @type {CGSGRegion}
               */
              this.slice = new CGSGRegion(0, 0, 0, 0);
  
              /**
               * @property _isLoaded
               * @type {Boolean}
               * @private
               */
              this.isLoaded = false;
  
              /**
               * Event Fired when the image is finally loaded
               * @property onLoadEnd
               * @default null
               * @type {Function} {node:this}
               */
              this.onLoadEnd = null;
              /**
               * Event Fired when the image failed to load
               * @property onLoadError
               * @default null
               * @type {Function} {node:this}
               */
              this.onLoadError = null;
              /**
               * Event Fired when the image loading is aborted
               * @property onLoadAbort
               * @default null
               * @type {Function} {node:this}
               */
              this.onLoadAbort = null;
  
              ///// INITIALIZATION //////
              //finally load the image
              if (cgsgExist(this._urlImage) && this._urlImage !== "") {
                  this.setURL(urlImage);
              }
          },
  
          /**
           * used to call delegate method when the image is finally loaded
           * @private
           * @method _createDelegate
           * @param objectContext
           * @param delegateMethod
           * @return {Function}
           */
          _createDelegate: function (objectContext, delegateMethod) {
              return function () {
                  return delegateMethod.call(objectContext);
              };
          },
  
          /**
           * fired when the image is loaded.
           * Check the dimension of the image and fired the onLoadEnd event
           * @private
           * @method _onImageLoaded
           * @param event {Event}
           */
          _onImageLoaded: function (event) {
              this.checkDimension();
              this.isLoaded = true;
  
              if (cgsgExist(event)) {
                  cgsgImgManager.set(this._urlImage, this.img);
              }
  
              if (cgsgExist(this.onLoadEnd)) {
                  CGSG.eventManager.dispatch(this, cgsgEventTypes.ON_LOAD_END, new CGSGEvent(this, {node: this}));
              }
              this.invalidate();
          },
  
          /**
           * To be overrided when the image failed to load
           * @method _onImageError
           * @protected
           * @param event {Event}
           */
          _onImageError: function (event) {
              if (this.onLoadError !== null) {
                  CGSG.eventManager.dispatch(this, cgsgEventTypes.ON_LOAD_ERROR, new CGSGEvent(this, {node: this}));
              }
          },
  
          /**
           * To be overrided when the image loading is aborted
           * @method _onImageAbort
           * @protected
           * @param event {Event}
           */
          _onImageAbort: function (event) {
              if (this.onLoadAbort !== null) {
                  CGSG.eventManager.dispatch(this, cgsgEventTypes.ON_LOAD_ABORT, new CGSGEvent(this, {node: this}));
              }
          },
  
          /**
           * Check the true dimension of the image and fill the this.dimension property with it,
           * only if dimension is not already defined in the constructor
           * @method checkDimension
           */
          checkDimension: function () {
              if (!this._isDimensionChanged) {
                  //if no width or height are specified in the constructor
                  if (this.dimension.width <= 0 && this.dimension.height <= 0) {
                      this.dimension.width = this._img.width;
                      this.dimension.height = this._img.height;
                  }
              }
  
              //if no slice was specified, adjust it with the full image
              if (this.slice.dimension.width <= 0 || this.slice.dimension.height <= 0) {
                  this.slice.dimension.width = this._img.width;
                  this.slice.dimension.height = this._img.height;
              }
          },
  
          /**
           * Set the slice into the image
           * @method setSlice
           * @param {Number} x
           * @param {Number} y
           * @param {Number} w
           * @param {Number} h
           * @param {Boolean} updateDimension If true, the dimension will be set with the dimension of the slice
           */
          setSlice: function (x, y, w, h, updateDimension) {
              this.slice.position.x = x;
              this.slice.position.y = y;
              this.slice.dimension.width = w;
              this.slice.dimension.height = h;
  
              if (updateDimension) {
                  this.resizeTo(w, h);
              }
  
              this.invalidate();
          },
  
          /**
           * @public
           * @method setImage
           * @param img {Image} new Image object. Must be already loaded before
           */
          setImage: function (img) {
              this._img = img;
              if (cgsgExist(this._img)) {
                  this._setUrl(this._img.src);
              }
              else {
                  this._urlImage = null;
                  this.isLoaded = false;
                  this.invalidate();
              }
          },
  
          /**
           * Set a new URL for the image of the node
           * @method setURL
           * @param {String} url
           */
          setURL: function (url) {
              this._urlImage = url;
  
              //first, check if the image was not already downloaded elsewhere in the application
              this._img = cgsgImgManager.get(url);
              if (cgsgExist(this._img)) {
                  this._onImageLoaded(null);
              }
              else {
                  delete(this._img);
                  this.isLoaded = false;
                  this._img = new Image();
  
                  this._img.onload = this._createDelegate(this, this._onImageLoaded);
                  this._img.onerror = this._createDelegate(this, this._onImageError);
                  this._img.onabort = this._createDelegate(this, this._onImageAbort);
                  this._img.src = this._urlImage;
              }
          },
  
          _setUrl: function (url) {
              this._urlImage = url;
              this.isLoaded = true;
              this.checkDimension();
              this.invalidate();
          },
  
          /**
           * return the Javascript image encapsulated in this node
           * @method getImage
           * @return {Image}
           */
          getImage: function () {
              return this._img;
          },
  
          /**
           * Must be defined to allow the scene graph to render the image nodes
           * @protected
           * @method render
           * @param {CanvasRenderingContext2D} context the context to render on
           * */
          render: function (context) {
              if (this.isLoaded && this._img.src !== "" && !this.slice.isEmpty()) {
                  context.drawImage(
                      this._img, // image
                      this.slice.position.x,
                      this.slice.position.y, // start position on the image
                      this.slice.dimension.width,
                      this.slice.dimension.height, // dimension on the image
                      0,
                      0,
                      // position on the screen. let it to [0,0] because the 'beforeRender' function will translate the image
                      this.getWidth(),
                      this.getHeight()                // dimension on the screen
                  );
              }
          },
  
          /**
           * @public
           * @method setEffect
           * @param {CGSGEffect} effect
           */
          setEffect: function (effect) {
              this.effect = effect;
          },
  
          /**
           * @public
           * @method copy
           * @return {CGSGNodeImage} a copy of this node
           */
          copy: function (node) {
              if (!cgsgExist(node)) {
                  node = new CGSGNodeImage(this.position.x, this.position.y, null);
              }
              //call the super method
              node = this._super(node);
  
              node._urlImage = this._urlImage;
  
              node.effect = this.effect;
              node.isProportionalResize = this.isProportionalResize;
              node._isLoaded = this.isLoaded;
  
              //the image object itself
              node.setImage(this._img);
  
              node.setSlice(this.slice.position.x, this.slice.position.y, this.slice.dimension.width,
                            this.slice.dimension.height, true);
              node.resizeTo(this.dimension.width, this.dimension.height);
  
              node.onLoadEnd = this.onLoadEnd;
  
              return node;
          }
      }
  );
  