// Copyright (c) 2008, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/*-------------------------------------------------------------------------*/
/*  DvtObj                 Base object implementation                      */
/*-------------------------------------------------------------------------*/
/**
  *   Base object for HTML toolkit derivative objects.
  *   @class The base object for HTML toolkit derivative objects.
  *   @constructor  
  */
var  DvtObj = function() {};

DvtObj._GET_FUNCTION_NAME_REGEXP = /function\s+([\S^]+)\s*\(/;

DvtObj.prototype = {};
DvtObj.prototype.constructor = DvtObj;

/**
 *  Provides inheritance by subclassing a class from a given base class.
 *  @param  {class} extendingClass  The class to be extended from the base class.
 *  @param  {class} baseClass  The base class
 *  @param  {string} typeName The type of the extending class
 */
DvtObj.createSubclass = function (extendingClass, baseClass, typeName) {
  if (extendingClass === undefined || extendingClass === null) {
    return;
  }
  if (baseClass === undefined) {
    // assume Object
    baseClass = Object;
  }

  if (extendingClass == baseClass) {
    return;
  }

  // use a temporary constructor to get our superclass as our prototype
  // without out having to initialize the superclass
  var tempConstructor = DvtObj._tempSubclassConstructor;

  tempConstructor.prototype = baseClass.prototype;
  extendingClass.prototype = new tempConstructor();

  extendingClass.prototype.constructor = extendingClass;
  extendingClass.superclass = baseClass.prototype;
  
  if(typeName)
    extendingClass._typeName = typeName;
} ;

/**  @private  */
DvtObj._tempSubclassConstructor = function () {};

DvtObj.getTypeName = function (clazz) {
  var typeName = clazz._typeName;
  if (typeName == null) {
    var constructorText = clazz.toString();
    var matches = DvtObj._GET_FUNCTION_NAME_REGEXP.exec(constructorText);

    typeName = matches[1];

    clazz._typeName = typeName;
  }

  return typeName;
}

DvtObj.prototype.getTypeName = function () {
  return DvtObj.getTypeName(this.constructor);
}


/*-------------------------------------------------------------------*/
/*   clone()                                                         */
/*-------------------------------------------------------------------*/
/**
  *  Returns a copy of this object.  Abstract method, subclasses
  *   must implement.
  *  @type DvtObj
  */
DvtObj.prototype.clone = function()
{
   return null ;
};

/*-------------------------------------------------------------------*/
/*   mergeProps()                                                    */
/*-------------------------------------------------------------------*/
/**
  *   Merge properties in the current object into the supplied object.
  *   Abstract method, subclasses must implement. Used internally by clone().
  *   @param {DvtObj}
  *   @private
  */
DvtObj.prototype.mergeProps = function(obj)
{
} ;

DvtObj._flashToolkit = false ;     // Flash needs a slightly different version
                                   // because the "string version" is not valid for Flash
                                   // this is set only by ActionScript.
/*
 * copy from AdfObject
 */
DvtObj.createCallback = function(thisPtr, func) {

  if (DvtObj._flashToolkit)
  {
    var  f = function()
              {
                 func.apply(thisPtr,arguments) ;
              } ;
    return f ;
  }
  else
  {
    // create a function that sets up "this" and delegates all of the parameters
    // to the passed in function
    var proxyFunction ;
    try {
          proxyFunction = new Function(
            "var f=arguments.callee; return f._func.apply(f._owner, arguments);");

          // attach ourselves as "this" to the created function
          proxyFunction._owner = thisPtr;

          // attach function to delegate to
          proxyFunction._func = func;
    } catch(e) {} ;

    return proxyFunction;
  }
};


// Copyright (c) 2008, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/*-------------------------------------------------------------------------*/
/*   DvtArrayUtils         Miscellaneous array utility functions           */
/*-------------------------------------------------------------------------*/
/**
  *  @class  DvtArrayUtils  A static class providing miscellaneous array utility
  *  functions.
  */
var  DvtArrayUtils = new Object();

//  Factor scaling operation types for toFloat()

/**
  * Factor operation for DvtArrayUtils.toFloat() - no scaling of converted float.
  * @final
  */
DvtArrayUtils.NONE = 0 ;
/**
  * Factor operation for DvtArrayUtils.toFloat() - add factor to converted float.
  * @final
  */
DvtArrayUtils.ADD  = 1 ;
/**
  * Factor operation for DvtArrayUtils.toFloat() - subtract factor from converted float.
  * @final
  */
DvtArrayUtils.SUB  = 2 ;
/**
  * Factor operation for DvtArrayUtils.toFloat() - divide converted float by factor.
  * @final
  */
DvtArrayUtils.DIV  = 3 ;
/**
  * Factor operation for DvtArrayUtils.toFloat() - multiply converted float by factor.
  * @final
  */
DvtArrayUtils.MULT = 4 ;
/**
  *  Factor operation for DvtArrayUtils.toFloat() - set converted float to mod(factor).
  * @final
  */
DvtArrayUtils.MOD  = 5 ;



DvtArrayUtils.argsToArray = function(args)
{
  if (args)
  {
    var array = new Array(args.length);
    if (args.length > 0)
    {
      for (var i = 0; i < args.length; i++)
      {
        array[i] = args[i];
      }
    }
    return array;
  }
  return args;
};


/*--------------------------------------------------------------------*/
/*  isArray()          Cross-browser array detection                  */
/*--------------------------------------------------------------------*/
/**
  *   Test if the specified object is an instance of Array (cross-browser safe).
  * @base DvtArrayUtils
  *   @param {Object}  obj
  *   @type Boolean
  *   @returns true if the object is an Array.
  */
DvtArrayUtils.isArray = function(obj)
{
   return Object.prototype.toString.apply(obj)  === '[object Array]' ;
} ;



/*--------------------------------------------------------------------*/
/*  toFloat()                                                         */
/*--------------------------------------------------------------------*/
/**
  *  Converts an array from string values to floats.  If optional 'factor'
  *  argument is supplied, the array values are scaled by this factor using
  *  the factorType  operator. e.g. <p><code>
  *  &nbsp; &nbsp; &nbsp;  DvtArrayUtils.toFloat(ar, 0.01, DvtArrayUtils.MULT) ;<p></code>
  *  converts an array of percentage value strings to an array of floats converted
  *  to dcimal percentages (between zero and 1).
  *  @param {Array} ar
  *  @param {number} factor
  *  @param {number} factorType
  *  @type {Array}
  *  @returns the Array that was supplied as the first argument.
  */
DvtArrayUtils.toFloat = function(ar, factor, factorType)
{
   if (! DvtArrayUtils.isArray(ar)) {
     return ar ;
   }

   if (! factor) {
     factorType = DvtArrayUtils.NONE ;
   }

   factorType = factorType || DvtArrayUtils.NONE ;

   if (factorType !== DvtArrayUtils.NONE) {
     if ((typeof factor) !== 'number') {
       factor = parseFloat(factor) ;
     } 
     if (isNaN(factor)) {
       factorType = DvtArrayUtils.NONE ;
     }
   }

   var len = ar.length ;
   var i ;

   if (factorType === DvtArrayUtils.NONE) {
     for (i = 0; i < len; i++) {
        ar[i] = parseFloat(ar[i]) ;
     }
   }
   else {
     for (i = 0; i < len; i++)  {
        var  v = parseFloat(ar[i]) ;

         switch (factorType) {
            case  DvtArrayUtils.MULT : v *= factor ;
                                       break ;
            case  DvtArrayUtils.ADD :  v += factor ;
                                       break ;
            case  DvtArrayUtils.SUB :  v -= factor ;
                                       break ;
            case  DvtArrayUtils.DIV :  v /= factor ;
                                       break ;
            case  DvtArrayUtils.MOD :  v %= factor ;
                                       break ;
         }
         ar[i] = v ;
     }

   }

   return ar ;
} ;



/*--------------------------------------------------------------------*/
/*   copy()       Performs a shallow copy of the array. (Much faster  */
/*                than Array.concat().                                */
/*--------------------------------------------------------------------*/
/**
  *  Create a shallow copy of the supplied array.
  *  @param {Array} ar The array to be copied.
  *  @type Array
  *  @returns A shallow copy of the supplied array.
  */
DvtArrayUtils.copy = function(ar)
{
   var arRet ;

   if (ar) {
     arRet = [] ; 
     var len = ar.length ;

     for (var i = 0; i < len; i++)  {
       arRet.push(ar[i]) ;
     }
   }
   return arRet ;
} ;


/**
  *  Returns the index of the first occurrence of an item in an array.  
  *  @param {Array} array  The array to be searched.
  *  @param {Object} item  The item to be found.
  *  @type number
  */
DvtArrayUtils.getIndex = function(array, item)
{
  for (var i = 0; i < array.length; i++) {
    if (array[i] === item) {
      return i;
    }
  }
  return -1;
};

/**
  *  Returns the index of the last occurrence of an item in an array.  
  *  @param {Array} array  The array to be searched.
  *  @param {Object} item  The item to be found.
  *  @type number
  */
DvtArrayUtils.getLastIndex = function(array, item)
{
  for (var i = array.length - 1; i >= 0; i--)  {
    if (array[i] === item) {
      return i;
    }
  }
  return -1;
};


/*--------------------------------------------------------------------*/
/*   getMinIndex(), getMaxIndex()                                     */
/*--------------------------------------------------------------------*/
/**
  *  Returns the index to the array entry containg the minimum value.
  *  Array entries with undefined or null values are ignored.
  *  @param {Array} ar the array to be searched.
  *  @type number
  *  @returns The index of the array entry containing the minimum value.
  *           If the array length is zero, or all entries are undefined
  *           or null, a value of -1 is returned.
  */
DvtArrayUtils.getMinIndex = function(ar)
{
  var nRet   = -1 ;
  var len    = ar.length; 
  var minVal = Number.MAX_VALUE ;
  var val ;
  
  for (var i = 0; i < len; i++) {
     val = ar[i] ;

     if (val && (typeof val === 'number') && (val < minVal)) {
       minVal = val ;
       nRet   = i ;
     }
  }

  return nRet ;
};


/**
  *  Returns the index to the array entry containg the maximum value.
  *  Array entries with undefined or null values are ignored.
  *  @param {Array} ar the array to be searched.
  *  @type number
  *  @returns The index of the array entry containing the maximum value.
  *           If the array length is zero, or all entries are undefined
  *           or null, a value of -1 is returned.
  */
DvtArrayUtils.getMaxIndex = function(ar)
{
  var nRet   = -1 ;
  var len    = ar.length; 
  var maxVal = Number.MIN_VALUE ;
  var val ;
  
  for (var i = 0; i < len; i++) {
     val = ar[i] ;

     if (val && (typeof val === 'number') && (val > maxVal)) {
       maxVal = val ;
       nRet   = i ;
     }
  }

  return nRet ;
};

/**
 * Returns true if the two arrays have the same contents.
 * @param {array} a
 * @param {array} b
 */
DvtArrayUtils.equals = function(a, b) {
  if(!a && b)
    return false;
  else if(a && !b)
    return false;
  else if(!a && !b)
    return true;
  else // a && b
  {
    if(a.length != b.length)
      return false;
    
    // Compare the individual items
    for(var i=0; i<=a.length; i++) {
      if(a[i] !== b[i])
        return false;
    }
    
    // Everything matched, return true
    return true;
  }
}

DvtArrayUtils.indexOf = function(a, value) {
  if (!a)
    return -1;
  for (var i=0;i<a.length;i++) {
      var item = a[i];
      if (item == value)
        return i;
  }
  return -1;
}
// Copyright (c) 2008, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/*-------------------------------------------------------------------------*/
/*   DvtStringUtils         Miscellaneous string utility functions         */
/*-------------------------------------------------------------------------*/
/**
  *  @class  DvtStringUtils  A static class providing miscellaneous string utility
  *  functions.
  */
var  DvtStringUtils = {} ;



/*--------------------------------------------------------------------*/
/*  trim(), ltrim(), rtrim()       Whitespace removal                 */
/*--------------------------------------------------------------------*/
/**
  *   Removes leading and trailing whitespace from a string.
  *   @base DvtStringUtils
  *   @param {String} s  The string to be trimmed.
  *   @type String
  *   @returns A string with leading and trailing whitespace removed.
  */
DvtStringUtils.trim = function(s)
{
	return s.replace(/^\s+|\s+$/g,"");
} ;

/**
  *   Removes leading whitespace from a string.
  *   @param {String} s  The string to be trimmed.
  *   @type String
  *   @returns A string with leading whitespace removed.
  */
DvtStringUtils.ltrim = function(s)
{
	return s.replace(/^\s+/,"");
} ;

/**
  *   Removes trailing whitespace from a string.
  *   @param {String} s  The string to be trimmed.
  *   @type String
  *   @returns A string with trailing whitespace removed.
  */
DvtStringUtils.rtrim = function(s)
{
	return s.replace(/\s+$/,"");
} ;


DvtStringUtils.endsWith = function(s, str)
{
  return (s.match(str+"$")==str)
};
// Copyright (c) 2008, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/*---------------------------------------------------------------------*/
/*   DvtContext                                                        */
/*---------------------------------------------------------------------*/
/**
 *   Generic application context.  Used as a single central object to
 *   maintain application specific context, as well as well as providing
 *   access to platform specific data and objects, such as the factory.
 *   @extends DvtObj
 *   @class DvtContext
 *   @constructor
 *   @param {DvtImplFactory} implFactory     The platform implementation factory
 *   @param {DvtStage} stage
 *   @param {DvtTooltipManager} tooltipManager
 */
var DvtContext = function (implFactory, root, id) {
  this.Init(implFactory, root, id);
};

DvtObj.createSubclass(DvtContext, DvtObj, "DvtContext");

/**
  * Initializes this context object with the platform dependent objects.
  * @param  {DvtImplFactory} implFactory
  * @param  {DvtStage} stage
  * @param  {DvtTooltipManager} tooltipManager
  * @protected
  */
DvtContext.prototype.Init = function (implFactory, root, id) {
  this._implFactory    = implFactory;
  this._stage          = new DvtStage(this, root, id + "_stage" );     // TODO use naming utils

  this._tooltipManagers = new Object();
  this._customTooltipManagers = new Object();
  
  this._scheduler      = null;
};

/**
 *  Returns a platform dependent implementation factory of the one and only
 *  implementation factory object.
 *  @type DvtImplFactory 
 */
DvtContext.prototype.getImplFactory = function () {
  return this._implFactory;
};


/**
 *  Returns a platform dependent implementation of the one and only
 *  stage.
 *  @type DvtStage 
 */
DvtContext.prototype.getStage = function () {
  return this._stage;
};

/**
 * Queues a rendering of the stage to occur.
 */
DvtContext.prototype.queueRender = function() {
  // Applicable subclasses should override this function.
}

/**
 *  Returns a platform dependent implementation of the one and only
 *  tooltip manager.
 *  @type DvtTooltipManager 
 */
DvtContext.prototype.getTooltipManager = function (id) {
    if (!id)
      id = "_dvtTooltip";
    var stageId = this.getStage().getId();
    id = id+stageId;
    var manager = this._tooltipManagers[id];
    if (!manager) {
        this._tooltipManagers[id] = this._implFactory.newTooltipManager(id);
    }
    return this._tooltipManagers[id];
};

/**
  * Get the single scheduler instance for this context.
  * 
  * @type DvtScheduler
  */
DvtContext.prototype.getScheduler = function () {
  if (!this._scheduler)
  {
    this._scheduler = new DvtScheduler(this);
  }
  
  return this._scheduler;
};

/**
  * Obtain document utils singleton.
  *
  * @type Object
  */
DvtContext.prototype.getDocumentUtils = function () {
  return this._implFactory.getDocumentUtils();
};

/**
  * Get coordinates relative to stage.
  *
  * @type DvtPoint
  */
DvtContext.prototype.getRelativePosition = function (pageX, pageY) {
  var docUtils     = this.getDocumentUtils();
  if (docUtils) {
      var stage = this.getStage();
      var position     = docUtils.getStageRelativePosition(stage, pageX, pageY);
      return position;
  }
  return null;
};

/**
  * Get absolute coordinates of stage.
  *
  * @type DvtPoint
  */
DvtContext.prototype.getStageAbsolutePosition = function () {
  var docUtils     = this.getDocumentUtils();
  if (docUtils) {
      var stage = this.getStage();
      var position     = docUtils.getStageAbsolutePosition(stage);
      return position;
  }
  return null;
}

/**
  * Determine if the platform is SVG.
  *
  * @type boolean
  */
DvtContext.prototype.isPlatformSvg = function () {
  return false;
};


DvtContext.prototype.initializeTouchManager = function() 
{
    if (this._touchManager)
        delete this._touchManager;
    this._touchManager = new DvtTouchManager("touchmanager", this);
}

DvtContext.prototype.getTouchManager = function()
{
    if (!this._touchManager) {
        this.initializeTouchManager();
    }
    return this._touchManager;
}

DvtContext.prototype.getCustomTooltipManager = function(id)
{
    if (!id)
      id = "_dvtCustomTooltip";
    var stageId = this.getStage().getId();
    id = id+stageId;
    var manager = this._customTooltipManagers[id];
    if (!manager) {
        this._customTooltipManagers[id] = new DvtCustomTooltipManager(this, id);
    }
    return this._customTooltipManagers[id];
}


/**
  *   Obtains the external Js interface singleton.
  *   @returns {DvtContext}  the external interface singleton.
  */
DvtContext.prototype.getJsExt = function()
{
   if (! this._externalInterface) {
     this._externalInterface = this._implFactory.newJsExt();
   }

   return this._externalInterface ;

};
// Copyright (c) 2008, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/*---------------------------------------------------------------------*/
/*   DvtImplFactory                                                    */
/*---------------------------------------------------------------------*/
/**
 * Abstract class defining implementation factory methods for creating
 * implementation instances for platform specific objects, such as shapes.
 * @extends DvtObj
 * @class DvtImplFactory
 * @constructor
 * @param {DvtContext} context The context object
 */
var DvtImplFactory = function(context) {
  this.Init(context);
};

DvtObj.createSubclass(DvtImplFactory, DvtObj, "DvtImplFactory");



/*---------------------------------------------------------------------*/
/*  Init()                                                             */
/*---------------------------------------------------------------------*/
/**
  *  Object initializer.
  *  @protected
  */
DvtImplFactory.prototype.Init = function(context) {
   this._context = context ;
} ;

/*---------------------------------------------------------------------*/
/*   getContext()                                                      */
/*---------------------------------------------------------------------*/
/**
 * @protected
 */
DvtImplFactory.prototype.GetContext = function() {
  return this._context;
}

/*---------------------------------------------------------------------*/
/*     Base container and shape constructors                           */
/*---------------------------------------------------------------------*/

/**
  *  @returns {DvtObj}
  */
DvtImplFactory.prototype.newContainer = function (id) {
  return null; // subclasses should override;
};

/**
  *  @returns {DvtObj}
  */
DvtImplFactory.prototype.newArc = function (cx, cy, rx, ry, sa, ae, clos,id) {
  return null; // subclasses should override
};

/**
  *  @returns {DvtObj}
  */
DvtImplFactory.prototype.newCircle = function (cx, cy, r, id) {
  return null; // subclasses should override
};

/**
  *  @returns {DvtObj}
  */
DvtImplFactory.prototype.newImage = function (imageSrc, x, y, w, h, id) {
  return null; // subclasses should override
};

/**
  *  @returns {DvtObj}
  */
DvtImplFactory.prototype.newLine = function (x1, y1, x2, y2, id) {
  return null; // subclasses should override
};

/**
  *  @returns {DvtObj}
  */
DvtImplFactory.prototype.newOval = function (cx, cy, rx, ry, id) {
  return null; // subclasses should override
};

/**
  *  @returns {DvtObj}
  */
DvtImplFactory.prototype.newPath = function (cmds, id) {
  return null; // subclasses should override
};

/**
  *  @returns {DvtObj}
  */
DvtImplFactory.prototype.newPolygon = function (arPoints, id) {
  return null; // subclasses should override
};

/**
  *  @returns {DvtObj}
  */
DvtImplFactory.prototype.newRect = function (x, y, w, h, id) {
  return null; // subclasses should override
};

/**
  *  @returns {DvtObj}
  */
DvtImplFactory.prototype.newText = function (textStr, x, y, id) {
  return null; // subclasses should override
};


/*---------------------------------------------------------------------*/
/*     Other Constructors                                              */
/*---------------------------------------------------------------------*/

DvtImplFactory.prototype.newParser = function() {
  return null; // subclasses should override
};

/**
  * Create a new timer.
  */
DvtImplFactory.prototype.newTimer = function () {
  return null; //subclasses must override
};

/**
 * Create a new context menu handler impl.
 */
DvtImplFactory.prototype.newContextMenuHandler = function () {
  return null; //subclasses must override
};

/**
  * Returns a new DvtTextArea object.
  * @param textStr {string} the text string
  * @param x {number} x the x position
  * @param y {number} y the y position
  * @param {String} id  Optional ID for the object (see also {@link DvtDisplayable#setId}) 
  * @override
  * @type DvtTruncatingText
  */
DvtImplFactory.prototype.newTextArea = function (x, y, id) {
  return null; // subclasses should override;
};

/**
  * Returns a new DvtTextFormatted object.
  * @param textStr {string} the text string
  * @param x {number} x the x position
  * @param y {number} y the y position
  * @param {String} id  Optional ID for the object (see also {@link DvtDisplayable#setId}) 
  * @override
  * @type DvtTruncatingText
  */
DvtImplFactory.prototype.newTextFormatted = function (x, y, id) {
  return null; // subclasses should override;
};

/**
 *  Returns a new DvtMarker object which represents a graph or legend marker.
 *  @param {number} type The type of the marker (see {@link DvtMarker}).
 *  @param {String} id  Optional ID for the shape (see {@link  DvtDisplayable#setId}).
 *  <p>
 *  Example:<br><br><code>
 *  var rect = factory.newMarker(type, 'myRect') ;<br>
 *  </code>
 *  @returns A new {@link DvtMarker} object.
 *  @type DvtMarker
 *  @override
 */
DvtImplFactory.prototype.newMarker = function (type, id) {
  return null;
};

/**
  * Create a new tooltip manager.
  */
DvtImplFactory.prototype.newTooltipManager = function (id) {
  return null;
};

/**
  * Create a new rich tooltip manager.
  */
DvtImplFactory.prototype.newRichTooltipManager = function (id) {
  return null;
};

/**
  * Obtain document utils singleton.
  *
  * @type Object
  * @override
  */
DvtImplFactory.prototype.getDocumentUtils = function () {
  return null;
};
// Copyright (c) 2008, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/*-------------------------------------------------------------------------*/
/*   DvtIterator   An iterator for walking the children of a DvtContainer  */
/*-------------------------------------------------------------------------*/
/**
  *  Do not create directly - use container.getIterator().
  *  @extends DvtObj
  *  @class  DvtIterator is an iterator for walking the children of DvtContainer. This object is
  *  returned by container.getIterator()  - do not create programatically.
  *  <p>
  *  Typical usage:<br><br><code>
  *  var iter = container.getIterator(true) ;       // deep iterator<br>  
  * <br>
  *  var  obj ;<br>
  *  while ((obj = iter.getNext()) !== null) {<br>
  *     . . .<br>
  *  }<br></code>
  *
  */
var  DvtIterator = function(arList, bDeep)
{
   this._Init(arList, bDeep) ;
};

DvtObj.createSubclass(DvtIterator, DvtObj, "DvtIterator");

/**
  *  Internal flags
  *   @private
  */
DvtIterator._NONE  = 0 ;
/** @private */
DvtIterator._FIRST = 1 ;
/** @private */
DvtIterator._LAST  = 2 ;
/** @private */
DvtIterator._NEXT  = 3 ;






/*--------------------------------------------------------------------*/
/*  getNext()          Return the next object from the collection     */
/*--------------------------------------------------------------------*/
/**
  *  Returns the next object in the collection.
  *  @returns {DvtObj}  The next object in the collection, or null if 
  *  all objects have been returned.
  */
DvtIterator.prototype.getNext = function()
{
   var  obj = null ;          // return value

   if (this._stackPos >= 0) {

      var se    = this._arStack[this._stackPos] ;
      var list  = se._list ;

      if (list) {
         if (se._currentObj) {
           obj = ((++se._pos < list.length)? list[se._pos] : null) ;
         }
         else {
           obj = list[0] ;        // get the first object
           se._pos = 0 ;
         }
         se._currentObj = obj ;
      }

      if (! obj) {
         this._pop() ;                   // pop current stack context
         if (this._stackPos >= 0) {
           this._bInRecurse = true ;
           obj = this.getNext() ;       // and recurse
           this._bInRecurse = false ;
         }
      }

      //  If we are returning a container and this is a deep iterator,
      //  make a note so that the next getNext() will drill down into the
      //  the container.

      if (! this._bInRecurse) {   // only do this out of getNext() recursion
        if ((this._stackPos >= 0) && this._bDeep && obj) {
           if (obj.getNumChildren() !== 0) {     // does object contain its own children?
             this._push(obj._getChildren()) ;        // save current stack context
           }
        }
      }
   }

   this._lastObjReturnedFlags = (obj? DvtIterator._NEXT : DvtIterator._NONE) ;
   this._lastObjReturned = obj ;              // remember for getPrevious()

   return obj ;
} ;


/*--------------------------------------------------------------------*/
/*   _Init()                                                          */
/*--------------------------------------------------------------------*/
/** @private */
DvtIterator.prototype._Init = function(arList, bDeep)
{
   this._bDeep      = bDeep ? bDeep : false ;
   this._bInRecurse = false ;

   this._arStack  = null ;
   this._stackPos = -1 ;

   this._lastObjReturned = null ;
   this._lastObjReturnedFlags = DvtIterator._NONE;

   if (arList) {
     this._push(arList) ;
   }

} ;


/*----------------------------------------------------------------------*/
/*   _pop()     Pop the current StackEntry from the stack context list  */
/*----------------------------------------------------------------------*/
/** @private */
DvtIterator.prototype._pop =  function()
{
   if ((this._arStack !== null) && (this._stackPos >= 0)) {

     var  se =  this._arStack[this._stackPos] ;  // destroy
     se._list       = null ;                     // the stack list
     se._currentObj = null ;                     // entry ;
     this._arStack[this._stackPos] = null ;

     if (--this._stackPos < 0) {
       this._arStack = null ;          // stack is now empty
     }
   }

   //  Note:  although we have logically popped the stack, the stack array
   //         length is unchanged. We will use the "next" position in the
   //         stack on the next push.
} ;



/*----------------------------------------------------------------------*/
/*   _push()          Place a list on the stack context list            */
/*----------------------------------------------------------------------*/
/** @private */
DvtIterator.prototype._push = function(ar)
{
   if (this._arStack === null) {
     this._arStack = [] ;
   }

   var  se  = {} ;                   // create a stacklist entry
   se._list       = ar ;
   se._currentObj = null ;
   se._pos        = -1 ;

   this._stackPos++ ;

   if (this._stackPos < this._arStack.length) {
     this._arStack[this._stackPos] = se ;            // reuse a slot
   }
   else {
     this._arStack.push(se) ;
   }
} ;

// Copyright (c) 2008, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/*---------------------------------------------------------------------*/
/*   DvtJsExt      Abstract implementation for Js external access      */
/*---------------------------------------------------------------------*/

//  Placeholder - revist if/when callbacks are used.


/**
  *  Provides a gateway for access to external Js functionality. 
  *  @class DvtJsExt
  *  @extends DvtObj
  *  @constructor
  */
var  DvtJsExt = function()
{
};

DvtObj.createSubclass(DvtJsExt, DvtObj, "DvtJsExt");


// ADF logger levels.

/** @final @type number  */
DvtJsExt.LOG_OFF      = 1 ;
/** @final @type number  */
DvtJsExt.LOG_SEVERE   = 2 ;
/** @final @type number  */
DvtJsExt.LOG_WARNING  = 3 ;
/** @final @type number  */
DvtJsExt.LOG_INFO     = 4 ;
/** @final @type number  */
DvtJsExt.LOG_CONFIG   = 5 ;
/** @final @type number  */
DvtJsExt.LOG_FINE     = 6 ;
/** @final @type number  */
DvtJsExt.LOG_FINER    = 7 ;
/** @final @type number  */
DvtJsExt.LOG_FINEST   = 8 ;
/** @final @type number  */
DvtJsExt.LOG_ALL      = 9 ;

//  Performance 

/** @final @type number  */
DvtJsExt.PERF_PROFILING   = 0;
/** @final @type number  */
DvtJsExt.PERF_TIMING      = 1;


//  PPR attributes

/** @final @type String  */
DvtJsExt.PPR_ATTRIB_HSS           = "hideShowSeriesInfo";

/** @final @type String  */
DvtJsExt.PPR_ATTRIB_SEL           = "selectionInfo";

/** @final @type String  */
DvtJsExt.PPR_ATTRIB_PIE_EXPLODE  = "pieSliceExplodeInfo";


//  External ADF DVT JS routines

/** @final @private @type String  */
DvtJsExt.JS_FPREQUESTREFRESH     = "adf_dvt_fpRefresh" ;
/** @final @private @type String  */
DvtJsExt.JS_FPGETLOGLEVEL        = "adf_dvt_fpGetLogLevel" ;
/** @final @private @type String  */
DvtJsExt.JS_FPINITNOTIFY         = "adf_dvt_fpInitNotify" ;
/** @final @private @type String  */
DvtJsExt.JS_FPLOGGER             = "adf_dvt_fpLogger" ;
/** @final @private @type String  */
DvtJsExt.JS_FPMSG                = "adf_dvt_fpMsg" ;
/** @final @private @type String  */
DvtJsExt.JS_FP_PERF_LOGGER       = "adf_dvt_fpPerfLogger" ;

/** @final @private @type String  */
DvtJsExt.JS_FP_SET_PPR_PROPERTY  = "AdfPage.PAGE.findComponent('X-ID-X').getPeer().setDVTPPRAttribute" ;

/** @final @private @type String  */
DvtJsExt.JS_FP_SEND_PPR          = "AdfPage.PAGE.findComponent('X-ID-X').getPeer().sendToServerPPR({source:'X-ID-X'})" ;
/** @final @private @type String  */
DvtJsExt.JS_FP_SEND_PPR_NON_BLOCKING = "AdfPage.PAGE.findComponent('X-ID-X').getPeer().sendToServerPPR3({source:'X-ID-X'})" ;

/** @final @private @type String  */
DvtJsExt.JS_FPUPDATEPOPUPBOUNDS  = "adf_dvt_fpUpdatePopupHelper";

/** @final @private @type String  */

DvtJsExt.JS_COMPONENT_LOADED     = "AdfDhtmlCommonFlashPeer.setComponentLoaded" ;




/*---------------------------------------------------------------------*/
/*                                 ADF                                 */
/*---------------------------------------------------------------------*/

/**  
  *  Sets a PPR property value.
  *  @param {String}  id  An id to be substituted in the function call.
  *  @param {String)  prop a property such as {@link DvtJsExt#PPR_ATTRIB_HSS}
  *  @param {String}  value  the property value.
  */
DvtJsExt.prototype.sendPPRProperty = function(id, prop, value)
{
};


DvtJsExt.prototype.sendPPR  = function(id)
{
};


DvtJsExt.prototype.sendPPRNonBlocking = function(id)
{
};



/*---------------------------------------------------------------------*/
/*                    External Javascript invocation                   */
/*---------------------------------------------------------------------*/

/**
  *   Performs the specified Javascript.
  *   @returns {unknown} the result, if any, of Javascript.
  */
DvtJsExt.prototype.callJs = function(js)
{
};


/*---------------------------------------------------------------------*/
/*                            Logging                                  */
/*---------------------------------------------------------------------*/

/**
  *   Returns the current ADF log level.
  *   @returns {number} the current ADF log level (such as {DvtJsExt#WARNING}).
  */
DvtJsExt.prototype.getLogLevel = function()
{
    return  adf_dvt_fpGetLogLevel() ;
};


/**
  *   Forwards a message to the ADF logger.
  *   @param  {String} msg the message to be logged.
  *   @param  {number} level the log level of the messsage.  If omitted
  *                          a value of {DvtJsExt#LOG_INFO} is assumed.
  */
DvtJsExt.prototype.log = function(msg, level)
{
};


/**
  *   Forwards a message string to ADF DVT.
  *   @param  {String} msg the message to be sent.
  */
DvtJsExt.prototype.msg = function(msg)
{
};



/*---------------------------------------------------------------------*/
/*                           Performance                               */
/*---------------------------------------------------------------------*/

/**
  *   Forwards a performance message.
  *   @param  {String} msg the performance message to be sent.
  *   @param  {number} type  the performance type (such as {DvtJsExt#PERF_TIMING}).
  */
DvtJsExt.prototype.perf = function(msg, type)
{
};


DvtJsExt.prototype.requestRefresh = function()
{
};



/**
 * A base class for shape fills, strokes, shadows, etc.
 * {@link DvtLockable}.
 * @extends DvtObj
 * @class DvtLockable  A base class for shape fills, strokes,shadows, etc.
 * @constructor  Do not create/use directly.
 */
var DvtLockable = function () {
  this._Init();
}

DvtObj.createSubclass(DvtLockable, DvtObj, "DvtLockable");

/** 
 * @private 
 */
DvtLockable.prototype._Init = function () {
  this._bLocked = false;
}

/**
 *  Returns true if the fill object is immutable, else false.
 *  @type Boolean
 */
DvtLockable.prototype.isLocked = function () {
  return this._bLocked;
}

/**
 *  Makes the property set immutable.  The only way to change the object's
 *  properties once it is immutable is to clone it and apply property changes
 *  to the cloned object.  This method should not be called by application code
 *  and should only be used by toolkit code.
 *  @private
 */
DvtLockable.prototype.__lock = function () {
  this._bLocked = true;
}

/**
 *  Makes the property set mutable. This method should not be called by application code
 *  and should only be used by toolkit code.
 *  @private
 */
DvtLockable.prototype.__unlock = function () {
  this._bLocked = false;
}
// Copyright (c) 2011, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/**
  * Class representing an item that can be scheduled to run with a scheduler.
  * @extends DvtObj
  * @class DvtScheduled
  * @constructor
  * 
  * @param {DvtContext}  context  platform specific context object
  * @param {DvtScheduler}  scheduler  scheduler used to run this item
  * @param {number}  duration  length of time to run item, in seconds
  * @param {number}  delay  time to delay start of item, in seconds
  * @param {function}  easing  easing function to use with this item
  */
var DvtScheduled = function(context, scheduler, duration, delay, easing)
{
  this.Init(context, scheduler, duration, delay, easing);
};

DvtObj.createSubclass(DvtScheduled, DvtObj, "DvtScheduled");

/**
  * @private
  * State: initialize.
  */
DvtScheduled._STATE_INITIALIZE = 0;
/**
  * @private
  * State: begin.
  */
DvtScheduled._STATE_BEGIN = 1;
/**
  * @private
  * State: run.
  */
DvtScheduled._STATE_RUN = 2;

/**
  * @protected
  * Calculate the percent progress of the given value between the min and max.
  * 
  * @param {number}  val  current value
  * @param {number}  min  minimum value
  * @param {number}  max  maximum value
  * @type number
  */
DvtScheduled.CalcProgress = function(val, min, max)
{
  var diff = (max - min);
  if (diff == 0)
  {
    return 0.5;
  }
  else
  {
    var ret = ((val - min) / diff);
    if (ret > 1)
    {
      ret = 1;
    }
    return ret;
  }
};

/**
  * @protected
  */
DvtScheduled.prototype.Init = function(context, scheduler, duration, delay, easing)
{
  this._scheduler = scheduler;
  this.setDuration(duration); //in seconds
  this.setDelay(delay); //in seconds
  this.setEasing(easing);
  
  this._bRunning = false;
  this._startTime = null;
  this._progress = 0;
  this._state = DvtScheduled._STATE_INITIALIZE;
  
  this._onInit = null;
  this._onInitObj = null;
  this._onStart = null;
  this._onStartObj = null;
  this._onEnd = null;
  this._onEndObj = null;
  this._onStep = null;
  this._onStepObj = null;
};

/**
  * Get the duration of this item, in seconds.
  * 
  * @type number
  */
DvtScheduled.prototype.getDuration = function()
{
  return this._duration;
};

/**
  * Set the duration of this item.
  * 
  * @param {number}  duration  duration of this item, in seconds
  */
DvtScheduled.prototype.setDuration = function(duration)
{
  this._duration = (duration ? duration : 0.5);
};

/**
  * Get the delay for the start of this item, in seconds.
  * 
  * @type number
  */
DvtScheduled.prototype.getDelay = function()
{
  return this._delay;
};

/**
  * Set the delay for the start of this item.
  * 
  * @param {number}  delay  delay for the start of this item, in seconds
  */
DvtScheduled.prototype.setDelay = function(delay)
{
  this._delay = (delay ? delay : 0);
};

/**
  * Get the easing function for this animation.
  * 
  * @type function
  */
DvtScheduled.prototype.getEasing = function()
{
  return this._easing;
};

/**
  * Set the easing function for this animation.
  * 
  * @param {function}  easing  easing function
  */
DvtScheduled.prototype.setEasing = function(easing)
{
  this._easing = (easing ? easing : DvtEasing.cubicInOut);
};

/**
  * Set the function to call when this item initializes.
  * 
  * @param {function}  onInit  function to call when this item initializes
  * @param {object}  onInitObj  optional reference to object instance on which the 
  *        function is defined
  */
DvtScheduled.prototype.setOnInit = function(onInit, onInitObj)
{
  this._onInit = onInit;
  if (onInitObj)
  {
    this._onInitObj = onInitObj;
  }
  else
  {
    this._onInitObj = null;
  }
};

/**
  * Get the function to call when this item initializes.
  * Returns an array of two elements: 
  * [0] the function
  * [1] optional reference to object instance on which the function is defined
  * 
  * @type array
  */
DvtScheduled.prototype.getOnInit = function()
{
  return [this._onInit, this._onInitObj];
};

/**
  * Set the function to call when this item starts.
  * 
  * @param {function}  onStart  function to call when this item starts
  * @param {object}  onStartObj  optional reference to object instance on which the 
  *        function is defined
  */
DvtScheduled.prototype.setOnStart = function(onStart, onStartObj)
{
  this._onStart = onStart;
  if (onStartObj)
  {
    this._onStartObj = onStartObj;
  }
  else
  {
    this._onStartObj = null;
  }
};

/**
  * Get the function to call when this item starts.
  * Returns an array of two elements: 
  * [0] the function
  * [1] optional reference to object instance on which the function is defined
  * 
  * @type array
  */
DvtScheduled.prototype.getOnStart = function()
{
  return [this._onStart, this._onStartObj];
};

/**
  * Set the function to call when this item ends.
  * 
  * @param {function}  onEnd  function to call when this item ends
  * @param {object}  onEndObj  optional reference to object instance on which the 
  *        function is defined
  */
DvtScheduled.prototype.setOnEnd = function(onEnd, onEndObj)
{
  this._onEnd = onEnd;
  if (onEndObj)
  {
    this._onEndObj = onEndObj;
  }
  else
  {
    this._onEndObj = null;
  }
};

/**
  * Get the function to call when this item ends.
  * Returns an array of two elements: 
  * [0] the function
  * [1] optional reference to object instance on which the function is defined
  * 
  * @type array
  */
DvtScheduled.prototype.getOnEnd = function()
{
  return [this._onEnd, this._onEndObj];
};


/**
  * Set the function to call at each step of this item.
  * 
  * @param {function}  onStep  function to call at each step of this item
  * @param {object}  onStepObj  optional reference to object instance on which the 
  *        function is defined
  */
DvtScheduled.prototype.setOnStep = function(onStep, onStepObj)
{
  this._onStep = onStep;
  if (onStepObj)
  {
    this._onSepObj = onStepObj;
  }
  else
  {
    this._onStepObj = null;
  }
};

/**
  * Get the function to call at each step of this item.
  * Returns an array of two elements: 
  * [0] the function
  * [1] optional reference to object instance on which the function is defined
  * 
  * @type array
  */
DvtScheduled.prototype.getOnStep = function()
{
  return [this._onStep, this._onStepObj];
};

/**
  * Determine if this item is running.
  * 
  * @type boolean
  */
DvtScheduled.prototype.isRunning = function()
{
  return this._bRunning;
};

/**
  * Play this item.
  */
DvtScheduled.prototype.play = function()
{
  if (!this._bRunning)
  {
    this._bRunning = true;
    this.ProcessPlay();
    this._scheduler.addScheduled(this);
  }
};

/**
  * Stop this item.
  * 
  * @param {boolean}  bJumpToEnd  true to jump to 100% progress, 
  *        false to stop at current progress
  */
DvtScheduled.prototype.stop = function(bJumpToEnd)
{
  this._scheduler.removeScheduled(this);
  if (bJumpToEnd)
  {
    this.ProcessStep(1);
  }
  this.ProcessEnd();
};

/**
  * Pause this item.
  */
DvtScheduled.prototype.pause = function()
{
  this._bRunning = false;
  //this._scheduler.removeScheduled(this);
};

/**
  * Reset this item.
  */
DvtScheduled.prototype.reset = function()
{
  this._state = DvtScheduled._STATE_INITIALIZE;
};

/**
  * Process this item for the given timestamp.
  * 
  * @param {number}  time  current timestamp, in milliseconds
  */
DvtScheduled.prototype.processTime = function(time)
{
  if (!this._bRunning)
  {
    return;
  }
  
  var elapsedTime = time - this._startTime;
  if (elapsedTime < 0)
  {
    return false;
  }
  
  var duration = 1000 * this.GetTotalDuration();
  var progress = 1;
  if (duration != 0)
  {
    progress = elapsedTime / duration;
  }
  if (progress > 1)
  {
    progress = 1;
   }
  this.ProcessStep(progress);
  
  var bDone = (progress >= 1);
  if (bDone)
  {
    this.ProcessEnd();
  }
  return bDone;
};

/**
  * @protected
  * Get the total duration of this item, in seconds.
  * 
  * @type number
  */
DvtScheduled.prototype.GetTotalDuration = function()
{
  return this._delay + this._duration;
};

/**
  * @protected
  * Process when this item is played.
  */
DvtScheduled.prototype.ProcessPlay = function()
{
  if (this._state == DvtScheduled._STATE_INITIALIZE)
  {
    this.ProcessInitialize();
  }
  
  if (this._state == DvtScheduled._STATE_BEGIN)
  {
    this._startTime = new Date().getTime();
    this.ProcessStart();
  }
  else
  {
    var elapsedTime = this._progress * 1000 * this.GetTotalDuration();
    this._startTime = new Date().getTime() - elapsedTime;
  }
  
  this._state = DvtScheduled._STATE_RUN;
};

/**
  * @protected
  * Process initialization of this item when it starts to play.
  */
DvtScheduled.prototype.ProcessInitialize = function()
{
  if (this._onInit)
  {
    this._onInit.call(this._onInitObj);
  }
  this.Initialize();
  this._state = DvtScheduled._STATE_BEGIN;
};

/**
  * @protected
  * Process the start of this item after it initializes.
  */
DvtScheduled.prototype.ProcessStart = function()
{
  this._bRunning = true;
  this._progress = 0;
  this.Start();
  if (this._onStart)
  {
    this._onStart.call(this._onStartObj);
  }
};

/**
  * @protected
  * Process a step of this item as it plays.
  * 
  * @param {number}  progress  percent progress of this item
  */
DvtScheduled.prototype.ProcessStep= function(progress)
{
  this._progress = progress;
  var prog = progress;
  if (this._delay > 0)
  {
    prog = DvtScheduled.CalcProgress(progress, this._delay / this.GetTotalDuration(), 1);
  }
  if (prog >= 0)
  {
    if (this._easing)
    {
      prog = this._easing(prog);
    }
    this.Step(prog);
    
    if (this._onStep)
    {
      this._onStep.call(this._onStepObj, prog);
    }
  }
};

/**
  * @protected
  * Process when this item stops.
  */
DvtScheduled.prototype.ProcessEnd = function()
{
  //only process end if still running
  if (this._bRunning)
  {
    this._bRunning = false;
    this._progress = 1;
    this.End();
    this._state = DvtScheduled._STATE_BEGIN;
    if (this._onEnd)
    {
      this._onEnd.call(this._onEndObj);
    }
  }
};

/**
  * @protected
  * Initialize this item.
  */
DvtScheduled.prototype.Initialize = function()
{
  //do nothing; subclasses should implement
};

/**
  * @protected
  * Start playing this item.
  */
DvtScheduled.prototype.Start = function()
{
  //do nothing; subclasses should implement
};

/**
  * @protected
  * Step this item.
  * 
  * @param {number}  progress  percent progress of this item
  */
DvtScheduled.prototype.Step = function(progress)
{
  //do nothing; subclasses should implement
};

/**
  * @protected
  * End this item.
  */
DvtScheduled.prototype.End = function()
{
  //do nothing; subclasses should implement
};
// Copyright (c) 2011, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/**
  * Class representing a scheduling service.
  * @extends DvtObj
  * @class DvtScheduler
  * @constructor
  * 
  * @param {DvtContext}  context  platform specific context object
  */
var DvtScheduler = function(context)
{
  this.Init(context);
};

DvtObj.createSubclass(DvtScheduler, DvtObj, "DvtScheduler");

/**
  * @protected
  */
DvtScheduler.prototype.Init = function(context)
{
  this._timer = new DvtTimer(context, 1000 / 30, this.HandleTimer, this);
  this._scheduledItems = new Array();
  this._bRunning = false;
};

/**
  * Set the interval between timer ticks, in milliseconds.
  * 
  * @param {number}  interval  interval between timer ticks, in milliseconds
  */
DvtScheduler.prototype.setInterval = function(interval)
{
  var i = interval;
  if (i < 0)
  {
    i = 0;
  }
  this.pause();
  this._timer.setInterval(i);
  this.play();
};

/**
  * Get the interval between timer ticks.
  * 
  * @type number
  */
DvtScheduler.prototype.getInterval = function()
{
  return this._timer.getInterval();
};

/**
  * @protected
  * Handle a timer tick.
  */
DvtScheduler.prototype.HandleTimer = function()
{
  var time = new Date().getTime();
  for (var i = 0; i < this._scheduledItems.length; i++)
  {
    var scheduled = this._scheduledItems[i];
    if (scheduled.processTime(time))
    {
      this.removeScheduled(scheduled);
    }
  }
  
  if (this._scheduledItems.length < 1)
  {
    this.pause();
  }
};

/**
  * Add a scheduled item to be run.  
  * 
  * @param {DvtScheduled}  scheduled  item to add
  */
DvtScheduler.prototype.addScheduled = function(scheduled)
{
  var i = DvtArrayUtils.getIndex(this._scheduledItems, scheduled)
  if (i < 0)
  {
    this._scheduledItems.push(scheduled);
  }
  
  this.play();
};

/**
  * Remove a scheduled item.
  * 
  * @param {DvtScheduled}  scheduled  item to remove
  */
DvtScheduler.prototype.removeScheduled = function(scheduled)
{
  var i = DvtArrayUtils.getIndex(this._scheduledItems, scheduled);
  if (i >= 0)
  {
    this._scheduledItems.splice(i, 1);
  }
};

/**
  * Play the scheduler.
  */
DvtScheduler.prototype.play = function()
{
  if (!this._bRunning)
  {
    for (var i = 0; i < this._scheduledItems.length; i++)
    {
      var scheduled = this._scheduledItems[i];
      if (!scheduled.isRunning())
      {
        scheduled.play();
      }
    }
    
    this._bRunning = true;
    this._timer.start();
  }
};

/**
  * Pause the scheduler.
  */
DvtScheduler.prototype.pause = function()
{
  if (this._bRunning)
  {
    this._bRunning = false;
    this._timer.stop();
    
    for (var i = 0; i < this._scheduledItems.length; i++)
    {
      var scheduled = this._scheduledItems[i];
      if (scheduled.isRunning())
      {
        scheduled.pause();
      }
    }
  }
};
// Copyright (c) 2011, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/**
  * Class representing an animator that animates a property change.
  * @extends DvtScheduled
  * @class DvtAnimator
  * @constructor
  * 
  * @param {DvtContext}  context  platform specific context object
  * @param {number}  duration  length of animation, in seconds
  * @param {number}  delay  time to delay start of animation, in seconds
  * @param {function}  easing  easing function to use with this animation
  */
var DvtAnimator = function(context, duration, delay, easing)
{
  this.Init(context, duration, delay, easing);
};

DvtObj.createSubclass(DvtAnimator, DvtScheduled, "DvtAnimator");

/**
  * Property type: number.
  */
DvtAnimator.TYPE_NUMBER = "typeNumber";
/**
  * Property type: matrix.
  */
DvtAnimator.TYPE_MATRIX = "typeMatrix";
/**
  * Property type: array of numbers.
  */
DvtAnimator.TYPE_NUMBER_ARRAY = "typeNumberArray";
/**
  * Property type: color.
  */
DvtAnimator.TYPE_COLOR = "typeColor";
/**
  * Property type: array of colors.
  */
DvtAnimator.TYPE_COLOR_ARRAY = "typeColorArray";
/**
  * Property type: grow polyline points.
  */
DvtAnimator.TYPE_GROW_POLYLINE = "typeGrowPolyline";
/**
  * Property type: rectangle.
  */
DvtAnimator.TYPE_RECTANGLE = "typeRectangle";
/**
  * Property type: point.
  */
DvtAnimator.TYPE_POINT = "typePoint";
/**
  * Property type: path.
  */
DvtAnimator.TYPE_PATH = "typePath";
/**
  * Property type: grow path points.
  */
DvtAnimator.TYPE_GROW_PATH = "typeGrowPath";
/**
  * Property type: fill.
  */
DvtAnimator.TYPE_FILL = "typeFill";
/**
  * Property type: polyline.
  */
DvtAnimator.TYPE_POLYLINE = "typePolyline";

/**
  * @private
  * Size of each property record in storage array.
  */
DvtAnimator._RECORD_SIZE = 5;

/**
  * @protected
  */
DvtAnimator.prototype.Init = function(context, duration, delay, easing)
{
  DvtAnimator.superclass.Init.call(this, context, context.getScheduler(), duration, delay, easing);
  
  this._context = context;
  this._props = new Array();
  this._startValues = new Array();
};

/**
  * Add a property to animate.
  * 
  * @param {string}  type  type of property
  * @param {object}  obj  object being animated
  * @param {function}  getter  getter function for property being animated
  * @param {function}  setter  setter function for property being animated
  * @param  destVal  destination value to animate to
  */
DvtAnimator.prototype.addProp = function(type, obj, getter, setter, destVal)
{
  var i = this.IndexOf(obj, getter);
  if (i > -1)
  {
    //this._props[i] = type;
    //this._props[i+1] = obj;
    //this._props[i+2] = getter;
    //this._props[i+3] = setter;
    this._props[i+4] = destVal;
  }
  else
  {
    this._props.push(type);
    this._props.push(obj);
    this._props.push(getter);
    this._props.push(setter);
    this._props.push(destVal);
  }
};

/**
  * Removes a property to animate.
  * 
  * @param {object}  obj  object being animated
  * @param {function}  getter  getter function for property being animated
  */
DvtAnimator.prototype.removeProp = function(obj, getter)
{
  var i = this.IndexOf(obj, getter);
  if (i > -1)
  {
    var destVal = this._props[i+4];
    this._props.splice(i, DvtAnimator._RECORD_SIZE);
    return destVal;
  }
  else
  {
    return null;
  }
};


/**
  * Get the destination value for a property being animated.
  * 
  * @param {object}  obj  object being animated
  * @param {function}  getter  getter function for property being animated
  */
DvtAnimator.prototype.getDestVal = function(obj, getter)
{
  var i = this.IndexOf(obj, getter);
  if (i > -1)
  {
    var destVal = this._props[i + 4];
    return destVal;
  }
  
  //if not part of the animation, return null
  return null;
};

/**
  * @protected
  * Get the index of the given property in the storage array, 
  * or -1 if the property is not found.
  * 
  * @param {object}  obj  object being animated
  * @param {function}  getter  getter function for property being animated
  */
DvtAnimator.prototype.IndexOf = function(obj, getter)
{
  for (var i = 0; i < this._props.length; i+=DvtAnimator._RECORD_SIZE)
  {
    var tmpObj = this._props[i + 1];
    var tmpGetter = this._props[i + 2];
    if (tmpObj === obj && tmpGetter === getter)
    {
      return i;
    }
  }
  return -1;
};

/**
  * @protected
  * @override
  */
DvtAnimator.prototype.Initialize = function()
{
  for (var i = 0; i < this._props.length; i+=DvtAnimator._RECORD_SIZE)
  {
    var obj = this._props[i + 1];
    var getter = this._props[i + 2];
    this._startValues.push(getter.call(obj));
  }
};

/**
  * @protected
  * @override
  */
DvtAnimator.prototype.Step = function(progress)
{
  for (var i = 0; i < this._props.length; i+=DvtAnimator._RECORD_SIZE)
  {
    var type = this._props[i];
    var obj = this._props[i + 1];
    var setter = this._props[i + 3];
    var destVal = this._props[i + 4];
    
    var startVal  = this._startValues[i / DvtAnimator._RECORD_SIZE];
    var interpVal = DvtInterpolator.interpolate(this._context, type, startVal, destVal, progress);
    setter.call(obj, interpVal);
  }
};
// Copyright (c) 2011, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/**
  * Abstract base class representing something that can be played, like an animation.
  * @extends DvtObj
  * @class DvtPlayable
  * @constructor
  * 
  * @param {DvtContext}  context  platform specific context object
  */
var DvtPlayable = function(context)
{
  this.Init(context);
};

DvtObj.createSubclass(DvtPlayable, DvtObj, "DvtPlayable");

/**
  * Append a function to the end of the given playable's current onEnd function.
  * 
  * @param {DvtPlayable}  playable  playable to append onEnd function to
  * @param {function}  onEnd  new function to append to current onEnd function
  * @param {object}  onEndObj  optional reference to object instance on which the new
  *        onEnd function is defined
  */
DvtPlayable.appendOnEnd = function(playable, onEnd, onEndObj)
{
  if (!playable || !onEnd)
  {
    return;
  }
  
  var arOnEnd = playable.getOnEnd();
  if (!arOnEnd || !arOnEnd[0])
  {
    playable.setOnEnd(onEnd, onEndObj);
  }
  else
  {
    var newOnEnd = function() 
      {
        arOnEnd[0].call(arOnEnd[1]);
        onEnd.call(onEndObj);
      };
    playable.setOnEnd(newOnEnd);
  }
};

/**
  * Prepend a function to the start of the given playable's current onEnd function.
  * 
  * @param {DvtPlayable}  playable  playable to prepend onEnd function to
  * @param {function}  onEnd  new function to prepend to current onEnd function
  * @param {object}  onEndObj  optional reference to object instance on which the new
  *        onEnd function is defined
  */
DvtPlayable.prependOnEnd = function(playable, onEnd, onEndObj)
{
  if (!playable || !onEnd)
  {
    return;
  }
  
  var arOnEnd = playable.getOnEnd();
  if (!arOnEnd || !arOnEnd[0])
  {
    playable.setOnEnd(onEnd, onEndObj);
  }
  else
  {
    var newOnEnd = function() 
      {
        onEnd.call(onEndObj);
        arOnEnd[0].call(arOnEnd[1]);
      };
    playable.setOnEnd(newOnEnd);
  }
};

/**
  * Append a function to the end of the given playable's current onStart function.
  * 
  * @param {DvtPlayable}  playable  playable to append onStart function to
  * @param {function}  onStart  new function to append to current onStart function
  * @param {object}  onStartObj  optional reference to object instance on which the new
  *        onStart function is defined
  */
DvtPlayable.appendOnStart = function(playable, onStart, onStartObj)
{
  if (!playable || !onStart || !playable.getOnStart || !playable.setOnStart)
  {
    return;
  }
  
  var arOnStart = playable.getOnStart();
  if (!arOnStart || !arOnStart[0])
  {
    playable.setOnStart(onStart, onStartObj);
  }
  else
  {
    var newOnStart = function() 
      {
        arOnStart[0].call(arOnStart[1]);
        onStart.call(onStartObj);
      };
    playable.setOnStart(newOnStart);
  }
};

/**
  * Prepend a function to the start of the given playable's current onStart function.
  * 
  * @param {DvtPlayable}  playable  playable to prepend onStart function to
  * @param {function}  onStart  new function to prepend to current onStart function
  * @param {object}  onStartObj  optional reference to object instance on which the new
  *        onStart function is defined
  */
DvtPlayable.prependOnStart = function(playable, onStart, onStartObj)
{
  if (!playable || !onStart || !playable.getOnStart || !playable.setOnStart)
  {
    return;
  }
  
  var arOnStart = playable.getOnStart();
  if (!arOnStart || !arOnStart[0])
  {
    playable.setOnStart(onStart, onStartObj);
  }
  else
  {
    var newOnStart = function() 
      {
        onStart.call(onStartObj);
        arOnStart[0].call(arOnStart[1]);
      };
    playable.setOnStart(newOnStart);
  }
};

/**
  * Append a function to the end of the given playable's current onInit function.
  * 
  * @param {DvtPlayable}  playable  playable to append onInit function to
  * @param {function}  onInit  new function to append to current onInit function
  * @param {object}  onInitObj  optional reference to object instance on which the new
  *        onInit function is defined
  */
DvtPlayable.appendOnInit = function(playable, onInit, onInitObj)
{
  if (!playable || !onInit || !playable.getOnInit || !playable.setOnInit)
  {
    return;
  }
  
  var arOnInit = playable.getOnInit();
  if (!arOnInit || !arOnInit[0])
  {
    playable.setOnInit(onInit, onInitObj);
  }
  else
  {
    var newOnInit = function() 
      {
        arOnInit[0].call(arOnInit[1]);
        onInit.call(onInitObj);
      };
    playable.setOnInit(newOnInit);
  }
};

/**
  * Prepend a function to the start of the given playable's current onInit function.
  * 
  * @param {DvtPlayable}  playable  playable to prepend onInit function to
  * @param {function}  onInit  new function to prepend to current onInit function
  * @param {object}  onInitObj  optional reference to object instance on which the new
  *        onInit function is defined
  */
DvtPlayable.prependOnInit = function(playable, onInit, onInitObj)
{
  if (!playable || !onInit || !playable.getOnInit || !playable.setOnInit)
  {
    return;
  }
  
  var arOnInit = playable.getOnInit();
  if (!arOnInit || !arOnInit[0])
  {
    playable.setOnInit(onInit, onInitObj);
  }
  else
  {
    var newOnInit = function() 
      {
        onInit.call(onInitObj);
        arOnInit[0].call(arOnInit[1]);
      };
    playable.setOnInit(newOnInit);
  }
};

/**
  * @protected
  */
DvtPlayable.prototype.Init = function(context)
{
  this.Context = context;
  this._onEnd = null;
  this._onEndObj = null;
};

/**
  * Set the function to call when this playable ends.
  * 
  * @param {function}  onEnd  function to call when this playable ends
  * @param {object}  onEndObj  optional reference to object instance on which the 
  *        onEnd function is defined
  */
DvtPlayable.prototype.setOnEnd = function(onEnd, onEndObj)
{
  this._onEnd = onEnd;
  if (onEndObj)
  {
    this._onEndObj = onEndObj;
  }
  else
  {
    this._onEndObj = null;
  }
  this.OnEndUpdated();
};

/**
  * Get the function to call when this playable ends.
  * Returns an array of two elements: 
  * [0] the function
  * [1] optional reference to object instance on which the function is defined
  * 
  * @type array
  */
DvtPlayable.prototype.getOnEnd = function()
{
  return [this._onEnd, this._onEndObj];
};

/**
  * @protected
  * Called when the onEnd funciton on this playable is set.
  */
DvtPlayable.prototype.OnEndUpdated = function()
{
  //subclasses must override
};

/**
  * Play this playable.
  */
DvtPlayable.prototype.play = function()
{
  //subclasses must override
};

/**
  * Stop this playable.
  */
DvtPlayable.prototype.stop = function()
{
  //subclasses must override
};

/**
  * Pause this playable.
  */
DvtPlayable.prototype.pause = function()
{
  //subclasses must override
};

// Copyright (c) 2011, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/**
  * Class representing a set of DvtPlayables that are played at the same time.
  * The playables should be passed into the constructor as either:
  * 1) individual arguments, for example:
  *    new DvtParallelPlayable(context, playable1, playable2, ...), or
  * 2) a single Array, for example:
  *    new DvtParallelPlayable(context, [playable1, playable2, ...]);
  * @extends DvtPlayable
  * @class DvtParallelPlayable
  * @constructor
  * 
  * @param {DvtContext}  context  platform specific context object
  */
var DvtParallelPlayable = function(context)
{
  var arPlayables;
  if (arguments && arguments.length > 1 && arguments[1] instanceof Array)
  {
    arPlayables = arguments[1];
  }
  else
  {
    arPlayables = DvtArrayUtils.argsToArray(arguments);
    //remove the context from the arPlayables array
    arPlayables.splice(0, 1);
  }
  
  this.Init(context, arPlayables);
};

DvtObj.createSubclass(DvtParallelPlayable, DvtPlayable, "DvtParallelPlayable");

/**
  * @protected
  * @override
  */
DvtParallelPlayable.prototype.Init = function(context, arPlayables)
{
  DvtParallelPlayable.superclass.Init.call(this, context);
  
  this._runningCounter = 0;
  this._arPlayables = arPlayables;
  this._bStarted = false;
};

/**
  * Get the list of playables.
  * @type Array
  */
DvtParallelPlayable.prototype.getPlayables = function()
{
  return this._arPlayables;
};

/**
  * @override
  */
DvtParallelPlayable.prototype.play = function()
{
  if (this._arPlayables && this._arPlayables.length > 0)
  {
    this._runningCounter = this._arPlayables.length;
    
    var playable;
    for (var i = 0; i < this._arPlayables.length; i++)
    {
      playable = this._arPlayables[i];
      if (playable instanceof DvtPlayable)
      {
        if (!this._bStarted)
        {
          //call internal onEnd function when each Playable ends
          DvtPlayable.appendOnEnd(playable, this.OnPlayableEnd, this);
        }
        playable.play();
      }
    }
    
    this._bStarted = true;
  }
  else {
    // The onEnd listener should still be called.
    var timer = new DvtTimer(this.Context, 0, this.DoEnd, this, 1);
    timer.start();
  }
};

/**
  * @override
  */
DvtParallelPlayable.prototype.stop = function()
{
  if (this._arPlayables)
  {
    var playable;
    for (var i = 0; i < this._arPlayables.length; i++)
    {
      playable = this._arPlayables[i];
      if (playable instanceof DvtPlayable)
      {
        playable.stop();
      }
    }
  }
};

/**
  * @override
  */
DvtParallelPlayable.prototype.pause = function()
{
  if (this._arPlayables)
  {
    var playable;
    for (var i = 0; i < this._arPlayables.length; i++)
    {
      playable = this._arPlayables[i];
      if (playable instanceof DvtPlayable)
      {
        playable.pause();
      }
    }
  }
};

/**
  * @protected
  * Called after each playable ends.
  */
DvtParallelPlayable.prototype.OnPlayableEnd = function()
{
  //decrement the count of running playables
  this._runningCounter--;
  
  //if no more running, call the onEnd function for this ParallelPlayable
  if (this._runningCounter < 1)
  {
    this.DoEnd();
  }
};

/**
  * @protected
  * Called after all the playables have finished.
  */
DvtParallelPlayable.prototype.DoEnd = function()
{
  if (this._onEnd)
  {
    this._onEnd.call(this._onEndObj);
  }
};

// Copyright (c) 2011, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/**
  * Class representing a set of DvtPlayables that are played one after another.
  * The playables should be passed into the constructor as either:
  * 1) individual arguments, for example:
  *    new DvtParallelPlayable(context, playable1, playable2, ...), or
  * 2) a single Array, for example:
  *    new DvtParallelPlayable(context, [playable1, playable2, ...]);
  * @extends DvtPlayable
  * @class DvtParallelPlayable
  * @constructor
  * 
  * @param {DvtContext}  context  platform specific context object
  */
var DvtSequentialPlayable = function(context)
{
  var arPlayables;
  if (arguments && arguments.length > 1 && arguments[1] instanceof Array)
  {
    arPlayables = arguments[1];
  }
  else
  {
    arPlayables = DvtArrayUtils.argsToArray(arguments);
    //remove the context from the arPlayables array
    arPlayables.splice(0, 1);
  }
  
  this.Init(context, arPlayables);
};

DvtObj.createSubclass(DvtSequentialPlayable, DvtPlayable, "DvtSequentialPlayable");

/**
  * @protected
  * @override
  */
DvtSequentialPlayable.prototype.Init = function(context, arPlayables)
{
  DvtSequentialPlayable.superclass.Init.call(this, context);
  
  this._arPlayables = arPlayables;
  this._currIndex = -1;
  this._bStarted = false;
};

/**
  * Get the list of playables.
  * @type Array
  */
DvtSequentialPlayable.prototype.getPlayables = function()
{
  return this._arPlayables;
};

/**
  * @override
  */
DvtSequentialPlayable.prototype.play = function()
{
  if (this._arPlayables && this._arPlayables.length > 0)
  {
    if (this._bStarted)
    {
      var currPlayable = this._arPlayables[this._currIndex];
      if (currPlayable instanceof DvtPlayable)
      {
        currPlayable.play();
      }
      return;
    }
    
    var firstPlayable;
    if (this._arPlayables[0] instanceof DvtPlayable)
      firstPlayable = this._arPlayables[0];
    var lastPlayable;
    if (this._arPlayables[this._arPlayables.length - 1] instanceof DvtPlayable)
      lastPlayable = this._arPlayables[this._arPlayables.length - 1];
    
    //var prevPlayable = firstPlayable;
    var playable;
    for (var i = 0; i < this._arPlayables.length - 1; i++)
    {
      playable = this._arPlayables[i];
      if (playable instanceof DvtPlayable)
      {
        //at the end of each playable, play the next one
        //DvtPlayable.appendOnEnd(prevPlayable, playable.play, playable);
        //prevPlayable = playable;
        
        DvtPlayable.appendOnEnd(playable, this.DoSequenceStep, this);
      }
    }
    
    //call the onEnd function for this DvtSequentialPlayable at the very
    //end of the sequence
    //if (playable)
    //  DvtPlayable.appendOnEnd(playable, this.DoEnd, this);
    if (lastPlayable)
      DvtPlayable.appendOnEnd(lastPlayable, this.DoEnd, this);
    
    this._bStarted = true;
    this._currIndex = 0;
    
    if (firstPlayable)
      firstPlayable.play();
  }
  else {
    // The onEnd listener should still be called.
    var timer = new DvtTimer(this.Context, 0, this.DoEnd, this, 1);
    timer.start();
  }
};

/**
  * @protected
  * Called after each playable, except the last one, ends.
  */
DvtSequentialPlayable.prototype.DoSequenceStep = function()
{
  var playable = this._arPlayables[++this._currIndex];
  if (playable instanceof DvtPlayable)
  {
    playable.play();
  }
  else
  {
    this.DoSequenceStep();
  }
};

/**
  * @override
  */
DvtSequentialPlayable.prototype.stop = function()
{
  if (this._arPlayables)
  {
    var playable;
    for (var i = this._currIndex; i < this._arPlayables.length; i++)
    {
      playable = this._arPlayables[i];
      if (playable && playable instanceof DvtPlayable)
      {
        playable.stop();
      }
    }
  }
};

/**
  * @override
  */
DvtSequentialPlayable.prototype.pause = function()
{
  if (this._arPlayables)
  {
    var playable = this._arPlayables[this._currIndex];
    if (playable instanceof DvtPlayable)
    {
      playable.pause();
    }
  }
};

/**
  * @protected
  * Called after the last playable has finished.
  */
DvtSequentialPlayable.prototype.DoEnd = function()
{
  if (this._onEnd)
  {
    this._onEnd.call(this._onEndObj);
  }
};

// Copyright (c) 2011, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/**
  * Class defining easing functions for animations.
  * @extends DvtObj
  * @class DvtEasing
  * @constructor
  */
var DvtEasing = function()
{
  this.Init();
};

DvtObj.createSubclass(DvtEasing, DvtObj, "DvtEasing");

/**
  * Linear easing function.
  * Returns the percent progress of the animation after applying the easing function.
  * @param {number}  progress  percent progress of the animation
  * @type number
  */
DvtEasing.linear = function(progress)
{
  return progress;
};

/**
  * Quadratic easing function that starts slow and speeds up at the beginning.
  * Returns the percent progress of the animation after applying the easing function.
  * @param {number}  progress  percent progress of the animation
  * @type number
  */
DvtEasing.quadraticIn = function(progress)
{
  return DvtEasing.PolyIn(progress, 2);
};

/**
  * Quadratic easing function that starts fast and slows down at the end.
  * Returns the percent progress of the animation after applying the easing function.
  * @param {number}  progress  percent progress of the animation
  * @type number
  */
DvtEasing.quadraticOut = function(progress)
{
  return DvtEasing.PolyOut(progress, 2);
};

/**
  * Quadratic easing function that starts slow, speeds up, and then slows down at the end.
  * Returns the percent progress of the animation after applying the easing function.
  * @param {number}  progress  percent progress of the animation
  * @type number
  */
DvtEasing.quadraticInOut = function(progress)
{
  return DvtEasing.PolyInOut(progress, 2);
};

/**
  * Cubic easing function that starts slow and speeds up at the beginning.
  * Returns the percent progress of the animation after applying the easing function.
  * @param {number}  progress  percent progress of the animation
  * @type number
  */
DvtEasing.cubicIn = function(progress)
{
  return DvtEasing.PolyIn(progress, 3);
};

/**
  * Cubic easing function that starts fast and slows down at the end.
  * Returns the percent progress of the animation after applying the easing function.
  * @param {number}  progress  percent progress of the animation
  * @type number
  */
DvtEasing.cubicOut = function(progress)
{
  return DvtEasing.PolyOut(progress, 3);
};

/**
  * Cubic easing function that starts slow, speeds up, and then slows down at the end.
  * Returns the percent progress of the animation after applying the easing function.
  * @param {number}  progress  percent progress of the animation
  * @type number
  */
DvtEasing.cubicInOut = function(progress)
{
  return DvtEasing.PolyInOut(progress, 3);
};

/**
  * Cubic easing function that starts fast and slows down at the end, 
  * overshooting the target and then coming back.
  * Returns the percent progress of the animation after applying the easing function.
  * @param {number}  progress  percent progress of the animation
  * @param {number}  overshoot  value to overshoot, with higher values 
  *        overshooting more (value of 0 means no overshoot, 
  *        default value of 1.7 overshoots by about 10%)
  * @type number
  */
DvtEasing.backOut = function(progress, overshoot)
{
  //t = progress, s = overshoot
  //(s+1)*t^3 - s*t^2
  if (!overshoot)
  {
    overshoot = 1.70158;
  }
  progress = 1 - progress;
  return 1 - progress*progress*((overshoot+1)*progress - overshoot);
};

/**
  * Cubic easing function that starts slow and speeds up at the beginning, 
  * overshooting the starting value in the opposite direction and then 
  * proceeding forward.
  * Returns the percent progress of the animation after applying the easing function.
  * @param {number}  progress  percent progress of the animation
  * @param {number}  overshoot  value to overshoot, with higher values 
  *        overshooting more (value of 0 means no overshoot, 
  *        default value of 1.7 overshoots by about 10%)
  * @type number
  */
DvtEasing.backIn = function(progress, overshoot)
{
  //t = progress, s = overshoot
  //(s+1)*t^3 - s*t^2
  if (!overshoot)
  {
    overshoot = 1.70158;
  }
  return progress*progress*((overshoot+1)*progress - overshoot);
};
	
/**
  * Easing function that oscillates at the start with an exponentially 
  * decaying sine wave.
  *
  * @param {number}  progress  percent progress of the animation
  * @param {number}  amplitude  amplitude of the sine wave
  * @param {number}  period  period of the sine wave
  * @type number
  */
DvtEasing.elasticIn = function(progress, amplitude, period)
{
  if (progress <= 0 || progress >= 1)
  {
    return progress;
  }
  if (!period)
  {
    period = 0.45;
  }
  var s;
  if (!amplitude || amplitude < 1)
  {
    amplitude = 1; 
    s = period / 4;
  }
  else
  {
    s = period / (2 * Math.PI) * Math.asin(1 / amplitude);
  }
  return -(amplitude*Math.pow(2,10*(progress-=1)) * Math.sin( (progress-s)*(2*Math.PI)/period ));
};
		
/**
  * Easing function that oscillates at the end with an exponentially 
  * decaying sine wave.
  *
  * @param {number}  progress  percent progress of the animation
  * @param {number}  amplitude  amplitude of the sine wave
  * @param {number}  period  period of the sine wave
  * @type number
  */
DvtEasing.elasticOut = function(progress, amplitude, period) {
  return 1 - DvtEasing.elasticIn(1-progress, amplitude, period);
};

/**
  * @protected
  * Polynomial easing function that starts slow and speeds up at the beginning.
  * Returns the percent progress of the animation after applying the easing function.
  * @param {number}  progress  percent progress of the animation
  * @param {number}  exp  exponent of the polynomial
  * @type number
  */
DvtEasing.PolyIn = function(progress, exp)
{
  if (progress < 0)
  {
    return 0;
  }
  if (progress > 1)
  {
    return 1;
  }
  else
  {
    return Math.pow(progress, exp);
  }
};

/**
  * @protected
  * Polynomial easing function that starts fast and slows down at the end.
  * Returns the percent progress of the animation after applying the easing function.
  * @param {number}  progress  percent progress of the animation
  * @param {number}  exp  exponent of the polynomial
  * @type number
  */
DvtEasing.PolyOut = function(progress, exp)
{
  if (progress < 0)
  {
    return 0;
  }
  if (progress > 1)
  {
    return 1;
  }
  else
 {
    return 1 - Math.pow(1 - progress, exp);
  }
};

/**
  * @protected
  * Polynomial easing function that starts slow, speeds up, and then slows down at the end.
  * Returns the percent progress of the animation after applying the easing function.
  * @param {number}  progress  percent progress of the animation
  * @param {number}  exp  exponent of the polynomial
  * @type number
  */
DvtEasing.PolyInOut = function(progress, exp)
{
  if (progress < 0)
  {
    return 0;
  }
  if (progress > 1)
  {
    return 1;
  }
  if (progress < .5)
  {
    return .5 * Math.pow(2 * progress, exp);
  }
  else
  {
    return .5 * (2 - Math.pow(2 * (1 - progress), exp));
  }
};

/**
  * @protected
  */
DvtEasing.prototype.Init = function()
{
};
// Copyright (c) 2011, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/**
  * Class defining interpolation functions for animations.
  * @extends DvtObj
  * @class DvtInterpolator
  * @constructor
  */
var DvtInterpolator = function()
{
  this.Init();
};

DvtObj.createSubclass(DvtInterpolator, DvtObj, "DvtInterpolator");

/**
  * Add an interpolator function to use for a given type of value.
  * @param {string}  type  type of value to use interpolator for
  * @param {function}  func  interpolator function
  */
DvtInterpolator.addInterpolator = function(type, func)
{
  var index = DvtArrayUtils.getIndex(DvtInterpolator._map, type);
  if (index > -1)
  {
    DvtInterpolator._map[index + 1] = func;
  }
  else
  {
    DvtInterpolator._map.push(type, func);
  }
};

/**
  * Remove an interpolator function.
  * @param {string}  type  type of value to remove interpolator for
  */
DvtInterpolator.removeInterpolator = function(type)
{
  var index = DvtArrayUtils.getIndex(DvtInterpolator._map, type);
  if (index > -1)
  {
    DvtInterpolator._map.splice(index, 2);
  }
};

/**
  * Interpolate a value between the original and destination values for the 
  * given percent progress.
  * @param {DvtContext}  context  platform specific context object
  * @param {string}  type  type of value being interpolated
  * @param  origVal  original property value
  * @param  destVal  destination property value
  * @param {number}  progress  percent progress to interpolate
  */
DvtInterpolator.interpolate = function(context, type, origVal, destVal, progress)
{
  //don't pin progress, so that we can do elastic type easing functions,
  //like backIn and backOut for popIn and popOut anims
  /*if (progress <= 0)
  {
    return origVal;
  }
  
  if (progress >= 1)
  {
    return destVal;
  }*/
  
  var interpolatorFunc = DvtInterpolator._getInterpolator(type);
  if (interpolatorFunc != null)
  {
    return interpolatorFunc(context, origVal, destVal, progress);
  }
  
  return destVal;
};

/**
  * @private
  * Get the interpolator to use for the given type of value.
  * @param {string}  type  type of value to interpolate
  * @type function
  */
DvtInterpolator._getInterpolator = function(type)
{
  var index = DvtArrayUtils.getIndex(DvtInterpolator._map, type);
  if (index > -1)
  {
    return DvtInterpolator._map[index + 1];
  }
  
  return null;
};

/**
  * Interpolate a number between the original and destination values for the 
  * given percent progress.
  * @param {DvtContext}  context  platform specific context object
  * @param {number}  origVal  original property value
  * @param {number}  destVal  destination property value
  * @param {number}  progress  percent progress to interpolate
  * @type number
  * @protected
  */
DvtInterpolator.InterpolateNumber = function(context, origVal, destVal, progress)
{
  //return (origVal + progress * (destVal - origVal));
  return DvtMath.interpolateNumber(origVal, destVal, progress);
};

/**
  * Interpolate an array of numbers between the original and destination 
  * values for the given percent progress.
  * @param {DvtContext}  context  platform specific context object
  * @param {number}  origVal  original property value
  * @param {number}  destVal  destination property value
  * @param {number}  progress  percent progress to interpolate
  * @type array
  * @protected
  */
DvtInterpolator.InterpolateNumberArray = function(context, origVal, destVal, progress)
{
  var origLength = origVal.length;
  var destLength = destVal.length;
  var array = [];
  for (var i = 0; i < Math.max(origLength, destLength); i++)
  {
    //if one array is shorter than the other, use the last actual value
    //from the shorter array to interpolate with all the extra elements
    //in the longer array
    var n1;
    var n2;
    if (i < origLength)
    {
      n1 = origVal[i];
    }
    else
    {
      n1 = origVal[origLength - 1];
    }
    if (i < destLength)
    {
      n2 = destVal[i];
    }
    else
    {
      n2 = destVal[destLength - 1];
    }
    array.push(DvtInterpolator.InterpolateNumber(context, n1, n2, progress));
  }
  return array;
};

/**
  * Interpolate a matrix between the original and destination values for the 
  * given percent progress.
  * @param {DvtContext}  context  platform specific context object
  * @param {DvtMatrix}  origVal  original property value
  * @param {DvtMatrix}  destVal  destination property value
  * @param {number}  progress  percent progress to interpolate
  * @type DvtMatrix
  * @protected
  */
DvtInterpolator.InterpolateMatrix = function(context, origVal, destVal, progress)
{
  var newA = DvtInterpolator.InterpolateNumber(context, origVal.getA(), destVal.getA(), progress);
  var newB = DvtInterpolator.InterpolateNumber(context, origVal.getB(), destVal.getB(), progress);
  var newC = DvtInterpolator.InterpolateNumber(context, origVal.getC(), destVal.getC(), progress);
  var newD = DvtInterpolator.InterpolateNumber(context, origVal.getD(), destVal.getD(), progress);
  var newTx = DvtInterpolator.InterpolateNumber(context, origVal.getTx(), destVal.getTx(), progress);
  var newTy = DvtInterpolator.InterpolateNumber(context, origVal.getTy(), destVal.getTy(), progress);
  
  var mat = new DvtMatrix(context);
  mat._a = newA;
  mat._b = newB;
  mat._c = newC;
  mat._d = newD;
  mat._tx = newTx;
  mat._ty = newTy;
  
  return mat;
};

/**
  * Interpolate a color between the original and destination values for the 
  * given percent progress.
  * @param {DvtContext}  context  platform specific context object
  * @param {number}  origVal  original property value
  * @param {number}  destVal  destination property value
  * @param {number}  progress  percent progress to interpolate
  * @protected
  */
DvtInterpolator.InterpolateColor = function(context, origVal, destVal, progress)
{
  return DvtColorUtils.interpolateColor(origVal, destVal, progress);
};

/**
  * Interpolate an array of colors between the original and destination 
  * values for the given percent progress.
  * @param {DvtContext}  context  platform specific context object
  * @param {number}  origVal  original property value
  * @param {number}  destVal  destination property value
  * @param {number}  progress  percent progress to interpolate
  * @type array
  * @protected
  */
DvtInterpolator.InterpolateColorArray = function(context, origVal, destVal, progress)
{
  var origLength = origVal.length;
  var destLength = destVal.length;
  var array = [];
  for (var i = 0; i < Math.max(origLength, destLength); i++)
  {
    //if one array is shorter than the other, use the last actual value
    //from the shorter array to interpolate with all the extra elements
    //in the longer array
    var n1;
    var n2;
    if (i < origLength)
    {
      n1 = origVal[i];
    }
    else
    {
      n1 = origVal[origLength - 1];
    }
    if (i < destLength)
    {
      n2 = destVal[i];
    }
    else
    {
      n2 = destVal[destLength - 1];
    }
    array.push(DvtInterpolator.InterpolateColor(context, n1, n2, progress));
  }
  return array;
};

/**
  * Interpolate an array of polyline points between the original and 
  * destination values for the given percent progress.
  * @param {DvtContext}  context  platform specific context object
  * @param {number}  origVal  original property value
  * @param {number}  destVal  destination property value
  * @param {number}  progress  percent progress to interpolate
  * @type array
  * @protected
  */
DvtInterpolator.InterpolateGrowPolyline = function(context, origVal, destVal, progress)
{
  if (progress === 0)
  {
    return [destVal[0], destVal[1]];
  }
  else if (progress === 1)
  {
    return destVal;
  }
  
  var destLength = destVal.length;
  var array = [destVal[0], destVal[1]];
  var totalLength = DvtInterpolator.CalcPolylineLength(destVal);
  var partialLength = progress * totalLength;
  var accumLength = 0;
  var currSegLength;
  for (var i = 2; i < destLength - 1; i+=2)
  {
    var x1 = destVal[i-2];
    var y1 = destVal[i-1];
    var x2 = destVal[i];
    var y2 = destVal[i+1];
    
    currSegLength = DvtInterpolator.CalcPolylineLength([x1, y1, x2, y2]);
    
    if (accumLength + currSegLength > partialLength)
    {
      var ratio = (partialLength - accumLength) / currSegLength;
      var diffX = x2 - x1;
      var diffY = y2 - y1;
      array.push(x1 + ratio * diffX);
      array.push(y1 + ratio * diffY);
      break;
    }
    else
    {
      accumLength += currSegLength;
      
      array.push(x2);
      array.push(y2);
    }
  }
  return array;
};

/**
  * Interpolate an array of path commands between the original and 
  * destination values for the given percent progress.
  * @param {DvtContext}  context  platform specific context object
  * @param {number}  origVal  original property value
  * @param {number}  destVal  destination property value
  * @param {number}  progress  percent progress to interpolate
  * @type array
  * @protected
  */
DvtInterpolator.InterpolateGrowPath = function(context, origVal, destVal, progress)
{
  if (progress === 0)
  {
    return [destVal[0], destVal[1]];
  }
  else if (progress === 1)
  {
    return destVal;
  }
  
  var destLength = destVal.length;
  var array = [];
  var totalLength = DvtInterpolator.CalcPathLength(destVal);
  var partialLength = progress * totalLength;
  var accumLength = 0;
  var currSegLength;
  var x1;
  var y1;
  var cpx1;
  var cpy1;
  var cpx2;
  var cpy2;
  var prevX;
  var prevY;
  for (var i = 0; i < destLength; i++)
  {
    var cmd = destVal[i];
    var segArray;
    switch (cmd)
    {
      case "M":
        x1 = destVal[++i];
        y1 = destVal[++i];
        prevX = x1;
        prevY = y1;
        segArray = [prevX, prevY, prevX, prevY];
        break;
      case "L":
        x1 = destVal[++i];
        y1 = destVal[++i];
        segArray = [prevX, prevY, x1, y1];
        break;
      case "Q":
        cpx1 = destVal[++i];
        cpy1 = destVal[++i];
        x1 = destVal[++i];
        y1 = destVal[++i];
        segArray = [prevX, prevY, x1, y1];
        break;
      case "C":
        cpx1 = destVal[++i];
        cpy1 = destVal[++i];
        cpx2 = destVal[++i];
        cpy2 = destVal[++i];
        x1 = destVal[++i];
        y1 = destVal[++i];
        segArray = [prevX, prevY, x1, y1];
        break;
    }
    
    currSegLength = DvtInterpolator.CalcPolylineLength(segArray);
    
    if (accumLength + currSegLength > partialLength)
    {
      var ratio = (partialLength - accumLength) / currSegLength;
      
      array.push(cmd);
      switch (cmd)
      {
        case "Q":
          array.push(prevX + ratio * (cpx1 - prevX), 
                     prevY + ratio * (cpy1 - prevY));
          break;
        case "C":
          array.push(prevX + ratio * (cpx1 - prevX), 
                     prevY + ratio * (cpy1 - prevY), 
                     prevX + ratio * (cpx2 - prevX), 
                     prevY + ratio * (cpy2 - prevY));
          break;
      }
      array.push(prevX + ratio * (x1 - prevX), 
                 prevY + ratio * (y1 - prevY));
      break;
    }
    else
    {
      accumLength += currSegLength;
      
      array.push(cmd);
      switch (cmd)
      {
        case "Q":
          array.push(cpx1, cpy1);
          break;
        case "C":
          array.push(cpx1, cpy1, cpx2, cpy2);
          break;
      }
      array.push(x1);
      array.push(y1);
    }
    prevX = x1;
    prevY = y1;
  }
  return array;
};

DvtInterpolator.CalcPolylineLength = function(arPoints)
{
  var length = 0;
  var oldX;
  var oldY;
  var xx;
  var yy;
  for (var i = 0; i < arPoints.length; i+=2)
  {
    xx = arPoints[i];
    yy = arPoints[i+1];
    
    if (i > 0)
    {
      if (xx === oldX)
      {
        length += (Math.abs(yy - oldY));
      }
      else if (yy === oldY)
      {
        length += (Math.abs(xx - oldX));
      }
      else
      {
        var diffX = Math.abs(xx - oldX);
        var diffY = Math.abs(yy - oldY);
        length += Math.sqrt((diffX * diffX) + (diffY * diffY));
      }
    }
    
    oldX = xx;
    oldY = yy;
  }
  return length;
};

DvtInterpolator.CalcPathLength = function(arPoints)
{
  var length = 0;
  var oldX;
  var oldY;
  var xx;
  var yy;
  var cmd;
  for (var i = 0; i < arPoints.length; )
  {
    cmd = arPoints[i];
    switch (cmd)
    {
      case "M":
        xx = arPoints[i+1];
        yy = arPoints[i+2];
        oldX = xx;
        oldY = yy;
        i += 3;
        continue;
        break;
      case "L":
        xx = arPoints[i+1];
        yy = arPoints[i+2];
        i += 3;
        break;
      case "Q":
        xx = arPoints[i+3];
        yy = arPoints[i+4];
        i += 5;
        break;
      case "Q":
        xx = arPoints[i+5];
        yy = arPoints[i+6];
        i += 7;
        break;
    }
    
    if (i > 0)
    {
      if (xx === oldX)
      {
        length += (Math.abs(yy - oldY));
      }
      else if (yy === oldY)
      {
        length += (Math.abs(xx - oldX));
      }
      else
      {
        var diffX = Math.abs(xx - oldX);
        var diffY = Math.abs(yy - oldY);
        length += Math.sqrt((diffX * diffX) + (diffY * diffY));
      }
    }
    
    oldX = xx;
    oldY = yy;
  }
  return length;
};

/**
  * Interpolate a rectangle between the original and destination values for
  * the given percent progress.
  * @param {DvtContext}  context  platform specific context object
  * @param {DvtRectangle}  origVal  original property value
  * @param {DvtRectangle}  destVal  destination property value
  * @param {number}  progress  percent progress to interpolate
  * @type DvtRectangle
  * @protected
  */
DvtInterpolator.InterpolateRectangle = function(context, origVal, destVal, progress)
{
  var newX = DvtInterpolator.InterpolateNumber(context, origVal.x, destVal.x, progress);
  var newY = DvtInterpolator.InterpolateNumber(context, origVal.y, destVal.y, progress);
  var newW = DvtInterpolator.InterpolateNumber(context, origVal.w, destVal.w, progress);
  var newH = DvtInterpolator.InterpolateNumber(context, origVal.h, destVal.h, progress);
  
  return new DvtRectangle(newX, newY, newW, newH);
};

/**
  * Interpolate a point between the original and destination values for
  * the given percent progress.
  * @param {DvtContext}  context  platform specific context object
  * @param {DvtPoint}  origVal  original property value
  * @param {DvtPoint}  destVal  destination property value
  * @param {number}  progress  percent progress to interpolate
  * @type DvtPoint
  * @protected
  */
DvtInterpolator.InterpolatePoint = function(context, origVal, destVal, progress)
{
  var newX = DvtInterpolator.InterpolateNumber(context, origVal.x, destVal.x, progress);
  var newY = DvtInterpolator.InterpolateNumber(context, origVal.y, destVal.y, progress);
  
  return new DvtPoint(newX, newY);
};

/**
  * Interpolate a path between the original and destination 
  * values for the given percent progress.
  * @param {DvtContext}  context  platform specific context object
  * @param {number}  origVal  original property value
  * @param {number}  destVal  destination property value
  * @param {number}  progress  percent progress to interpolate
  * @type array
  * @protected
  */
DvtInterpolator.InterpolatePath = function(context, origVal, destVal, progress)
{
  var origLength = origVal.length;
  var destLength = destVal.length;
  //TO DO:
  //for now, if the paths are not of equal length, just return the dest val
  if (origLength != destLength)
  {
    return destVal;
  }
  
  var array = [];
  var i = 0;
  var j = 0;
  for (; i < origLength && j < destLength; )
  {
    var n1 = origVal[i];
    var n2 = destVal[j];
    var bNumberN1 = !isNaN(n1);
    var bNumberN2 = !isNaN(n2);
    if (!bNumberN1 && !bNumberN2)
    {
      if (n1 === n2)
      {
        array.push(n1);
      }
      //TO DO: handle case where commands are different
    }
    else if (bNumberN1 && bNumberN2)
    {
      array.push(DvtInterpolator.InterpolateNumber(context, n1, n2, progress));
    }
    i++;
    j++;
  }
  return array;
};

/**
  * Interpolate a fill between the original and destination values for the 
  * given percent progress.
  * @param {DvtContext}  context  platform specific context object
  * @param {number}  origVal  original property value
  * @param {number}  destVal  destination property value
  * @param {number}  progress  percent progress to interpolate
  * @protected
  */
DvtInterpolator.InterpolateFill = function(context, origVal, destVal, progress)
{
  if (origVal instanceof DvtSolidFill && destVal instanceof DvtSolidFill) {
    var color = DvtInterpolator.InterpolateColor(context, origVal.getColor(), destVal.getColor(), progress);
    var alpha = DvtInterpolator.InterpolateNumber(context, origVal.getAlpha(), destVal.getAlpha(), progress);
    var rgb = DvtColorUtils.makeRGB(DvtColorUtils.getRed(color),
                                    DvtColorUtils.getGreen(color),
                                    DvtColorUtils.getBlue(color));
    return new DvtSolidFill(rgb, alpha);
  }
  
  return destVal;
};

/**
  * Interpolate an array of polyline coordinates between the original and 
  * destination values for the given percent progress.
  * @param {DvtContext}  context  platform specific context object
  * @param {number}  origVal  original property value
  * @param {number}  destVal  destination property value
  * @param {number}  progress  percent progress to interpolate
  * @type array
  * @protected
  */
DvtInterpolator.InterpolatePolyline = function(context, origVal, destVal, progress)
{
  var origLength = origVal.length;
  var destLength = destVal.length;
  var array = [];
  for (var i = 0; i < Math.max(origLength, destLength); i++)
  {
    //if one array is shorter than the other, use the last actual coords
    //from the shorter array to interpolate with all the extra coords
    //in the longer array
    //BUG FIX #13376738: use the last coordinate pair, not just the last 
    //element in the array
    var endOffset = 2;
    if (i % 2 == 1) {
      endOffset = 1;
    }
    var n1;
    var n2;
    if (i < origLength)
    {
      n1 = origVal[i];
    }
    else
    {
      n1 = origVal[origLength - endOffset];
    }
    if (i < destLength)
    {
      n2 = destVal[i];
    }
    else
    {
      n2 = destVal[destLength - endOffset];
    }
    array.push(DvtInterpolator.InterpolateNumber(context, n1, n2, progress));
  }
  
  //trim the array to remove redundant coords at the end
  if (destLength < origLength) {
    var arLength = array.length;
    var lastX = array[arLength - 2];
    var lastY = array[arLength - 1];
    for (var i = arLength - 4; i >= 0; i-=2) {
      var currX = array[i];
      var currY = array[i+1];
      if (currX == lastX && currY == lastY) {
        array.splice(i, 2);
      }
      else {
        break;
      }
    }
  }
  
  return array;
};

/**
  * @protected
  */
DvtInterpolator.prototype.Init = function()
{
};

//need to define the map after the functions are defined above
/**
  * @private
  */
DvtInterpolator._map = 
  [
    DvtAnimator.TYPE_NUMBER, DvtInterpolator.InterpolateNumber,
    DvtAnimator.TYPE_MATRIX, DvtInterpolator.InterpolateMatrix,
    DvtAnimator.TYPE_NUMBER_ARRAY, DvtInterpolator.InterpolateNumberArray,
    DvtAnimator.TYPE_COLOR, DvtInterpolator.InterpolateColor,
    DvtAnimator.TYPE_COLOR_ARRAY, DvtInterpolator.InterpolateColorArray,
    DvtAnimator.TYPE_GROW_POLYLINE, DvtInterpolator.InterpolateGrowPolyline,
    DvtAnimator.TYPE_RECTANGLE, DvtInterpolator.InterpolateRectangle,
    DvtAnimator.TYPE_POINT, DvtInterpolator.InterpolatePoint,
    DvtAnimator.TYPE_PATH, DvtInterpolator.InterpolatePath,
    DvtAnimator.TYPE_GROW_PATH, DvtInterpolator.InterpolateGrowPath,
    DvtAnimator.TYPE_FILL, DvtInterpolator.InterpolateFill,
    DvtAnimator.TYPE_POLYLINE, DvtInterpolator.InterpolatePolyline
  ];
// Copyright (c) 2011, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/**
  * Abstract class representing a timer.
  * @extends DvtObj
  * @class DvtTimer
  * @constructor
  * 
  * @param {DvtContext}  context  platform specific context object
  * @param {number}  interval  interval between timer ticks, in milliseconds
  * @param {function}  callback  function to call for each timer tick
  * @param {object}  callbackObj  optional object instance that callback function is defined on
  * @param {number}  repeatCount  optional number of times for timer to repeat;
  *        timer repeats indefinitely if 0 or undefined
  */
var DvtTimer = function(context, interval, callback, callbackObj, repeatCount)
{
  this.Init(context, interval, callback, callbackObj, repeatCount);
};

DvtObj.createSubclass(DvtTimer, DvtObj, "DvtTimer");

/**
  * @protected
  */
DvtTimer.prototype.Init = function(context, interval, callback, callbackObj, repeatCount)
{
  if (!this._impl)
  {
    this._impl = context.getImplFactory().newTimer();
  }
  
  this._interval = interval; //in ms
  this._callback = callback;
  if (callbackObj)
  {
    this._callbackObj = callbackObj;
  }
  this._repeatCount = repeatCount;
  this._bRunning = false;
  this._numIterations = 0;
};

/**
  * Start this timer.
  */
DvtTimer.prototype.start = function()
{
  if (!this._bRunning)
  {
    this._bRunning = true;
    this.StartTimer();
  }
};

/**
  * Stop this timer.
  */
DvtTimer.prototype.stop = function()
{
  if (this._bRunning)
  {
    this._bRunning = false;
    this.StopTimer();
  }
};

/**
 * Reset this timer.
 */
DvtTimer.prototype.reset = function()
{
  if (this._bRunning) {
    this.stop();
  }
  
  this._numIterations = 0;
}

/**
  * Determine if this timer is running.
  * @type boolean
  */
DvtTimer.prototype.isRunning = function()
{
  return this._bRunning;
};

/**
  * @protected
  * Handle a timer tick.
  */
DvtTimer.prototype.HandleTimer = function()
{
  if (this._callback)
  {
    this._callback.call(this._callbackObj);
    
    if (this._repeatCount)
    {
      this._numIterations++;
      if (this._numIterations >= this._repeatCount)
      {
        this.stop();
      }
    }
  }
};

/**
  * Set the interval between timer ticks, in milliseconds.
  * @param {number}  interval  interval between timer ticks, in milliseconds
  */
DvtTimer.prototype.setInterval = function(interval)
{
  var i = interval;
  if (i < 0)
  {
    i = 0;
  }
  var oldBRunning = this._bRunning;
  if (oldBRunning)
  {
    this.stop();
  }
  this._interval = i;
  if (oldBRunning)
  {
    this.start();
  }
};

/**
  * Get the interval between timer ticks.
  * @type number
  */
DvtTimer.prototype.getInterval = function()
{
  return this._interval;
};

/**
  * @protected
  * Start the internal timer implementation.  
  * Called when the timer is stopped.
  */
DvtTimer.prototype.StartTimer = function()
{
  if (this._impl && this._impl.startTimer)
  {
    this._impl.startTimer(this.getInterval(), this.HandleTimer, this);
  }
};

/**
  * @protected
  * Stop the internal timer implementation.  
  * Called when the timer is started.
  */
DvtTimer.prototype.StopTimer = function()
{
  if (this._impl && this._impl.stopTimer)
  {
    this._impl.stopTimer();
  }
};
// Copyright (c) 2011, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/**
  * Abstract base class representing an animation.
  * @extends DvtPlayable
  * @class DvtBaseAnimation
  * @constructor
  * 
  * @param {DvtContext}  context  platform specific context object
  * @param objs  a single DvtContainer or Array of DvtContainers to animate
  * @param {number}  duration  length of animation, in seconds
  * @param {number}  delay  time to delay start of animation, in seconds
  */
var DvtBaseAnimation = function(context, objs, duration, delay)
{
  this.Init(context, objs, duration, delay);
};

DvtObj.createSubclass(DvtBaseAnimation, DvtPlayable, "DvtBaseAnimation");

/**
  * Easing: linear.
  */
DvtBaseAnimation.EASING_LINEAR = 1;
/**
  * Easing: cubic in and out.
  */
DvtBaseAnimation.EASING_CUBIC_IN_OUT = 2;
/**
  * Easing: cubic in.
  */
DvtBaseAnimation.EASING_CUBIC_IN = 3;
/**
  * Easing: cubic out.
  */
DvtBaseAnimation.EASING_CUBIC_OUT = 4;
/**
  * Easing: quadratic in and out.
  */
DvtBaseAnimation.EASING_QUADRATIC_IN_OUT = 5;
/**
  * Easing: quadratic in.
  */
DvtBaseAnimation.EASING_QUADRATIC_IN = 6;
/**
  * Easing: quadratic out.
  */
DvtBaseAnimation.EASING_QUADRATIC_OUT = 7;
/**
  * Easing: bounce in.
  */
DvtBaseAnimation.EASING_BOUNCE_IN = 8;
/**
  * Easing: bounce out.
  */
DvtBaseAnimation.EASING_BOUNCE_OUT = 9;
/**
  * Easing: elastic in.
  */
DvtBaseAnimation.EASING_ELASTIC_IN = 10;
/**
  * Easing: elastic out.
  */
DvtBaseAnimation.EASING_ELASTIC_OUT = 11;

/**
  * Direction: center.
  */
DvtBaseAnimation.DIR_C = 1;
/**
  * Direction: north.
  */
DvtBaseAnimation.DIR_N = 2;
/**
  * Direction: northeast.
  */
DvtBaseAnimation.DIR_NE = 3;
/**
  * Direction: east.
  */
DvtBaseAnimation.DIR_E = 4;
/**
  * Direction: southeast.
  */
DvtBaseAnimation.DIR_SE = 5;
/**
  * Direction: south.
  */
DvtBaseAnimation.DIR_S = 6;
/**
  * Direction: southwest.
  */
DvtBaseAnimation.DIR_SW = 7;
/**
  * Direction: west.
  */
DvtBaseAnimation.DIR_W = 8;
/**
  * Direction: northwest.
  */
DvtBaseAnimation.DIR_NW = 9;

//axis constants
/**
 * Axis: x-axis
 */
DvtBaseAnimation.AXIS_X = 1;
/**
 * Axis: y-axis
 */
DvtBaseAnimation.AXIS_Y = 2;

//rotation directions
/**
 * Rotation direction: clockwise
 */
DvtBaseAnimation.ROT_DIR_CLOCKWISE = 1;
/**
 * Rotation direction: counter-clockwise
 */
DvtBaseAnimation.ROT_DIR_COUNTERCLOCKWISE = 2;

/**
  * @protected
  * Get the easing function corresponding to the given constant.
  * @param easing  constant representing the easing function
  * @type function
  */
DvtBaseAnimation.GetEasingFunction = function(easing)
{
  switch (easing)
  {
    case DvtBaseAnimation.EASING_LINEAR:
      return DvtEasing.linear;
    case DvtBaseAnimation.EASING_CUBIC_IN:
      return DvtEasing.cubicIn;
    case DvtBaseAnimation.EASING_CUBIC_OUT:
      return DvtEasing.cubicOut;
    case DvtBaseAnimation.EASING_QUADRATIC_IN_OUT:
      return DvtEasing.quadraticInOut;
    case DvtBaseAnimation.EASING_QUADRATIC_IN:
      return DvtEasing.quadraticIn;
    case DvtBaseAnimation.EASING_QUADRATIC_OUT:
      return DvtEasing.quadraticOut;
    case DvtBaseAnimation.EASING_BOUNCE_IN:
      return DvtEasing.bounceIn;
    case DvtBaseAnimation.EASING_BOUNCE_OUT:
      return DvtEasing.bounceOut;
    case DvtBaseAnimation.EASING_ELASTIC_IN:
      return DvtEasing.elasticIn;
    case DvtBaseAnimation.EASING_ELASTIC_OUT:
      return DvtEasing.elasticOut;
    case DvtBaseAnimation.EASING_CUBIC_IN_OUT:
    default:
      return DvtEasing.cubicInOut;
  }
};

/**
  * @protected
  * Get the point corresponding to the given compass direction
  * on the given bounding box.
  * @param {DvtRectangle}  boundsRect  bounding box
  * @param direction  constant representing the compass direction
  * @type DvtPoint
  */
DvtBaseAnimation.GetCompassPoint = function(boundsRect, direction)
{
  switch (direction)
  {
    case DvtBaseAnimation.DIR_N:
      return new DvtPoint(boundsRect.x + 0.5 * boundsRect.w, boundsRect.y);
    case DvtBaseAnimation.DIR_NE:
      return new DvtPoint(boundsRect.x + boundsRect.w,      boundsRect.y);
    case DvtBaseAnimation.DIR_E:
      return new DvtPoint(boundsRect.x + boundsRect.w,      boundsRect.y + 0.5 * boundsRect.h);
    case DvtBaseAnimation.DIR_SE:
      return new DvtPoint(boundsRect.x + boundsRect.w,      boundsRect.y + boundsRect.h);
    case DvtBaseAnimation.DIR_S:
      return new DvtPoint(boundsRect.x + 0.5 * boundsRect.w, boundsRect.y + boundsRect.h);
    case DvtBaseAnimation.DIR_SW:
      return new DvtPoint(boundsRect.x,                         boundsRect.y + boundsRect.h);
    case DvtBaseAnimation.DIR_W:
      return new DvtPoint(boundsRect.x,                         boundsRect.y + 0.5 * boundsRect.h);
    case DvtBaseAnimation.DIR_NW:
      return new DvtPoint(boundsRect.x,                         boundsRect.y);
    case DvtBaseAnimation.DIR_C:
    default:
      return new DvtPoint(boundsRect.x + 0.5 * boundsRect.w, boundsRect.y + 0.5 * boundsRect.h);
  }
};

/**
  * @protected
  * Get the point to position the given object rectangle so that it aligns to the 
  * boundary rectangle in the compass direction.
  * @param {DvtRectangle}  objRect  object bounding box
  * @param {DvtRectangle}  boundsRect  bounding box
  * @param direction  constant representing the compass direction
  * @type DvtPoint
  */
DvtBaseAnimation.GetAlignCompassPoint = function(objRect, boundsRect, direction)
{
  var compassPoint = DvtBaseAnimation.GetCompassPoint(boundsRect, direction);
  var point;
  switch (direction)
  {
    case DvtBaseAnimation.DIR_N:
      return new DvtPoint(compassPoint.x - 0.5 * objRect.w, compassPoint.y);
    case DvtBaseAnimation.DIR_NE:
      return new DvtPoint(compassPoint.x - objRect.w,      compassPoint.y);
    case DvtBaseAnimation.DIR_E:
      return new DvtPoint(compassPoint.x - objRect.w,      compassPoint.y - 0.5 * objRect.h);
    case DvtBaseAnimation.DIR_SE:
      return new DvtPoint(compassPoint.x - objRect.w,      compassPoint.y - objRect.h);
    case DvtBaseAnimation.DIR_S:
      return new DvtPoint(compassPoint.x - 0.5 * objRect.w, compassPoint.y - objRect.h);
    case DvtBaseAnimation.DIR_SW:
      return new DvtPoint(compassPoint.x,                      compassPoint.y - objRect.h);
    case DvtBaseAnimation.DIR_W:
      return new DvtPoint(compassPoint.x,                      compassPoint.y - 0.5 * objRect.h);
    case DvtBaseAnimation.DIR_NW:
      return new DvtPoint(compassPoint.x,                      compassPoint.y);
    case DvtBaseAnimation.DIR_C:
    default:
      return new DvtPoint(compassPoint.x - 0.5 * objRect.w, compassPoint.y - 0.5 * objRect.h);
  }
};

/**
  * @protected
  * @override
  */
DvtBaseAnimation.prototype.Init = function(context, objs, duration, delay)
{
  DvtBaseAnimation.superclass.Init.call(this, context);
  
  this._context = context;
  
  if (objs instanceof Array)
  {
    this._arObjects = objs;
  }
  else
  {
    this._arObjects = [objs];
  }
  
  this._duration = (duration ? duration : .5);
  this._delay = (delay ? delay : 0);
  this._easing = DvtBaseAnimation.EASING_CUBIC_IN_OUT;
  this._bInitialized = false;
  
  this._bSaveAndRestoreOriginalMatrices = false;
  this._origMatrixArray = null;
  this._bHideObjectsOnEnd = false;
  
  this.CreateAnimator(context);
};

/**
  * @protected
  * Get the platform dependent context object.
  * @type DvtContext
  */
DvtBaseAnimation.prototype.GetContext = function()
{
  return this._context;
};

/**
  * @override
  */
DvtBaseAnimation.prototype.play = function()
{
  if (!this._bInitialized)
  {
    //initialize the desired end results of the animation before the start
    //states because the end results may depend on the object states
    //before the start states are applied
    this.InitializeEndStates(this._arObjects);
    //initialize the display objects appropriately for the start of the animation
    this.InitializeStartStates(this._arObjects);
    
    this.InitializePlay();
    
    this._bInitialized = true;
  }
  
  if (this._animator)
    this._animator.play();
};

/**
  * @override
  */
DvtBaseAnimation.prototype.stop = function()
{
  if (this._animator)
    this._animator.stop();
};

/**
  * @override
  */
DvtBaseAnimation.prototype.pause = function()
{
  if (this._animator)
    this._animator.pause();
};

/**
  * Get the duration of this animation, in seconds.
  * @type number
  */
DvtBaseAnimation.prototype.getDuration = function()
{
  return this._duration;
};

/**
  * Set the duration of this animation.
  * @param {number}  duration  duration of this animation, in seconds
  */
DvtBaseAnimation.prototype.setDuration = function(duration)
{
  this._duration = (duration ? duration : 0);
  
  if (this._animator)
    this._animator.setDuration(this._duration);
};

/**
  * Get the delay for the start of this animation, in seconds.
  * @type number
  */
DvtBaseAnimation.prototype.getDelay = function()
{
  return this._delay;
};

/**
  * Set the delay for the start of this animation.
  * @param {number}  delay  delay for the start of this animation, in seconds
  */
DvtBaseAnimation.prototype.setDelay = function(delay)
{
  this._delay = (delay ? delay : 0);
  
  if (this._animator)
    this._animator.setDelay(this._delay);
};

/**
  * Get the easing function for this animation.
  * Returns one of the EASING_ constants defined on DvtBaseAnimation.
  */
DvtBaseAnimation.prototype.getEasing = function()
{
  return this._easing;
};

/**
  * Set the easing function for this animation.
  * @param  easing  one of the EASING_ constants defined on DvtBaseAnimation
  */
DvtBaseAnimation.prototype.setEasing = function(easing)
{
  this._easing = easing;
  
  if (this._animator)
    this._animator.setEasing(DvtBaseAnimation.GetEasingFunction(this._easing));
};

/**
  * @protected
  * Create the underlying animator used by this animation.
  * @param {DvtContext}  context  platform specific context object
  */
DvtBaseAnimation.prototype.CreateAnimator = function(context)
{
  this._animator = new DvtAnimator(context, this._duration, this._delay, DvtBaseAnimation.GetEasingFunction(this._easing));
  this._animator.setOnEnd(this.OnAnimEnd, this);
};

/**
  * @protected
  * Called when the underlying animator ends.
  */
DvtBaseAnimation.prototype.OnAnimEnd = function()
{
  //hide objects first
  if (this._bHideObjectsOnEnd)
  {
    this.HideObjects();
  }
  
  //restore original transforms after hiding objects
  if (this._bSaveAndRestoreOriginalMatrices)
  {
    this.RestoreOriginalMatrices();
  }
  
  //call external onEnd func after any internal cleanup
  if (this._onEnd)
  {
    this._onEnd.call(this._onEndObj);
  }
};

/**
  * @protected
  * Called when play is called.
  */
DvtBaseAnimation.prototype.InitializePlay = function()
{
  //for subclasses to implement
};

/**
  * @protected
  * Called when play is called to initialize the start states of
  * the objects being animated.
  * @param {array}  arObjects  array of objects being animated
  */
DvtBaseAnimation.prototype.InitializeStartStates = function(arObjects)
{
  if (arObjects)
  {
    var obj;
    for (var i = 0; i < arObjects.length; i++)
    {
      obj = arObjects[i];
      if (obj)
      {
        if (this._bSaveAndRestoreOriginalMatrices)
        {
          if (!this._origMatrixArray)
          {
            this._origMatrixArray = [];
          }
          
          this._origMatrixArray.push(obj.getMatrix().clone());
        }
        
        this.InitStartState(obj);
      }
    }
  }
};

/**
  * @protected
  * Called when play is called to initialize the end states of
  * the objects being animated.
  * @param {array}  arObjects  array of objects being animated
  */
DvtBaseAnimation.prototype.InitializeEndStates = function(arObjects)
{
  if (arObjects)
  {
    var obj;
    for (var i = 0; i < arObjects.length; i++)
    {
      obj = arObjects[i];
      if (obj)
      {
        this.InitEndState(obj);
      }
    }
  }
};

/**
  * @protected
  * Initialize the start state of the given object being animated.
  * @param {object}  obj  object being animated
  */
DvtBaseAnimation.prototype.InitStartState = function(obj)
{
  //subclasses must implement
};

/**
  * @protected
  * Initialize the end state of the given object being animated.
  * @param {object}  obj  object being animated
  */
DvtBaseAnimation.prototype.InitEndState = function(obj)
{
  //subclasses must implement
};

/**
  * @protected
  * Set objects to be visible.  
  */
DvtBaseAnimation.prototype.ShowObjects = function()
{
  this.SetObjectsVisible(true);
};

/**
  * @protected
  * Set objects to be hidden.
  */
DvtBaseAnimation.prototype.HideObjects = function()
{
  this.SetObjectsVisible(false);
};

/**
 * @protected
 * Set visibility of objects.
 * 
 * @param {boolean}  bVisible  true to show, false to hide
 */
DvtBaseAnimation.prototype.SetObjectsVisible = function(bVisible)
{
  if (this._arObjects)
  {
    var obj;
    for (var i = this._arObjects.length - 1; i >= 0; i--)
    {
      obj = this._arObjects[i];
      if (obj)
      {
        obj.setVisible(bVisible);
      }
    }
  }
};

/**
  * @protected
  * Restore objects' original matrices as they were before animation.
  */
DvtBaseAnimation.prototype.RestoreOriginalMatrices = function()
{
  if (this._arObjects)
  {
    var obj;
    for (var i = this._arObjects.length - 1; i >= 0; i--)
    {
      obj = this._arObjects[i];
      if (obj)
      {
        if (this._origMatrixArray)
        {
          obj.setMatrix(this._origMatrixArray.pop());
        }
      }
    }
  }
};

// Copyright (c) 2011, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/**
 * Class providing the ability to create a custom animation using a DvtAnimator.
 * @param {DvtContext} context The platform specific context object.
 * @param {obj} obj The object to animate.
 * @param {number} duration The length of animation, in seconds.
 * @param {number} delay The time to delay start of animation, in seconds.
 * @extends DvtBaseAnimation
 * @class DvtSunburstAnimation
 * @constructor
 */
var DvtCustomAnimation = function(context, obj, duration, delay)
{
  this.Init(context, obj, duration, delay);
};

DvtObj.createSubclass(DvtCustomAnimation, DvtBaseAnimation, "DvtCustomAnimation");

/**
 * Returns the animator, which can be used to add animated properties.
 * @return {DvtAnimator} The animator for this animation.
 */
DvtCustomAnimation.prototype.getAnimator = function()
{
  return this._animator;
};
// Copyright (c) 2011, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/**
  * Class representing an animation to move an object into view as 
  * if on a conveyor belt.  The object will in from the background on 
  * its side and then rotate to face forward.
  * @extends DvtBaseAnimation
  * @class DvtAnimConveyorIn
  * @constructor
  * 
  * @param {DvtContext}  context  platform specific context object
  * @param objs  a single DvtContainer or Array of DvtContainers to animate
  * @param direction compass direction to move display objects in from; 
  *        can be one of: DIR_N, DIR_E, DIR_S, DIR_W
  * @param {number}  duration  length of animation, in seconds
  * @param {number}  delay  time to delay start of animation, in seconds
  */
var DvtAnimConveyorIn = function(context, objs, direction, duration, delay)
{
  this.Init(context, objs, direction, duration, delay);
};

DvtObj.createSubclass(DvtAnimConveyorIn, DvtBaseAnimation, "DvtAnimConveyorIn");

/**
  * @protected
  * @override
  */
DvtAnimConveyorIn.prototype.Init = function(context, objs, direction, duration, delay)
{
  DvtAnimConveyorIn.superclass.Init.call(this, context, objs, duration, delay);
  
  this._direction = direction;
  
  this._SCALE = .2;
  this._SKEW_ANGLE = Math.PI / 12;
  
  this._bSaveAndRestoreOriginalMatrices = true;
};

/**
  * @protected
  * @override
  */
DvtAnimConveyorIn.prototype.CreateAnimator = function(context)
{
  DvtAnimConveyorIn.superclass.CreateAnimator.call(this, context);
  
  this.setEasing(DvtBaseAnimation.EASING_CUBIC_IN);
  this._animator.setDuration(this.getDuration() / 2);
  this._animator.setOnEnd(this.PlayEndAnim, this);
  
  this._endAnim = new DvtAnimator(context, this.getDuration() / 2, 0, DvtBaseAnimation.GetEasingFunction(DvtBaseAnimation.EASING_CUBIC_OUT));
  this._endAnim.setOnEnd(this.OnAnimEnd, this);
};

/**
  * @protected
  * @override
  */
DvtAnimConveyorIn.prototype.InitializePlay = function()
{
  DvtAnimConveyorIn.superclass.InitializePlay.call(this);
  
  this.ShowObjects();
};

/**
  * @protected
  * @override
  */
DvtAnimConveyorIn.prototype.InitStartState = function(obj)
{
  DvtAnimConveyorIn.superclass.InitStartState.call(this, obj);
  
  obj.setVisible(false);
  
  //rotate first
  var scale = this._SCALE;
  var diffScale = 1 - scale;
  
  var bounds = obj.getDimensions();
  var halfWidth = bounds.w * diffScale;
  var halfHeight = bounds.h * diffScale;
  
  var mat = this.GetConcatenatedRotationMatrix(obj, bounds);
  
  //slide into background after
  var mat2 = new DvtMatrix(this.GetContext());
  if (this._direction === DvtBaseAnimation.DIR_W ||
      this._direction === DvtBaseAnimation.DIR_E)
  {
    if (this._direction === DvtBaseAnimation.DIR_W)
    {
      mat2.translate(bounds.w, 0);
    }
    else
    {
      mat2.translate(-bounds.w, 0);
    }
  }
  else
  {
    if (this._direction === DvtBaseAnimation.DIR_N)
    {
      mat2.translate(0, bounds.h);
    }
    else
    {
      mat2.translate(0, -bounds.h);
    }
  }
  mat2.concat(mat);
  obj.setMatrix(mat2);
  obj.setAlpha(0);
};

/**
  * @protected
  * @override
  */
DvtAnimConveyorIn.prototype.InitEndState = function(obj)
{
  DvtAnimConveyorIn.superclass.InitEndState.call(this, obj);
  
  var bounds = obj.getDimensions();
  
  //slide into foreground first
  var concatRotMat = this.GetConcatenatedRotationMatrix(obj, bounds).clone();
  this._animator.addProp(DvtAnimator.TYPE_MATRIX, obj, obj.getMatrix, obj.setMatrix, concatRotMat);
  this._animator.addProp(DvtAnimator.TYPE_NUMBER, obj, obj.getAlpha, obj.setAlpha, 1);
  
  //rotate after
  var currMat = obj.getMatrix().clone();
  this._endAnim.addProp(DvtAnimator.TYPE_MATRIX, obj, obj.getMatrix, obj.setMatrix, currMat);
};

/**
  * @protected
  * Play the end animation, which rotates the object to face forward again.
  */
DvtAnimConveyorIn.prototype.PlayEndAnim = function()
{
  this._endAnim.play();
};

/**
  * @protected
  * Get the concatenation of the rotation matrix with the current matrix.
  * 
  * @param  obj  display object being animated
  * @param {DvtRectangle}  bounds  bounding box for the object
  * @type DvtMatrix
  */
DvtAnimConveyorIn.prototype.GetConcatenatedRotationMatrix = function(obj, bounds)
{
  var scale = this._SCALE;
  var diffScale = 1 - scale;
  
  var halfWidth = bounds.w * diffScale;
  var halfHeight = bounds.h * diffScale;
  
  var skewAngle = this._SKEW_ANGLE;
  if (this._direction === DvtBaseAnimation.DIR_W ||
      this._direction === DvtBaseAnimation.DIR_S)
  {
    skewAngle = -skewAngle;
  }
  var tanAngle = Math.tan(skewAngle);
  
  var currMat = obj.getMatrix().clone();
  var mat = new DvtMatrix(this.GetContext());
  if (this._direction === DvtBaseAnimation.DIR_W ||
      this._direction === DvtBaseAnimation.DIR_E)
  {
    mat.skew(0, skewAngle);
    mat.scale(scale, 1);
    if (this._direction === DvtBaseAnimation.DIR_W)
    {
      mat.translate(0, 0);
    }
    else
    {
      mat.translate(halfWidth, -bounds.w * tanAngle);
    }
  }
  else
  {
    mat.skew(skewAngle, 0);
    mat.scale(1, scale);
    if (this._direction === DvtBaseAnimation.DIR_N)
    {
      mat.translate(0, 0);
    }
    else
    {
      mat.translate(-bounds.h * tanAngle, halfHeight);
    }
  }
  mat.concat(currMat);
  return mat;
};

// Copyright (c) 2011, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/**
  * Class representing an animation to move an object out of view as 
  * if on a conveyor belt.  The object will rotate onto its side and 
  * slide into the background.  
  * @extends DvtBaseAnimation
  * @class DvtAnimConveyorOut
  * @constructor
  * 
  * @param {DvtContext}  context  platform specific context object
  * @param objs  a single DvtContainer or Array of DvtContainers to animate
  * @param direction compass direction to move display objects out; 
  *        can be one of: DIR_N, DIR_E, DIR_S, DIR_W
  * @param {number}  duration  length of animation, in seconds
  * @param {number}  delay  time to delay start of animation, in seconds
  */
var DvtAnimConveyorOut = function(context, objs, direction, duration, delay)
{
  this.Init(context, objs, direction, duration, delay);
};

DvtObj.createSubclass(DvtAnimConveyorOut, DvtBaseAnimation, "DvtAnimConveyorOut");

/**
  * @protected
  * @override
  */
DvtAnimConveyorOut.prototype.Init = function(context, objs, direction, duration, delay)
{
  DvtAnimConveyorOut.superclass.Init.call(this, context, objs, duration, delay);
  
  this._direction = direction;
  
  this._bSaveAndRestoreOriginalMatrices = true;
  this._bHideObjectsOnEnd = true;
};

/**
  * @protected
  * @override
  */
DvtAnimConveyorOut.prototype.CreateAnimator = function(context)
{
  DvtAnimConveyorOut.superclass.CreateAnimator.call(this, context);
  
  this.setEasing(DvtBaseAnimation.EASING_CUBIC_IN);
  this._animator.setDuration(this.getDuration() / 2);
  this._animator.setOnEnd(this.PlayEndAnim, this);
  
  this._endAnim = new DvtAnimator(context, this.getDuration() / 2, 0, DvtBaseAnimation.GetEasingFunction(DvtBaseAnimation.EASING_CUBIC_OUT));
  this._endAnim.setOnEnd(this.OnAnimEnd, this);
};

/**
  * @protected
  * @override
  */
DvtAnimConveyorOut.prototype.InitEndState = function(obj)
{
  DvtAnimConveyorOut.superclass.InitEndState.call(this, obj);
  
  //rotate first
  var scale = .2;
  var diffScale = 1 - scale;
  
  var bounds = obj.getDimensions();
  var halfWidth = bounds.w * diffScale;
  var halfHeight = bounds.h * diffScale;
  
  var skewAngle = Math.PI / 12;
  if (this._direction === DvtBaseAnimation.DIR_W ||
      this._direction === DvtBaseAnimation.DIR_S)
  {
    skewAngle = -skewAngle;
  }
  var tanAngle = Math.tan(skewAngle);
  
  var currMat = obj.getMatrix().clone();
  var mat = new DvtMatrix(this.GetContext());
  if (this._direction === DvtBaseAnimation.DIR_W ||
      this._direction === DvtBaseAnimation.DIR_E)
  {
    mat.skew(0, skewAngle);
    mat.scale(scale, 1);
    if (this._direction === DvtBaseAnimation.DIR_W)
    {
      mat.translate(0, 0);
    }
    else
    {
      mat.translate(halfWidth, -bounds.w * tanAngle);
    }
  }
  else
  {
    mat.skew(skewAngle, 0);
    mat.scale(1, scale);
    if (this._direction === DvtBaseAnimation.DIR_N)
    {
      mat.translate(0, 0);
    }
    else
    {
      mat.translate(-bounds.h * tanAngle, halfHeight);
    }
  }
  mat.concat(currMat);
  this._animator.addProp(DvtAnimator.TYPE_MATRIX, obj, obj.getMatrix, obj.setMatrix, mat);
  
  //slide into background after
  var mat2 = new DvtMatrix(this.GetContext());
  if (this._direction === DvtBaseAnimation.DIR_W ||
      this._direction === DvtBaseAnimation.DIR_E)
  {
    if (this._direction === DvtBaseAnimation.DIR_W)
    {
      mat2.translate(bounds.w, 0);
    }
    else
    {
      mat2.translate(-bounds.w, 0);
    }
  }
  else
  {
    if (this._direction === DvtBaseAnimation.DIR_N)
    {
      mat2.translate(0, bounds.h);
    }
    else
    {
      mat2.translate(0, -bounds.h);
    }
  }
  mat2.concat(mat);
  this._endAnim.addProp(DvtAnimator.TYPE_MATRIX, obj, obj.getMatrix, obj.setMatrix, mat2);
  this._endAnim.addProp(DvtAnimator.TYPE_NUMBER, obj, obj.getAlpha, obj.setAlpha, 0);
};

/**
  * @protected
  * Play the end animation, which slides the object into the background.
  */
DvtAnimConveyorOut.prototype.PlayEndAnim = function()
{
  this._endAnim.play();
};

// Copyright (c) 2011, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/**
  * Class representing an animation to flip an object into view,
  * as if flipping a playing card.
  * @extends DvtBaseAnimation
  * @class DvtAnimFlipIn
  * @constructor
  * 
  * @param {DvtContext}  context  platform specific context object
  * @param objs  a single DvtContainer or Array of DvtContainers to animate
  * @param axis axis of rotation; can be one of: AXIS_X, AXIS_Y
  * @param rotationDir direction of rotation about the axis; can be one of:
  *        ROT_DIR_CLOCKWISE, ROT_DIR_COUNTERCLOCKWISE;
  *        direction is determined by looking down the axis from the positive side
  * @param {number}  duration  length of animation, in seconds
  * @param {number}  delay  time to delay start of animation, in seconds
  */
var DvtAnimFlipIn = function(context, objs, axis, rotationDir, duration, delay)
{
  this.Init(context, objs, axis, rotationDir, duration, delay);
};

DvtObj.createSubclass(DvtAnimFlipIn, DvtBaseAnimation, "DvtAnimFlipIn");

/**
  * @protected
  * @override
  */
DvtAnimFlipIn.prototype.Init = function(context, objs, axis, rotationDir, duration, delay)
{
  DvtAnimFlipIn.superclass.Init.call(this, context, objs, duration, delay);
  
  this._axis = axis;
  this._rotationDir = rotationDir;
  
  this._bSaveAndRestoreOriginalMatrices = true;
  this._cubeEffect = false;
};

/**
  * @protected
  * @override
  */
DvtAnimFlipIn.prototype.InitStartState = function(obj)
{
  DvtAnimFlipIn.superclass.InitStartState.call(this, obj);
  
  obj.setVisible(false);
  
  var bounds = obj.getDimensions();
  var halfWidth = bounds.w / 2;
  var halfHeight = bounds.h / 2;
  
  var skewAngle = Math.PI / 6;
  if (this._rotationDir === DvtBaseAnimation.ROT_DIR_COUNTERCLOCKWISE)
  {
    skewAngle = -skewAngle;
  }
  var tanAngle = Math.tan(skewAngle);
  
  var currMat = obj.getMatrix().clone();
  var mat = new DvtMatrix(this.GetContext());
  if (this._axis === DvtBaseAnimation.AXIS_Y)
  {
    mat.skew(0, skewAngle);
    mat.scale(0, 1);
    if (this._cubeEffect)
    {
      if (this._rotationDir === DvtBaseAnimation.ROT_DIR_COUNTERCLOCKWISE)
      {
        mat.translate(bounds.w, 0);
      }
      else
      {
        mat.translate(0, -bounds.w * tanAngle);
      }
    }
    else
    {
      mat.translate(halfWidth, -halfWidth * tanAngle);
    }
  }
  else
  {
    mat.skew(skewAngle, 0);
    mat.scale(1, 0);
    if (this._cubeEffect)
    {
      if (this._rotationDir === DvtBaseAnimation.ROT_DIR_COUNTERCLOCKWISE)
      {
        mat.translate(-bounds.h *tanAngle, 0);
      }
      else
      {
        mat.translate(0, bounds.h);
      }
    }
    else
    {
      mat.translate(-halfHeight * tanAngle, halfHeight);
    }
  }
  mat.concat(currMat);
  obj.setMatrix(mat);
  
  if (this._cubeEffect)
  {
    obj.setAlpha(0);
  }
};

/**
  * @protected
  * @override
  */
DvtAnimFlipIn.prototype.InitEndState = function(obj)
{
  DvtAnimFlipIn.superclass.InitEndState.call(this, obj);
  
  var currMat = obj.getMatrix().clone();
  this._animator.addProp(DvtAnimator.TYPE_MATRIX, obj, obj.getMatrix, obj.setMatrix, currMat);
  
  if (this._cubeEffect)
  {
    this._animator.addProp(DvtAnimator.TYPE_NUMBER, obj, obj.getAlpha, obj.setAlpha, 1);
  }
};

/**
  * @protected
  * @override
  */
DvtAnimFlipIn.prototype.InitializePlay = function()
{
  DvtAnimFlipIn.superclass.InitializePlay.call(this);
  
  this.ShowObjects();
};

// Copyright (c) 2011, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/**
  * Class representing an animation to flip an object out of view,
  * as if flipping a playing card.
  * @extends DvtBaseAnimation
  * @class DvtAnimFlipOut
  * @constructor
  * 
  * @param {DvtContext}  context  platform specific context object
  * @param objs  a single DvtContainer or Array of DvtContainers to animate
  * @param axis axis of rotation; can be one of: AXIS_X, AXIS_Y
  * @param rotationDir direction of rotation about the axis; can be one of:
  *        ROT_DIR_CLOCKWISE, ROT_DIR_COUNTERCLOCKWISE;
  *        direction is determined by looking down the axis from the positive side
  * @param {number}  duration  length of animation, in seconds
  * @param {number}  delay  time to delay start of animation, in seconds
  */
var DvtAnimFlipOut = function(context, objs, axis, rotationDir, duration, delay)
{
  this.Init(context, objs, axis, rotationDir, duration, delay);
};

DvtObj.createSubclass(DvtAnimFlipOut, DvtBaseAnimation, "DvtAnimFlipOut");

/**
  * @protected
  * @override
  */
DvtAnimFlipOut.prototype.Init = function(context, objs, axis, rotationDir, duration, delay)
{
  DvtAnimFlipOut.superclass.Init.call(this, context, objs, duration, delay);
  
  this._axis = axis;
  this._rotationDir = rotationDir;
  
  this._bSaveAndRestoreOriginalMatrices = true;
  this._bHideObjectsOnEnd = true;
  this._cubeEffect = false;
};

/**
  * @protected
  * @override
  */
DvtAnimFlipOut.prototype.InitEndState = function(obj)
{
  DvtAnimFlipOut.superclass.InitEndState.call(this, obj);
  
  var bounds = obj.getDimensions();
  var halfWidth = bounds.w / 2;
  var halfHeight = bounds.h / 2;
  
  var skewAngle = Math.PI / 6;
  if (this._rotationDir === DvtBaseAnimation.ROT_DIR_CLOCKWISE)
  {
    skewAngle = -skewAngle;
  }
  var tanAngle = Math.tan(skewAngle);
  
  var currMat = obj.getMatrix().clone();
  var mat = new DvtMatrix(this.GetContext());
  if (this._axis === DvtBaseAnimation.AXIS_Y)
  {
    mat.skew(0, skewAngle);
    mat.scale(0, 1);
    if (this._cubeEffect)
    {
      if (this._rotationDir === DvtBaseAnimation.ROT_DIR_CLOCKWISE)
      {
        mat.translate(bounds.w, 0);
      }
      else
      {
        mat.translate(0, -bounds.w * tanAngle);
      }
    }
    else
    {
      mat.translate(halfWidth, -halfWidth * tanAngle);
    }
  }
  else
  {
    mat.skew(skewAngle, 0);
    mat.scale(1, 0);
    if (this._cubeEffect)
    {
      if (this._rotationDir === DvtBaseAnimation.ROT_DIR_CLOCKWISE)
      {
        mat.translate(-bounds.h *tanAngle, 0);
      }
      else
      {
        mat.translate(0, bounds.h);
      }
    }
    else
    {
      mat.translate(-halfHeight * tanAngle, halfHeight);
    }
  }
  mat.concat(currMat);
  this._animator.addProp(DvtAnimator.TYPE_MATRIX, obj, obj.getMatrix, obj.setMatrix, mat);
  
  if (this._cubeEffect)
  {
    this._animator.addProp(DvtAnimator.TYPE_NUMBER, obj, obj.getAlpha, obj.setAlpha, 0);
  }
};

// Copyright (c) 2011, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/**
  * Class representing an animation to rotate an object into view,
  * as if rotating a cube.
  * @extends DvtAnimFlipIn
  * @class DvtAnimCubeIn
  * @constructor
  * 
  * @param {DvtContext}  context  platform specific context object
  * @param objs  a single DvtContainer or Array of DvtContainers to animate
  * @param axis axis of rotation; can be one of: AXIS_X, AXIS_Y
  * @param rotationDir direction of rotation about the axis; can be one of:
  *        ROT_DIR_CLOCKWISE, ROT_DIR_COUNTERCLOCKWISE;
  *        direction is determined by looking down the axis from the positive side
  * @param {number}  duration  length of animation, in seconds
  * @param {number}  delay  time to delay start of animation, in seconds
  */
var DvtAnimCubeIn = function(context, objs, axis, rotationDir, duration, delay)
{
  this.Init(context, objs, axis, rotationDir, duration, delay);
};

DvtObj.createSubclass(DvtAnimCubeIn, DvtAnimFlipIn, "DvtAnimCubeIn");

/**
  * @protected
  * @override
  */
DvtAnimCubeIn.prototype.Init = function(context, objs, axis, rotationDir, duration, delay)
{
  DvtAnimCubeIn.superclass.Init.call(this, context, objs, axis, rotationDir, duration, delay);
  
  this._cubeEffect = true;
};

// Copyright (c) 2011, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/**
  * Class representing an animation to rotate an object out of view,
  * as if rotating a cube.
  * @extends DvtAnimFlipOut
  * @class DvtAnimCubeOut
  * @constructor
  * 
  * @param {DvtContext}  context  platform specific context object
  * @param objs  a single DvtContainer or Array of DvtContainers to animate
  * @param axis axis of rotation; can be one of: AXIS_X, AXIS_Y
  * @param rotationDir direction of rotation about the axis; can be one of:
  *        ROT_DIR_CLOCKWISE, ROT_DIR_COUNTERCLOCKWISE;
  *        direction is determined by looking down the axis from the positive side
  * @param {number}  duration  length of animation, in seconds
  * @param {number}  delay  time to delay start of animation, in seconds
  */
var DvtAnimCubeOut = function(context, objs, axis, rotationDir, duration, delay)
{
  this.Init(context, objs, axis, rotationDir, duration, delay);
};

DvtObj.createSubclass(DvtAnimCubeOut, DvtAnimFlipOut, "DvtAnimCubeOut");

/**
  * @protected
  * @override
  */
DvtAnimCubeOut.prototype.Init = function(context, objs, axis, rotationDir, duration, delay)
{
  DvtAnimCubeOut.superclass.Init.call(this, context, objs, axis, rotationDir, duration, delay);
  
  this._cubeEffect = true;
};

// Copyright (c) 2011, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/**
  * Class representing an animation to fade in an object.
  * @extends DvtBaseAnimation
  * @class DvtAnimFadeIn
  * @constructor
  * 
  * @param {DvtContext}  context  platform specific context object
  * @param objs  a single DvtContainer or Array of DvtContainers to animate
  * @param {number}  duration  length of animation, in seconds
  * @param {number}  delay  time to delay start of animation, in seconds
  */
var DvtAnimFadeIn = function(context, objs, duration, delay)
{
  this.Init(context, objs, duration, delay);
};

DvtObj.createSubclass(DvtAnimFadeIn, DvtBaseAnimation, "DvtAnimFadeIn");

/**
  * @protected
  * @override
  */
DvtAnimFadeIn.prototype.Init = function(context, objs, duration, delay)
{
  DvtAnimFadeIn.superclass.Init.call(this, context, objs, duration, delay);
};

/**
  * @protected
  * @override
  */
DvtAnimFadeIn.prototype.InitStartState = function(obj)
{
  obj.setAlpha(0);
};

/**
  * @protected
  * @override
  */
DvtAnimFadeIn.prototype.InitEndState = function(obj)
{
  this._animator.addProp(DvtAnimator.TYPE_NUMBER, obj, obj.getAlpha, obj.setAlpha, 1);
};

// Copyright (c) 2011, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/**
  * Class representing an animation to fade out an object.
  * @extends DvtBaseAnimation
  * @class DvtAnimFadeOut
  * @constructor
  * 
  * @param {DvtContext}  context  platform specific context object
  * @param objs  a single DvtContainer or Array of DvtContainers to animate
  * @param {number}  duration  length of animation, in seconds
  * @param {number}  delay  time to delay start of animation, in seconds
  */
var DvtAnimFadeOut = function(context, objs, duration, delay)
{
  this.Init(context, objs, duration, delay);
};

DvtObj.createSubclass(DvtAnimFadeOut, DvtBaseAnimation, "DvtAnimFadeOut");

/**
  * @protected
  * @override
  */
DvtAnimFadeOut.prototype.Init = function(context, objs, duration, delay)
{
  DvtAnimFadeOut.superclass.Init.call(this, context, objs, duration, delay);
};

/**
  * @protected
  * @override
  */
DvtAnimFadeOut.prototype.InitEndState = function(obj)
{
  this._animator.addProp(DvtAnimator.TYPE_NUMBER, obj, obj.getAlpha, obj.setAlpha, 0);
};

// Copyright (c) 2011, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/**
  * Class representing an animation to transform an object by a given matrix.
  * @extends DvtBaseAnimation
  * @class DvtAnimMatrixTransformBy
  * @constructor
  * 
  * @param {DvtContext}  context  platform specific context object
  * @param objs  a single DvtContainer or Array of DvtContainers to animate
  * @param {DvtMatrix}  transformMat  the matrix to use for transforming
  * @param {number}  duration  length of animation, in seconds
  * @param {number}  delay  time to delay start of animation, in seconds
  */
var DvtAnimMatrixTransformBy = function(context, objs, transformMatrix, duration, delay)
{
  this.Init(context, objs, transformMatrix, duration, delay);
};

DvtObj.createSubclass(DvtAnimMatrixTransformBy, DvtBaseAnimation, "DvtAnimMatrixTransformBy");

/**
  * @protected
  * @override
  */
DvtAnimMatrixTransformBy.prototype.Init = function(context, objs, transformMatrix, duration, delay)
{
  this._transformMatrix = transformMatrix;
  
  DvtAnimMatrixTransformBy.superclass.Init.call(this, context, objs, duration, delay);
};

/**
  * @protected
  * @override
  */
DvtAnimMatrixTransformBy.prototype.InitEndState = function(obj)
{
  var mat = obj.getMatrix();
  if (mat)
  {
    mat = mat.clone();
    mat.concat(this._transformMatrix);
    
    this._animator.addProp(DvtAnimator.TYPE_MATRIX, obj, obj.getMatrix, obj.setMatrix, mat);
  }
};

// Copyright (c) 2011, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/**
  * Class representing an animation to move an object by a given amount.
  * @extends DvtBaseAnimation
  * @class DvtAnimMoveBy
  * @constructor
  * 
  * @param {DvtContext}  context  platform specific context object
  * @param objs  a single DvtContainer or Array of DvtContainers to animate
  * @param offsets  a single DvtPoint or Array of DvtPoints to move by
  * @param {number}  duration  length of animation, in seconds
  * @param {number}  delay  time to delay start of animation, in seconds
  */
var DvtAnimMoveBy = function(context, objs, offsets, duration, delay)
{
  this.Init(context, objs, offsets, duration, delay);
};

DvtObj.createSubclass(DvtAnimMoveBy, DvtBaseAnimation, "DvtAnimMoveBy");

/**
  * @protected
  * @override
  */
DvtAnimMoveBy.prototype.Init = function(context, objs, offsets, duration, delay)
{
  if (offsets instanceof Array)
  {
    this._arOffsets = offsets;
  }
  else if (offsets instanceof DvtPoint)
  {
    this._arOffsets = [offsets];
  }
  else
  {
    this._arOffsets = [new DvtPoint(0, 0)];
  }
  
  this._currIndex = 0;
  
  DvtAnimMoveBy.superclass.Init.call(this, context, objs, duration, delay);
};

/**
  * @protected
  * @override
  */
DvtAnimMoveBy.prototype.InitEndState = function(obj)
{
  var offset;
  if (this._currIndex < this._arOffsets.length)
  {
    offset = this._arOffsets[this._currIndex];
  }
  else
  {
    offset = this._arOffsets[this._arOffsets.length - 1];
  }
  
  this._animator.addProp(DvtAnimator.TYPE_NUMBER, obj, obj.getTranslateX, obj.setTranslateX, obj.getTranslateX() + offset.x);
  this._animator.addProp(DvtAnimator.TYPE_NUMBER, obj, obj.getTranslateY, obj.setTranslateY, obj.getTranslateY() + offset.y);
  
  this._currIndex++;
};

// Copyright (c) 2011, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/**
  * Class representing an animation to move an object to a given point.
  * @extends DvtBaseAnimation
  * @class DvtAnimMoveTo
  * @constructor
  * 
  * @param {DvtContext}  context  platform specific context object
  * @param objs  a single DvtContainer or Array of DvtContainers to animate
  * @param points  a single DvtPoint or Array of DvtPoints to move to
  * @param {number}  duration  length of animation, in seconds
  * @param {number}  delay  time to delay start of animation, in seconds
  */
var DvtAnimMoveTo = function(context, objs, points, duration, delay)
{
  this.Init(context, objs, points, duration, delay);
};

DvtObj.createSubclass(DvtAnimMoveTo, DvtBaseAnimation, "DvtAnimMoveTo");

/**
  * @protected
  * @override
  */
DvtAnimMoveTo.prototype.Init = function(context, objs, points, duration, delay)
{
  if (points instanceof Array)
  {
    this._arPoints = points;
  }
  else if (points instanceof DvtPoint)
  {
    this._arPoints = [points];
  }
  else
  {
    this._arPoints = [new DvtPoint(0, 0)];
  }
  
  this._currIndex = 0;
  
  DvtAnimMoveTo.superclass.Init.call(this, context, objs, duration, delay);
};

/**
  * @protected
  * @override
  */
DvtAnimMoveTo.prototype.InitEndState = function(obj)
{
  var point;
  if (this._currIndex < this._arPoints.length)
  {
    point = this._arPoints[this._currIndex];
  }
  else
  {
    point = this._arPoints[this._arPoints.length - 1];
  }
  
  this._animator.addProp(DvtAnimator.TYPE_NUMBER, obj, obj.getTranslateX, obj.setTranslateX, point.x);
  this._animator.addProp(DvtAnimator.TYPE_NUMBER, obj, obj.getTranslateY, obj.setTranslateY, point.y);
  
  this._currIndex++;
};

// Copyright (c) 2011, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/**
  * Class representing an animation to rotate an object by a given angle.
  * @extends DvtBaseAnimation
  * @class DvtAnimRotateBy
  * @constructor
  * 
  * @param {DvtContext}  context  platform specific context object
  * @param objs  a single DvtContainer or Array of DvtContainers to animate
  * @param angles  a single number or Array of numbers to rotate by, in radians
  * @param {number}  duration  length of animation, in seconds
  * @param {number}  delay  time to delay start of animation, in seconds
  */
var DvtAnimRotateBy = function(context, objs, angles, duration, delay)
{
  this.Init(context, objs, angles, duration, delay);
};

DvtObj.createSubclass(DvtAnimRotateBy, DvtBaseAnimation, "DvtAnimRotateBy");

/**
  * @protected
  * @override
  */
DvtAnimRotateBy.prototype.Init = function(context, objs, angles, duration, delay)
{
  if (angles instanceof Array)
  {
    this._arAngles = angles;
  }
  else if (typeof angles == 'number')
  {
    this._arAngles = [angles];
  }
  else
  {
    this._arAngles = [0];
  }
  
  this._currIndex = 0;
  
  DvtAnimRotateBy.superclass.Init.call(this, context, objs, duration, delay);
};

/**
  * @protected
  * @override
  */
DvtAnimRotateBy.prototype.InitEndState = function(obj)
{
  var angle;
  if (this._currIndex < this._arAngles.length)
  {
    angle = this._arAngles[this._currIndex];
  }
  else
  {
    angle = this._arAngles[this._arAngles.length - 1];
  }
  
  this._animator.addProp(DvtAnimator.TYPE_NUMBER, obj, obj.getRotation, obj.setRotation, obj.getRotation() + angle);
  
  this._currIndex++;
};

// Copyright (c) 2011, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/**
  * Class representing an animation to rotate an object to a given angle.
  * @extends DvtBaseAnimation
  * @class DvtAnimRotateTo
  * @constructor
  * 
  * @param {DvtContext}  context  platform specific context object
  * @param objs  a single DvtContainer or Array of DvtContainers to animate
  * @param angles  a single number or Array of numbers to rotate to, in radians
  * @param {number}  duration  length of animation, in seconds
  * @param {number}  delay  time to delay start of animation, in seconds
  */
var DvtAnimRotateTo = function(context, objs, angles, duration, delay)
{
  this.Init(context, objs, angles, duration, delay);
};

DvtObj.createSubclass(DvtAnimRotateTo, DvtBaseAnimation, "DvtAnimRotateTo");

/**
  * @protected
  * @override
  */
DvtAnimRotateTo.prototype.Init = function(context, objs, angles, duration, delay)
{
  if (angles instanceof Array)
  {
    this._arAngles = angles;
  }
  else if (typeof angles == 'number')
  {
    this._arAngles = [angles];
  }
  else
  {
    this._arAngles = [0];
  }
  
  this._currIndex = 0;
  
  DvtAnimRotateTo.superclass.Init.call(this, context, objs, duration, delay);
};

/**
  * @protected
  * @override
  */
DvtAnimRotateTo.prototype.InitEndState = function(obj)
{
  var angle;
  if (this._currIndex < this._arAngles.length)
  {
    angle = this._arAngles[this._currIndex];
  }
  else
  {
    angle = this._arAngles[this._arAngles.length - 1];
  }
  
  this._animator.addProp(DvtAnimator.TYPE_NUMBER, obj, obj.getRotation, obj.setRotation, angle);
  
  this._currIndex++;
};

// Copyright (c) 2011, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/**
  * Class representing an animation to scale an object by a given amount.
  * @extends DvtBaseAnimation
  * @class DvtAnimScaleBy
  * @constructor
  * 
  * @param {DvtContext}  context  platform specific context object
  * @param objs  a single DvtContainer or Array of DvtContainers to animate
  * @param scales  a single DvtPoint or Array of DvtPoints to scale by
  * @param {number}  duration  length of animation, in seconds
  * @param {number}  delay  time to delay start of animation, in seconds
  */
var DvtAnimScaleBy = function(context, objs, scales, duration, delay)
{
  this.Init(context, objs, scales, duration, delay);
};

DvtObj.createSubclass(DvtAnimScaleBy, DvtBaseAnimation, "DvtAnimScaleBy");

/**
  * @protected
  * @override
  */
DvtAnimScaleBy.prototype.Init = function(context, objs, scales, duration, delay)
{
  if (scales instanceof Array)
  {
    this._arScales = scales;
  }
  else if (scales instanceof DvtPoint)
  {
    this._arScales = [scales];
  }
  else
  {
    this._arScales = [new DvtPoint(1, 1)];
  }
  
  this._currIndex = 0;
  
  DvtAnimScaleBy.superclass.Init.call(this, context, objs, duration, delay);
};

/**
  * @protected
  * @override
  */
DvtAnimScaleBy.prototype.InitEndState = function(obj)
{
  var scale;
  if (this._currIndex < this._arScales.length)
  {
    scale = this._arScales[this._currIndex];
  }
  else
  {
    scale = this._arScales[this._arScales.length - 1];
  }
  
  this._animator.addProp(DvtAnimator.TYPE_NUMBER, obj, obj.getScaleX, obj.setScaleX, obj.getScaleX() * scale.x);
  this._animator.addProp(DvtAnimator.TYPE_NUMBER, obj, obj.getScaleY, obj.setScaleY, obj.getScaleY() * scale.y);
  
  this._currIndex++;
};

// Copyright (c) 2011, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/**
  * Class representing an animation to move and fade in an object.  The object 
  * is moved in from the edges of a provided rectangle as it fades.  
  * The object is also scaled as it fades, so it becomes larger as it is 
  * more opaque.
  * @extends DvtAnimFadeIn
  * @class DvtAnimScaleFadeIn
  * @constructor
  * 
  * @param {DvtContext}  context  platform specific context object
  * @param objs  a single DvtContainer or Array of DvtContainers to animate
  * @param {DvtRectangle}  boundsRect  a rectangle defining the bounds for moving the object
  * @param direction  compass direction to move display object in from; 
  *        can be one of the values defined in DvtBaseAnimation:
  *        DIR_C, DIR_N, DIR_NE, DIR_E, DIR_SE, DIR_S, DIR_SW, DIR_W, DIR_NW (default is DIR_NW)
  * @param {number}  minScale  minimum scale to make the object as it starts
  * @param {number}  duration  length of animation, in seconds
  * @param {number}  delay  time to delay start of animation, in seconds
  */
var DvtAnimScaleFadeIn = function(context, objs, boundsRect, direction, minScale, duration, delay)
{
  this.Init(context, objs, boundsRect, direction, minScale, duration, delay);
};

DvtObj.createSubclass(DvtAnimScaleFadeIn, DvtAnimFadeIn, "DvtAnimScaleFadeIn");

/**
  * @protected
  * @override
  */
DvtAnimScaleFadeIn.prototype.Init = function(context, objs, boundsRect, direction, minScale, duration, delay)
{
  this._boundsRect = boundsRect;
  this._direction = (direction ? direction : DvtBaseAnimation.DIR_NW);
  this._minScale = (minScale ? minScale : 0.5);
  
  DvtAnimScaleFadeIn.superclass.Init.call(this, context, objs, duration, delay);
  
  //need to do this AFTER calling superclass Init because member will
  //initially be defined there
  this._bSaveAndRestoreOriginalMatrices = true;
};

/**
  * @protected
  * @override
  */
DvtAnimScaleFadeIn.prototype.InitStartState = function(obj)
{
  DvtAnimScaleFadeIn.superclass.InitStartState.call(this, obj);
  
  var newScaleX = this._minScale * obj.getScaleX();
  var newScaleY = this._minScale * obj.getScaleY();
  
  //move the dispObj to the edge of the bounding rect and scale it down
  var objBounds = obj.getDimensions();
  var rect = new DvtRectangle(0, 0, newScaleX * objBounds.w, newScaleY * objBounds.h);
  var point = DvtBaseAnimation.GetAlignCompassPoint(rect, this._boundsRect, this._direction);
  obj.setTranslateX(point.x);
  obj.setTranslateY(point.y);
  obj.setScaleX(newScaleX);
  obj.setScaleY(newScaleY);
};

/**
  * @protected
  * @override
  */
DvtAnimScaleFadeIn.prototype.InitEndState = function(obj)
{
  DvtAnimScaleFadeIn.superclass.InitEndState.call(this, obj);
  
  var currMat = obj.getMatrix().clone();
  this._animator.addProp(DvtAnimator.TYPE_MATRIX, obj, obj.getMatrix, obj.setMatrix, currMat);
};

// Copyright (c) 2011, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/**
  * Class representing an animation to move and fade out an object.  The object 
  * is moved out toward the edges of a provided rectangle as it fades.  
  * The object is also scaled as it fades, so it becomes smaller as it is 
  * more transparent.
  * @extends DvtAnimFadeOut
  * @class DvtAnimScaleFadeOut
  * @constructor
  * 
  * @param {DvtContext}  context  platform specific context object
  * @param objs  a single DvtContainer or Array of DvtContainers to animate
  * @param {DvtRectangle}  boundsRect  a rectangle defining the bounds for moving the object
  * @param direction  compass direction to move display object out to; 
  *        can be one of the values defined in DvtBaseAnimation:
  *        DIR_C, DIR_N, DIR_NE, DIR_E, DIR_SE, DIR_S, DIR_SW, DIR_W, DIR_NW (default is DIR_NE)
  * @param {number}  minScale  minimum scale to make the object as it starts
  * @param {number}  duration  length of animation, in seconds
  * @param {number}  delay  time to delay start of animation, in seconds
  */
var DvtAnimScaleFadeOut = function(context, objs, boundsRect, direction, minScale, duration, delay)
{
  this.Init(context, objs, boundsRect, direction, minScale, duration, delay);
};

DvtObj.createSubclass(DvtAnimScaleFadeOut, DvtAnimFadeOut, "DvtAnimScaleFadeOut");

/**
  * @protected
  * @override
  */
DvtAnimScaleFadeOut.prototype.Init = function(context, objs, boundsRect, direction, minScale, duration, delay)
{
  this._boundsRect = boundsRect;
  this._direction = (direction ? direction : DvtBaseAnimation.DIR_NE);
  this._minScale = (minScale ? minScale : 0.5);
  
  DvtAnimScaleFadeOut.superclass.Init.call(this, context, objs, duration, delay);
  
  //need to do this AFTER calling superclass Init because member will
  //initially be defined there
  this._bSaveAndRestoreOriginalMatrices = true;
};

/**
  * @protected
  * @override
  */
DvtAnimScaleFadeOut.prototype.InitEndState = function(obj)
{
  DvtAnimScaleFadeOut.superclass.InitEndState.call(this, obj);
  
  var newScaleX = this._minScale * obj.getScaleX();
  var newScaleY = this._minScale * obj.getScaleY();
  
  //move the dispObj to the edge of the bounding rect and scale it down
  var objBounds = obj.getDimensions();
  var rect = new DvtRectangle(0, 0, newScaleX * objBounds.w, newScaleY * objBounds.h);
  var point = DvtBaseAnimation.GetAlignCompassPoint(rect, this._boundsRect, this._direction);
  
  this._animator.addProp(DvtAnimator.TYPE_NUMBER, obj, obj.getScaleX, obj.setScaleX, newScaleX);
  this._animator.addProp(DvtAnimator.TYPE_NUMBER, obj, obj.getScaleY, obj.setScaleY, newScaleY);
  
  this._animator.addProp(DvtAnimator.TYPE_NUMBER, obj, obj.getTranslateX, obj.setTranslateX, point.x);
  this._animator.addProp(DvtAnimator.TYPE_NUMBER, obj, obj.getTranslateY, obj.setTranslateY, point.y);
};

// Copyright (c) 2011, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/**
  * Class representing an animation to scale an object to a given value.
  * @extends DvtBaseAnimation
  * @class DvtAnimScaleTo
  * @constructor
  * 
  * @param {DvtContext}  context  platform specific context object
  * @param objs  a single DvtContainer or Array of DvtContainers to animate
  * @param scales  a single DvtPoint or Array of DvtPoints to scale to
  * @param {number}  duration  length of animation, in seconds
  * @param {number}  delay  time to delay start of animation, in seconds
  */
var DvtAnimScaleTo = function(context, objs, scales, duration, delay)
{
  this.Init(context, objs, scales, duration, delay);
};

DvtObj.createSubclass(DvtAnimScaleTo, DvtBaseAnimation, "DvtAnimScaleTo");

/**
  * @protected
  * @override
  */
DvtAnimScaleTo.prototype.Init = function(context, objs, scales, duration, delay)
{
  if (scales instanceof Array)
  {
    this._arScales = scales;
  }
  else if (scales instanceof DvtPoint)
  {
    this._arScales = [scales];
  }
  else
  {
    this._arScales = [new DvtPoint(1, 1)];
  }
  
  this._currIndex = 0;
  
  DvtAnimScaleTo.superclass.Init.call(this, context, objs, duration, delay);
};

/**
  * @protected
  * @override
  */
DvtAnimScaleTo.prototype.InitEndState = function(obj)
{
  var scale;
  if (this._currIndex < this._arScales.length)
  {
    scale = this._arScales[this._currIndex];
  }
  else
  {
    scale = this._arScales[this._arScales.length - 1];
  }
  
  this._animator.addProp(DvtAnimator.TYPE_NUMBER, obj, obj.getScaleX, obj.setScaleX, scale.x);
  this._animator.addProp(DvtAnimator.TYPE_NUMBER, obj, obj.getScaleY, obj.setScaleY, scale.y);
  
  this._currIndex++;
};

// Copyright (c) 2011, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/**
  * Class representing an animation to pop an object in.
  * @extends DvtBaseAnimation
  * @class DvtAnimPopIn
  * @constructor
  * 
  * @param {DvtContext}  context  platform specific context object
  * @param objs  a single DvtContainer or Array of DvtContainers to animate
  * @param {boolean}  bCenter  true to scale the object from its center, 
  *        false to scale from its origin (true is not implemented yet)
  * @param {number}  duration  length of animation, in seconds
  * @param {number}  delay  time to delay start of animation, in seconds
  */
var DvtAnimPopIn = function(context, objs, bCenter, duration, delay)
{
  this.Init(context, objs, bCenter, duration, delay);
};

DvtObj.createSubclass(DvtAnimPopIn, DvtAnimScaleTo, "DvtAnimPopIn");

/**
  * @protected
  */
DvtAnimPopIn.BackOut = function(progress)
{
  return DvtEasing.backOut(progress, 2.5);
};

/**
  * @protected
  * @override
  */
DvtAnimPopIn.prototype.Init = function(context, objs, bCenter, duration, delay)
{
  this._bCenter = bCenter;
  DvtAnimPopIn.superclass.Init.call(this, context, objs, new DvtPoint(1, 1), duration, delay);
};

/**
  * @override
  */
DvtAnimPopIn.prototype.setEasing = function(easing)
{
  //do nothing because we want to use our own easing
};

/**
  * @protected
  * @override
  */
DvtAnimPopIn.prototype.CreateAnimator = function(context)
{
  DvtAnimPopIn.superclass.CreateAnimator.call(this, context);
  this._animator.setEasing(DvtAnimPopIn.BackOut);
};

/**
  * @protected
  * @override
  */
DvtAnimPopIn.prototype.InitStartState = function(obj)
{
  obj.setScaleX(.01);
  obj.setScaleY(.01);
  obj.setVisible(true);
};

// Copyright (c) 2011, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/**
  * Class representing an animation to pop an object out.
  * @extends DvtBaseAnimation
  * @class DvtAnimPopOut
  * @constructor
  * 
  * @param {DvtContext}  context  platform specific context object
  * @param objs  a single DvtContainer or Array of DvtContainers to animate
  * @param {boolean}  bCenter  true to scale the object from its center, 
  *        false to scale from its origin (true is not implemented yet)
  * @param {number}  duration  length of animation, in seconds
  * @param {number}  delay  time to delay start of animation, in seconds
  */
var DvtAnimPopOut = function(context, objs, bCenter, duration, delay)
{
  this.Init(context, objs, bCenter, duration, delay);
};

DvtObj.createSubclass(DvtAnimPopOut, DvtAnimScaleTo, "DvtAnimPopOut");

/**
  * @protected
  */
DvtAnimPopOut.BackIn = function(progress)
{
  return DvtEasing.backIn(progress, 2.5);
};

/**
  * @protected
  * @override
  */
DvtAnimPopOut.prototype.Init = function(context, objs, bCenter, duration, delay)
{
  this._bCenter = bCenter;
  DvtAnimPopOut.superclass.Init.call(this, context, objs, new DvtPoint(.01, .01), duration, delay);
  
  //need to do this AFTER calling superclass Init because member will
  //initially be defined there
  this._bSaveAndRestoreOriginalMatrices = true;
  this._bHideObjectsOnEnd = true;
};

/**
  * @override
  */
DvtAnimPopOut.prototype.setEasing = function(easing)
{
  //do nothing because we want to use our own easing
};

/**
  * @protected
  * @override
  */
DvtAnimPopOut.prototype.CreateAnimator = function(context)
{
  DvtAnimPopOut.superclass.CreateAnimator.call(this, context);
  this._animator.setEasing(DvtAnimPopOut.BackIn);
};

// Copyright (c) 2011, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/**
  * Class used to animate replacing one set of display objects with another
  * set by rotating and moving them as if on a conveyor belt.  The old 
  * objects will move back into the display while the new objects will be 
  * moved to the front.
  * @extends DvtParallelPlayable
  * @class DvtCombinedAnimConveyor
  * @constructor
  * 
  * @param {DvtContext}  context  platform specific context object
  * @param outObjs  a single DvtContainer or Array of DvtContainers to fade out
  * @param inObjs  a single DvtContainer or Array of DvtContainers to fade in
  * @param outDir compass direction to move old display objects out; can be 
  *        one of: DIR_N, DIR_E, DIR_S, DIR_W
  * @param inDir compass direction to move new display objects in from; can 
  *        be one of: DIR_N, DIR_E, DIR_S, DIR_W
  * @param {number}  duration  length of individual out and in animations, in seconds
  * @param {number}  delay  time to delay start of animation, in seconds
  */
var DvtCombinedAnimConveyor = function(context, outObjs, inObjs, outDir, inDir, duration, delay)
{
  this.Init(context, outObjs, inObjs, outDir, inDir, duration, delay);
};

DvtObj.createSubclass(DvtCombinedAnimConveyor, DvtParallelPlayable, "DvtCombinedAnimConveyor");

/**
  * @protected
  * @override
  */
DvtCombinedAnimConveyor.prototype.Init = function(context, outObjs, inObjs, outDir, inDir, duration, delay)
{
  if (!duration)
    duration = 0.5;
  if (!delay)
    delay = 0;
  
  var conveyorOut = new DvtAnimConveyorOut(context, outObjs, outDir, duration, delay);
  var conveyorIn = new DvtAnimConveyorIn(context, inObjs, inDir, duration, (duration / 3) + delay);
  
  DvtCombinedAnimConveyor.superclass.Init.call(this, context, [conveyorOut, conveyorIn]);
};

// Copyright (c) 2011, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/**
  * Class used to animate replacing one set of display objects with 
  * another set by rotating out the old and rotating in the new, 
  * as if on a cube.
  * @extends DvtParallelPlayable
  * @class DvtCombinedAnimCube
  * @constructor
  * 
  * @param {DvtContext}  context  platform specific context object
  * @param outObjs  a single DvtContainer or Array of DvtContainers to fade out
  * @param inObjs  a single DvtContainer or Array of DvtContainers to fade in
  * @param axis axis of rotation; can be one of: AXIS_X, AXIS_Y
  * @param rotationDir direction of rotation about the axis; can be one of:
  *        ROT_DIR_CLOCKWISE, ROT_DIR_COUNTERCLOCKWISE;
  *        direction is determined by looking down the axis from the positive side
  * @param {number}  duration  length of individual out and in animations, in seconds
  * @param {number}  delay  time to delay start of animation, in seconds
  */
var DvtCombinedAnimCube = function(context, outObjs, inObjs, axis, rotationDir, duration, delay)
{
  this.Init(context, outObjs, inObjs, axis, rotationDir, duration, delay);
};

DvtObj.createSubclass(DvtCombinedAnimCube, DvtParallelPlayable, "DvtCombinedAnimCube");

/**
  * @protected
  * @override
  */
DvtCombinedAnimCube.prototype.Init = function(context, outObjs, inObjs, axis, rotationDir, duration, delay)
{
  if (!duration)
    duration = 0.5;
  if (!delay)
    delay = 0;
  
  var cubeOut = new DvtAnimCubeOut(context, outObjs, axis, rotationDir, duration, delay);
  var cubeIn = new DvtAnimCubeIn(context, inObjs, axis, rotationDir, duration, delay);
  
  DvtCombinedAnimCube.superclass.Init.call(this, context, [cubeOut, cubeIn]);
};

// Copyright (c) 2011, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/**
  * Class used to animate replacing one set of display objects with another set by
  * fading out the old and fading in the new.
  * @extends DvtParallelPlayable
  * @class DvtCombinedAnimFade
  * @constructor
  * 
  * @param {DvtContext}  context  platform specific context object
  * @param outObjs  a single DvtContainer or Array of DvtContainers to fade out
  * @param inObjs  a single DvtContainer or Array of DvtContainers to fade in
  * @param {number}  duration  length of individual out and in animations, in seconds
  * @param {number}  delay  time to delay start of animation, in seconds
  */
var DvtCombinedAnimFade = function(context, outObjs, inObjs, duration, delay)
{
  this.Init(context, outObjs, inObjs, duration, delay);
};

DvtObj.createSubclass(DvtCombinedAnimFade, DvtParallelPlayable, "DvtCombinedAnimFade");

/**
  * @protected
  * @override
  */
DvtCombinedAnimFade.prototype.Init = function(context, outObjs, inObjs, duration, delay)
{
  if (!duration)
    duration = 0.5;
  if (!delay)
    delay = 0;
  
  var fadeOut = new DvtAnimFadeOut(context, outObjs, duration, delay);
  //delay the fade out by a little bit to make both animations easier to see
  var fadeIn = new DvtAnimFadeIn(context, inObjs, duration, 0.5 * fadeOut.getDuration() + delay);
  
  DvtCombinedAnimFade.superclass.Init.call(this, context, [fadeOut, fadeIn]);
};

// Copyright (c) 2011, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/**
  * Class used to animate replacing one set of display objects with 
  * another set by flipping out the old and flipping in the new, 
  * as if on a playing card.
  * @extends DvtSequentialPlayable
  * @class DvtCombinedAnimFlip
  * @constructor
  * 
  * @param {DvtContext}  context  platform specific context object
  * @param outObjs  a single DvtContainer or Array of DvtContainers to fade out
  * @param inObjs  a single DvtContainer or Array of DvtContainers to fade in
  * @param axis axis of rotation; can be one of: AXIS_X, AXIS_Y
  * @param rotationDir direction of rotation about the axis; can be one of:
  *        ROT_DIR_CLOCKWISE, ROT_DIR_COUNTERCLOCKWISE;
  *        direction is determined by looking down the axis from the positive side
  * @param {number}  duration  length of individual out and in animations, in seconds
  * @param {number}  delay  time to delay start of animation, in seconds
  */
var DvtCombinedAnimFlip = function(context, outObjs, inObjs, axis, rotationDir, duration, delay)
{
  this.Init(context, outObjs, inObjs, axis, rotationDir, duration, delay);
};

DvtObj.createSubclass(DvtCombinedAnimFlip, DvtSequentialPlayable, "DvtCombinedAnimFlip");

/**
  * @protected
  * @override
  */
DvtCombinedAnimFlip.prototype.Init = function(context, outObjs, inObjs, axis, rotationDir, duration, delay)
{
  if (!duration)
    duration = 0.5;
  if (!delay)
    delay = 0;
  
  var flipOut = new DvtAnimFlipOut(context, outObjs, axis, rotationDir, duration, delay);
  //adjust easing so that animation is slow at the beginning, 
  //but fast at the end
  flipOut.setEasing(DvtBaseAnimation.EASING_CUBIC_IN);
  var flipIn = new DvtAnimFlipIn(context, inObjs, axis, rotationDir, duration, delay);
  //adjust easing so that animation is fast at the beginning, 
  //but slow at the end
  flipIn.setEasing(DvtBaseAnimation.EASING_CUBIC_OUT);
  
  //because the flipOut and flipIn animations are played in sequence,
  //and because the initState of the flipIn won't be set until it starts
  //to play, we need to explicitly hide the flipIn objects here so that
  //they're not visible during the first flipOut part of the sequence
  flipIn.HideObjects();
  
  DvtCombinedAnimFlip.superclass.Init.call(this, context, [flipOut, flipIn]);
};

// Copyright (c) 2011, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/**
  * Class used to animate replacing one set of display objects with another set by
  * moving out the old and moving in the new.
  * @extends DvtParallelPlayable
  * @class DvtCombinedAnimMoveBy
  * @constructor
  * 
  * @param {DvtContext}  context  platform specific context object
  * @param outObjs  a single DvtContainer or Array of DvtContainers to move out
  * @param inObjs  a single DvtContainer or Array of DvtContainers to move in
  * @param outOffsets  a single DvtPoint or Array of DvtPoints to move out by
  * @param inOffsets  a single DvtPoint or Array of DvtPoints to move in by
  * @param {number}  duration  length of individual out and in animations, in seconds
  * @param {number}  delay  time to delay start of animation, in seconds
  */
var DvtCombinedAnimMoveBy = function(context, outObjs, inObjs, outOffsets, inOffsets, duration, delay)
{
  this.Init(context, outObjs, inObjs, outOffsets, inOffsets, duration, delay);
};

DvtObj.createSubclass(DvtCombinedAnimMoveBy, DvtParallelPlayable, "DvtCombinedAnimMoveBy");

/**
  * @protected
  * @override
  */
DvtCombinedAnimMoveBy.prototype.Init = function(context, outObjs, inObjs, outOffsets, inOffsets, duration, delay)
{
  if (!duration)
    duration = 0.5;
  if (!delay)
    delay = 0;
  
  var moveOut = new DvtAnimMoveBy(context, outObjs, outOffsets, duration, delay);
  var moveIn = new DvtAnimMoveBy(context, inObjs, inOffsets, duration, delay);
  
  DvtCombinedAnimMoveBy.superclass.Init.call(this, context, [moveOut, moveIn]);
};

// Copyright (c) 2011, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/**
  * Class used to animate replacing one set of display objects with another set by
  * moving and fading out the old and moving and fading in the new.  The objects 
  * are moved out toward and in from the edges of a provided rectangle as they fade.  
  * The objects are also scaled as they fade, so they become smaller as they are 
  * more transparent.
  * @extends DvtParallelPlayable
  * @class DvtCombinedAnimScaleFade
  * @constructor
  * 
  * @param {DvtContext}  context  platform specific context object
  * @param outObjs  a single DvtContainer or Array of DvtContainers to fade out
  * @param inObjs  a single DvtContainer or Array of DvtContainers to fade in
  * @param {DvtRectangle}  boundsRect  a rectangle defining the bounds for moving the objects
  * @param outDirection  compass direction to move old display objects out to; 
  *        can be one of the values defined in DvtBaseAnimation:
  *        DIR_C, DIR_N, DIR_NE, DIR_E, DIR_SE, DIR_S, DIR_SW, DIR_W, DIR_NW (default is DIR_NE)
  * @param inDirection  compass direction to move new display objects in from; 
  *        can be one of the values defined in DvtBaseAnimation:
  *        DIR_C, DIR_N, DIR_NE, DIR_E, DIR_SE, DIR_S, DIR_SW, DIR_W, DIR_NW (default is DIR_NW)
  * @param {number}  minScale  minimum scale to make the objects as they fade
  * @param {number}  duration  length of individual out and in animations, in seconds
  * @param {number}  delay  time to delay start of animation, in seconds
  */
var DvtCombinedAnimScaleFade = function(context, outObjs, inObjs, boundsRect, outDirection, inDirection, minScale, duration, delay)
{
  this.Init(context, outObjs, inObjs, boundsRect, outDirection, inDirection, minScale, duration, delay);
};

DvtObj.createSubclass(DvtCombinedAnimScaleFade, DvtParallelPlayable, "DvtCombinedAnimScaleFade");

/**
  * @protected
  * @override
  */
DvtCombinedAnimScaleFade.prototype.Init = function(context, outObjs, inObjs, boundsRect, outDirection, inDirection, minScale, duration, delay)
{
  if (!outDirection)
    outDirection = DvtBaseAnimation.DIR_NE;
  if (!inDirection)
    inDirection = DvtBaseAnimation.DIR_NW;
  if (!minScale)
    minScale = 0.5;
  if (!duration)
    duration = 0.5;
  if (!delay)
    delay = 0;
  
  var fadeOut = new DvtAnimScaleFadeOut(context, outObjs, boundsRect, outDirection, minScale, duration, delay);
  var fadeIn = new DvtAnimScaleFadeIn(context, inObjs, boundsRect, inDirection, minScale, duration, 0.3 * fadeOut.getDuration() + delay);
  
  DvtCombinedAnimScaleFade.superclass.Init.call(this, context, [fadeOut, fadeIn]);
};

// Copyright (c) 2011, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/**
  * Class used to animate a set of display objects popping into the display
  * at staggered times.  
  * @extends DvtParallelPlayable
  * @class DvtCombinedAnimPopIn
  * @constructor
  * 
  * @param {DvtContext}  context  platform specific context object
  * @param objs  a single DvtContainer or Array of DvtContainers to pop in
  * @param {boolean}  bCenter  true to scale the object from its center, 
  *        false to scale from its origin (true is not implemented yet)
  * @param {number}  popDuration  length of individual pop animations, 
  *        in seconds
  * @param {number}  totalDuration  total length of time in which all 
  *        individiual animations must run, in seconds
  * @param {number}  delay  time to delay start of animation, in seconds
  */
var DvtCombinedAnimPopIn = function(context, objs, bCenter, popDuration, totalDuration, delay)
{
  this.Init(context, objs, bCenter, popDuration, totalDuration, delay);
};

DvtObj.createSubclass(DvtCombinedAnimPopIn, DvtParallelPlayable, "DvtCombinedAnimPopIn");

/**
  * @protected
  * @override
  */
DvtCombinedAnimPopIn.prototype.Init = function(context, objs, bCenter, popDuration, totalDuration, delay)
{
  var array = [];
  var dispObjArray;
    
  if (objs instanceof Array)
  {
    dispObjArray = objs;
  }
  else
  {
    dispObjArray = [objs];
  }
  
  delay = delay || 0;
  
  for (var i = 0; i < dispObjArray.length; i++)
  {
    var dispObj = dispObjArray[i];
    //if (dispObj instanceof DvtDisplayable)
    //{
      var individualDelay = delay + (Math.random() * (totalDuration - popDuration));
      var popIn = new DvtAnimPopIn(context, dispObj, bCenter, popDuration, individualDelay);
      array.push(popIn);
    //}
  }
  
  DvtCombinedAnimPopIn.superclass.Init.call(this, context, array);
};

// Copyright (c) 2011, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/**
  * Class used to animate a set of display objects popping out of the display
  * at staggered times.  
  * @extends DvtParallelPlayable
  * @class DvtCombinedAnimPopOut
  * @constructor
  * 
  * @param {DvtContext}  context  platform specific context object
  * @param objs  a single DvtContainer or Array of DvtContainers to pop out
  * @param {boolean}  bCenter  true to scale the object from its center, 
  *        false to scale from its origin (true is not implemented yet)
  * @param {number}  popDuration  length of individual pop animations, 
  *        in seconds
  * @param {number}  totalDuration  total length of time in which all 
  *        individiual animations must run, in seconds
  * @param {number}  delay  time to delay start of animation, in seconds
  */
var DvtCombinedAnimPopOut = function(context, objs, bCenter, popDuration, totalDuration, delay)
{
  this.Init(context, objs, bCenter, popDuration, totalDuration, delay);
};

DvtObj.createSubclass(DvtCombinedAnimPopOut, DvtParallelPlayable, "DvtCombinedAnimPopOut");

/**
  * @protected
  * @override
  */
DvtCombinedAnimPopOut.prototype.Init = function(context, objs, bCenter, popDuration, totalDuration, delay)
{
  var array = [];
  var dispObjArray;
  
    
  if (objs instanceof Array)
  {
    dispObjArray = objs;
  }
  else
  {
    dispObjArray = [objs];
  }
  
  delay = delay || 0;
  
  for (var i = 0; i < dispObjArray.length; i++)
  {
    var dispObj = dispObjArray[i];
    //if (dispObj instanceof DvtDisplayable)
    //{
      var individualDelay = delay + (Math.random() * (totalDuration - popDuration));
      var popIn = new DvtAnimPopOut(context, dispObj, bCenter, popDuration, individualDelay);
      array.push(popIn);
    //}
  }
  
  DvtCombinedAnimPopOut.superclass.Init.call(this, context, array);
};

// Copyright (c) 2008, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/*-------------------------------------------------------------------------*/
/*   DvtBaseDrawEffect                                                     */
/*-------------------------------------------------------------------------*/
/**
 * A base class for draw effects like sahodws, glows, etc.
 * {@link DvtBaseDrawEffect}.
 * @extends DvtLockable
 * @class DvtBaseDrawEffect  A base class for draw effects like sahodws, glows, etc.
 * @constructor  Do not create/use directly.
 */
var DvtBaseDrawEffect = function () {
  this._Init();
}

DvtObj.createSubclass(DvtBaseDrawEffect, DvtLockable, "DvtBaseDrawEffect");

/** 
 * @private 
 */
DvtBaseDrawEffect.prototype._Init = function () {
   DvtBaseDrawEffect.superclass._Init.call(this) ;
}

/**
 *   Returns the id of this draw effect.
 *   @type String
 */
DvtBaseDrawEffect.prototype.getId = function () {
  return this._id;
}

/**
 *   Sets the id of this fill.
 *   @param {String} id  The id for the fill.
 */
DvtBaseDrawEffect.prototype.setId = function (id) {
  this._id = id;
}

/**
 *   Merge properties in the current object into the supplied object.
 *   Abstract method, subclasses must implement. Used internally by clone().
 *   @param {DvtObj}
 *   @private
 */
DvtBaseDrawEffect.prototype.mergeProps = function (obj) {
  obj.setId(this._id);
}
// Copyright (c) 2008, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/*-------------------------------------------------------------------------*/
/*   DvtColorUtils       A static class for css color manipulation         */
/*-------------------------------------------------------------------------*/
/*   The static utility functions operate on color specifications of the   */
/*   format #rrggbb, or rgb(r,g,b), or rgba(r,g,b,a).                      */
/*-------------------------------------------------------------------------*/
/**  Static utility functions that operate on color specification strings of the
  *  format #rrggbb, or rgb(r,g,b), or rgba(r,g,b,a).
  *  @base DvtColorUtils
  */
var DvtColorUtils = {} ;

//  Channel definition constants

DvtColorUtils._RED   = 0 ;  // Channels. Don't change
DvtColorUtils._GREEN = 1 ;  // defs unless the routines
DvtColorUtils._BLUE  = 2 ;  // below are changed.
DvtColorUtils._ALPHA = 3 ;

//  private constants

DvtColorUtils._RGBA  = 'rgba(' ;
DvtColorUtils._RGB   = 'rgb(' ;
DvtColorUtils._POUND = '#'

DvtColorUtils._FACTOR = 0.15 ;  // default darkening percentage.

/** @private */
DvtColorUtils._names ;          // associative array


/*-------------------------------------------------------------------------*/
/*  getColorFromName()                                                     */
/*-------------------------------------------------------------------------*/
/**
  * Returns a color definition string from the named color.
  * @param {String}  name  The color name.
  * @type String
  * @return  An #rrggbb color string.
  */
DvtColorUtils.getColorFromName = function(name)
{
  if (! DvtColorUtils._names) {
    var ar = [] ;
    ar['aqua']    = '#00FFFF';
    ar['black']   = '#000000';
    ar['blue']    = '#0000FF'
    ar['white']   = '#FFFFFF';
    ar['fuchsia'] = '#FF00FF';
    ar['gray']    = '#848284';
    ar['lime']    = '#00FF00';
    ar['maroon']  = '#840000';
    ar['green']   = '#008200';
    ar['navy']    = '#000084';
    ar['olive']   = '#848200';
    ar['red']     = '#FF0000';
    ar['silver']  = '#C6C3C6';
    ar['teal']    = '#008284';
    ar['yellow']  = '#FFFF00';
    ar['purple']  = '#800080';

    // name colors for testing
    ar['cyan']          = '#D2B48C';
    ar['goldenrod']     = '#DAA520';
    ar['lightblue']     = '#ADD8E6';
    ar['lightyellow']   = '#FFFFE0';
    ar['orange']        = '#FFA500';
    ar['paleGoldenRod'] = '#EEE8AA';
    ar['paleturquoise'] = '#AFEEEE';
    ar['peachpuff']     = '#FFDAB9';
    ar['pink']          = '#FFC0CB';
    ar['tan']           = '#D2B48C';
    ar['thistle']       = '#D8BFD8';

    ar['transparent']   = 'rgba(255,255,255,0)';

    DvtColorUtils._names = ar ;
  }
  return DvtColorUtils._names[name] ;

} ;


/*-------------------------------------------------------------------------*/
/*  isColor()                                                              */
/*-------------------------------------------------------------------------*/
/**
 * Determine if the given string specifies a color value.
 * @param {String}  s  The string to be evaluated.
 * @param {Boolean}  bValid  Optional.  If omitted or false, the string prefix
 *                           is checked for validity only. If true, a deeper
 *                           check of the rgb component values is performed.
 * @type Boolean
 * @returns true if the string specifies a color value, else false.
 */
DvtColorUtils.isColor = function(s, bValid)
{
  if (! bValid) {
    return ((s.charAt(0) === DvtColorUtils._POUND) ||
            (s.indexOf(DvtColorUtils._RGBA) === 0) ||
            (s.indexOf(DvtColorUtils._RGB) === 0)) ;
  }

  // Deeper validation

  var bRet = false ;

  s = DvtStringUtils.ltrim(s);
  s = s.toLowerCase() ;

  if  (s.charAt(0) === DvtColorUtils._POUND) {
     if (s.length === 7) {
       var pat = new RegExp(/^#[0-9a-f]{6}$/i);
       bRet = pat.test(s);
     }
  }
  else {
    var bRGBA = (s.indexOf(DvtColorUtils._RGBA) === 0) ;
    var bRGB  ;
    
    if (! bRGBA) {
      bRGB = (s.indexOf(DvtColorUtils._RGB) === 0) ;
    }

    if (bRGBA || bRGB) {
      var x = s.indexOf(')') ;

      if (x >= 0) {
        var ar  = s.substring((bRGBA? 5 : 4), x).split(',') ;
        var len = ar.length ;
        var bVals = true ;

        for (var i = 0; i < len; i++) {
           var n = ar[i] ;
           if (( (1 < 3) && (n < 0 || n > 255)) ||  ((i > 3) && (n < 0 || n > 1))) {
             bVals = false ;
             break ;
           }
        }

        if (bVals) {
          bRet = (bRGBA? (len === 4) : (len === 3)) ;
        }
      }
    }
  }

  return bRet ;
} ;



/*-------------------------------------------------------------------------*/
/*   get/setAlpha()                                                        */
/*-------------------------------------------------------------------------*/
/**
  *  Returns the alpha value (or implied value) of the specified color string.
  *  @param {String} c The color specification.
  *  @type {number}
  *  @returns {number}  The alpha-channel value (between 0 and 1).
  */
DvtColorUtils.getAlpha = function(c)
{
   return DvtColorUtils._getChannel(c, DvtColorUtils._ALPHA) ;
} ;


/**
  *  Changes the alpha channel in the supplied color string.
  *  @param {String} c The color specification.
  *  @param {number} a The alpha value (range 0 to 1).
  *  @type String
  *  @returns  A new color specification.
  */
DvtColorUtils.setAlpha = function(c, a)
{
   return DvtColorUtils._setChannel(c, DvtColorUtils._ALPHA, a) ;
} ;


/*-------------------------------------------------------------------------*/
/*   get/setRed()                                                          */
/*-------------------------------------------------------------------------*/
/**
  *  Returns the red-channel value of the specified color string.
  *  @param {String} c The color specification.
  *  @type number
  *  @returns   The red-channel value as a decimal number between 0 and 255.
  */
DvtColorUtils.getRed = function(c)
{
   return DvtColorUtils._getChannel(c, DvtColorUtils._RED) ;
} ;

/**
  *  Changes the red-channel value in the supplied color string.
  *  @param {String} c The color specification.
  *  @param {number} r The red channel value as a decimal number between 0 and 255.
  *  @type String
  *  @returns  A new color string specification.
  */
DvtColorUtils.setRed = function(c, r)
{
   return DvtColorUtils._setChannel(c, DvtColorUtils._RED, r) ;
} ;



/*-------------------------------------------------------------------------*/
/*   get/setBlue()                                                         */
/*-------------------------------------------------------------------------*/
/**
  *  Returns the blue-channel value of the specified color string.
  *  @param {String} c The color specification.
  *  @type number
  *  @returns  The blue-channel value as a decimal number between 0 and 255.
  */
DvtColorUtils.getBlue = function(c)
{
   return DvtColorUtils._getChannel(c, DvtColorUtils._BLUE) ;
} ;


/**
  *  Changes the blue-channel value in the supplied color string.
  *  @param {String} c The color specification.
  *  @param {number} b The blue channel value as a decimal number.
  *  @type String
  *  @returns  A new color string specification.
  */
DvtColorUtils.setBlue = function(c, b)
{
   return DvtColorUtils._setChannel(c, DvtColorUtils._BLUE, b) ;
} ;



/*-------------------------------------------------------------------------*/
/*   get/setGreen()                                                        */
/*-------------------------------------------------------------------------*/
/**
  *  Returns the green-channel value of the specified color string.
  *  @param {String} c The color specification.
  *  @type number
  *  @returns   The green value as a decimal number between 0 and 255.
  */
DvtColorUtils.getGreen = function(c)
{
   return DvtColorUtils._getChannel(c, DvtColorUtils._GREEN) ;
} ;

/**
  *  Changes the green-channel value in the supplied color string.
  *  @param {String} c The color specification.
  *  @param {number} g The green channel value as a decimal number between 0 and 255.
  *  @type String
  *  @returns  A new color string specification.
  */
DvtColorUtils.setGreen = function(c, g)
{
   return DvtColorUtils._setChannel(c, DvtColorUtils._GREEN, g) ;
} ;



/*-------------------------------------------------------------------------*/
/*   getChannel()     Returns a channel from a #, rgb or rgba string.      */
/*                    (Note: if an alpha channel is requested and a # or   */
/*                    rgb string is supplied, the implied value of 1 is    */
/*                    returned.                                            */
/*-------------------------------------------------------------------------*/
/**
  *  Returns a specifed channel value from a css color specification (#, rgb(), rgba()).
  *  If an alpha channel is requested and a # or rgb string is supplied,
  *  an implied value of 1 is returned.
  *  @private
  *  @param  {String} c  The color string. 
  *  @param  {number} chan  The channel (see {@DvtColorUtils#_RED} for example).
  *  @type number
  *  @returns The channel value as a decimal number (between 0 and 255).
  */
DvtColorUtils._getChannel = function(c, chan)
{
    var clr = c;
    var chval = null;// the return value
    if (chan === DvtColorUtils._ALPHA) {

        if (clr.charAt(0) === '#') {
            chval = (clr.length > 7) ? parseInt(clr.substring(1, 3), 16) / 255 : 1;//check for MT extended format of #aarrggbb
        }
        else if (clr === 'none') {
            chval = 0;
        }

    }
    if (chval !== null) {
        return chval;
    }

    var x1 = clr.indexOf('(');

    if (x1 < 0) {
        //  #rrggbb format
        ar = [];
        ar[0] = parseInt(clr.substr(1, 2), 16);
        ar[1] = parseInt(clr.substr(3, 2), 16);
        ar[2] = parseInt(clr.substr(5, 2), 16);
        ar[3] = 1;
        chval = ar[chan];
    }
    else {

        //  rgb() or rgba() format
        var x2 = clr.indexOf(')');
        var ar = clr.substring(x1 + 1, x2).split(',');

        if (ar.length === 3 && chan === DvtColorUtils._ALPHA) {
            chval = 1;
        }
        else {
            chval = ar[chan];
            chval = parseFloat(chval);
        }
    }

    return chval;
} ;



/*-------------------------------------------------------------------------*/
/*   getDarker()                                                           */
/*-------------------------------------------------------------------------*/
/**
  * Returns the specified color made darker by the specified percentage.
  * <p>
  * Example:<br><br><code>
  * // create a color darkened by 25%). 
  *  var darker = DvtColorUtils.getDarker("rgba(220,128,49)", 0.25) ;<br>
  *  </code>
  * @param {String} color   A color specification.
  * @param {number} factor  An optional percentage by which each color component is to be
  *                         darkened (0 returns unchanged) specified as a decimal
  *                         (e.g. 25% = 0.25).  If omitted, a default percentage of
  *                         15% (i.e 0.15) is applied.
  * @type String
  * @returns A darkened color specification in RGBA format.
  */
DvtColorUtils.getDarker = function(color, factor)
{
   //TDO

   var  r = DvtColorUtils._getChannel(color, DvtColorUtils._RED);
   var  g = DvtColorUtils._getChannel(color, DvtColorUtils._GREEN);
   var  b = DvtColorUtils._getChannel(color, DvtColorUtils._BLUE);
   var  a = DvtColorUtils._getChannel(color, DvtColorUtils._ALPHA);

   if (! factor) {
     factor = DvtColorUtils._FACTOR ;    // use default factor
   }
   
   r = Math.max(parseInt(r * factor), 0);
   g = Math.max(parseInt(g * factor), 0);
   b = Math.max(parseInt(b * factor), 0);

   return DvtColorUtils.makeRGBA(r, g, b, a);
}; 



/*-------------------------------------------------------------------------*/
/*   getGrey()                                                             */
/*-------------------------------------------------------------------------*/
/**
  *   Returns a greyscale version of the supplied color (in the same format).
  *   @param {String} color  The color to be converted.
  *   @returns a greyscale version of the supplied color
  *   @type String
  *   @returns a greyscale version of the supplied color (in the same format).
  */
DvtColorUtils.getGrey = function(color)
{
   var  ret ;

   var  r = DvtColorUtils._getChannel(color, DvtColorUtils._RED);
   var  g = DvtColorUtils._getChannel(color, DvtColorUtils._BLUE);
   var  b = DvtColorUtils._getChannel(color, DvtColorUtils._GREEN);

   var gray = Math.round((r * 0.3) + (g * 0.59) + (b * 0.11));

   return this.setRGB(color, gray, gray, gray) ;
} ;



/*-------------------------------------------------------------------------*/
/*   invert()                                                              */
/*-------------------------------------------------------------------------*/
/**
  *   Inverts the specified color. 
  *   @param {String} c   The color to be inverted.
  *   @type  String
  *   @returns The inverted color in the same color format as supplied.
  */
DvtColorUtils.invert = function(c) {

   var  ret ;

   var  r = 255 - DvtColorUtils._getChannel(c, DvtColorUtils._RED);
   var  g = 255 - DvtColorUtils._getChannel(c, DvtColorUtils._BLUE);
   var  b = 255 - DvtColorUtils._getChannel(c, DvtColorUtils._GREEN);

   if (c.charAt(0) === '#') {
      ret = DvtColorUtils.makePound(r,g,b) ;
   }
   else if (c.substr(0,4) === DvtColorUtils._RGB) {
      ret = DvtColorUtils.makeRGB(r,g,b) ;
   }
   else {
      ret = DvtColorUtils.makeRGBA(r,g,b,DvtColorUtils._getChannel(c, DvtColorUtils._ALPHA)) ;
   }

   return ret ;
} ;



/*-------------------------------------------------------------------------*/
/*   isRGBA()                                                              */
/*-------------------------------------------------------------------------*/
/**
  *   Returns true if the color string is of rgba(...) format.
  *   @param {String} c   the color to be tested.
  *   @returns {boolean}  true if the color is of rgba(. . .) type, else false.
  */
DvtColorUtils.isRGBA = function(c)
{
   return (c.substr(0,5) === DvtColorUtils._RGBA) ;
};



/*-------------------------------------------------------------------------*/
/*   makeRGB()                                                             */
/*-------------------------------------------------------------------------*/
/**
  *  Creates an rgb(...) format from the supplied red, green, blue channel values.
  *  @param {number} r  The red value as a decimal number in the range 0 - 255. 
  *  @param {number} g  The green value as a decimal number in the range 0 - 255. 
  *  @param {number} b  The blue value as a decimal number in the range 0 - 255. 
  *  @type String
  *  @returns A new rgb(. . .) format string.
  */
DvtColorUtils.makeRGB = function(r,g,b)
{
   b = (b || 0) ;
   g = (g || 0) ;
   r = (r || 0) ;

   return  DvtColorUtils._RGB  + r + ',' + g + ',' + b + ')' ;
} ;


/*-------------------------------------------------------------------------*/
/*   makeRGBA()                                                            */
/*-------------------------------------------------------------------------*/
/**
  *  Creates an rgba(...) format string using the supplied red, green, blue,
  *   and alpha channel values.
  *  @param {number} r  The red value as a decimal number in the range 0 - 255. 
  *  @param {number} g  The green value as a decimal number in the range 0 - 255. 
  *  @param {number} b  The blue value as a decimal number in the range 0 - 255. 
  *  @param {number} a  The alpha value as a decimal number in the range 0 - 1.
  *                  If omitted, 1 is assumed.
  *  @type String
  *  @returns A new rgba(. . .) format string.
  */
DvtColorUtils.makeRGBA = function(r,g,b,a)
{
   b = (b || 0) ;
   g = (g || 0) ;
   r = (r || 0) ;
   a = (a == undefined)? 1 : a ;

   return  DvtColorUtils._RGBA  + r + ',' + g + ',' + b + ',' + a + ')' ;
} ;


/*-------------------------------------------------------------------------*/
/*   makePound()                                                           */
/*-------------------------------------------------------------------------*/
/**
  *  Creates a #rrggbb format string using the supplied red, green and blue
  *  channel values.
  *  @param {number} r  The red value as a decimal number in the range 0 - 255. 
  *  @param {number} g  The green value as a decimal number in the range 0 - 255. 
  *  @param {number} b  The blue value as a decimal number in the range 0 - 255. 
  *  @type String
  *  @returns A new #rrggbb format string.
  */
DvtColorUtils.makePound = function(r,g,b)
{
   var red   = r.toString(16) ;
   var green = g.toString(16) ;
   var blue  = b.toString(16) ;

   return '#' + (red.length === 1  ? '0' : '') + red + (green.length === 1 ? '0' : '') + green +
                (blue.length === 1 ? '0' : '') + blue ;
} ;



/*-------------------------------------------------------------------------*/
/*   getPound()  Returns a "#rrggbb" string from a color string            */
/*              specification such as #rr[gg[bb[aa]]], rgba(...), rgb(...) */
/*-------------------------------------------------------------------------*/
/**
  *   Returns a "#rrggbb"  color string from the supplied color string. Formats
  *   accepted are the extended middle-tier "#aarrggbb" string, "rgba(r,g,b,a)",
  *   or an "rgb(r,g,b)". If a "#rrggbb" is supplied, the same object will be
  *   returned.  (See also {@link DvtColorUtils#makePound}.)
  *   @param {String} s  A color string specification.
  *   @returns {String}  a string of the format "#rrggbb".
  */
DvtColorUtils.getPound = function(s)
{
   var ret ;

   if (s.charAt(0) === '#') {

     var len = s.length ;

     if (len <= 7) {
       return s ;
     }
     else  {             // alpha specified (#aarrggbb) - middle-tier extended format
       ret = DvtColorUtils._POUND ;
       ret += s.substring(3, 5) + s.substring(5,7) + s.substring(7,9)  ;
     }
   }
   else {
     var r =  DvtColorUtils.getRed(s).toString(16) ;
     var g =  DvtColorUtils.getGreen(s).toString(16) ;
     var b =  DvtColorUtils.getBlue(s).toString(16) ;
     ret   = DvtColorUtils.makePound(r,g,b) ;
   }

   return ret;

} ;



/*-------------------------------------------------------------------------*/
/*   getRGB()   Returns an rgb(rr,gg,bb) string from a color string        */
/*              specification such as #rr[gg[bb[aa]]], rgba(...), rgb(...) */
/*-------------------------------------------------------------------------*/
/**
  *   Returns an "rgb(r,g,b)"  color string from a supplied "#rrggbb" or
  *   extended middle-tier "#aarrggbb" string, or an rgb(r,g,b,a).
  *   If an "rgb(r,g,b)" is supplied, the same object will be returned.  (See also {@link DvtColorUtils#makePound}.)
  *   @param {String} s  A color string specification.
  *   @type String.
  */
DvtColorUtils.getRGB = function(s)
{
   var ret ;

   if (s.charAt(0) === '#') {
     ret = DvtColorUtils._RGB ;

     var len = s.length ;

     if (len > 7) {             // alpha specified (#aarrggbb) - middle-tier extended format
       ret += parseInt(s.substring(3, 5),16) + ","  +  parseInt(s.substring(5,7),16) + "," +
              parseInt(s.substring(7,9),16)  ;
     }
     else if (len === 7) {      // alpha not specified (#rrggbb)
       ret += parseInt(s.substring(1, 3),16) + "," + parseInt(s.substring(3,5),16) + "," + 
              parseInt(s.substr(5),16) ;
     }
     else if (len === 5) {      // #rrgg
         ret += parseInt(s.substring(1, 3),16) + "," + parseInt(s.substring(3,5),16) + ",0,1" ;
     }
     else if (len === 3) {      // #rr
         ret += parseInt(s.substring(1, 3),16) + ",0,0,1" ;
     }
     
     ret += ')' ;
   }
   else if (s.substr(0,5) === DvtColorUtils._RGBA) {
     var x = s.lastIndexOf(',') ;
     ret = DvtColorUtils._RGB ;
     ret += s.substring(5, x);
     ret += ')' ;
   }
   else {
     ret = s ;
   }
   return ret;

} ;




/*-------------------------------------------------------------------------*/
/*   getRGBA()  Returns an rgba(rr,gg,bb,aa) string from a color string    */
/*              specification such as #rr[gg[bb[aa]]], rgb(...), rgba(...) */
/*-------------------------------------------------------------------------*/
/**
  *   Returns an "rgba(r,g,b,a)"  color string from a supplied "#rrggbb" or
  *   extended middle-tier "#aarrggbb" string.  Will also accept an rgb(r,g,b)
  *   string (in which case the implied alpha is 1).  If an "rgba(r,g,b,a)" is
  *   supplied, the same object will be returned.  (See also {@link DvtColorUtils#makePound}.)
  *   @param {String} s  A color string specification.
  *   @type String.
  */
DvtColorUtils.getRGBA = function(s)
{
   var ret ;

   if (s.charAt(0) === '#') {
     ret = DvtColorUtils._RGBA ;

     var len = s.length ;

     if (len > 7) {             // alpha specified (#aarrggbb)
       ret += parseInt(s.substring(3, 5),16) + ","  +  parseInt(s.substring(5,7),16) + "," +
              parseInt(s.substring(7,9),16)  + ","  + (parseInt(s.substring(1, 3),16)/255)  ;
     }
     else if (len === 7) {      // alpha not specified (#rrggbb)  - alpha of 1 is assumed
       ret += parseInt(s.substring(1, 3),16) + "," + parseInt(s.substring(3,5),16) + "," + 
              parseInt(s.substr(5),16)  + ",1" ;
     }
     else if (len === 5) {      // #rrgg
         ret += parseInt(s.substring(1, 3),16) + "," + parseInt(s.substring(3,5),16) + ",0,1" ;
     }
     else if (len === 3) {      // #rr
         ret += parseInt(s.substring(1, 3),16) + ",0,0,1" ;
     }
     
     ret += ')' ;
   }
   else if (s.substr(0,4) === DvtColorUtils._RGB) {
     ret = DvtColorUtils._RGBA ;
     ret += s.substring(4, s.length -1) + ',1)';
   }
   else {
     ret = s ;
   }
   return ret;

} ;


/*-------------------------------------------------------------------------*/
/*  _setChannel()     Replaces a channel in an rgb or rgba string.  (Note: */
/*                    if an alpha channel is added and an rgb string was   */
/*                    supplied, the string is changed to an rgba string.)  */
/*-------------------------------------------------------------------------*/
/**
  *  Returns a new color String with the specifed channel value set.
  *  If an alpha channel is requested and a # or rgb string is supplied,
  *  an rgba(...) string is returned.
  *  @private
  *  @param {String} s     A color specification to be changed.
  *  @param {number} chan  The channel to be changed.
  *  @param {number} chval The new channel value (as a decimal number).
  *  @type {String}
  */
DvtColorUtils._setChannel = function(s, chan, chval)
{
   if ((chan === undefined) || (chval === undefined) || (chan < DvtColorUtils._RED) || (chan > DvtColorUtils._ALPHA)) {
     return s ;
   }

   var  ar ;
   var  bPound = (s.charAt(0) === '#') ;
   var  bRGBA ;
   var ret ;
   if (bPound) {
     ar = [] ;
     ar.push(parseInt(s.substr(1,2), 16)) ;
     ar.push(parseInt(s.substr(3,2), 16)) ;
     ar.push(parseInt(s.substr(5,2), 16)) ;
     if (chan === DvtColorUtils._ALPHA) {
       ar.push(chval) ;
       bPound = false ;
       bRGBA  = true ;
     }
   } 
   else {
     var  bRGBA = (s.substr(0,5) === DvtColorUtils._RGBA);
     var x1     = s.indexOf('(') ;
     var x2     = s.indexOf(')') ;
     var ar     = s.substring(x1+1, x2).split(',') ;

     if ((! bRGBA) && chan === DvtColorUtils._ALPHA) {
       ar.push(chval) ;
       bRGBA = true ;
     }
   }

   ar[chan] = chval ;

   if (bPound) {
     ret = DvtColorUtils.makePound(ar[0],ar[1],ar[2]) ;
   }
   else {
      ret = (bRGBA?  DvtColorUtils.makeRGBA(ar[0],ar[1],ar[2], ar[3]) :
                     DvtColorUtils.makeRGB(ar[0],ar[1],ar[2])) ;
   }
   return ret ;
   
} ;


/*-------------------------------------------------------------------------*/
/*   setRGB()                                                              */
/*-------------------------------------------------------------------------*/
/**
  *  Returns a string of the same format as the input string, with the red, green,
  *  and blue channels replaced.
  *  @param {String}  s  The input string.
  *  @param {number}  r  The red value as a decimal number. 
  *  @param {number}  g  The green value as a decimal number. 
  *  @param {number}  b  The blue value as a decimal number. 
  *  @type String
  *  @returns A new color string of the same format as the input string, with
  *  the new color values.
  */
DvtColorUtils.setRGB = function(s, r, g, b)
{
   b = (b || 0) ;
   g = (g || 0) ;
   r = (r || 0) ;

   if (s.charAt(0) === '#')
   {
      return DvtColorUtils.makePound(r, g, b);
   }

   var  bRGBA = (s.substr(0,5) === DvtColorUtils._RGBA);

   var ret = (bRGBA? DvtColorUtils._RGBA : DvtColorUtils._RGB) + r + ',' + g + ',' + b ;

   if (bRGBA) {
     var x1 = s.lastIndexOf(5,',') ;
     var x2 = s.indexOf(')') ;

     ret += ',' + s.substring(x1+1, x2) ;
   }
   ret += ')' ;
   return ret ;
} ;




/**
  * Returns a brighter color of the supplied color based on a percentage factor.
  * @param {String} color   A color specification.
  * @param {number} factor  An optional percentage by which the color is to be brightened
  *                         lightened (0 returns unchanged) specified as a decimal
  *                         (e.g. 25% = 0.25).  If omitted, a default percentage of
  *                         15% (i.e 0.15) is applied.
  * @type String
  * @returns  A new color string brightened by the factor <code>uint</code> containing the new color value.
  */
DvtColorUtils.getBrighter = function(color, factor)
{
   var  r = DvtColorUtils._getChannel(color, DvtColorUtils._RED);
   var  g = DvtColorUtils._getChannel(color, DvtColorUtils._GREEN);
   var  b = DvtColorUtils._getChannel(color, DvtColorUtils._BLUE);
   var  a = DvtColorUtils._getChannel(color, DvtColorUtils._ALPHA);

   if (! factor) {
     factor = DvtColorUtils._FACTOR ;    // use default factor
   }

   // From 2D group:
   // 1. black.brighter() should return grey
   // 2. applying brighter to blue will always return blue, brighter
   // 3. non pure color (non zero rgb) will eventually return white
   
   var i = parseInt(1.0 / (1.0 - factor));
   if (r === 0 && g === 0 && b ===0) {
     return DvtColorUtils.makeRGBA(i, i, i, a);
   }
   
   if (r > 0 && r < i) {
     r = i;
   }
   if (g > 0 && g < i) {
     g = i;
   }
   if (b > 0 && b < i) {
     b = i;
   }
   
   r = Math.min(parseInt(r / factor), 255);
   g = Math.min(parseInt(g / factor), 255);
   b = Math.min(parseInt(b / factor), 255);

   return DvtColorUtils.makeRGBA(r, g, b, a);
};



/**
  * Converts an HSV color to RGB.
  * 
  * @param (number) hue hue of the HSV color
  * @param (number) sat saturation of the HSV color
  * @param (number) val value of the HSV color
  * 
  * @type object
  * @returns an object defining r,g,b for the color
  */
DvtColorUtils.hsv2rgb = function(hue, sat, val)
{
  var red;
  var grn;
  var blu; 
  var i; 
  var f; 
  var p; 
  var q; 
  var t;
  
  hue %= 360;
  if (val == 0)
  {
    return (
    {
      r : 0, g : 0, v : 0
    });
  }
  sat /= 100;
  val /= 100;
  hue /= 60;
  i = Math.floor(hue);
  f = hue - i;
  p = val * (1 - sat);
  q = val * (1 - (sat * f));
  t = val * (1 - (sat * (1 - f)));
  if (i == 0)
  {
    red = val;
    grn = t;
    blu = p;
  }
  else if (i == 1)
  {
    red = q;
    grn = val;
    blu = p;
  }
  else if (i == 2)
  {
    red = p;
    grn = val;
    blu = t;
  }
  else if (i == 3)
  {
    red = p;
    grn = q;
    blu = val;
  }
  else if (i == 4)
  {
    red = t;
    grn = p;
    blu = val;
  }
  else if (i == 5)
  {
    red = val;
    grn = p;
    blu = q;
  }
  red = Math.floor(red * 255);
  grn = Math.floor(grn * 255);
  blu = Math.floor(blu * 255);
  return ({r : red, g : grn, b : blu});
}



/**
  * Converts an RGB color to HSV.
  * 
  * @param (number) red red of the RGB color
  * @param (number) grn green of the RGB color
  * @param (number) blu blue of the RGB color
  * 
  * @type object
  * @returns an object defining h,s,v for the color
  */
DvtColorUtils.rgb2hsv = function(red, grn, blu)
{
  var x;
  var val;
  var f;
  var i;
  var hue;
  var sat;
  
  red /= 255;
  grn /= 255;
  blu /= 255;
  x = Math.min(red, grn, blu);
  val = Math.max(red, grn, blu);
  if (x == val)
  {
    return ({h : undefined, s : 0, v : val * 100});
  }
  f = (red == x) ? grn - blu : ((grn == x) ? blu - red : red - grn);
  i = (red == x) ? 3 : ((grn == x) ? 5 : 1);
  hue = Math.floor((i - f / (val - x)) * 60) % 360;
  sat = Math.floor(((val - x) / val) * 100);
  val = Math.floor(val * 100);
  return ({h : hue, s : sat, v : val});
};

 

/**
  * Returns a pastel color using the supplied color based on a ratio.
  *
  *
  * @param (String) color  A color specification.
  * @param (number) factor An optional percentage by which to apply the pastel effect (0 returns unchanged) 
  *                        specified as a decimal (e.g., 25% = 0.25).  If omitted, the default percentage of 
  *                        15% (i.e., 0.15) is applied.
  *
  * @return A <code>uint</code> containing the new color value.
  */
DvtColorUtils.getPastel = function(color, factor)
{
  // TDO
  var a = DvtColorUtils._getChannel(color, DvtColorUtils._ALPHA) ;
  var r = DvtColorUtils._getChannel(color, DvtColorUtils._RED) ;
  var g = DvtColorUtils._getChannel(color, DvtColorUtils._GREEN) ;
  var b = DvtColorUtils._getChannel(color, DvtColorUtils._BLUE) ; ;

  var gR = Math.min(r + parseInt((255 - r) * factor), 255) ;
  var gG = Math.min(g + parseInt((255 - g) * factor), 255) ;
  var gB = Math.min(b + parseInt((255 - b) * factor), 255) ;
   
  return DvtColorUtils.makeRGBA( gR, gG, gB, a ) ;    
     
};



/**
  * Interpolate a color between the original and destination values for the 
  * given percent.
  * @param  origVal  original color value, a string
  * @param  destVal  destination color value, a string
  * @param {number}  percent  percent value to interpolate
  */
DvtColorUtils.interpolateColor = function(origVal, destVal, percent)
{
    var oldR = DvtColorUtils.getRed(origVal);
    var oldG = DvtColorUtils.getGreen(origVal);
    var oldB = DvtColorUtils.getBlue(origVal);
    var oldA = DvtColorUtils.getAlpha(origVal);

    var destR = DvtColorUtils.getRed(destVal);
    var destG = DvtColorUtils.getGreen(destVal);
    var destB = DvtColorUtils.getBlue(destVal);
    var destA = DvtColorUtils.getAlpha(destVal);

    var newR = Math.round(DvtMath.interpolateNumber(oldR, destR, percent));
    var newG = Math.round(DvtMath.interpolateNumber(oldG, destG, percent));
    var newB = Math.round(DvtMath.interpolateNumber(oldB, destB, percent));
    var newA = Math.round(DvtMath.interpolateNumber(oldA, destA, percent));

    return DvtColorUtils.makeRGBA(newR, newG, newB, newA);
};

 

// Copyright (c) 2008, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/*---------------------------------------------------------------------------*/
/*    Class ClipPath           Represents a clipping rectangle               */
/*---------------------------------------------------------------------------*/
/*  History:                                                                 */
/*  --------                                                                 */
/*                                                                           */
/*---------------------------------------------------------------------------*/

/**
  *  @class DvtClipPath
  *  Defines a clipping region composed of the union of one or more outlines.
  *  @param {String} id  The id of the clip path.
  *  @constructor
  */
var DvtClipPath = function(id)
{
   /** Id of the clip path. @type String  */
   this._id = id;
   /** the clipping outline  @type Object  */
   this._regions  = null ;
} ;

//  Clipping path outlines

/**  @final  @type number  */
DvtClipPath.NONE    = 0 ;
/**  @final  @type number  */
DvtClipPath.RECT    = 1 ;
/**  @final  @type number  */
DvtClipPath.PATH    = 2 ;
/**  @final  @type number  */
DvtClipPath.POLYGON = 3 ;
/**  @final  @type number  */
DvtClipPath.ELLIPSE = 4 ;


/**
  *   @private
  */
DvtClipPath.prototype._addRegion = function(obj)
{
   if (! this._regions) {
     this._regions = obj ;
     return ;
   }
   else if (! DvtArrayUtils.isArray(this._regions)) {
     var region = this._regions ;
     this._regions = [] ;
     this._regions.push(obj) ;
   }
};


/**
  *   Returns the ID of the clip path
  *   @returns {String}  The ID of the clip path
  */ 

DvtClipPath.prototype.getId = function()
{
   return this._id ;
};


/**
 *   Returns a  clipping region outline object (by index).
 *   @type Object
 */

DvtClipPath.prototype.getRegion = function(idx)
{
   var region = null ;

   if (this._regions) {
     if (DvtArrayUtils.isArray(this._regions)) {
       if (idx <  this._regions.length) {
         region = this._regions[idx] ;
       }
     }
     else {
       region = this._regions ;
     }
   }

   return region ;
};


/**
  *    Returns the number of clipping regions in this clip path.
  *    @returns {number}  The number of clipping regions in this clip path.
  */ 
DvtClipPath.prototype.getRegionCount = function()
{
   var count = 0 ;
   if (this._regions) {
     if (DvtArrayUtils.isArray(this._regions)) {
       count = this._regions.length ;
     }
     else {
       count = 1 ;
     }
   }

   return count ;
};



/**
  *  Adds a rectangular clipping region to the clip path.
  *  @param {number}  x   The top left x position of the rectangular region.
  *  @param {number}  y   The top left y position of the rectangular region.
  *  @param {number}  w   The width of the rectangular region.
  *  @param {number}  h   The height of the rectangular region.
  */ 
DvtClipPath.prototype.addRect = function(x, y, w, h)
{
   var obj  = {} ;
   obj.type = DvtClipPath.RECT ;
   obj.x    = x ;
   obj.y    = y ;
   obj.w    = w ;
   obj.h    = h ;

   this._addRegion(obj);
};

// TDO  JRM  add more region types.  Maybe should also be able to take a displayable ?


// Copyright (c) 2008, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/*-------------------------------------------------------------------------*/
/*   DvtFill                                                               */
/*-------------------------------------------------------------------------*/
/**
  * A base class for shape fills. DvtFill is intended to be subclassed (e.g.
  * {@link DvtSolidFill}).
  * @extends DvtBaseDrawEffect
  * @class DvtFill  is a base class for shape fill specifications.  DvtFill is intended to be subclassed (e.g.
  * {@link DvtSolidFill}).
  * @constructor  Do not create/use directly.  
  * @param {String} id  Optional ID for the object (see also {@link DvtBaseDrawEffect#setId}). 
  */
var  DvtFill = function()
{
   this._Init() ;
};

DvtObj.createSubclass(DvtFill, DvtLockable, "DvtFill");


//  Fill type definitions

/**   @final @type number  */
DvtFill.NONE     = 0 ;            // No fill specified.
/**   @final @type number  */
DvtFill.COLOR    = 1 ;            // Solid color fill. 
/**   @final @type number  */
DvtFill.GRADIENT = 2 ;            // Gradient fill.
/**   @final @type number  */
DvtFill.PATTERN  = 3 ;            // Pattern fill.
/**   @final @type number  */
DvtFill.IMAGE    = 4 ;            // Image fill.

/** 
 * @private 
 */
DvtFill.prototype._Init = function() {
  DvtFill.superclass._Init.call(this) ;
}

/**
 *   Returns the id of this draw effect.
 *   @type String
 */
DvtFill.prototype.getId = function () {
  return this._id;
}

/**
 *   Sets the id of this fill.
 *   @param {String} id  The id for the fill.
 */
DvtFill.prototype.setId = function (id) {
  this._id = id;
}

// Copyright (c) 2008, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/*---------------------------------------------------------------------*/
/*   DvtFont                                                           */
/*---------------------------------------------------------------------*/
/**
  * Encapsulates font properties.
  * @extends DvtObj
  * @class DvtFont
  * @constructor
 */
var  DvtFont = function(size, color, alpha, name, bold, italic, underline)
{
   this._Init(size, color, alpha, name, bold, italic, underline) ;
};

DvtObj.createSubclass(DvtFont, DvtObj, "DvtFont") ;



/*---------------------------------------------------------------------*/
/*   _Init()                                                           */
/*---------------------------------------------------------------------*/
/** @private */
DvtFont.prototype._Init = function(size, color, alpha, name, bold, italic, underline)
{
   this.size      = (size || 12) ;
   this.color     = (color || '#000000') ;
   this.alpha     = ((alpha === undefined)? 1 : alpha) ;
   this.name      = (name || 'sans-serif') ;
   this.bold      = (bold || false) ;
   this.italic    = (italic || false) ;
   this.underline = (underline || false) ;
};




/*---------------------------------------------------------------------*/
/*   property getters                                                  */
/*---------------------------------------------------------------------*/
/**
  * Returns the font size
  * @type number
  */
DvtFont.prototype.getSize = function()
{
   return this.size ;
} ;

/**
  * Returns the font alpha
  * @type number
  */
DvtFont.prototype.getAlpha = function()
{
   return this.alpha ;
};

/**
  * Returns the font color
  * @type String
  */
DvtFont.prototype.getColor = function()
{
   return this.color ;
};
/**
  * Returns the font name
  * @type String
  */
DvtFont.prototype.getName = function()
{
   return this.name ;
} ;
/**
  * Returns true if bold text is required.
  * @type boolean
  */
DvtFont.prototype.isBold = function()
{
   return this.bold ;
} ;
/**
  * Returns true if italic text is required.
  * @type boolean
  */
DvtFont.prototype.isItalic = function()
{
   return this.italic ;
} ;
/**
  * Returns true if underlined text is required.
  * @type boolean
  */
DvtFont.prototype.isUnderline = function()
{
   return this.underline ;
};

/**
 * @return {DvtCSSStyle} The CSS style attributes associated with this DvtFont
 */
DvtFont.prototype.getCSSStyle = function()
{
  var style = new DvtCSSStyle();

  style.setStyle(DvtCSSStyle.FONT_FAMILY, this.getName());
  style.setStyle(DvtCSSStyle.COLOR, this.getColor());
  style.setStyle(DvtCSSStyle.FONT_SIZE, this.getSize());

  if (this.isBold())
    style.setStyle(DvtCSSStyle.FONT_WEIGHT, "bold");

  if (this.isItalic())
    style.setStyle(DvtCSSStyle.FONT_STYLE, "italic");

  if (this.isUnderline())
    style.setStyle(DvtCSSStyle.TEXT_DECORATION, "underline");
  
  return style;
};


// Copyright (c) 2008, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/*-------------------------------------------------------------------------*/
/*   DvtSolidFill                                                          */
/*-------------------------------------------------------------------------*/
/**
  * A shape fill class rendering a solid fill color.
  * @extends DvtFill
  * @class DvtSolidFill
  * @constructor
  * @param {String} fc  A css color specification for the fill color.  If omitted,
  * a transparent fill is created.
  * @param {String} fa  An optional alpha. Can be used to supplement the alpha
  * specified (or implied) by the fill color.  If omitted, the alpha specifed
  * by the fill color (or 1 if it does not specify an alpha) is used.
  * @param {String} id  Optional ID for the object (see also {@link DvtBaseDrawEffect#setId}) 
 */
var  DvtSolidFill = function(fc, fa)
{
   this._Init(fc, fa) ;
};

DvtObj.createSubclass(DvtSolidFill, DvtFill, "DvtSolidFill") ;


/*-------------------------------------------------------------------------*/
/*   clone()                                                               */
/*-------------------------------------------------------------------------*/
/**
  *  Returns an (unlocked) copy of this object.
  *  @type DvtSolidFill
  */
DvtSolidFill.prototype.clone = function()
{
   var o = new DvtSolidFill() ;

   this.mergeProps(o) ;    // merge properties into cloned obj.

   return o ;
};




/*-------------------------------------------------------------------------*/
/*   _Init()                                                               */
/*-------------------------------------------------------------------------*/

/** @private */
DvtSolidFill.prototype._Init = function(fc, fa)
{
   DvtSolidFill.superclass._Init.call(this) ;

   if (! fc) {
     fc = 'none' ;
   }

   if (fa === undefined || fa === null) {
     fa = DvtColorUtils.getAlpha(fc) ;
     fc = DvtColorUtils.getRGB(fc);
   }

   this._fc  = fc ;
   this._fa  = fa ;
};


/*-------------------------------------------------------------------------*/
/*   get/setColor()           Gets/Sets the fill color                     */
/*-------------------------------------------------------------------------*/
/**
  *  Returns the fill's solid color (and alpha).
  *  @type String
  */
DvtSolidFill.prototype.getColor = function()
{
   return  this._fc ;
} ;

/**
  *  Sets the fill color.
  *  @param  {String} fc  A color specification. 
  *  e.g.  #123456, &nbsp; rgb(128,42,200), &nbsp; rgba(28, 128, 56, 0.7)
  *  &nbsp;or &nbsp;'green'&nbsp; or&nbsp; 'none'
  */
DvtSolidFill.prototype.setColor = function(fc)
{
   if (! this.isLocked()) {
     this._fc = fc ;
   }
} ;


/*-------------------------------------------------------------------------*/
/*   get/setAlpha()                                                        */
/*-------------------------------------------------------------------------*/
/**
  *  Returns the fill's solid color alpha channel value in the range 0 (invisible) to 1 (opaque).
  *  @type number
  */
DvtSolidFill.prototype.getAlpha = function()
{
   return this._fa ;
};

/**
  *  Sets the fill alpha.
  *  @param {number} alpha  A value between 0 (invisible) and 1 (opaque).
  */
DvtSolidFill.prototype.setAlpha = function(alpha)
{
   if (! this.isLocked()) {
     this._fa = alpha ;
   }
};


/*-------------------------------------------------------------------------*/
/*   mergeProps()                                                          */
/*-------------------------------------------------------------------------*/
/**
  *   Merges the fill properties in the current object into the supplied fill
  *   object.
  *   Used internally by clone().
  *   @private
  */
DvtSolidFill.prototype.mergeProps = function(obj)
{
   DvtSolidFill.superclass.mergeProps.call(this, obj) ;   // merge in subclass props

   obj._fc  = this._fc ;   // color
   obj._fa  = this._fa ;   // alpha
};

// Copyright (c) 2008, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/*-------------------------------------------------------------------------*/
/*   DvtStroke                 Base stroke properties                      */
/*-------------------------------------------------------------------------*/
/**
  * An abstract base class representing stroke properties.  
  * @class DvtStroke
  * @extends DvtObj
  * @constructor
  * @param {number} sw  The width of the stroke line.  If omitted, default is 1.
  * @param {String} id  Optional ID for the object (see also {@link DvtBaseDrawEffect#setId}). 
  */
var  DvtStroke = function(sw, id)
{
   this._Init(sw, id) ;
};

DvtObj.createSubclass(DvtStroke, DvtLockable, "DvtStroke");

/**
  * Stroke Types
  */
DvtStroke.SOLID         = 0 ;
DvtStroke.DASHED        = 1 ;
DvtStroke.DOTTED        = 2 ;
DvtStroke.DASHED_DOTTED = 3 ;

/**
  *   Standard dash type definitions
  */
DvtStroke.DASH      = "6" ;
DvtStroke.DOT       = "3" ;
DvtStroke.DASH_DOT  = "6,4,3,4" ;

/*
DvtStroke.LONG_DASH = "9" ;
DvtStroke.LONG_DOT  = "5" ;
DvtStroke.LONG_DASH_DOT  = "9,6,5,6" ;
*/

/**
  * Stroke joins
  */
DvtStroke.SQUARE = 'square' ;
DvtStroke.ROUND  = 'round' ;
DvtStroke.BEVEL  = 'bevel' ;
DvtStroke.MITER  = 'miter';

/**
  * Stroke endings
  */
//DvtSTROKE.SQUARE  ;     // same as for join
//DvtSTROKE.ROUND   ;     //  ..   .  ..  ..
DvtStroke.BUTT    = 'butt' ;

/**
 * Converts the specified stroke type string to its constant value.
 * @param {string} shape The stroke type.
 * @return {number} The corresponding constant value.
 */
DvtStroke.convertTypeString = function(type) {
  if(type == "solid")
    return DvtStroke.SOLID;
  else if(type == "dashed")
    return DvtStroke.DASHED;
  else if(type == "dotted")
    return DvtStroke.DOTTED;
  else
    return DvtStroke.SOLID;
}




/*-------------------------------------------------------------------------*/
/*   _Init()                                                               */
/*-------------------------------------------------------------------------*/
/** @private */
DvtStroke.prototype._Init = function(sw)
{
   this._sw   = (sw || 1);    // stroke_width

   DvtStroke.superclass._Init.call(this) ;
};

/**
 *   Returns the id of this draw effect.
 *   @type String
 */
DvtStroke.prototype.getId = function () {
  return this._id;
}

/**
 *   Sets the id of this fill.
 *   @param {String} id  The id for the fill.
 */
DvtStroke.prototype.setId = function (id) {
  this._id = id;
}


/*-------------------------------------------------------------------------*/
/*   mergeProps()                                                          */
/*-------------------------------------------------------------------------*/

DvtStroke.prototype.mergeProps = function(to)
{
   to._sw   = this._sw ;      // stroke width
   to._st   = this._st ;      // stroke type (solid, dashed, etc)
   to._sd   = this._sd ;      // dash details 
   to._sj   = this._sj ;      // line join style
   to._se   = this._se ;      // line ending style
   to._sm   = this._sm ;      // miter limit

   DvtStroke.superclass.mergeProps.call(this, to) ;
} ;


/*-------------------------------------------------------------------------*/
/*   setStyle()                                                            */
/*-------------------------------------------------------------------------*/
/**
  *  Sets the stroke style (e.g solid line, or intermittent line, and optionally
  *  the stroke join type and the line ending type). Null may be used to ignore
  *  any argument.
  *  <p>
  *  Dashed line examples :<br><br><code>   
  *  // 3 pixel dash followed by a 3 pixel gap<br><br>
  *  obj.setStyle(DvtStroke.DASHED, "3");<br><br>
  *  // 5 pixel dash, 3 pixel gap, 9 pixel dash, 2 pixel gap.  The pattern then repeats
  *  to fill the line<br><br>
  *  obj.setStyle(DvtStroke.DASHED, "5,3,9,2");
  *
  *  @param {number} type  DvtStroke.SOLID or DvtStroke.DASHED.
  *  @param {String} dashsize  For dashed lines, specifies the dash and space size.
  *                            The string contains a list of numbers separated by commas
  *                            or whitespace, specifying dash length and gaps. The list
  *                            should have an even number of entries, but if an odd number
  *                            is used the list will be repeated so that the entry count is even.
  *  @param {String} join  Specifies the type of line join.  May be DvtStroke.SQUARE,
  *                        DvtStroke.ROUND, DvtStroke.BEVEL, or DvtStroke.MITER.
  *  @param {String} end   Specifies the type of line end.  May be DvtSTROKE.SQUARE,
  *                        DvtSTROKE.ROUND, or DvtStroke.BUTT.
  *  @param {number} miter miter limit when join is DvtStroke.MITER
  */
DvtStroke.prototype.setStyle = function(type, dashsize, join, end, miter)
{
   if (this.isLocked()) {
     return ;
   }

   //  Line-type attributes

   if (type) {
     if (! dashsize) {
       if (type === DvtStroke.DASHED) {
         dashsize = DvtStroke.DASH ;       // default 
       }
       else if (type === DvtStroke.DOTTED) {
         dashsize = DvtStroke.DOT ;       // default 
       }
       else if (type === DvtStroke.DASHED_DOTTED) {
         dashsize = DvtStroke.DASH_DOT ;       // default 
       }
     }
   }

   this._st = type ;
   this._sd = dashsize ;


   //  Line-joining attributes

   if (join) {
     this._sj = join ;
   } 

   //  Line-ending attributes

   if (end) {
     this._se = end ;
   } 

   //  miter limit attributes

   if (miter) {
     this._sm = miter ;
   } 

} ;


DvtStroke.prototype.getDash = function()
{
   return this._sd ;
};


DvtStroke.prototype.getLineJoin = function()
{
   return this._sj ;
};

DvtStroke.prototype.setLineJoin = function(join)
{
   if (! this.isLocked()) {
     this._sj = join ;
   }
};

DvtStroke.prototype.getLineEnd = function()
{
   return this._se ;
};

DvtStroke.prototype.setLineEnd = function(end)
{
   if (! this.isLocked()) {
     this._se = end ;
   }
};

DvtStroke.prototype.getMiterLimit = function()
{
   return this._sm ;
};

DvtStroke.prototype.setMiterLimit = function(limit)
{
   if (! this.isLocked()) {
     this._sm = limit ;
   }
};


/*-------------------------------------------------------------------------*/
/*   get/setType()     Gets/Sets the type of stroke (e.g. solid or dashed  */
/*-------------------------------------------------------------------------*/

DvtStroke.prototype.getType = function()
{
   return this._st ;
};

//  dash size is optional.  May also specify alternating sizes  e.g. "3, 5, 3"
/**
  *  Sets the type of the stroke.
  *  @param {number} type  The stroke type, such as {@link DvtStroke#DASHED}. 
  *  @param {number} dashsize  Optional dash details if the stroke type is not {@link DvtStroke#SOLID}.
  */
DvtStroke.prototype.setType = function(type, dashsize)
{
   if (this.isLocked()) {
     return ;
   }

   if (type === DvtStroke.SOLID) {
     dashsize = null ;
   }
   else  if (! dashsize) {
     if (type === DvtStroke.DASHED) {
       dashsize = DvtStroke.DASH ;       // default 
     }
     else if (type === DvtStroke.DOTTED) {
       dashsize = DvtStroke.DOT ;       // default 
     }
     else if (type === DvtStroke.DASHED_DOTTED) {
       dashsize = DvtStroke.DASH_DOT ;       // default 
     }
   }

   this._st  = type ;
   this._sd  = dashsize ;

} ;


/*-------------------------------------------------------------------------*/
/*   get/setWidth()                                                        */
/*-------------------------------------------------------------------------*/
/**
  *  Returns the stroke width.
  *  @type number
  */
DvtStroke.prototype.getWidth = function()
{
   return this._sw ;
} ;

/**
  *  Sets the stroke width.
  *  @param {number} sw  The stroke width.
  */
DvtStroke.prototype.setWidth = function(sw)
{
 if (! this.isLocked()) {
   this._sw = sw ;
 }
} ;

// Copyright (c) 2008, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/*---------------------------------------------------------------------------*/
/*    DvtGradientStroke            Gradient stroke definition class          */
/*---------------------------------------------------------------------------*/
/*  Can be used to share a gradient definition among several shapes, or as a */
/*  convenience to maintain a gradient definition separately from a shape.   */
/*---------------------------------------------------------------------------*/
/**
  *   Creates a gradient specification (shareable by other shapes).
  *   @extends DvtStroke
  *   @class
  *   @constructor
  *   @param {Array} arColors  An array of color specifications (which do not include alpha values).
  *   @param {Array} arAlphas  An optional array of alpha values (between 0 and 1).  If omitted,
  *                            alphas of 1 are assumed.
  *   @param {Array} arStops   An optional array of stop boundary positions (between 0 and 1).
  *                            If omitted, an equal distribution of colors is assumed.
  *   @param {Array} arBounds  An optional bounding box array (x, y, w, h).
  *   @param {number} sw       Stroke width
  *   @param {String} id
  */
var  DvtGradientStroke = function(arColors, arAlphas, arStops, arBounds, sw, id)
{
   this._Init(arColors, arAlphas, arStops, arBounds, sw, id) ;
};


DvtObj.createSubclass(DvtGradientStroke, DvtStroke, "DvtGradientStroke") ;




/**
 * Return the first alpha in the alphas array
 * 
 * @return {number}
 */
DvtGradientStroke.prototype.getAlpha = function()
{
  return 1;
}

/**
  *   Returns an array of alpha's.
  *   @type Array
  */
DvtGradientStroke.prototype.getAlphas = function()
{
   return  this._arAlphas ;
} ;
/**
  *   Returns the bounding box for the gradient as an array (x, y, w, h).
  *   @type Array
  */
DvtGradientStroke.prototype.getBounds = function()
{
   return  this._arBounds ;
} ;

/**
  *   Returns an array of colors.
  *   @type Array
  */
DvtGradientStroke.prototype.getColors = function()
{
   return  this._arColors ;
} ;

/**
  *   Returns an array of stop ratios.
  *   @type Array
  */
DvtGradientStroke.prototype.getStops = function()
{
   return  this._arStops ;
} ;



/*---------------------------------------------------------------------------*/
/*    _Init()                                                                */
/*---------------------------------------------------------------------------*/
/**
  *  @private
  */
DvtGradientStroke.prototype._Init = function(arColors, arAlphas, arStops, arBounds, sw, id)
{
   DvtGradientStroke.superclass._Init.call(this, sw, id) ;

   this._arColors = arColors ;
   this._arBounds = arBounds ;

   var len = arColors.length - 1;

   if (! arAlphas) {
     arAlphas = DvtGradientStroke.createDefaultAlphas(len);
   }
   this._arAlphas = arAlphas ;

   if (! arStops) {     // if no stops, generate default stops
                        // for a uniform distribution of colors.
      arStops = DvtGradientStroke.createDefaultStops(len) ;
   }

   this._arStops = arStops ;
} ;

/**
 * @param {number} size
 * @return {Array} An array with size number of elements, with each element equal to 1, or null if size 
 *                  is less than 0.
 */
DvtGradientStroke.createDefaultAlphas = function(size)
{
  if(size < 0)
    return null;
    
  var arAlphas = [] ;
  for (var i = 0; i < size; i++) 
  {
    arAlphas.push(1) ;
  }
  return arAlphas;
}

/**
 * Creates a uniformly distributed range of gradient stops
 * 
 * @param {number} numStops
 * @return {Array}
 */
 DvtGradientStroke.createDefaultStops = function(numStops)
 {
  var arStops = [] ;
  var  incr   = 1/numStops ;
  var curStop = 0 ;

  do {
    arStops.push(curStop) ;
    curStop += incr ;
  } while ( --numStops > 0) ;
  arStops.push(1) ;   
  
  return arStops;
 }

/*-------------------------------------------------------------------------*/
/*   mergeProps()                                                          */
/*-------------------------------------------------------------------------*/
/**
  *   Merges the gradient properties in the current object into the supplied gradient object.
  *   Used internally by clone().
  *   @private
  */
DvtGradientStroke.prototype.mergeProps = function(obj)
{
   obj._arColors = this._arColors ;
   obj._arStops  = this._arStops ;
   obj._arAlphas = this._arAlphas ;
   obj._arBounds = this._arBounds ;

   DvtGradientStroke.superclass.mergeProps.call(this) ;
};

// Copyright (c) 2008, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/*---------------------------------------------------------------------------*/
/*    DvtLinearGradientStroke       Linear Gradient stroke class             */
/*---------------------------------------------------------------------------*/
/**
  *   Creates a linear gradient stroke.
  *   @extends DvtGradientStroke
  *   @class
  *   <p>
  *   <b>Example usage:</b><br><br><code>
  *
  *   //  Fill rectangle with a left-to-right gradient of red through blue to green.<br> 
  *   //  The colors are evenly graduated because the stop values have been omitted.<br><br> 
  *   rect.setStroke(<b>new DvtLinearGradientStroke(0, ['red', 'green, 'blue']</b>) ;<br><br>
  *
  *   //  Fill rectangle with a north-east direction gradient of red to green
  *   with an unequal gradient distribution of colors.<br><br> 
  *   rect.setStroke(<b>new DvtLinearGradientStroke(45, ['red', 'green], [0, 0.75,1]</b>) ;<br><br>

  *   @constructor
  *   @param {number} angle  Specifies the direction of the gradient as an
  *                          angle in degrees (using the standard anti-clockwise convention
  *                           for positive angles, i.e. 0 = horizontal and 90 = vertically up, etc).
  *   @param {Array} arColors  An array of color specifications (which do not include alpha values).
  *   @param {Array} arColors  An optional array of alpha values (between 0 and 1).  If omitted,
  *                            alphas of 1 are assumed.
  *   @param {Array} arStops   An optional array of stop boundary positions (between 0 and 1).
  *                            If omitted, an equal distribution of colors is assumed.
  *   @param {Array} arBounds  An optional bounding box array (x, y, w, h).
  *   @param {number} sw    An optional number for stroke width. 
  *   @param {String} id
  */
var  DvtLinearGradientStroke = function(angle, arColors, arAlphas, arStops, arBounds, sw, id)
{
   this._Init(angle, arColors, arAlphas, arStops, arBounds, sw, id) ;
};

DvtObj.createSubclass(DvtLinearGradientStroke, DvtGradientStroke, "DvtLinearGradientStroke") ;



/*---------------------------------------------------------------------------*/
/*    clone()                                                                */
/*---------------------------------------------------------------------------*/
/**
  *  Returns an (unlocked) copy of this object.
  *  @type DvtLinearGradientStroke
  */
DvtLinearGradientStroke.prototype.clone = function()
{
   var o = new DvtLinearGradientStroke() ;

   this.mergeProps(o) ;    // merge properties into cloned obj.
   return o ;
};



/*---------------------------------------------------------------------------*/
/*     Init()                                                                */
/*---------------------------------------------------------------------------*/
/**
  *  @private
  */
DvtLinearGradientStroke.prototype._Init = function(angle, arColors, arAlphas, arStops, arBounds, sw, id)
{
   DvtLinearGradientStroke.superclass._Init.call(this, arColors, arAlphas, arStops, arBounds, sw, id) ;

   this._angle = (angle || 0) ;
} ;



/*---------------------------------------------------------------------------*/
/*   getAngle()    Returns the gradient angle property for linear gradients  */
/*                 see also setAngle().                                      */
/*---------------------------------------------------------------------------*/
/**
  *  Gets the angle of the gradient in degrees.
  *  @type number
  *  @returns The angle of the gradient in degrees.  The zero degree direction is
  *  left-to-right (due east). Positive angles rotate anti-clockwise, and negative
  *  angles rotate clockwise.
  */
DvtLinearGradientStroke.prototype.getAngle = function()
{
    return this._angle ;
} ;


/*-------------------------------------------------------------------------*/
/*   mergeProps()                                                          */
/*-------------------------------------------------------------------------*/
/**
  *   Merges the linear gradient properties in the current object into the
  *   DvtLinearGradientStroke object.
  *   Used internally by clone().
  *   @private
  */
DvtLinearGradientStroke.prototype.mergeProps = function(obj)
{
   DvtLinearGradientStroke.superclass.mergeProps.call(this, obj) ;

   obj._angle  = this._angle ;      // gradient angle
};



/*---------------------------------------------------------------------------*/
/*   setAngle()         Set the gradient angle for linear gradients          */
/*---------------------------------------------------------------------------*/
//  Be default, the gradient angle is zero (due east).  Angles greater
// than zero rotate anti-clockwise.  Angles less than zero rotate clockwise.

/**
  * Sets the angle of the gradient in degrees.  The zero degree direction is
  * left-to-right (due east). Positive angles rotate anti-clockwise, and negative
  * angles rotate clockwise.
  * @param {number} The gradient direction in degrees.
  */
DvtLinearGradientStroke.prototype.setAngle = function(degrees)
{
   if (this.isLocked()) {
     return ;
   }

   if (degrees !== 0) {
     if (Math.abs(degrees) > 360) {
       degrees %= 360 ;
     }
     this._angle = degrees ;
   }
} ;


// Copyright (c) 2008, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/*-------------------------------------------------------------------------*/
/*   DvtSolidStroke            Solid Stroke properties                     */
/*-------------------------------------------------------------------------*/
/**
  * A class representing the stroke properties for a solid line.
  * @class DvtSolidStroke
  * @extends DvtStroke
  * @constructor
  * @param {String} sc  A css color specification for the color (and optionally
  * alpha)of the stroke.
  * @param {number} sa  The stroke alpha.  If the alpha is already specified in
  * the color string, null can be specified. If the alpha is not specified in
  * the color, and this argument is null, the default of 1 will be used. If alpha 
  * is specified and an alpha is also specfied in the color string, then this
  * argument takes precedence.
  * @param {number} sw  The width of the stroke line.  If omitted, the default width is 1.
  * @param {String} id  Optional ID for the object (see also {@link DvtBaseDrawEffect#setId}) 
  */
var  DvtSolidStroke = function(sc, sa, sw, id)
{
   this._Init(sc, sa, sw, id) ;
};

DvtObj.createSubclass(DvtSolidStroke, DvtStroke, "DvtSolidStroke") ;


/*-------------------------------------------------------------------------*/
/*   clone()                                                               */
/*-------------------------------------------------------------------------*/
/**
  *  Returns an (unlocked) copy of this stroke object.
  *  @type DvtSolidStroke
  */
DvtSolidStroke.prototype.clone = function()
{
   var o = new DvtSolidStroke() ;

   this.mergeProps(o) ;    // merge properties into cloned obj.
   return o ;
};







/*-------------------------------------------------------------------------*/
/*   _Init()                                                               */
/*-------------------------------------------------------------------------*/
/** @private */
DvtSolidStroke.prototype._Init = function(sc, sa, sw, id)
{
   this._sc = sc ;
   if (sa !== null && sa !== undefined) {
     this._sa = sa ;
   }
   this._st = DvtStroke.SOLID ;

   DvtSolidStroke.superclass._Init.call(this, sw, id) ;
};


/*-------------------------------------------------------------------------*/
/*   get/setAlpha()                                                        */
/*-------------------------------------------------------------------------*/
/**
  *  Returns the stroke alpha as a value between 0 (invisible) and 1 (opaque).
  *  @type {number}
  */
DvtSolidStroke.prototype.getAlpha = function()
{
   return ((this._sa !== null && this._sa !== undefined) ? this._sa : 1);
};

/**
  *  Sets the stroke alpha.
  *  @param {number} alpha  A value between 0 (invisible) and 1 (opaque).
  */
DvtSolidStroke.prototype.setAlpha = function(alpha)
{
   if (! this.bLocked)
     this._sa = alpha ;
};


/*-------------------------------------------------------------------------*/
/*   get/setColor()                                                        */
/*-------------------------------------------------------------------------*/
/**
  *  Returns the stroke color.
  *  @type String
  */
DvtSolidStroke.prototype.getColor = function()
{
   return this._sc ;
} ;

/**
  *  Sets the stroke color.
  *  @param {String}  sc  A css color specification. e.g.  '#123456',  'rgb(128,42,200)',
  *                       rgba(128,42,200,0.8), or 'green'
  */
DvtSolidStroke.prototype.setColor = function(sc)
{
   if (! this.bLocked)
     this._sc = sc ;
} ;



/*-------------------------------------------------------------------------*/
/*   mergeProps()                                                          */
/*-------------------------------------------------------------------------*/
/**
  *   Merges the stroke properties in the current object into the supplied
  *   stroke object.
  *   Used internally by clone().
  *   @private
  */
DvtSolidStroke.prototype.mergeProps = function(obj)
{
   DvtSolidStroke.superclass.mergeProps.call(this, obj) ;   // merge in the subclass's props

   obj._sc  = this._sc ;      // stroke color
   obj._sa  = this._sa ;      // stroke alpha
};

// Copyright (c) 2011, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/*-------------------------------------------------------------------------*/
/*   DvtBevel                     Base bevel                               */
/*-------------------------------------------------------------------------*/
/**
  * @class DvtBevel
  * Represents a bevel.  The bevel object properties are a superset of values, and 
  *                      each platform implementation should take those required
  *                      by that specfic platform.
  *                             
  * @constructor
  * @param {number} distance The offset distance for the bevel, in pixels.   Default is 4.
  * @param {number} angle  The angle of the bevel. Valid values are 0.0 to 360.0 degrees.  Default is 45 deg.   
  * @param {String} hilightRgba  The color and transparency of the bevel.  Default is 0xffffffff.
  * @param {String} shadowRgba  The color and transparency of the bevel.  Default is 0xff000000.                       
  * @param {number} blurX  The amount of horizontal blur. Valid values are 0.0 to 255.0  Default is 4.                                    
  * @param {number} blurY  The amount of vertical blur (float). Valid values are 0.0 to 255.0  Default is 4.
  * @param {number} strength  The strength of the imprint or spread. Default is 1.
  *                           Note: The higher the value, the more color is imprinted and the
  *                           stronger the contrast between the bevel and the background.
  *                           Valid values are from 0 to 255.0     
  * @param {number} quality  An integer number of times to apply the effect. Valid values are 0
  *                          to 15.  Default is 1.  Note: bevels with lower values are rendered
  *                          more quickly. For most applications, a quality value of 1 (low), 2
  *                          (medium), or 3 (high) is sufficient.  Although you can use additional     
  *                          numeric values up to 15 to achieve different effects, higher values
  *                          are rendered more slowly. Instead of increasing the value of quality,
  *                          you can often get a similar effect, and with faster rendering, by
  *                          simply increasing the values of the blurX and blurY properties.              
  * @param {Boolean} inner  A string value indicating whether the bevel is an inner, outer, or full bevel.
  * @param {Boolean} knockout  Applies a knockout effect if true which effectively makes the object's  
  *                         fill transparent, and reveals the background color of the document.                                         
  *
  */
var  DvtBevel = function(distance, angle, hilightRgba, shadowRgba, blurX, blurY, 
                         strength, quality, type, knockout)

{
   this._Init(distance, angle, hilightRgba, shadowRgba, blurX, blurY, strength, 
              quality, type, knockout) ;
} ;


DvtObj.createSubclass(DvtBevel, DvtBaseDrawEffect, "DvtBevel");


/**
 * 
 */
DvtBevel.TYPE_INNER = "inner";
/**
 * @private
 */
DvtBevel.TYPE_OUTER = "outer";
/**
 * @private
 */
DvtBevel.TYPE_FULL = "full";

/**
 * @private
 */
DvtBevel._uniqueId = 1 ;

/*-------------------------------------------------------------------------*/
/*   _Init()                                                               */
/*-------------------------------------------------------------------------*/
/** @private */
DvtBevel.prototype._Init = function(distance, angle, hilightRgba, shadowRgba, 
                                    blurX, blurY, strength, quality, type, 
                                    knockout)
{
   DvtBevel.superclass._Init.call(this) ;

   this._distance   = (distance || 4);
   //BUG FIX #12661565: if arg is set to 0, then set value to 0 also
   if (distance === 0) {
     this._distance = 0;
   }
   this._angle      = (angle || 45);
   if (angle === 0) {
     this._angle = 0;
   }
   this._hilightRgba       = (hilightRgba || "rgba(255,255,255,1)");
   this._shadowRgba       = (shadowRgba || "rgba(0,0,0,1)");
   this._blurX      = (blurX || 4) ;
   if (blurX === 0) {
     this._blurX = 0;
   }
   this._blurY      = (blurY || 4) ;
   if (blurY === 0) {
     this._blurY = 0;
   }
   this._strength   = (strength || 1);
   this._quality    = (quality || 1) ;
   this._type       = type ;
   this._bKnockout  = false ;
   this._Id         = 'bv' + DvtBevel._uniqueId++ ;
};

/**
  *  Returns an (unlocked) copy of this object.
  *  @type DvtBevel
  */
DvtBevel.prototype.clone = function()
{
   var o = new DvtBevel() ;

   this.mergeProps(o) ;    // merge properties into cloned obj.

   return o ;
};

/**
  *   Merges the fill properties in the current object into the supplied fill
  *   object.
  *   Used internally by clone().
  *   @private
  */
DvtBevel.prototype.mergeProps = function(obj)
{
   DvtBevel.superclass.mergeProps.call(this, obj) ;   // merge in subclass props

   obj._distance = this._distance;
   obj._angle = this._angle;
   obj._hilightRgba = this._hilightRgba;
   obj._shadowRgba = this._shadowRgba;
   obj._blurX = this._blurX;
   obj._blurY = this._blurY;
   obj._strength = this._strength;
   obj._quality = this._quality;
   obj._type = this._type;
   obj._bKnockout = this._bKnockout;
   obj._Id = this._Id;
};



// Copyright (c) 2011, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/*-------------------------------------------------------------------------*/
/*   DvtGlow                     Base glow effect                          */
/*-------------------------------------------------------------------------*/
/**
  * @class DvtGlow
  * Represents a glow effect.  The glow object properties are a superset of values, and 
  *                            each platform implementation should take those required
  *                            by that specfic platform.
  *                             
  * @constructor
  * @param {String} rgba  The color and transparency of the glow.  Default is rgb(255,255,255,1).
  * @param {number} blurX  The amount of horizontal blur. Valid values are 0.0 to 255.0  Default is 4.
  * @param {number} blurY  The amount of vertical blur (float). Valid values are 0.0 to 255.0  Default is 4.    
  * @param {number} strength  The strength of the imprint or spread. Default is 1.
  *                           Note: The higher the value, the more color is imprinted and the
  *                           stronger the contrast between the shadow and the background.
  *                           Valid values are from 0 to 255.
  * @param {number} quality  An integer number of times to apply the effect. Valid values are 0
  *                          to 15.  Default is 1.  Note: glows with lower values are rendered
  *                          more quickly. For most applications, a quality value of 1 (low), 2
  *                          (medium), or 3 (high) is sufficient.  Although you can use additional     
  *                          numeric values up to 15 to achieve different effects, higher values
  *                          are rendered more slowly. Instead of increasing the value of quality,
  *                          you can often get a similar effect, and with faster rendering, by
  *                          simply increasing the values of the blurX and blurY properties.              
  * @param {Boolean} inner  A boolean value indicating whether or not the glow is an inner glow.
  *                         A true value specifies an inner glow. False specifies an outer glow 
  *                         (a glow around the outer edges of the object).  Default is false.
  * @param {Boolean} knockout  Applies a knockout effect if true which effectively makes the object's  
  *                         fill transparent, and reveals the background color of the document.
  *                         Default is false.
  *
  */
var DvtGlow = function(rgba, blurX, blurY, strength, 
                        quality, inner, knockout)

{
   this.Init(rgba, blurX, blurY, strength, 
             quality, inner, knockout) ;
} ;


DvtObj.createSubclass(DvtGlow, DvtBaseDrawEffect, "DvtGlow");


DvtGlow._uniqueId = 1 ;

/** 
  * @protected
  */
DvtGlow.prototype.Init = function(rgba, blurX, blurY, strength,
                                   quality, inner, knockout)
{
  DvtGlow.superclass._Init.call(this) ;
  
  this._rgba       = (rgba || "rgba(255,255,255,1)");
  this._blurX      = (blurX || 4) ;
  this._blurY      = (blurY || 4) ;
  this._strength   = (strength || 1);
  this._quality    = (quality || 1) ;
  this._bInner     = (inner ? true : false) ;
  this._bKnockout  = (knockout ? true : false) ;
  this._Id         = 'dg' + (DvtGlow._uniqueId++) ;
};

/**
  *  Returns an (unlocked) copy of this object.
  *  @type DvtGlow
  */
DvtGlow.prototype.clone = function()
{
   var o = new DvtGlow() ;

   this.mergeProps(o) ;    // merge properties into cloned obj.

   return o ;
};

/**
  *   Merges the fill properties in the current object into the supplied fill
  *   object.
  *   Used internally by clone().
  *   @private
  */
DvtGlow.prototype.mergeProps = function(obj)
{
   DvtGlow.superclass.mergeProps.call(this, obj) ;   // merge in subclass props

   obj._rgba = this._rgba;
   obj._blurX = this._blurX;
   obj._blurY = this._blurY;
   obj._strength = this._strength;
   obj._quality = this._quality;
   obj._bInner = this._bInner;
   obj._bKnockout = this._bKnockout;
   obj._Id = this._Id;
};

// Copyright (c) 2008, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/*-------------------------------------------------------------------------*/
/*   DvtShadow                     Base drop shadow                        */
/*-------------------------------------------------------------------------*/
/**
  * @class DvtShadow
  * Represents a drop shadow.  The shadow object properties are a superset of values, and 
  *                            each platform implementation should take those required
  *                            by that specfic platform.
  *                             
  * @constructor
  * @param {number} sw  The width of the stroke line.  If omitted, default is 1.
  * @param {String} id  Optional ID for the object (see also {@link DvtBaseDrawEffect#setId}). 
  * @param {String} rgba  The color and transparency of the shadow.  Default is      0x59333333.
  * @param {number} distance The offset distance for the shadow, in pixels.   Default is 4.
  * @param {number} strength  The strength of the imprint or spread. Default is 1.
  *                           Note: The higher the value, the more color is imprinted and the
  *                           stronger the contrast between the shadow and the background.
  *                           Valid values are from 0 to 255.0               
  * @param {number} angle  The angle of the shadow. Valid values are 0.0 to 360.0 degrees.  Default is 45 deg.                
  * @param {number} blurX  The amount of horizontal blur. Valid values are 0.0 to 255.0  Default is 4.                                    
  * @param {number} blurY  The amount of vertical blur (float). Valid values are 0.0 to 255.0  Default is 4.                                       
  * @param {number} quality  An integer number of times to apply the effect. Valid values are 0
  *                          to 15.  Default is 1.  Note: shadows with lower values are rendered
  *                          more quickly. For most applications, a quality value of 1 (low), 2
  *                          (medium), or 3 (high) is sufficient.  Although you can use additional     
  *                          numeric values up to 15 to achieve different effects, higher values
  *                          are rendered more slowly. Instead of increasing the value of quality,
  *                          you can often get a similar effect, and with faster rendering, by
  *                          simply increasing the values of the blurX and blurY properties.              
  * @param {Boolean} inner  A boolean value indicating whether or not the shadow is an inner shadow.
  *                         A true value specifies an inner shadow. False specifies an outer shadow 
  *                         (a shadow around the outer edges of the object).
  * @param {Boolean} knockout  Applies a knockout effect if true which effectively makes the object's  
  *                         fill transparent, and reveals the background color of the document.                                                 
  * @param {Boolean} hide   A value indicating whether or not the object is hidden. A true value
  *                         indicates that the object itself is not drawn; only the shadow is visible.    
  *                         If false, the object is shown.                                                     
  *
  */
var  DvtShadow = function(rgba, distance, blurX, blurY, angle, strength,
                          quality,inner,knockout,hide)

{
   this._Init(rgba, distance, blurX, blurY, angle, strength, quality,inner,knockout,hide) ;
} ;


DvtObj.createSubclass(DvtShadow, DvtBaseDrawEffect, "DvtShadow");


DvtShadow._uniqueId = 1 ;

/*-------------------------------------------------------------------------*/
/*   _Init()                                                               */
/*-------------------------------------------------------------------------*/
/** @private */
DvtShadow.prototype._Init = function(rgba, distance, blurX, blurY, angle, strength,
                                     quality,inner,knockout,hide)
{
  DvtShadow.superclass._Init.call(this) ;

   this._rgba       = (rgba || "rgba(48,48,48,0.35)");
   this._distance   = (distance || 4);
   //BUG FIX #12661565: if arg is set to 0, then set value to 0 also
   if (distance === 0) {
     this._distance = 0;
   }
   this._strength   = (strength || 1);
   this._blurX      = (blurX || 4) ;
   if (blurX === 0) {
     this._blurX = 0;
   }
   this._blurY      = (blurY || 4) ;
   if (blurY === 0) {
     this._blurY = 0;
   }
   this._angle      = (angle || 45);
   if (angle === 0) {
     this._angle = 0;
   }
   this._quality    = (quality || 1) ;
   this._bInner     = (inner ? true : false) ;
   this._bKnockout  = false ;
   this._bHide      = false ;
   this._Id         = 'ds' + DvtShadow._uniqueId++ ;
};

/**
  *  Returns an (unlocked) copy of this object.
  *  @type DvtShadow
  */
DvtShadow.prototype.clone = function()
{
   var o = new DvtShadow() ;

   this.mergeProps(o) ;    // merge properties into cloned obj.

   return o ;
};

/**
  *   Merges the fill properties in the current object into the supplied fill
  *   object.
  *   Used internally by clone().
  *   @private
  */
DvtShadow.prototype.mergeProps = function(obj)
{
   DvtShadow.superclass.mergeProps.call(this, obj) ;   // merge in subclass props

   obj._rgba = this._rgba;
   obj._distance = this._distance;
   obj._strength = this._strength;
   obj._blurX = this._blurX;
   obj._blurY = this._blurY;
   obj._angle = this._angle;
   obj._quality = this._quality;
   obj._bInner = this._bInner;
   obj._bKnockout = this._bKnockout;
   obj._bHide = this._bHide;
   obj._Id = this._Id;
};



// Copyright (c) 2008, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/*---------------------------------------------------------------------------*/
/*    DvtGradientFill            Gradient fill definition class              */
/*---------------------------------------------------------------------------*/
/*  Can be used to share a gradient definition among several shapes, or as a */
/*  convenience to maintain a gradient definition separately from a shape.   */
/*---------------------------------------------------------------------------*/
/**
  *   Creates a gradient specification (shareable by other shapes).
  *   @extends DvtFill
  *   @class
  *   @constructor
  *   @param {Array} arColors  An array of color specifications (which do not include alpha values).
  *   @param {Array} arColors  An optional array of alpha values (between 0 and 1).  If omitted,
  *                            alphas of 1 are assumed.
  *   @param {Array} arStops   An optional array of stop boundary positions (between 0 and 1).
  *                            If omitted, an equal distribution of colors is assumed.
  *   @param {Array} arBounds  An optional bounding box array (x, y, w, h).
  */
var  DvtGradientFill = function(arColors, arAlphas, arStops, arBounds)
{
   this._Init(arColors, arAlphas, arStops, arBounds) ;
};


DvtObj.createSubclass(DvtGradientFill, DvtFill, "DvtGradientFill") ;





/**
  *   Returns an array of alpha's.
  *   @type Array
  */
DvtGradientFill.prototype.getAlphas = function()
{
   return  this._arAlphas ;
} ;
/**
  *   Returns the bounding box for the gradient as an array (x, y, w, h).
  *   @type Array
  */
DvtGradientFill.prototype.getBounds = function()
{
   return  this._arBounds ;
} ;

/**
  *   Returns an array of colors.
  *   @type Array
  */
DvtGradientFill.prototype.getColors = function()
{
   return  this._arColors ;
} ;

/**
  *   Returns an array of stop ratios.
  *   @type Array
  */
DvtGradientFill.prototype.getStops = function()
{
   return  this._arStops ;
} ;



/*---------------------------------------------------------------------------*/
/*     Init()                                                                */
/*---------------------------------------------------------------------------*/
/**
  *  @private
  */
DvtGradientFill.prototype._Init = function(arColors, arAlphas, arStops, arBounds)
{
   DvtGradientFill.superclass._Init.call(this) ;

   this._arColors = arColors ;
   this._arBounds = arBounds ;

   var len = 0;
   if (arColors) {
       len = arColors.length - 1;
   }

   if (! arAlphas) {
     arAlphas = [] ;
     for (var i = 0; i < len; i++) {
        arAlphas.push(1) ;
     }
   }
   this._arAlphas = arAlphas ;

   if (! arStops) {     // if no stops, generate default stops
                        // for a uniform distribution of colors.
      arStops = [] ;
      var  incr   = (len > 0) ? 1/len : 0 ;
      var curStop = 0 ;

      do {
         arStops.push(curStop) ;
         curStop += incr ;
      } while ( --len > 0) ;
      arStops.push(1) ;
   }

   this._arStops = arStops ;
} ;



/*-------------------------------------------------------------------------*/
/*   mergeProps()                                                          */
/*-------------------------------------------------------------------------*/
/**
  *   Merges the gradient properties in the current object into the supplied gradient object.
  *   Used internally by clone().
  *   @private
  */
DvtGradientFill.prototype.mergeProps = function(obj)
{
   obj._arColors = this._arColors ;
   obj._arStops  = this._arStops ;
   obj._arAlphas = this._arAlphas ;
   obj._arBounds = this._arBounds ;

   DvtGradientFill.superclass.mergeProps.call(this, obj) ;
};

// Copyright (c) 2008, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/*---------------------------------------------------------------------------*/
/*    DvtLinearGradientFill       Linear Gradient fill class                     */
/*---------------------------------------------------------------------------*/
/**
  *   Creates a linear gradient fill.
  *   @extends DvtGradientFill
  *   @class
  *   <p>
  *   <b>Example usage:</b><br><br><code>
  *
  *   //  Fill rectangle with a left-to-right gradient of red through blue to green.<br> 
  *   //  The colors are evenly graduated because the stop values have been omitted.<br><br> 
  *   rect.setFill(<b>new DvtLinearGradientFill(0, ['red', 'green, 'blue']</b>) ;<br><br>
  *
  *   //  Fill rectangle with a north-east direction gradient of red to green
  *   with an unequal gradient distribution of colors.<br><br> 
  *   rect.setFill(<b>new DvtLinearGradientFill(45, ['red', 'green], [0, 0.75,1]</b>) ;<br><br>

  *   @constructor
  *   @param {number} angle  Specifies the direction of the gradient as an
  *                          angle in degrees (using the standard anti-clockwise convention
  *                           for positive angles, i.e. 0 = horizontal and 90 = vertically up, etc).
  *   @param {Array} arColors  An array of color specifications (which do not include alpha values).
  *   @param {Array} arColors  An optional array of alpha values (between 0 and 1).  If omitted,
  *                            alphas of 1 are assumed.
  *   @param {Array} arStops   An optional array of stop boundary positions (between 0 and 1).
  *                            If omitted, an equal distribution of colors is assumed.
  *   @param {Array} arBounds  An optional bounding box array (x, y, w, h).
  */
var  DvtLinearGradientFill = function(angle, arColors, arAlphas, arStops, arBounds)
{
   this._Init(angle, arColors, arAlphas, arStops, arBounds) ;
};

DvtObj.createSubclass(DvtLinearGradientFill, DvtGradientFill, "DvtLinearGradientFill") ;



/*---------------------------------------------------------------------------*/
/*    clone()                                                                */
/*---------------------------------------------------------------------------*/
/**
  *  Returns an (unlocked) copy of this object.
  *  @type DvtLinearGradientFill
  */
DvtLinearGradientFill.prototype.clone = function()
{
   var o = new DvtLinearGradientFill() ;

   this.mergeProps(o) ;    // merge properties into cloned obj.
   return o ;
};



/*---------------------------------------------------------------------------*/
/*     Init()                                                                */
/*---------------------------------------------------------------------------*/
/**
  *  @private
  */
DvtLinearGradientFill.prototype._Init = function(angle, arColors, arAlphas, arStops, arBounds)
{
   DvtLinearGradientFill.superclass._Init.call(this, arColors, arAlphas, arStops, arBounds) ;

   this._angle = (angle || 0) ;
} ;



/*---------------------------------------------------------------------------*/
/*   getAngle()    Returns the gradient angle property for linear gradients  */
/*                 see also setAngle().                                      */
/*---------------------------------------------------------------------------*/
/**
  *  Gets the angle of the gradient in degrees.
  *  @type number
  *  @returns The angle of the gradient in degrees.  The zero degree direction is
  *  left-to-right (due east). Positive angles rotate anti-clockwise, and negative
  *  angles rotate clockwise.
  */
DvtLinearGradientFill.prototype.getAngle = function()
{
    return this._angle ;
} ;


/*-------------------------------------------------------------------------*/
/*   mergeProps()                                                          */
/*-------------------------------------------------------------------------*/
/**
  *   Merges the linear gradient properties in the current object into the
  *   DvtLinearGradientFill object.
  *   Used internally by clone().
  *   @private
  */
DvtLinearGradientFill.prototype.mergeProps = function(obj)
{
   DvtLinearGradientFill.superclass.mergeProps.call(this, obj) ;

   obj._angle  = this._angle ;      // gradient angle
};



/*---------------------------------------------------------------------------*/
/*   setAngle()         Set the gradient angle for linear gradients          */
/*---------------------------------------------------------------------------*/
//  Be default, the gradient angle is zero (due east).  Angles greater
// than zero rotate anti-clockwise.  Angles less than zero rotate clockwise.

/**
  * Sets the angle of the gradient in degrees.  The zero degree direction is
  * left-to-right (due east). Positive angles rotate anti-clockwise, and negative
  * angles rotate clockwise.
  * @param {number} The gradient direction in degrees.
  */
DvtLinearGradientFill.prototype.setAngle = function(degrees)
{
   if (this.isLocked()) {
     return ;
   }

   if (degrees !== 0) {
     if (Math.abs(degrees) > 360) {
       degrees %= 360 ;
     }
     this._angle = degrees ;
   }
} ;


// Copyright (c) 2008, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/*---------------------------------------------------------------------------*/
/*    DvtImageFill            Image fill definition class                    */
/*---------------------------------------------------------------------------*/
/*  Can be used to share an image fill definition among several shapes, or   */
/*  as a convenience to maintain an image fill definition separately from a  */
/*  shape.                                                                   */
/*---------------------------------------------------------------------------*/
/**
  *   Creates an image fill specification (shareable by other shapes).
  *   @extends DvtFill
  *   @class
  *   @constructor
  *   @param {String} src  image source
  *   @param {dimension} bound  bounding box (x, y, w, h).
  *   @param {String} repeat  specify how background image is repeated.
  *                           valid values: repeat-x, repeat-y, repeat, no-repeat
  */
var DvtImageFill = function(src, bound, repeat)
{
  this._Init(src, bound, repeat) ;
};


DvtObj.createSubclass(DvtImageFill, DvtFill, "DvtImageFill") ;






/**
  *   Returns the bounding box for the image fill as (x, y, w, h).
  *   @type (x, y, w, h)
  */
DvtImageFill.prototype.getBound = function()
{
   return this._bound ;
} ;

/**
  *   Returns the image source
  *   @type String
  */
DvtImageFill.prototype.getSrc = function()
{
   return this._src ;
} ;

/**
  *   Returns how the image is repeated
  *   @type String
  */
DvtImageFill.prototype.getRepeat = function()
{
   return this._repeat ;
} ;


/*---------------------------------------------------------------------------*/
/*     Init()                                                                */
/*---------------------------------------------------------------------------*/
/**
  *  @private
  */
DvtImageFill.prototype._Init = function(src, bound, repeat)
{
   DvtImageFill.superclass._Init.call(this) ;

   this._src = src ;
   this._bound = bound ;
   this._repeat = repeat ;

} ;



/*-------------------------------------------------------------------------*/
/*   mergeProps()                                                          */
/*-------------------------------------------------------------------------*/
/**
  *   Merges the image fill properties in the current object into the 
  *   supplied image fill object.
  *   Used internally by clone().
  *   @private
  */
DvtImageFill.prototype.mergeProps = function(obj)
{
   obj._src = this._src ;
   obj._bound = this._bound ;
   obj._repeat = this._repeat ;

   DvtImageFill.superclass.mergeProps.call(this) ;
};

// Copyright (c) 2011, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/*---------------------------------------------------------------------------*/
/*    DvtPatternFill            Pattern definition class                     */
/*---------------------------------------------------------------------------*/
/*  Can be used to share a pattern definition among several shapes, or as a  */
/*  convenience to maintain a pattern definition separately from a shape.    */
/*---------------------------------------------------------------------------*/
/**
  *   Creates a pattern specification (shareable by other shapes).
  *   @extends DvtFill
  *   @class
  *   @constructor
  *   @param {String} pattern  constant for the type of pattern
  *   @param {String} fillColor  color of the pattern
  *   @param {String} backgroundColor  background color of the pattern
  */
var DvtPatternFill = function(pattern, fillColor, backgroundColor)
{
   this.Init(pattern, fillColor, backgroundColor) ;
};


DvtObj.createSubclass(DvtPatternFill, DvtFill, "DvtPatternFill") ;


/**   @final @type String  */
DvtPatternFill.SM_DIAG_UP_LT      = "sDUL" ;
/**   @final @type String  */
DvtPatternFill.LG_DIAG_UP_LT      = "lDUL" ;
/**   @final @type String  */
DvtPatternFill.SM_DIAG_UP_RT      = "sDUR" ;
/**   @final @type String  */
DvtPatternFill.LG_DIAG_UP_RT      = "lDUR" ;
/**   @final @type String  */
DvtPatternFill.SM_CROSSHATCH      = "sC" ;  
/**   @final @type String  */
DvtPatternFill.LG_CROSSHATCH      = "lC" ;  
/**   @final @type String  */
DvtPatternFill.SM_CHECK           = "sCh" ; 
/**   @final @type String  */
DvtPatternFill.LG_CHECK           = "lCh" ; 
/**   @final @type String  */
DvtPatternFill.SM_TRIANGLE_CHECK  = "sTCh" ;
/**   @final @type String  */
DvtPatternFill.LG_TRIANGLE_CHECK  = "lTCh" ;
/**   @final @type String  */
DvtPatternFill.SM_DIAMOND_CHECK   = "sDCh" ;
/**   @final @type String  */
DvtPatternFill.LG_DIAMOND_CHECK   = "lDCh" ;



/*---------------------------------------------------------------------------*/
/*     Init()                                                                */
/*---------------------------------------------------------------------------*/
/**
  *  @protected
  */
DvtPatternFill.prototype.Init = function(pattern, fillColor, backgroundColor)
{
   DvtPatternFill.superclass._Init.call(this) ;

   this._pattern = (pattern ? pattern : DvtPatternFill.SM_DIAG_UP_LT) ;
   this._fillColor = (fillColor ? fillColor : "#000000");
   this._backgroundColor = (backgroundColor ? backgroundColor : "#ffffff");
} ;



/*---------------------------------------------------------------------------*/
/*     getPattern()                                                          */
/*---------------------------------------------------------------------------*/
/**
  *   Returns the type of pattern
  *   @type String
  */
DvtPatternFill.prototype.getPattern = function()
{
   return this._pattern ;
} ;



/*---------------------------------------------------------------------------*/
/*     getColor()                                                          */
/*---------------------------------------------------------------------------*/
/**
  *   Returns the color of the pattern
  *   @type String
  */
DvtPatternFill.prototype.getColor = function()
{
   return this._fillColor ;
} ;



/*---------------------------------------------------------------------------*/
/*     getBackgroundColor()                                                  */
/*---------------------------------------------------------------------------*/
/**
  *   Returns the background color of the pattern
  *   @type String
  */
DvtPatternFill.prototype.getBackgroundColor = function()
{
   return this._backgroundColor ;
} ;






/*-------------------------------------------------------------------------*/
/*   mergeProps()                                                          */
/*-------------------------------------------------------------------------*/
/**
  *   Merges the pattern properties in the current object into the supplied 
  *   pattern object.
  *   Used internally by clone().
  *   @private
  */
DvtPatternFill.prototype.mergeProps = function(obj)
{
   obj._pattern = this._pattern ;
   obj._fillColor = this._fillColor;
   obj._backgroundColor = this.backgroundColor;

   DvtPatternFill.superclass.mergeProps.call(this) ;
};

// Copyright (c) 2008, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/*---------------------------------------------------------------------------*/
/*    DvtRadialGradientFill       Radial Gradient fill class                 */
/*---------------------------------------------------------------------------*/
/**
  *   Creates a radial gradient specification (shareable by other shapes).
  *   @extends DvtGradientFill
  *   @class
  *   <p>
  *   <b>Example usage:</b><br><br><code>
  *
  *   //  Fill a circle with a radial gradient of red to green.<br><br> 
  *   circle.setFill(<b>new DvtRadialGradientFill(0, ['red', 'green]</b>) ;<br><br>
  *
  *   //  Fill rectangle with a north-east direction gradient of red to green
  *   with an unequal gradient distribution of colors.<br><br> 
  *   rect.setFill(<b>new DvtRadialGradientFill(45, ['red', 'green], [0, 0.75,1]</b>) ;<br><br>

  *   @constructor
  *   @param {number} radius 
  *   @param {Array} arColors  An array of color specifications (which do not include alpha values).
  *   @param {Array} arAlphas  An optional array of alpha values (between 0 and 1).  If omitted,
  *                            alphas of 1 are assumed.
  *   @param {Array} arStops   An optional array of stop boundary positions (between 0 and 1).
  *                            If omitted, an equal distribution of colors is assumed.
  *   @param {Number} cx       the radial gradient center x position.
  *   @param {Number} cy       the radial gradient center y position.
  *   @param {Number} r        the radius of the radial gradient.
  *   @param {Array} arBounds  An optional bounding box array (x, y, w, h).
  */
var  DvtRadialGradientFill = function(arColors, arAlphas, arStops, cx, cy, r, arBounds)
{
   this._Init(arColors, arAlphas, arStops, cx, cy, r, arBounds) ;
};

DvtObj.createSubclass(DvtRadialGradientFill, DvtGradientFill, "DvtRadialGradientFill") ;



/*---------------------------------------------------------------------------*/
/*    clone()                                                                */
/*---------------------------------------------------------------------------*/
/**
  *  Returns an (unlocked) copy of this object.
  *  @type DvtRadialGradientFill
  */
DvtRadialGradientFill.prototype.clone = function()
{
   var o = new DvtRadialGradientFill() ;

   this.mergeProps(o) ;    // merge properties into cloned obj.

   return o ;
};



/*---------------------------------------------------------------------------*/
/*    getRadius()                                                            */
/*---------------------------------------------------------------------------*/
/**
  *  Returns the radial-gradient radius.
  *  @type number
  */
DvtRadialGradientFill.prototype.getRadius = function()
{
    return this._r ;
};


/*---------------------------------------------------------------------------*/
/*    getCx()                                                                */
/*---------------------------------------------------------------------------*/
/**
  *  Returns the radial-gradient center x coordinate.
  *  @type number
  */
DvtRadialGradientFill.prototype.getCx = function()
{
    return this._cx ;
};


/*---------------------------------------------------------------------------*/
/*    getCy()                                                                */
/*---------------------------------------------------------------------------*/
/**
  *  Returns the radial-gradient center y coordinate.
  *  @type number
  */
DvtRadialGradientFill.prototype.getCy = function()
{
    return this._cy ;
};


/*---------------------------------------------------------------------------*/
/*     Init()                                                                */
/*---------------------------------------------------------------------------*/
/**
  *  @private
  */
DvtRadialGradientFill.prototype._Init = function(arColors, arAlphas, arStops, cx, cy, r, arBounds)
{
   DvtRadialGradientFill.superclass._Init.call(this, arColors, arAlphas, arStops, arBounds) ;

   this._cx = cx;
   this._cy = cy;
   this._r  = r;


} ;


/*-------------------------------------------------------------------------*/
/*   mergeProps()                                                          */
/*-------------------------------------------------------------------------*/
/**
  *   Merges the radial gradient properties in the current object into the
  *   supplied DvtRadialGradientFill object.
  *   Used internally by clone().
  *   @private
  */
DvtRadialGradientFill.prototype.mergeProps = function(obj)
{
   DvtRadialGradientFill.superclass.mergeProps.call(this, obj) ;

   obj._cx = this._cx ;
   obj._cy = this._cy ;
   obj._r  = this._r ;
};


// Copyright (c) 2011, 2012, Oracle and/or its affiliates. 
// All rights reserved. 

/**
  *   Selection effect utilities.
  *   @class DvtSelectionEffectUtils
  *   @constructor
  */
var DvtSelectionEffectUtils = {};

//SEL_TYPE_<selecting>_<selected>
/** 
 * @protected
 */
DvtSelectionEffectUtils.SEL_TYPE_STROKE_FILTERS  = 0;
/** 
 * @protected
 */
DvtSelectionEffectUtils.SEL_TYPE_STROKE_NO_FILTERS = 1;

/** 
 * @protected
 */
DvtSelectionEffectUtils.DEFAULT_SEL_TYPE        = DvtSelectionEffectUtils.SEL_TYPE_STROKE_FILTERS;

/**
 * Get the border color to use for a selectable marker when
 * the mouse hovers over it.
 * 
 * @param {String}  color  color of the data marker
 * 
 * @type String 
 */
DvtSelectionEffectUtils.getSelectingBorderColor = function(color)
{
  var r = DvtColorUtils.getRed(color) ;
  var g = DvtColorUtils.getGreen(color) ;
  var b = DvtColorUtils.getBlue(color) ;
  //var a = DvtColorUtils.getAlpha(color) ;
  
  // Converting RGB values to HSB
  var colhsv = DvtColorUtils.rgb2hsv(r, g, b);

  var hue = colhsv.h;
  // setting Saturation to 100%
  var sat = 100;//colhsv.s;
  var val = colhsv.v;
  // function adjusts the base colors HSB value 
  val = DvtSelectionEffectUtils.ModBrightness(val);

  //  it might be achieved with less conversions
  // converting back to RGB
  var colrgb = DvtColorUtils.hsv2rgb(hue, sat, val);
  //only make RGB color so that it works in Safari
  //return DvtColorUtils.makeRGBA(colrgb.r, colrgb.g, colrgb.b, a);
  return DvtColorUtils.makeRGB(colrgb.r, colrgb.g, colrgb.b);
};

/**
 * @protected
 * Modify the brightness of a color.
 * 
 * @param {number}  v  brightness (v) of an HSV color
 * 
 * @type number
 */
DvtSelectionEffectUtils.ModBrightness = function(v)
{
  var dv = 25;
  var val;
  if (v < 95)
  {
    val = 100;
  }
  else
  {
    val = v - dv;
  }
  return val;
};

/**
 * Get an array of draw effects to use to indicate selection.
 * 
 * @param {String}  selColor  color of the data marker
 * 
 * @type Array 
 */
DvtSelectionEffectUtils.createSelectionEffects = function(selColor)
{
  var selectedColor ="#000000";
  var selectingColor = this.getSelectingBorderColor(selColor);
  
  var fAlpha = 0.8;
  var fBlurX = 2;
  var fBlurY = 2;
  var fStrength = 10;
  var fQuality = 3;
  var fInner = false;
  var fKnockout = false;
  
  var arEffects = [];
  
  //m_selFilter1 = new Glow(fHiColor, fAlpha, fBlurX, fBlurY, fStrength, fQuality, fInner, fKnockout) ;
  arEffects.push(new DvtGlow(DvtColorUtils.setAlpha(selectingColor, 1), 
                             2*fBlurX, 2*fBlurY, fStrength, 
                             fQuality, true, fKnockout)) ;
  
  //m_selFilter2 = new Glow(selectedColor, fAlpha, fBlurX, fBlurY, 12, fQuality, fInner, fKnockout) ;
  arEffects.push(new DvtGlow(DvtColorUtils.setAlpha(selectedColor, 1), fBlurX, fBlurY, 12, fQuality, true, fKnockout)) ;
  
  //m_selFilter3 = new Glow(selectingColor, 0.5, 7.0, 7.0, 3, fQuality, fInner, fKnockout) ;
  //FIX BUG #12806442: fix order of arguments to DvtShadow() constructor
  //flash shadow: new Shadow(0x05283f, .7, 2, 1, 35, 10, 7);
  arEffects.push(new DvtShadow(DvtColorUtils.setAlpha("#05283f", .7), 
                               2, 10, 7, 35, 1));
  
  return arEffects;
};

/**
 * Get an array of draw effects to use to indicate selection on markers.
 * 
 * @param {DvtContext}  context  platform specific context object
 * @param {String}  selColor  color of the data marker
 * 
 * @type Array 
 */
DvtSelectionEffectUtils.createMarkerSelectionEffects = function(context, selColor)
{
  var bSvg = context.isPlatformSvg();
  
  var selectedColor = DvtColorUtils.getDarker(selColor, 0.8);
  var selectingColor = DvtColorUtils.getBrighter(selColor, 0.5);
  
  var fAlpha = 0.8;
  var fBlurX = 2;
  var fBlurY = 2;
  var fStrength = 10;
  var fQuality = 3;
  var fInner = false;
  var fKnockout = false;
  
  var midBlurX = fBlurX;
  var midBlurY = fBlurY;
  
  var outerBlurX = 7;
  var outerBlurY = 7;
  var outerStrength = 3;
  
  if (bSvg)
  {
    fBlurX = 3;
    fBlurY = 3;
    
    midBlurX = 2 * fBlurX;
    midBlurY = 2 * fBlurY;
  
    outerBlurX = 16;
    outerBlurY = 16;
    outerStrength = 6;
  }
  
  //m_selFilter1 = new Glow(fHiColor, fAlpha, fBlurX, fBlurY, fStrength, fQuality, fInner, fKnockout) ;
  var glow1 = new DvtGlow(DvtColorUtils.setAlpha("#ffffff", fAlpha), 
                          fBlurX, fBlurY, fStrength, 
                          fQuality, fInner, fKnockout) ;
  
  //m_selFilter2 = new Glow(selectedColor, fAlpha, fBlurX, fBlurY, 12, fQuality, fInner, fKnockout) ;
  var glow2 = new DvtGlow(DvtColorUtils.setAlpha(selectedColor, fAlpha), 
                          midBlurX, midBlurY, 12, 
                          fQuality, fInner, fKnockout) ;
  
  //m_selFilter3 = new Glow(selectingColor, 0.5, 7.0, 7.0, 3, fQuality, fInner, fKnockout) ;
  var glow3 = new DvtGlow(DvtColorUtils.setAlpha(selectingColor, 0.5), 
                          outerBlurX, outerBlurY, outerStrength, 
                          fQuality, fInner, fKnockout);
  
  var arEffects = [];
  //for SVG, effects overwrite each other instead of accumulating outward,
  //so need to add them in reverse order, with outermost one on bottom
  if (bSvg)
  {
    arEffects.push(glow3);
    arEffects.push(glow2);
    arEffects.push(glow1);
  }
  else
  {
    arEffects.push(glow1);
    arEffects.push(glow2);
    arEffects.push(glow3);
  }
  return arEffects;
};

/**
 * Apply a draw effect to a given displayable object.
 * 
 * @param {DvtDisplayable}  displayable  object to apply draw effect to
 * @param {DvtBaseDrawEffect}  drawEffect  effect to apply
 */
DvtSelectionEffectUtils.applyDrawEffect = function(displayable, drawEffect)
{
  if (DvtAgent.getAgent().isTouchDevice()) {
    // TODO: Change to actual effect when filters work in safari
    var stroke = new DvtSolidStroke("black", 1, 2);
    displayable.setStroke(stroke);
  } else {
    var numEffects = displayable.getNumDrawEffects();
    if (numEffects == 0) {
      displayable.addDrawEffect(drawEffect);
    } else {
      var pos = displayable.getDrawEffectIndex(drawEffect);
      if (pos > -1) {
        displayable.removeDrawEffectAt(pos);
        displayable.addDrawEffectAt(drawEffect, pos);
      } else {
        displayable.addDrawEffect(drawEffect);
      }
    }
  }
};

/**
 * Create a stroke to use when the mouse hovers over a selectable marker.
 * 
 * @param {String}  selColor  color of the data marker
 * 
 * @type DvtStroke
 */
DvtSelectionEffectUtils.createSelectingStroke = function(selColor)
{
  var selectingColor = DvtSelectionEffectUtils.getSelectingBorderColor(selColor);
  var strokeWidth = 1.5;
  var stroke = new DvtSolidStroke(selectingColor, 1, strokeWidth);
  //set low miter limit to avoid bits sticking out at corners of 3D bars,
  //for example
  stroke.setMiterLimit(1);
  return stroke;
};

/**
 * Create a fill to use for a marker selection or hover effect.
 * 
 * @param {String}  selColor  color of the data marker
 * @param {boolean}  bMouseOver  true if mouse is over the marker, false
 *        otherwise
 * @param {boolean}  bSelected  true if marker is selected, false
 *        otherwise
 * 
 * @type DvtFill
 */
DvtSelectionEffectUtils.createSelectionFill = function(selColor, bMouseOver, bSelected)
{
  var selectingColor = DvtSelectionEffectUtils.getSelectingBorderColor(selColor);
  //yellow "#ffff00"
  //cyan "#00ffff"
  //pink "#ff00ff"
  var selectedColor = "#ffff00";
  
  /*
  var selColorR = DvtColorUtils.getRed(selColor);
  var selColorB = DvtColorUtils.getBlue(selColor);
  var selColorG = DvtColorUtils.getGreen(selColor);
  
  var selectedColorR = DvtColorUtils.getRed(selectedColor);
  var selectedColorB = DvtColorUtils.getBlue(selectedColor);
  var selectedColorG = DvtColorUtils.getGreen(selectedColor);
  
  var f1 = 1;
  selectedColor = DvtColorUtils.makeRGB(
                    Math.round(f1 * selectedColorR + (1 - f1) * selColorR),
                    Math.round(f1 * selectedColorG + (1 - f1) * selColorG),
                    Math.round(f1 * selectedColorB + (1 - f1) * selColorB));
  */
  
  //var fill = new DvtSolidFill(selectingColor, 1);
  var colors;
  var alphas;
  var stops;
  var startStop = 0;
  var midStop = .5;
  var endStop = 1;
  var angle = -65;
  if (bMouseOver && bSelected)
  {
    colors = [selectedColor, selColor, selectingColor];
    alphas = [1, 1, 1];
    stops = [startStop, midStop, endStop];
  }
  else if (bMouseOver)
  {
    colors = [selColor, selectingColor];
    alphas = [1, 1];
    stops = [midStop, endStop];
  }
  else if (bSelected)
  {
    colors = [selectedColor, selColor];
    alphas = [1, 1];
    stops = [startStop, midStop];
  }
  var fill = new DvtLinearGradientFill(angle, colors, alphas, stops);
  return fill;
};

/**
 * Get the type of cursor to use when the mouse hovers over a 
 * selectable marker.
 * 
 * @type String
 */
DvtSelectionEffectUtils.getSelectingCursor = function()
{
  return "pointer";
};

/**
 * Create a radial gradient fill to use when a marker is selected.
 * 
 * @param {String}  selColor  color of the data marker
 * 
 * @type DvtFill
 */
DvtSelectionEffectUtils.createSelectedRadialGradientFill = function(selColor)
{
  var colors = [selColor, "#ffffff"];
  var alphas = [1, 1];
  var stops = [0, 1];
  var fill = new DvtRadialGradientFill(colors, alphas, stops);
  return fill;
};

DvtSelectionEffectUtils.applySelectingState = function(selectable, strokeColor)
{  
  if (selectable._bSelecting) {
      DvtSelectionEffectUtils._saveUpStrokeFill(selectable);
      var stroke = DvtSelectionEffectUtils.createSelectingStroke(strokeColor);
      selectable._savedHoverStroke = stroke;
      selectable._savedHoverFill = selectable._savedUpFill;
  } else {
      selectable._savedHoverStroke = selectable._savedUpStroke;
      selectable._savedHoverFill = selectable._savedUpFill;
  }

  switch (selectable._selectionType)
  {
    case DvtSelectionEffectUtils.SEL_TYPE_STROKE_NO_FILTERS:
      DvtSelectionEffectUtils.ApplySelectingNoFilters();
      break;
    case DvtSelectionEffectUtils.SEL_TYPE_STROKE_FILTERS:
    default:
      DvtSelectionEffectUtils.ApplySelectingFilters();
      break;
  }

  DvtSelectionEffectUtils.ApplySelectingStrokeFill(selectable);
}
/**
 * @protected
 * Apply any selection effects to this object.
 */
DvtSelectionEffectUtils.applySelectionState = function(selectable, strokeColor)
{
  if (selectable._bSelected) {
      DvtSelectionEffectUtils._saveUpStrokeFill(selectable);
  }
  
  if (selectable._bSelecting) {
      selectable._savedSelectionFill = selectable._savedHoverFill;
      selectable._savedSelectionStroke = selectable._savedHoverStroke;
  } else {
      selectable._savedSelectionFill = selectable._savedUpFill;
      selectable._savedSelectionStroke = selectable._savedUpStroke;
  }

  switch (selectable._selectionType)
  {
    case DvtSelectionEffectUtils.SEL_TYPE_STROKE_NO_FILTERS:
      DvtSelectionEffectUtils.ApplySelectionNoFilters(selectable, strokeColor);
      break;
    case DvtSelectionEffectUtils.SEL_TYPE_STROKE_FILTERS:
    default:
      DvtSelectionEffectUtils.ApplySelectionFilters(selectable, strokeColor);
      break;
  }
  
  DvtSelectionEffectUtils.ApplySelectionStrokeFill(selectable);

};

DvtSelectionEffectUtils.ApplySelectionNoFilters = function(selectable, strokeColor)
{
    if (selectable._bSelected) {
        var stroke = new DvtSolidStroke(strokeColor, 1, 1);
        selectable._savedSelectionStroke = stroke;
        var fill = new DvtSolidFill("#ffffff", 1);
        selectable._savedSelectionFill = fill;
    }
}

DvtSelectionEffectUtils.ApplySelectionFilters = function(selectable, strokeColor)
{
  if (!selectable._selectionEffects)
  {
    DvtSelectionEffectUtils.UpdateSelectionEffects(selectable, strokeColor);
  }
    if (selectable._bSelected)
    {
          if (selectable._selectionEffects)
          {
            for (var i = 0; i < selectable._selectionEffects.length; i++)
            {
              var drawEffect = selectable._selectionEffects[i];
              if (!(drawEffect instanceof DvtShadow) || selectable._bSelectedShadow)
              {
                DvtSelectionEffectUtils.applyDrawEffect(selectable, drawEffect);
              }
            }
          }
    }
    else
    {
      DvtSelectionEffectUtils.ClearSelectionEffects(selectable);
    }
}

/**
 * @protected
 * Clear any selection effects.
 */
DvtSelectionEffectUtils.ClearSelectionEffects = function(selectable)
{
  if (selectable._selectionEffects)
  {
    for (var i = 0; i < selectable._selectionEffects.length; i++)
    {
      selectable.removeDrawEffect(selectable._selectionEffects[i]);
    }
  }
};


/**
 * @protected
 * Destroy any selection effects.
 */
DvtSelectionEffectUtils.DestroySelectionEffects = function(selectable)
{
  selectable._selectionEffects = null;
};


/**
 * @protected
 * Update any selection effects.
 */
DvtSelectionEffectUtils.UpdateSelectionEffects = function(selectable, strokeColor)
{
  selectable._selectionEffects = DvtSelectionEffectUtils.createSelectionEffects(strokeColor);
};

DvtSelectionEffectUtils._saveUpStrokeFill = function(selectable)
{
    //if there is already a saved stroke, don't save again
    if (!selectable._savedUpStroke && !selectable._upStrokeSaved)
    {
      selectable._savedUpStroke = selectable.getStroke();
      selectable._upStrokeSaved = true;
    }
    //if there is already a saved fill, don't save again
    if (!selectable._savedUpFill && !selectable._upFillSaved)
    {
      selectable._savedUpFill = selectable.getFill();
      selectable._upFillSaved = true;
    }
}

DvtSelectionEffectUtils.ApplySelectingFilters = function()
{

}

DvtSelectionEffectUtils.ApplySelectingNoFilters = function()
{

}

DvtSelectionEffectUtils.ApplySelectingStrokeFill = function(selectable) {
  var transferObj = new DvtSelectionEffectTransferObj();

  var stroke = null;
  var fill = null;
  var applyStroke = false;
  var applyFill = false;
  if (selectable._bSelecting) {
      stroke = selectable._savedHoverStroke;
      applyStroke = true;
  } else {
      if (selectable._bSelected) {
          stroke = selectable._savedSelectionStroke ;
          fill = selectable._savedSelectionFill ;
          applyStroke = true;
          applyFill = true;
      } else {
          stroke = selectable._savedUpStroke ;
          fill = selectable._savedUpFill ;
          applyStroke = true;
          applyFill = true;
      }
  }  
  transferObj._fill = fill;
  transferObj._stroke = stroke;
  transferObj._applyStroke = applyStroke;
  transferObj._applyFill = applyFill;
  
  DvtSelectionEffectUtils.PerformStrokeFillUpdate(selectable, transferObj, true);
}

DvtSelectionEffectUtils.ApplySelectionStrokeFill = function(selectable) {
  var transferObj = new DvtSelectionEffectTransferObj();

  var stroke = null;
  var fill = null;
  var applyStroke = false;
  var applyFill = false;

  if (selectable._bSelected) {
      stroke = selectable._savedSelectionStroke;
      fill = selectable._savedSelectionFill;
      applyStroke = true;
      applyFill = true;
  } else {
      if (selectable._bSelecting) {
          stroke = selectable._savedHoverStroke ;
          fill = selectable._savedHoverFill ;
          applyStroke = true;
          applyFill = true;
      } else {
          stroke = selectable._savedUpStroke ;
          fill = selectable._savedUpFill ;
          applyStroke = true;
          applyFill = true;
      }
  }
  transferObj._fill = fill;
  transferObj._stroke = stroke;
  transferObj._applyStroke = applyStroke;
  transferObj._applyFill = applyFill;

  DvtSelectionEffectUtils.PerformStrokeFillUpdate(selectable, transferObj, true);
}

DvtSelectionEffectUtils.PerformStrokeFillUpdate = function(selectable, transferObj, allowTimeout) {
  transferObj._selectable = selectable;
  if (allowTimeout && selectable.getContext().getDocumentUtils().isStrokeTimeoutRequired()) {
      //TODO: either figure out a better way to handle this,
      //or only do the defer if in Chrome and rendering to SVG
      //deferring the setStroke call because in Chrome setting
      //the stroke at the same time as changing z-order results
      //in the new stroke not being displayed

      //if there is an existing saved timer, stop and clear it
      if (selectable._applyStrokeTimer)
      {
        selectable._applyStrokeTimer.stop();
        selectable._applyStrokeTimer = null;
      }
      selectable._applyStrokeTimer = new DvtTimer(selectable.getContext(), 0, transferObj.applyStrokeFill, transferObj, 1);
      transferObj._timer = selectable._applyStrokeTimer ;
      selectable._applyStrokeTimer.start();
  } else {
      transferObj.applyStrokeFill();
  }
}

/*
 * Temporary object used to apply the stroke and fill to the selectable object 
*/
var   DvtSelectionEffectTransferObj = function()
{
};  

DvtObj.createSubclass(DvtSelectionEffectTransferObj, DvtObj, "DvtSelectionEffectTransferObj");


DvtSelectionEffectTransferObj.prototype.applyStrokeFill = function() {
    if (this._applyStroke)
        this._selectable.setStroke(this._stroke);
    if (this._applyFill)
        this._selectable.setFill(this._fill);
          //clear the saved timer that called this func
    if (this._timer) {
        this._timer.stop();
        this._timer = null;
    }
    if (this._selectable) {
        this._selectable.getContext().getDocumentUtils().fixWebkitFiltersForDisplayable(this._selectable);
    }
}

// Copyright (c) 2011, 2012, Oracle and/or its affiliates. 
// All rights reserved. 

/**
  *  Creates a matrix object.
  *  @extends DvtObj
  *  @class DvtMatrix is a platform independent class representing a transformation
  *  matrix.  
  *  <p>
  *  The matrix is in the form:<br>
  *  [ a  b  tx ]<br>
  *  [ c  d  ty ]<br>
  *  [ 0  0  1  ]<br>
  *  <p>
  *  <b>Example:</b><br><br> <code>
  *  var mat = new DvtMatrix(context) ;<br>
  *  mat.translate(15, 30) ;<br>
  *</code>
  *  @constructor  
  *  @param {DvtContext}  context  the platform specific context
  */
var DvtMatrix = function(context)
{
  //don't allow users to set individual elements, because we
  //may need to adjust transforms for different platforms, for
  //example if the angle of rotation increases in different 
  //directions on different platforms, and we don't want to try
  //to deconstruct the matrix
  //this.Init(a, b, c, d, tx, ty);
  this.Init(context);
};

DvtObj.createSubclass(DvtMatrix, DvtLockable, "DvtMatrix");

//   [ a  b  tx ]
//   [ c  d  ty ]
//   [ 0  0  1  ]

/** 
  *  @private
  */
DvtMatrix._DECOMP_TX = 0;
/** 
  *  @private
  */
DvtMatrix._DECOMP_TY = 1;
/** 
  *  @private
  */
DvtMatrix._DECOMP_R = 2;
/** 
  *  @private
  */
DvtMatrix._DECOMP_SKEWX = 3;
/** 
  *  @private
  */
DvtMatrix._DECOMP_SX = 4;
/** 
  *  @private
  */
DvtMatrix._DECOMP_SY = 5;

//don't allow users to set individual elements, because we
//may need to adjust transforms for different platforms, for
//example if the angle of rotation increases in different 
//directions on different platforms, and we don't want to try
//to deconstruct the matrix
//DvtMatrix.prototype.Init = function(a, b, c, d, tx, ty)
/** 
  *  @protected
  */
DvtMatrix.prototype.Init = function(context)
{
  this.Identity();

  this._u = 0;
  this._v = 0;
  this._w = 1;

  this._context = context;
  
  DvtMatrix.superclass._Init.call(this) ;
};

/**
  *  @protected
  *  Make this matrix the identity matrix.
  */
DvtMatrix.prototype.Identity = function()
{
  this._a = 1;
  this._b = 0;
  this._c = 0;
  this._d = 1;
  this._tx = 0;
  this._ty = 0;
};

/**
  *  Get the A element of this matrix.
  *  @returns {Number}  The A element of this matrix.
  */
DvtMatrix.prototype.getA = function()
{
  return this._a;
};

/**
  *  Get the B element of this matrix.
  *  @returns {Number}  The B element of this matrix.
  */
DvtMatrix.prototype.getB = function()
{
  return this._b;
};

/**
  *  Get the C element of this matrix.
  *  @returns {Number}  The C element of this matrix.
  */
DvtMatrix.prototype.getC = function()
{
  return this._c;
};

/**
  *  Get the D element of this matrix.
  *  @returns {Number}  The D element of this matrix.
  */
DvtMatrix.prototype.getD = function()
{
  return this._d;
};

/**
  *  Get the TX element of this matrix.
  *  @returns {Number}  The TX element of this matrix.
  */
DvtMatrix.prototype.getTx = function()
{
  return this._tx;
};

/**
  *  Get the TY element of this matrix.
  *  @returns {Number}  The TY element of this matrix.
  */
DvtMatrix.prototype.getTy = function()
{
  return this._ty;
};

/**
  *  Clone this matrix.
  *  @returns {DvtMatrix}  A clone of this matrix.
  */
DvtMatrix.prototype.clone = function()
{
  var mat = new DvtMatrix(this._context);
  mat._a = this._a;
  mat._b = this._b;
  mat._c = this._c;
  mat._d = this._d;
  mat._tx = this._tx;
  mat._ty = this._ty;
  return mat;
};



/**
  *  Concatenate the given matrix with this matrix.
  *  @param {DvtMatrix} mat   The matrix to concatenate with this matrix.
  */
DvtMatrix.prototype.concat = function(mat)
{
  // A * B = B.concat(A) = childMatrix.concat(parentMatrix)
  
  if (this.isLocked())
  {
    return;
  }
  
  var newA = this._a * mat._a + this._c * mat._b + this._u * mat._tx;
  var newB = this._b * mat._a + this._d * mat._b + this._v * mat._tx;
  var newTX = this._tx * mat._a + this._ty * mat._b + this._w * mat._tx;
  
  var newC = this._a * mat._c + this._c * mat._d + this._u * mat._ty;
  var newD = this._b * mat._c + this._d * mat._d + this._v * mat._ty;
  var newTY = this._tx * mat._c + this._ty * mat._d + this._w * mat._ty;
  
  //var newU = this._a * mat._u + this._c * mat._v + this._u * mat._w;
  //var newV = this._b * mat._u + this._d * mat._v + this._v * mat._w;
  //var newW = this._tx * mat._u + this._ty * mat._v + this._w * mat._w;
  
  this._a = newA;
  this._b = newB;
  this._c = newC;
  this._d = newD;
  this._tx = newTX;
  this._ty = newTY;
};

/**
  *  Translate this matrix.
  *  @param {Number} dx   The horizontal distance to translate by, in pixels.
  *  @param {Number} dy   The vertical distance to translate by, in pixels.
  */
DvtMatrix.prototype.translate = function(dx, dy)
{
  if (this.isLocked())
  {
    return;
  }
  
  var tMat = new DvtMatrix(this._context);
  tMat._tx = dx;
  tMat._ty = dy;
  
  this.concat(tMat);
};

/**
  *  Scale this matrix.
  *  @param {Number} sx   The horizontal value to scale by.
  *  @param {Number} sy   The vertical value to scale by.
  */
DvtMatrix.prototype.scale = function(sx, sy)
{
  if (this.isLocked())
  {
    return;
  }
  
  var tMat = new DvtMatrix(this._context);
  tMat._a = sx;
  tMat._d = sy;
  
  this.concat(tMat);
};

/**
  *  Rotate this matrix.
  *  @param {Number} angleRads   The angle to rotate by, in radians.
  */
DvtMatrix.prototype.rotate = function(angleRads)
{
  if (this.isLocked())
  {
    return;
  }
  
  var tMat = new DvtMatrix(this._context);
  tMat._a = Math.cos(angleRads);
  tMat._d = tMat._a;
  tMat._c = Math.sin(angleRads);
  tMat._b = -tMat._c;
  
  this.concat(tMat);
};

/**
  *  Skew this matrix.
  *  @param {Number} sxRads   The horizontal angle to skew by, in radians.
  *  @param {Number} syRads   The vertical angle to skew by, in radians.
  */
DvtMatrix.prototype.skew = function(sxRads, syRads)
{
  if (this.isLocked())
  {
    return;
  }
  
  var tMat = new DvtMatrix(this._context);
  tMat._b = Math.tan(sxRads);
  tMat._c = Math.tan(syRads);
  
  this.concat(tMat);
};

/**
  *  @protected
  *  Calculate the determinant of this matrix.
  *  @return {number} determinant of this matrix
  */
DvtMatrix.prototype.Determinant = function()
{
  var determinant = this._a * (this._d * this._w - this._ty * this._v) - 
                    this._b * (this._c * this._w - this._ty * this._u) + 
                    this._tx * (this._c * this._v - this._d * this._u);
  return determinant;
};

/**
  *  Invert this matrix.
  */
DvtMatrix.prototype.invert = function()
{
  if (this.isLocked())
  {
    return;
  }
  
  var determinant = this.Determinant();
  var A = (this._d * this._w - this._ty * this._v);
  var B = (this._tx * this._v - this._b * this._w);
  var TX = (this._b * this._ty - this._tx * this._d);
  var C = (this._ty * this._u - this._c * this._w);
  var D = (this._a * this._w - this._tx * this._u);
  var TY = (this._tx * this._c - this._a * this._ty);
  //var U = (this._c * this._v - this._d * this._u);
  //var V = (this._b * this._u - this._a * this._v);
  //var W = (this._a * this._d - this._b * this._c);
  
  this._a = A / determinant;
  this._b = B / determinant;
  this._tx = TX / determinant;
  this._c = C / determinant;
  this._d = D / determinant;
  this._ty = TY / determinant;
  //this._u = U / determinant;
  //this._v = V / determinant;
  //this._w = W / determinant;
};

/**
  *  @private
  *  Decompose this matrix into its constituent transforms.
  *  @returns {Array} array of transform values in the form
  *           [translateX, translateY, rotationRadians, skewXRadians, scaleX, scaleY],
  *           of null if decomposition doesn't exist
  */
DvtMatrix.prototype._decompose = function()
{
  var A = this._a;
  var B = this._b;
  var C = this._c;
  var D = this._d;
  var Tx = this._tx;
  var Ty = this._ty;
  
  if (A * D - B * C === 0)
    return null;
  
  //x scale factor
  var Sx = Math.sqrt(A * A + C * C);
  A = A / Sx;
  C = C / Sx;
  
  //xy shear
  var K = A * B + C * D;
  B = B - A * K;
  D = D - C * K;
  
  //y scale factor
  var Sy = Math.sqrt(B * B + D * D);
  B = B / Sy;
  D = D / Sy;
  K = K / Sy;
  
  var determinant = A * D - B * C;
  if (determinant === -1)
  {
    K = -K;
    Sy = -Sy;
  }
  
  //rotation
  var R = Math.atan2(C, A);
  
  //skew
  var skewX = Math.atan(K);
  
  //to create new matrix with same transforms, use order:
  //1) scale(Sx, Sy)
  //2) skew(skewX, 0);
  //3) rotate(R);
  //4) translate(Tx, Ty);
  return [Tx, Ty, R, skewX, Sx, Sy];
};

/**
  *  @private
  *  Recompose this matrix from the given decomposition.
  *  @param {Array}  arDecomposition  array of transform values returned from 
  *         calling decompose()
  */
DvtMatrix.prototype._recompose = function(arDecomposition)
{
  if (this.isLocked())
  {
    return;
  }
  
  this.Identity();
  
  var Tx = arDecomposition[0];
  var Ty = arDecomposition[1];
  var R = arDecomposition[2];
  var skewX = arDecomposition[3];
  var Sx = arDecomposition[4];
  var Sy = arDecomposition[5];
  
  this.scale(Sx, Sy);
  this.skew(skewX, 0);
  this.rotate(R);
  this.translate(Tx, Ty);
};

/**
  *  @private
  *  Determine whether this matrix is equal to another.
  *  @param {DvtMatrix} mat   The matrix to compare with this matrix.
  *  @return {Boolean} True if equal, false if not.
  */
DvtMatrix.prototype.equals = function(mat) {
    if (!this && mat) return false;
    else if (this && !mat) return false;
    else if (!this && !mat) return true;
    else return (this._a == mat._a && this._b == mat._b && this._c == mat._c &&
            this._d == mat._d && this._tx == mat._tx && this._ty == mat._ty);
};

/**
 * Transform a point using this matrix.
 * @param {DvtPoint}  p  point to transform
 * @type DvtPoint
 */
DvtMatrix.prototype.transformPoint = function(p)
{
  var newX = this._a * p.x + this._b * p.y + this._tx * 1;
  var newY = this._c * p.x + this._d * p.y + this._ty * 1;
  return new DvtPoint(newX, newY);
};

// Copyright (c) 2008, 2012, Oracle and/or its affiliates. 
// All rights reserved. 

/**
  *  Defines an (x,y) coordinate.
  *  @class DvtPoint
  *  @extends DvtObj
  *  @constructor
  *  @param {number} x
  *  @param {number} y
  */

var DvtPoint = function(x,y)
{
  this.Init(x, y);
};


DvtObj.createSubclass(DvtPoint, DvtObj, "DvtPoint");

DvtPoint.prototype.Init = function(x, y)
{
  this.x = (x || 0) ;
  this.y = (y || 0) ;
}

// Copyright (c) 2008, 2012, Oracle and/or its affiliates. 
// All rights reserved. 

/**
  *  Defines the geometry of a rectangle. Top-left (x,y), and width and height.
  *  @class DvtRectangle
  *  @extends DvtObj
  *  @constructor
  *  @param {number} x
  *  @param {number} y
  *  @param {number} w
  *  @param {number} h
  *  @type {DvtRectangle}
  */
var   DvtRectangle = function(x,y,w,h)
{
  this.x = (x || 0) ;
  this.y = (y || 0) ;
  this.w = (w || 0) ;
  this.h = (h || 0) ;
};

DvtObj.createSubclass(DvtRectangle, DvtObj, "DvtRectangle");


/**
 * Creates a new DvtRectangle from an array of coordinates.
 * @param {Array} ar  an array of rectangle coordinates, where x = ar[0], y = ar[1], w = ar[2], h = ar[3].
 * @returns  {DvtRectangle}
 */ 
DvtRectangle.create = function (ar)
{
  return new DvtRectangle (ar[0], ar[1], ar[2], ar[3]);
};


/**
 * Returns true if the rectangle contains the given point.
 */ 
DvtRectangle.prototype.containsPoint = function(nX, nY) 
{
   return (nX >= this.x && nX <= this.x + this.w && nY >= this.y && nY <= this.y + this.h);
};


DvtRectangle.prototype.getCenter = function ()
{
  return new DvtPoint(this.x + (this.w / 2.0), this.y + (this.h / 2.0));
};



/**
 * Returns the union of this and the supplied rectangle.
 * @param {DvtRectangle}  rect  the supplied rectangle.
 * @returns {DvtRectangle} a new rectangle that is the union of this and the supplied rectangle.
 */ 
DvtRectangle.prototype.getUnion = function(rect) 
{
   var  u = new DvtRectangle() ;

   if (rect && rect.w !== 0 && rect.h !== 0) {  // ignore zero size rect's
     if (this.w !== 0 && this.h !== 0) {        //  ..     ..   ..    ..
       var  thisR = this.x + this.w ;             // this right
       var  thisB = this.y + this.h ;             // this bottom
       var  rectR = rect.x + rect.w ;             // rect right
       var  rectB = rect.y + rect.h ;             // rect bottom

       var  minx  = Math.min(this.x, rect.x) ;
       var  miny  = Math.min(this.y, rect.y) ;

       u.w = (thisR < rectR)? (rectR - minx) : (thisR - minx) ;
       u.h = (thisB > rectB)? (thisB - miny) : (rectB - miny) ;
       u.x = minx ;
       u.x = miny ;
     }
     else {
      u.x = rect.x ;
      u.y = rect.y ;
      u.w = rect.w ;
      u.h = rect.h ;
     }
   }
   else  {
      u.x = this.x ;
      u.y = this.y ;
      u.w = this.w ;
      u.h = this.h ;
   }

   return u ;
};

/**
 * Grow this rectangle to include the given coordinates.
 * @param {number}  xx  x coordinate
 * @param {number}  yy  y coordinate
 */ 
DvtRectangle.prototype.grow = function(xx, yy) 
{
  var minX = this.x;
  var minY = this.y;
  var maxX = this.x + this.w;
  var maxY = this.y + this.h;
  
  if (xx < minX) {
    minX = xx;
  }
  if (xx > maxX) {
    maxX = xx;
  }
  if (yy < minY) {
    minY = yy;
  }
  if (yy > maxY) {
    maxY = yy;
  }
  this.x = minX;
  this.y = minY;
  this.w = maxX - minX;
  this.h = maxY - minY;
};

/**
 * Returns true if the rectangle intersectes the supplied rectangle.
 * @param {DvtRectangle}  rect  the supplied rectangle.
 */ 
DvtRectangle.prototype.intersects = function(rect) 
{
   if (rect && rect.w !== 0 && rect.h !== 0) {  // ignore zero size rect's
     if (this.w !== 0 && this.h !== 0) {        //  ..     ..   ..    ..
       var  thisR = this.x + this.w ;             // this right
       var  thisB = this.y + this.h ;             // this bottom
       var  rectR = rect.x + rect.w ;             // rect right
       var  rectB = rect.y + rect.h ;             // rect bottom

       return !(rect.x > thisR || rectR < this.x || rect.y > thisB || rectB < this.y);
     }
  }
  return false;
};

// Copyright (c) 2008, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/*-------------------------------------------------------------------------*/
/*  DvtGeomUtils()       Utility geometry functions                        */
/*-------------------------------------------------------------------------*/

var DvtGeomUtils = {} ;

DvtGeomUtils.getCenterPoint = function (rect) {
    return new DvtPoint(rect.x+rect.w/2, rect.y+rect.h/2);
}

DvtGeomUtils.intersects = function (rect1, rect2) {
    if (rect1.x > rect2.x + rect2.w || rect1.x + rect1.w < rect2.x || rect1.y > rect2.y + rect2.h || rect1.y + rect1.h < rect2.y)
        return false;
    return true;
}

DvtGeomUtils.getPaddedRectangle = function (rect, buffer) {
    return DvtGeomUtils.getSpecificPaddedRectangle(rect, buffer, buffer, buffer, buffer);
}

DvtGeomUtils.getSpecificPaddedRectangle = function (rect, bufferTop, bufferBottom, bufferLeft, bufferRight) {
    return new DvtRectangle(rect.x - bufferLeft, rect.y - bufferTop, rect.w + bufferLeft + bufferRight, rect.h + bufferTop + bufferBottom);
}

DvtGeomUtils.GetOffsetValues = function(objBounds, containerBounds, padding) {
    var offsetY = 0;
    var lowerY = objBounds.y;
    var higherY = objBounds.y + objBounds.h;     
    if (lowerY < padding) {
        offsetY += padding - lowerY;
    } else if (higherY > containerBounds.h - padding) {
        offsetY += containerBounds.h - padding - higherY;
    }

    // Adjust position of box depending on stage bounds    
    var lowerX = objBounds.x;
    var higherX = objBounds.x + objBounds.w;     

    var offsetX = 0;
    if (lowerX < padding) {
        offsetX += padding - lowerX;
    } else if (higherX > containerBounds.w - padding) {
        offsetX += containerBounds.w - padding - higherX;
    }
    return {offsetX: offsetX, offsetY: offsetY};
}
// Copyright (c) 2008, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/*-------------------------------------------------------------------------*/
/*  DvtLineUtils()       Utility functions for lines                       */
/*-------------------------------------------------------------------------*/

var DvtLineUtils = {} ;

/**
 * Computes the point of intersection of two lines in the same plane.
 * @param   {DvtPoint} p1 end point on line 1
 * @param   {DvtPoint} p2 other end point on line 1
 * @param   {DvtPoint} p3 end point on line 2
 * @param   {DvtPoint} p4 other end point on line 2
 * @param   {DvtPoint} pt optional DvtPoint object that will be updated with the
 *                     point of intersection.  If omitted, a new DvtPoint will be created
 *                     and returned.
 * @returns {DvtPoint} the point of intersection. If null is returned, then either
 *                     the lines are parallel, or both of the lines have a zero length.
 */
DvtLineUtils.intersect2Lines = function(p1, p2, p3, p4, pt)
{
   //  Using Penner's Method

   var x1  = p1.x; 
   var y1  = p1.y;
   var x4  = p4.x;
   var y4  = p4.y;
   var dx1 = p2.x - x1;            // the x diff
   var dx2 = p3.x - x4;            //  .. ..  ..

   if (dx1 === 0 && dx2 === 0)     // both lines vertical? (i.e. undefined slope)
     return null ;

   var m1 = (p2.y - y1) / dx1;
   var m2 = (p3.y - y4) / dx2;

   if (m1 === m2)                  // both lines parallel?
     return null ;

   if (! pt) {
     pt =  new DvtPoint() ;        // return value
   }

   if (dx1 === 0) {
     pt.x = x1 ;
     pt.y = (m2 * (x1 - x4) + y4) ;
     return pt ;
   }
   else if (dx2 === 0) {
     pt.x = x4 ;
     pt.y = (m1 * (x4 - x1) + y1) ;
     return pt ;
   }

   var xInt  = (-m2 * x4 + y4 + m1 * x1 - y1) / (m1 - m2);
   var yInt  = m1 * (xInt - x1) + y1;

   pt.x = xInt ;
   pt.y = yInt ;
   return pt ;
} ;


/**
  * Returns the length of a line segment with end points (x1, y1) and (x2, y2).
  * @param {number} x1  endpoint x
  * @param {number} y1  endpoint y
  * @param {number} x2  other endpoint x
  * @param {number} y2  other endpoint y
  * @returns {number}   the length of the line segment with end points (x1, y1) and (x2, y2).
  */
DvtLineUtils.lineLen = function(x1, y1, x2, y2)
{
   var dx = (x2 - x1) ;
   var dy = (y2 - y1) ;
   return Math.sqrt((dx * dx) + (dy * dy)) ;
};


/**
* Returns the midpoint (x,y) of a line segment with end points (x1,y1) and (x2,y2).
* @param {number}   x1 end point x.
* @param {number}   y1 end point y.
* @param {number}   x2 other end point x
* @param {number}   y2 other end point y.
* @param {DvtPoint} pt optional DvtPoint object that will be updated with the mid-point.
*                   If omitted, a new DvtPoint will be created.
* @returns (DvtPoint} the midpoint (x,y) of the line segment in the supplied DvtPoint,
*                     or a new DvtPoint if not supplied.
*/
DvtLineUtils.midPt = function(x1, y1, x2, y2, pt)
{
   if (! pt) {
     pt = new DvtPoint() ; 
   }
   pt.x  =  (x1 + x2)/2 ;
   pt.y  =  (y1 + y2)/2 ;
   return pt ;
};


/**
 *  A static class for chart layout.
 *  @class DvtLayoutUtils
 *  @constructor
*/
var DvtLayoutUtils = function()
{};

/**
 * Positions the specified displayable in the available space.
 * @param {DvtRectangle} availSpace The available space.
 * @param {string} position The position within the available space.  Valid values are "top", "bottom", "left", and "right".
 * @param {DvtDisplayable} displayable The displayable to be positioned.
 * @param {number} width The width of the displayable.
 * @param {number} height The height of the displayable.
 * @param {number} gap The gap to leave between the displayable and other content.  This gap is applied only if
 *                     the displayable's area is greater than 0.
 */
DvtLayoutUtils.position = function(availSpace, position, displayable, width, height, gap) {
  if(!displayable)
    return;
    
  // Adjust the gap if the displayable has no area
  gap = (width*height > 0) ? gap : 0;
  
  if(position == "top") {
    displayable.setTranslateX(availSpace.x + availSpace.w/2 - width/2);
    displayable.setTranslateY(availSpace.y);
    availSpace.y += (height + gap);
    availSpace.h -= (height + gap);
  }
  else if(position == "bottom") {
    displayable.setTranslateX(availSpace.x + availSpace.w/2 - width/2);
    displayable.setTranslateY(availSpace.y + availSpace.h - height);
    availSpace.h -= (height + gap);
  }
  else if(position == "left") {
    displayable.setTranslateX(availSpace.x);
    displayable.setTranslateY(availSpace.y + availSpace.h/2 - height/2);
    availSpace.x += (width + gap);
    availSpace.w -= (width + gap);
  }
  else if(position == "right") {
    displayable.setTranslateX(availSpace.x + availSpace.w - width);
    displayable.setTranslateY(availSpace.y + availSpace.h/2 - height/2);
    availSpace.w -= (width + gap);
  }
}

/**
 * Aligns the specified displayable in the available space.
 * @param {DvtRectangle} availSpace The available space.
 * @param {string} position The position within the available space.  Valid values are "start", "center", and "end".
 * @param {DvtDisplayable} displayable The displayable to be positioned.
 * @param {number} width The width of the displayable.
 */
DvtLayoutUtils.align = function(availSpace, align, displayable, width) {
  if(!displayable)
    return;
    
  // Account for the locale and find the position  
  var position = align;
  if(position == "start")
    position = DvtStyleUtils.isLocaleR2L() ? "right" : "left";
  else if(position == "end")
    position = DvtStyleUtils.isLocaleR2L() ? "left" : "right";
    
  // Align the text  
  if(position == "left") 
    displayable.setX(availSpace.x);
  else if(position == "center") 
    displayable.setX(availSpace.x + availSpace.w/2 - width/2);
  else if(position == "right") 
    displayable.setX(availSpace.x + availSpace.w - width);
}

/**
 * Sets text anchor on a text object to start in normal mode and adjusts accordingly for BIDI mode depending on browser.
 * @param {DvtText} text The object to align
 */
DvtLayoutUtils.alignTextStart = function(text) {
  var isBIDI = DvtStyleUtils.isLocaleR2L();
  var agent = DvtAgent.getAgent();
  if (agent.isGecko() || !isBIDI)
    text.alignStart();
  else 
    text.alignEnd();
}

/**
 * Sets text anchor on a text object to end in normal mode and adjusts accordingly for BIDI mode depending on browser.
 * @param {DvtText} text The object to align
 */
DvtLayoutUtils.alignTextEnd = function(text) {
  var isBIDI = DvtStyleUtils.isLocaleR2L();
  var agent = DvtAgent.getAgent();
  if (agent.isGecko() || !isBIDI)
    text.alignEnd();
  else 
    text.alignStart();
}
// Copyright (c) 2008, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/*--------------------------------------------------------------------------*/
/*   DvtMath             Miscellaneous Math constants and routines          */
/*--------------------------------------------------------------------------*/
/**
  *  @class DvtMath  Defines miscellaneous math constants and routines.
  */
var  DvtMath = new Object();

/**
  *  Number of radians in 1 degree.
  *  @type number
  */
DvtMath.RADS_PER_DEGREE = (Math.PI/180) ;
/**
  *  Number of degrees in 1 radian.
  *  @type number
  */
DvtMath.DEGREES_PER_RAD = (180/Math.PI) ;
/**
  *  Half the value of Pi radians.
  *  @type number
  */
DvtMath.HALF_PI  = (Math.PI/2) ;
/**
  *  One quarter the value of Pi radians.
  *  @type number
  */
DvtMath.QUARTER_PI  = (Math.PI/4); 

/**
 *   Converts degrees to radians.
 *   @param {number}  deg  The value in degrees to be converted. 
 *   @type number
 */
DvtMath.degreesToRads = function(deg)
{
   return (deg * DvtMath.RADS_PER_DEGREE);
};

/**
 *   Converts radians to degrees.
 *   @param {number}  rad  The valie in radians to be converted. 
 *   @type number
 */
DvtMath.radsToDegrees = function(rad)
{
   return (rad * DvtMath.DEGREES_PER_RAD);
};

/**
  * Interpolate a number between the original and destination values for the 
  * given percent.
  * @param {number}  origVal  original value
  * @param {number}  destVal  destination value
  * @param {number}  percent  percent value to interpolate
  * @type number
  */
DvtMath.interpolateNumber = function(origVal, destVal, percent)
{
  return (origVal + percent * (destVal - origVal));
};

/**
 * property map
 */
var DvtPropMap = function() {
  this.Init();
};

DvtPropMap.REGEXP = new RegExp("#\\{([^\\}]*)\\}", "g");


/**
 * make DvtPropMap a subclass of DvtObj
 */
DvtObj.createSubclass(DvtPropMap, DvtObj, "DvtPropMap");


/**
 * Initializes the instance. 
 */
DvtPropMap.prototype.Init = function() {
  //Note: there is no Init method in superclass
  // DvtPropMap.superclass.Init.call(this);
  this._props = {};
};


/*-------------------------------------------------------------------------*/
/*   AfComponent propibutes                                                */
/*-------------------------------------------------------------------------*/
DvtPropMap.prototype.getProperty = function(propName) {
  return this._props[propName];
};

DvtPropMap.prototype.setProperty = function(propName, val) {
  this._props[propName] = val;
};


DvtPropMap.prototype.getStringProp = function(propName, defString) {
  var val = this._props[propName];
  return val ? val : defString;
};

DvtPropMap.prototype.getBooleanProp = function(propName, defBool) {
  var val = this._props[propName];
  if (val) {
    return (val == "true");
  }
  return defBool;
};

DvtPropMap.prototype.getIntegerProp = function(propName, defInt) {
  var val = this._props[propName];
  var ret;
  if (val)
    ret = parseInt(val);
  return (ret) ? ret : defInt;
};

DvtPropMap.prototype.getFloatProp = function(propName, defFloat) {
  var val = this._props[propName];
  var ret;
  if (val)
    ret = parseFloat(val);
  return (ret) ? ret : defFloat;
};

/**
 * Returns the id of this component.
 * @type String
 */
DvtPropMap.prototype.getId = function() {
  return this.getProperty("id");
};

/**
 * Set the id of this component.
 * @param {String} id  ID for the component
 */
DvtPropMap.prototype.setId = function(id) {
  this.setProperty("id", id);
};

/**
 * set a list of properties
 * @param {NamedNodeMap} attributes array
 */
DvtPropMap.prototype.setProperties = function(attrArray) {
  for (var i = 0; i < attrArray.length; i++) {
    var attr = attrArray[i];
    if (attr.name && attr.value !== undefined) {
      this.setProperty(attr.name, attr.value);
    }
  }
};


/*-------------------------------------------------------------------------*/
/*   stamp                                                                 */
/*-------------------------------------------------------------------------*/

/**
 * Stamp out this template object only. 
 * @param {} elcontext EL binding context
 * @return {DvtAfComponent} a new DvtAfComponent tree
 */
DvtPropMap.prototype.stamp = function(elcontext) {

  // create a new DvtAfComponent object of the same type
  var result = new this.constructor();

  // copy properties
  var newProps = {};
//   var regexp = /#{([^\}]*)}/g;
  for (var attr in this._props) {
    //TODO: test for string
    if (this._props[attr].replace) {
        newProps[attr] = this._props[attr].replace(DvtPropMap.REGEXP, 
          function(str, bindVar) {
            if (elcontext && elcontext[bindVar] !== undefined) {
              return elcontext[bindVar];
            }
            return str;
          }
        );
    } else {
        newProps[attr] = this._props[attr];
    }
  }

  result._props = newProps;
  return result;
};


/**
 * Convert an attribute array of a EL node to an EL context object
 * @param {DvtXmlNode} xmlNode The EL xml node
 */
DvtPropMap.toELContext = function(xmlNode) {
  var arr = xmlNode.getAttributes();
  var prop;
  var obj = {};
  for (var i = 0; i < arr.length; i++) {
    prop = arr[i];
    obj[prop.name] = prop.value;
  }
  return obj;
}


/**
 * @usage
 * DvtGoLink.goLink("http://www.oracle.com", "_self");
 */
var DvtGoLink = new Object();

/**
 *  Navigates directly to the location given in the destination
 *  @param {DvtContext} context The context object
 *  @param {DvtShape}  shape  The text or image shape of the link
 *  @param {destination}  dest  The url of the link
 *  @param {targetFrame}  frame The target frame for the form.
 */
DvtGoLink.addLink = function(context, shape, dest, frame)
{
  var linkImpl = context.getImplFactory().getGoLink();
  linkImpl.addLink(shape, dest, frame);

};


// Copyright (c) 2008, 2012, Oracle and/or its affiliates. 
// All rights reserved. 

/**
 * @usage
 * DvtImageLoader.loadImage("pic.png", function(image) {
 *   alert(image.width);
 *   alert(image.height);
 * });
 * 
 */


/**
 * DvtImageLoader
 */
var DvtImageLoader = {};


/**
 * Load an image.
 * 
 * @param {DvtContext} context The context object
 * @param src URL of the image to load
 * @param onComplete function to call when the image is loaded
 * 
 * @return image if image is already loaded and onComplete
 *         function is null, otherwise null
 */
DvtImageLoader.loadImage = function(context, src, onComplete) {

  var loader = context.getImplFactory().getImageLoader();
  return loader.loadImage(src, onComplete);

};



/**
 * JSON utilities.
 * @class
 */
var DvtJSONUtils = new Object();

DvtObj.createSubclass(DvtJSONUtils, DvtObj, "DvtJSONUtils");

/**
 * Returns a deep clone of the object.
 * @param {object} obj The object to clone.
 * @return {object} The clone.
 */
DvtJSONUtils.clone = function(obj) {
  var ret = null;
  
  if(obj instanceof Array) {
    ret = [];
    
    // Loop through and copy the Array
    for(var i=0; i<obj.length; i++) {
      if(DvtJSONUtils._isDeepClonable(obj[i])) // deep clone objects
        ret[i] = DvtJSONUtils.clone(obj[i]);
      else // copy values
        ret[i] = obj[i];
    }
  }
  else if(obj instanceof Object) {
    ret = {};
    
    // Loop through all properties of the object
    var key;
    for(key in obj) {
      var value = obj[key];
      if(DvtJSONUtils._isDeepClonable(value)) // deep clone objects
        ret[key] = DvtJSONUtils.clone(value);
      else // copy values
        ret[key] = value;
    }
  }
  
  return ret;
}

/**
 * Returns a new object with the merged properties of the given objects.  Properties
 * in the first object take precedence.
 * @param {object} a
 * @param {object} b
 * @return {object} A new object containing the merged properties.
 */
DvtJSONUtils.merge = function(a, b) {
  // Clone so that contents aren't modified
  var one = DvtJSONUtils.clone(a);
  var two = DvtJSONUtils.clone(b);
  DvtJSONUtils._copy(one, two);
  return two;
}

/**
 * Copys the properties from the first object onto the second.
 * @param {object} a The source of the properties to copy.
 * @param {object} b The destination of the copied properties.
 */
DvtJSONUtils._copy = function(a, b) {
  var key;
  for(key in a) {
    var value = a[key];
    if(value instanceof Array) {
      // Copy the array over, since we don't want arrays to be merged
      b[key] = value;      
    }
    else if(DvtJSONUtils._isDeepClonable(value)) {
      // Deep clone if object exists in b, copy otherwise
      if(b[key])
        DvtJSONUtils._copy(value, b[key]);
      else
        b[key] = value;
    }
    else
      b[key] = value;
  }
}

DvtJSONUtils._isDeepClonable = function(obj) {
	return (obj instanceof Object) && !(obj instanceof String) && !(obj instanceof Number) && !(obj instanceof Function);
}

/*---------------------------------------------------------------------*/
/*   DvtDisplayableUtils          Static Utility Functions             */
/*---------------------------------------------------------------------*/

/**
 *   Static Utility Functions for DvtDisplayable
 *   @class DvtDisplayableUtils
 *   @constructor
 */
var  DvtDisplayableUtils = function()
{} ;


/*
 * Temporarily add the display object to the stage to get dimensions.
 * Remove it from stage after done
 * cached dimensions in obj._dim
 */
DvtDisplayableUtils._getDimForced = function(context, obj) {
  //if there is a cache or context is null, return it.
  if (obj._dim || ! context) {
    return obj._dim;
  }

  //save original parent
  var oParent = obj.getParent();
  var stage = context.getStage();
  stage.addChild(obj);

  //cached the dimensions
  DvtDisplayableUtils._setDimForced(obj, obj.getDimensions());
  stage.removeChild(obj);

  //restore original parent
  if (oParent) {
    oParent.addChild(obj);
  }

  return obj._dim;
}


/*
 * cached dimensions in obj._dim
 */
DvtDisplayableUtils._setDimForced = function(obj, dim) {
  //cached the dimensions
  obj._dim = dim;
}



// Copyright (c) 2008, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/*---------------------------------------------------------------------*/
/*  DvtPathUtils()       Utility functions for SVG paths               */
/*---------------------------------------------------------------------*/

var DvtPathUtils = {} ;

/**
 * Returns a path command for a move to the specified coordinates
 * @param x the destination x coordinate
 * @param y the destination y coordinate
 * @return the moveTo path command
 */
DvtPathUtils.moveTo = function(x,y) {
  return "M" + x + "," + y;
};

/**
 * Returns a path command for a line to the specified coordinates
 * @param x the destination x coordinate
 * @param y the destination y coordinate
 * @return the lineTo path command
 */
DvtPathUtils.lineTo = function(x,y) {
  return "L" + x + "," + y;
};

DvtPathUtils.quadTo = function(x1,y1,x,y) {
  return "Q" + x1 + "," + y1 + "," + x + "," + y;
};

DvtPathUtils.cubicTo = function(x1,y1,x2,y2,x,y) {
  return "C" + x1 + "," + y1 + "," + x2 + "," + y2 + "," + x + "," + y;
};

/**
 * Returns a path command for an arc to the specified coordinates
 * @param radius the radius of the ellipse whose arc will be drawn
 * @param angleExtent the sweep of the arc to be drawn
 * @param direction 1 for clockwise, 0 for counter-clockwise 
 * @param x the ending x coordinate
 * @param y the ending y coordinate
 */
DvtPathUtils.arcTo = function(radius, angleExtent, direction, x, y) {
  var cmd = "A" + radius + "," + radius + ",0,";
  if(angleExtent > Math.PI) {
    cmd += "1,";
  }
  else {
    cmd += "0,";
  }
  cmd += (direction + "," + x + "," + y);
  return cmd;
};

/**
 * Returns a path command that closes the path.
 */
DvtPathUtils.closePath = function() {
  return "Z";
};



/*---------------------------------------------------------------------*/
/*    createPathArray()                                                */
/*---------------------------------------------------------------------*/
/**
  *  Creates an array of path/coords from an Svg path string.
  *  @param {String} cmds A string containing SVG path command sequences.
  *  @returns {Array}  an array of consecutive path command/coords, or null
  *                    if no command string supplied.
  */
DvtPathUtils.createPathArray = function(cmds)
{
   if (! cmds) {
     return null ;
   }

   //  Unpack into an array of commands and coords.

   var cmds = cmds.replace(/([mlqzMLCZQ])/gi, ',$1,');   // create array of coords from the
   var cmds = cmds.replace(/ /gi, ',');   // create array of coords from the
   var ar   = cmds.split(',') ;                           // the string.
   var len  = ar.length
   var i ;

   if (! ar[0]) {
     ar.splice(0,1) ;       // remove probable empty 1st from list
     len-- ;
   }
   if (! ar[len-1]) {
     ar.splice(len-1,1) ;   // remove probable empty last from list
     len-- ;
   }

   for (i = 0; i < len; i++) {
     if (! ar[i]) {
       ar.splice(i,1) ;     // remove possible other empty entries.
       i-- ;
       len-- ;
     }
   }
      
   //  Convert coordinates in command array to floats.

   for (i = 0; i < len;  i++) {
      var s = ar[i] ;
      if (! isNaN(s)) {
        ar[i] = parseFloat(ar[i]) ;
      }
   }

   return ar ;
} ;




/**
 * Returns the bounding box of the supplied path commands.
 * @param {Array} arCmds the path commands.
 * @returns {DvtRectangle} the bounding box of the supplied path commands.
 */
DvtPathUtils.getDimensions = function(aCmds)
{
  if (! (aCmds && aCmds.length)) {
    return new DvtRectangle() ;
  }

  var  len = aCmds.length ;
  var  c ;
  var  xSubPath, ySubPath ;
  var  bFirst = true ;           // false after first command
  var  bRel ;                    // true if relative command
  var  x, y, x2, y2, x3, y3 ;

  var minX = Number.MAX_VALUE ;
  var maxX = Number.MIN_VALUE ;
  var minY = Number.MAX_VALUE ;
  var maxY = Number.MIN_VALUE ;
  var  aPos = [] ;
  var  i, j, k ;

  for (i = 0; i < len;  i++)  {
     bRel = false ;
     var iMulti = 0 ;
     j = 0 ;

     c = aCmds[i] ;

     switch (c)
     {
        case 'm' :  bRel = true ;
        case 'M' :  do {
                      x = aCmds[i+1] ;
                      y = aCmds[i+2] ;

                      if (bFirst) {        // note if first is 'm', it is treated as absolute.
                        bFirst = false ;
                      }
                      else if (bRel) {
                        x += xSubPath ;
                        y += ySubPath ;
                      }
                      xSubPath = x ;
                      ySubPath = y ;

                      aPos[j++] = x ;
                      aPos[j++] = y ;
                      iMulti++ ;
                      i += 2 ;
                    } while (! isNaN(aCmds[i +1])) ;
                    break ;

        case 'c' :  bRel = true ;
        case 'C' :  do {
                      x  = aCmds[i+1] ;
                      y  = aCmds[i+2] ;
                      x2 = aCmds[i+3] ;
                      y2 = aCmds[i+4] ;
                      x3 = aCmds[i+5] ;
                      y3 = aCmds[i+6] ;

                      if (bRel) {
                        x  += xSubPath ;
                        y  += ySubPath ;
                        x2 += xSubPath ;
                        y2 += ySubPath ;
                        x3 += xSubPath ;
                        y3 += ySubPath ;
                      }
                      xSubPath = x3 ;
                      ySubPath = y3 ;

                      aPos[j++] = x3 ;
                      aPos[j++] = y3 ;
                      iMulti++ ;
                      i += 6 ;
                    } while (! isNaN(aCmds[i +1])) ;
                    break ;

        case 'q' :  bRel = true ;
        case 'Q' :  do {
                      x  = aCmds[i+1] ;
                      y  = aCmds[i+2] ;
                      x2 = aCmds[i+3] ;
                      y2 = aCmds[i+4] ;
                      if (bRel) {
                        x  += xSubPath ;
                        y  += ySubPath ;
                        x2 += xSubPath ;
                        y2 += ySubPath ;
                      }
                      xSubPath = x2 ;
                      ySubPath = y2 ;

                      aPos[j++] = x2 ;
                      aPos[j++] = y2 ;
                      iMulti++ ;
                      i += 4 ;
                    } while (! isNaN(aCmds[i +1])) ;
                    break ;

        case 'l' :  bRel = true ;
        case 'L' :
                    do {
                      x = aCmds[i+1] ;
                      y = aCmds[i+2] ;
                      if (bRel) {
                        x += xSubPath ;
                        y += ySubPath ;
                      }
                      xSubPath = x ;
                      ySubPath = y ;

                      aPos[j++] = x ;
                      aPos[j++] = y ;
                      iMulti++ ;
                      i += 2 ;
                    } while (! isNaN(aCmds[i+1])) ;
                    break ;

        case 'z' :
        case 'Z' :  break ;

        default :   console.log("Unknown path cmd=" + c + "  i=" + i) ;
                    break ;
     }                                    // end switch

     j = 0 ;
     for (k = 0 ; k < iMulti; k++) {
        x = aPos[j++] ;
        y = aPos[j++] ;
        minX = Math.min(minX, x) ;
        maxX = Math.max(maxX, x) ;
        minY = Math.min(minY, y) ;
        maxY = Math.max(maxY, y) ;
     }
  }

  return new DvtRectangle(minX, minY, Math.abs(maxX - minX), Math.abs(maxY - minY)) ;
};


/**
 *  Converts a platform independent array of consecutive commands and coords
 *  to an SVG path string.
 *  @param {Array} ar  The array of commands and coordinates to be converted.
 *  @type String
 */
DvtPathUtils.getPathString = function(ar)
{
   var sOut = '' ;
   var len = ar.length ;
   var s ;

   for (var i = 0; i < len;  i++) {
      s = ar[i] ;
      sOut += s + ' ' ;
      if (s !== 'Z' || s === 'z') {
        sOut += ar[i+1] + ',' + ar[i+2] + ' ' ;
        i += 2 ; 
      }
      else {
        continue ;
      }
      if (s === 'M' || s === 'm' || s === 'L' || s === 'l') {
        continue;
      }
      if (s === 'C' || s === 'c') {
        sOut += ar[i+1] + ',' + ar[i+2] + ' ' ;
        sOut += ar[i+3] + ',' + ar[i+4] + ' ' ;
        i += 4 ; 
      }
      if (s === 'Q' || s === 'q') {
        sOut += ar[i+1] + ',' + ar[i+2] + ' ' ;
        i += 2 ; 
      }
   }

   return sOut ;
};

/*
 * DvtMarkerDefElem 
 */
function DvtMarkerDefElem() {
  this.Init();
}

/*
 * make DvtMarkerDefElem a subclass of DvtObj
 */
DvtObj.createSubclass(DvtMarkerDefElem, DvtPropMap, "DvtMarkerDefElem");

// DvtMarkerDef Attributes
DvtMarkerDefElem.ATTR_ELEMENTS = "elements";
DvtMarkerDefElem.ATTR_SHAPE = "shape";
DvtMarkerDefElem.ATTR_BORDER_COLOR = "bc";
DvtMarkerDefElem.ATTR_FILL_COLOR = "fc";
DvtMarkerDefElem.ATTR_FILL_PATTERN = "fp";
DvtMarkerDefElem.ATTR_FILL_GRADIENT = "fg";
DvtMarkerDefElem.ATTR_DATA = "d";
DvtMarkerDefElem.ATTR_POINTS = "p";
DvtMarkerDefElem.ATTR_LINE_WIDTH = "lw";

DvtMarkerDefElem.ATTR_ANGLES = "ang";
DvtMarkerDefElem.ATTR_CLOSURE_TYPE = "ct";

DvtMarkerDefElem.ATTR_TRANSFORM = "transform";


/*
 * Initializes the instance. 
 */
DvtMarkerDefElem.prototype.Init = function() {
  DvtMarkerDefElem.superclass.Init.call(this);
};


/*-------------------------------------------------------------------------*/
/*   DvtMarkerDef attributes                                                */
/*-------------------------------------------------------------------------*/

/**
 * Gets the shape of the marker. The list of shapes are :
 * "circle"
 * "ellipse"
 * "line"
 * "path"
 * "polygone"
 * "polyline"
 * "rectangle"
 *
 * @return the shape of the marker
 */
DvtMarkerDefElem.prototype.getShape = function() {
  return this.getProperty(DvtMarkerDefElem.ATTR_SHAPE);
};


/**
 * Specifies the shape of the marker. The list of shapes are :
 * "circle"
 * "ellipse"
 * "line"
 * "path"
 * "polygone"
 * "polyline"
 * "rectangle"
 *
 * @param shape the shape of the marker
 */
DvtMarkerDefElem.prototype.setShape = function(shape) {
  this.setProperty(DvtMarkerDefElem.ATTR_SHAPE, shape);
};



/**
 * Gets the data of the component. 
 * @return data of the component
 */
DvtMarkerDefElem.prototype.getData = function() {
  return this.getProperty(DvtMarkerDefElem.ATTR_DATA);
};

/**
 * Sets the data of the component. 
 * @param data data of the component
 */
DvtMarkerDefElem.prototype.setData = function(data) {
  return this.setProperty(DvtMarkerDefElem.ATTR_DATA, data);
};

/**
 * Gets the points of the component. 
 * @return points of the component
 */
DvtMarkerDefElem.prototype.getPoints = function() {
  return this.getProperty(DvtMarkerDefElem.ATTR_POINTS);
};

/**
 * Sets the points of the component. 
 * @param points points of the component
 */
DvtMarkerDefElem.prototype.setPoints = function(points) {
  this.setProperty(DvtMarkerDefElem.ATTR_POINTS, points);
};

/**
 * Gets the closure type of the component. 
 * @return closure type of the component
 */
DvtMarkerDefElem.prototype.getClosureType = function() {
  return this.getProperty(DvtMarkerDefElem.ATTR_CLOSURE_TYPE);
};

/**
 * Sets the closure type of the component. 
 * @param closureType closure type of the component
 */
DvtMarkerDefElem.prototype.setClosureType = function(closureType) {
  this.setProperty(DvtMarkerDefElem.ATTR_CLOSURE_TYPE, closureType);
};


/**
 * Gets the angles of the component. 
 * @return angles of the component
 */
DvtMarkerDefElem.prototype.getAngles = function() {
  return this.getProperty(DvtMarkerDefElem.ATTR_ANGLES);
};

/**
 * Sets the angles of the component. 
 * @param angles angles of the component
 */
DvtMarkerDefElem.prototype.setAngles = function(angles) {
  return this.setProperty(DvtMarkerDefElem.ATTR_ANGLES, angles);
};

/**
 * Gets the border color of the component. 
 * @return border color of the component
 */
DvtMarkerDefElem.prototype.getBorderColor = function() {
  return this.getProperty(DvtMarkerDefElem.ATTR_BORDER_COLOR);
};

/**
 * Sets the border color of the component. 
 * @param borderColor border color of the component
 */
DvtMarkerDefElem.prototype.setBorderColor = function(borderColor) {
  this.setProperty(DvtMarkerDefElem.ATTR_BORDER_COLOR, borderColor);
};


/**
 * Gets the line width of the component. 
 * @return line width of the component
 */
DvtMarkerDefElem.prototype.getLineWidth = function() {
  return this.getProperty(DvtMarkerDefElem.ATTR_LINE_WIDTH);
};

/**
 * Sets the line width of the component. 
 * @param lineWidth line width of the component
 */
DvtMarkerDefElem.prototype.setLineWidth = function(lineWidth) {
  this.setProperty(DvtMarkerDefElem.ATTR_LINE_WIDTH, lineWidth);
};


/**
 * Gets the fill color of the component. 
 * @return fill color of the component
 */
DvtMarkerDefElem.prototype.getFillColor = function() {
  return this.getProperty(DvtMarkerDefElem.ATTR_FILL_COLOR);
};

/**
 * Sets the fill color of the component. 
 * @param fillColor fill color of the component
 */
DvtMarkerDefElem.prototype.setFillColor = function(fillColor) {
  this.setProperty(DvtMarkerDefElem.ATTR_FILL_COLOR, fillColor);
};


/**
 * Gets the fill pattern of the component. 
 * @return fill pattern of the component
 */
DvtMarkerDefElem.prototype.getFillPattern = function() {
  return this.getProperty(DvtMarkerDefElem.ATTR_FILL_PATTERN);
};

/**
 * Sets the fill pattern of the component. 
 * @param fillPattern fill pattern of the component
 */
DvtMarkerDefElem.prototype.setFillPattern = function(fillPattern) {
  this.setProperty(DvtMarkerDefElem.ATTR_FILL_PATTERN, fillPattern);
};


/**
 * Gets the fill gradient of the component. 
 * @return fill gradient of the component
 */
DvtMarkerDefElem.prototype.getFillGradient = function() {
  return this.getProperty(DvtMarkerDefElem.ATTR_FILL_GRADIENT);
};

/**
 * Sets the fill gradient of the component. 
 * @param fillGradient fill gradient of the component
 */
DvtMarkerDefElem.prototype.setFillGradient = function(fillGradient) {
  this.setProperty(DvtMarkerDefElem.ATTR_FILL_GRADIENT, fillGradient);
};

/**
 * Gets the transform of the component. 
 * @return transform of the component
 */
DvtMarkerDefElem.prototype.getTransform = function() {
  return this.getProperty(DvtMarkerDefElem.ATTR_TRANSFORM);
};

/**
 * Sets the transform of the component. 
 * @param transform transform of the component
 */
DvtMarkerDefElem.prototype.setTransform = function(transform) {
  return this.setProperty(DvtMarkerDefElem.ATTR_TRANSFORM, transform);
};


/*
 * DvtMarkerDef
 */
var DvtMarkerDef = function() {
  this.Init();
}

/*
 * make DvtMarkerDef a subclass of DvtObj
 */
DvtObj.createSubclass(DvtMarkerDef, DvtPropMap, "DvtMarkerDef");

DvtMarkerDef.MARKER_DEF = "markerDef";

// List of marker shapes
DvtMarkerDef.MARKER_DEF_CIRCLE = "c";
DvtMarkerDef.MARKER_DEF_ELLIPSE = "o";
DvtMarkerDef.MARKER_DEF_LINE = "l";
DvtMarkerDef.MARKER_DEF_PATH = "p";
DvtMarkerDef.MARKER_DEF_PATHOLYGON = "pg";
DvtMarkerDef.MARKER_DEF_PATHOLYLINE = "pl";
DvtMarkerDef.MARKER_DEF_RECT = "r";


// DvtMarkerDef Attributes
DvtMarkerDef.ATTR_ELEMENTS = "elements";
DvtMarkerDef.ATTR_BORDER_COLOR = "bc";
DvtMarkerDef.ATTR_LINE_WIDTH = "lw";
DvtMarkerDef.ATTR_FILL_COLOR = "fc";
DvtMarkerDef.ATTR_FILL_PATTERN = "fp";
DvtMarkerDef.ATTR_FILL_GRADIENT = "fg";



DvtMarkerDef.BI_DEFAULT_MARKER_SIZE = 9;

DvtMarkerDef.HUMAN_CMDS = "m 38.07,36.467856 q 13.414,0 13.414,-13.406 l 0,-9.258 q 0,-13.4039999 -13.414," +
"-13.4039999 -13.414,0 -13.414,13.4039999 l 0,9.258 q 0,13.406 13.414,13.406 l 0,0 z m 16.219,7.275 -32.435999," +
"0 q -10.139552,0 -15.9400009,7.443875 Q 0.5,58.133383 0.5,69.156856 l 0,54.396004 12.746001,0 0,-51.609004 q 0," +
"-2.824 0.793,-2.824 0.742,0 0.742,2.709 l 0,124.267994 q 0,2.82401 2.823999,2.82401 l 12.531,0 q 2.824,0 2.824," +
"-2.824 l 0,-66.25 10.219,0 0,66.25 q 0,2.824 2.824,2.824 l 12.528,0 q 2.825,0 2.825,-2.824 l 0,-124.268004 q 0," +
"-2.709 0.839,-2.709 0.792,0 0.792,2.824 l 0,51.609004 12.65,0 0,-54.396004 Q 75.6386,58.132927 70.227626," +
"51.186731 64.428999,43.742856 54.289,43.742856 l 0,0 z";




/*
 * Initializes the instance. 
 */
DvtMarkerDef.prototype.Init = function() {
  DvtMarkerDef.superclass.Init.call(this);
};



/*-------------------------------------------------------------------------*/
/*   DvtMarkerDef attributes                                                */
/*-------------------------------------------------------------------------*/

/**
 * Gets the border color of the component. 
 * @return border color of the component
 */
DvtMarkerDef.prototype.getBorderColor = function() {
  return this.getProperty(DvtMarkerDef.ATTR_BORDER_COLOR);
};

/**
 * Sets the border color of the component. 
 * @param borderColor border color of the component
 */
DvtMarkerDef.prototype.setBorderColor = function(borderColor) {
  this.setProperty(DvtMarkerDef.ATTR_BORDER_COLOR, borderColor);
};


/**
 * Gets the line width of the component. 
 * @return line width of the component
 */
DvtMarkerDef.prototype.getLineWidth = function() {
  return this.getProperty(DvtMarkerDef.ATTR_LINE_WIDTH);
};

/**
 * Sets the line width of the component. 
 * @param lineWidth line width of the component
 */
DvtMarkerDef.prototype.setLineWidth = function(lineWidth) {
  this.setProperty(DvtMarkerDef.ATTR_LINE_WIDTH, lineWidth);
};


/**
 * Gets the fill color of the component. 
 * @return fill color of the component
 */
DvtMarkerDef.prototype.getFillColor = function() {
  return this.getProperty(DvtMarkerDef.ATTR_FILL_COLOR);
};

/**
 * Sets the fill color of the component. 
 * @param fillColor fill color of the component
 */
DvtMarkerDef.prototype.setFillColor = function(fillColor) {
  this.setProperty(DvtMarkerDef.ATTR_FILL_COLOR, fillColor);
};


/**
 * Gets the fill pattern of the component. 
 * @return fill pattern of the component
 */
DvtMarkerDef.prototype.getFillPattern = function() {
  return this.getProperty(DvtMarkerDef.ATTR_FILL_PATTERN);
};

/**
 * Sets the fill pattern of the component. 
 * @param fillPattern fill pattern of the component
 */
DvtMarkerDef.prototype.setFillPattern = function(fillPattern) {
  this.setProperty(DvtMarkerDef.ATTR_FILL_PATTERN, fillPattern);
};


/**
 * Gets the fill gradient of the component. 
 * @return fill gradient of the component
 */
DvtMarkerDef.prototype.getFillGradient = function() {
  return this.getProperty(DvtMarkerDef.ATTR_FILL_GRADIENT);
};

/**
 * Sets the fill gradient of the component. 
 * @param fillGradient fill gradient of the component
 */
DvtMarkerDef.prototype.setFillGradient = function(fillGradient) {
  this.setProperty(DvtMarkerDef.ATTR_FILL_GRADIENT, fillGradient);
};


/**
 * Gets the dimensions of the component. 
 * @return dimensions of the component
 */
DvtMarkerDef.prototype.getDimensions = function() {
  var x = this.getProperty("dx");
  var y = this.getProperty("dy");
  var w = this.getProperty("dw");
  var h = this.getProperty("dh");

  if (w && h) {
    return new DvtRectangle(x, y, w, h);
  }
  return null;
};


/**
 * Gets the elements of the marker. The list of elementss are :
 *
 * @return the elements of the marker
 */
DvtMarkerDef.prototype.getElements = function() {
  return this.getProperty(DvtMarkerDef.ATTR_ELEMENTS);
};


/**
 * Add an element to the marker.
 *
 * @param {DvtMarkerDefElem} element to be added
 */
DvtMarkerDef.prototype.addElement = function(element) {
  var elems = this.getElements();
  if (! elems) {
    elems = [];
    this.setProperty(DvtMarkerDef.ATTR_ELEMENTS, elems);
  }
  elems.push(element);
};



var DvtMarkerGradient = function ()
{
}


DvtMarkerGradient.createMarkerGradient = function (color, marker, opacity)
{
  var arColors = [];
  var arRatios = [];
  var arAlphas = [opacity, opacity, opacity, opacity];
  var gfs = null;

  var shapeType = marker.getType();
  var dim = DvtDisplayableUtils._getDimForced (marker.getContext(), marker);
  var center = dim.getCenter();
  var size = Math.min (dim.w, dim.h);

  if (shapeType != DvtMarker.HUMAN)
  {
     arRatios = [0.0, 0.5, 0.75, 1];
     var c0 = DvtColorUtils.getPastel(color, 0.20);
     var c1 = DvtColorUtils.getPastel(color, 0.10);
     var c2 = DvtColorUtils.getDarker(color, 0.8);
     
     var radius = size / 2.0;
     var cx = center.x;
     var cy = center.y;
     var arColors = [DvtColorUtils.getPound(c0), DvtColorUtils.getPound(c1), color, DvtColorUtils.getPound(c2)];    
     var bound = new DvtRectangle(-radius, -radius, radius * 2.0, radius* 2.0);
     var arBound = [bound, bound, bound, bound];
     gfs = new DvtRadialGradientFill(arColors, arAlphas, arRatios, cx, cy, radius, arBound);
  } else
  {
     arRatios = [0.0, 0.3, 0.7, 1];
     var c0 = DvtColorUtils.getPastel(color, 0.20);
     var c1 = DvtColorUtils.getDarker(color, 0.9);
     var c2 = DvtColorUtils.getDarker(color, 0.8);
     var arColors = [DvtColorUtils.getPound(c0), DvtColorUtils.getPound(c1), color, DvtColorUtils.getPound(c2)];    
     var bound = new DvtRectangle(-size/ 2.0, -size /2.0, size, size);
     var arBound = [bound, bound, bound, bound];
     gfs = new DvtLinearGradientFill(135, arColors, arAlphas, arRatios, arBound);
  }

  return gfs ;
}
/**
 * DvtMarkerUtils
 */
var DvtMarkerUtils = {_cache:{}};


/**
 * parse markerDefXmlString and return a markerDef object
 */
DvtMarkerUtils.createMarkerDef = function(context, markerDefNode) {
  var markerDef = new DvtMarkerDef();
  markerDef.setProperties(markerDefNode.getAttributes());

  var childNodes = markerDefNode.getChildNodes();
  var childElems;

  for (var i = 0; i < childNodes.length; i++) {
    var child = childNodes[i];
    if (child) {
      childElems = new DvtMarkerDefElem();
      childElems.setProperties(child.getAttributes());
      childElems.setShape(child.getName());
      markerDef.addElement(childElems);
    }
  }
  if (markerDef) {
    this._addMarkerDef(context, markerDef);
  }
  return markerDef;
};



/**
 * add a markerDef object to the marker list
 */
DvtMarkerUtils._addMarkerDef = function(context, markerDef) {
  var stageId = context.getStage().getId();
  var markerId = markerDef.getId();
  var markerList = DvtMarkerUtils.getMarkerList(stageId);

  //first look for a cached copy of the custom marker 
  //if not found, add to the custom marker list
  if (! markerList[markerId]) {
    var marker = this.createMultiPaths(context, markerDef, markerId);
    if (marker) {
      // set id on the root 
      marker.setId("custom" + markerId);
      markerList[markerId] = marker;

      // get custom dimensions and cache it in the shape object
      var dim = markerDef.getDimensions();
      if (dim) {
        DvtDisplayableUtils._setDimForced(marker, dim);
      }
    }
  }
};


/**
 * Get Custom Marker List
 */
DvtMarkerUtils.getMarkerList = function(stageId)
{
  if (!this._cache[stageId]) {
    this._cache[stageId] = {};
  }
  return this._cache[stageId];
};


/**
 * Returns a DvtPath
 * 
 * @param context  the context
 * @param markerDef the custom marker definition
 */
DvtMarkerUtils.createMarkerShape = function(context, markerDef, markerId) {

  var marker;
  var type = markerDef.getShape();

  if (type == DvtMarkerDef.MARKER_DEF_PATH) {
    marker = this.createPathMarker(context, markerDef, markerId);
  }
  /*
  else if (type == DvtMarkerDef.MARKER_DEF_CIRCLE ||
      type == DvtMarkerDef.MARKER_DEF_ELLIPSE) {
    marker = this.createCircleMarker(context, markerDef, markerId, type);
  }
  else if (type == DvtMarkerDef.MARKER_DEF_LINE) {
    marker = this.createLineMarker(context, markerDef, markerId);
  }
  else if (type == DvtMarkerDef.MARKER_DEF_PATHOLYGON) {
    marker = this.createPolygoneMarker(context, markerDef, markerId);
  }
  else if (type == DvtMarkerDef.MARKER_DEF_PATHOLYLINE) {
    marker = this.createPolylineMarker(context, markerDef, markerId);
  }
  else if (type == DvtMarkerDef.MARKER_DEF_RECT_TYPE) {
    marker = this.createRectMarker(context, markerDef, markerId);
  }
  */

  //set common attributes
  if (marker) {
    DvtMarkerUtils.setCommonAttrs(markerDef, marker);
  }

  return marker;
};


/**
 * @type DvtPath or DvtContainer (contains a list of DvtPaths)
 */
DvtMarkerUtils.createMultiPaths = function(context, markerDef, markerId) {
  var shapes = markerDef.getElements();
  if (! shapes || shapes.length == 0)
    return null;

  var root;
  if (shapes.length == 1) {
    root = DvtMarkerUtils.createMarkerShape(context, shapes[0], markerId);
  }
  else {
    root = new DvtContainer(context, markerId);
    var child;
    var childElem;
    for (var i = 0; i < shapes.length; i++) {
      child = shapes[i];
      childElem = DvtMarkerUtils.createMarkerShape(context, child, markerId + "_" + i);
      root.addChild(childElem);
    }
  }
  return root;

};

// type: circle or ellipse
DvtMarkerUtils.createCircleMarker = function(context, markerDef, markerId, type) {
  var points = markerDef.getPoints();
  var cx = points[0];
  var cy = points[1];
  var rx = points[2];
  var ry;
  if (type == DvtMarkerDef.MARKER_DEF_ELLIPSE) {
    ry = points[3];
  }
  var marker ;
  var closureType = markerDef.getClosureType();
  if (closureType) {
    var angles = markerDef.getAngles();
    var anglesStart;
    var anglesExtent;
    if (angles) {
      anglesStart = angles[0];
      anglesExtent = angles[1];
    }
    marker = new DvtArc(context, cx, cy, rx, ry, 
                        anglesStart, anglesExtent, closureType, markerId);
  }
  else {
    marker = new DvtCircle(context, cx, cy, rx, markerId);
  }

  return marker;
};


DvtMarkerUtils.createRectMarker = function(context, markerDef, markerId) {
  var points = markerDef.getPoints();
  var x = points[0];
  var y = points[1];
  var w = points[2];
  var h = points[3];

  return new DvtRect(context, x, y, w, h, markerId);
};


DvtMarkerUtils.createLineMarker = function(context, markerDef, markerId) {
  var points = markerDef.getPoints();
  var x1 = points[0];
  var y1 = points[1];
  var x2 = points[2];
  var y2 = points[3];

  return new DvtLine(context, x1, y1, x2, y2, markerId);
};

DvtMarkerUtils.createPathMarker = function(context, markerDef, markerId) {
  var data = markerDef.getData();

  return new DvtPath(context, data, markerId);
};


DvtMarkerUtils.createPolygoneMarker = function(context, markerDef, markerId) {
  var points = markerDef.getPoints();

  return new DvtPolygon(context, points, markerId);
};


DvtMarkerUtils.createPolylineMarker = function(context, markerDef, markerId) {
  var points = markerDef.getPoints();

  return new DvtPolyline(context, points, markerId);
};


DvtMarkerUtils.setCommonAttrs = function(markerDef, marker) {
  // solid, gradient, pattern fill?
  var fc = markerDef.getFillColor();
  var fa = null; //TODO getAlpha
  var fg = markerDef.getFillGradient();
  var fp = markerDef.getFillPattern();

  if (fp) {
    marker.setFill(new DvtPatternFill(fp, fc));
  }
  else if (fg) {
    marker.setFill(new DvtGradientFill([fc], fa ? [fa] : fa));
  }
  else if (fc || fa) {
    marker.setFill(new DvtSolidFill(fc, fa));
  }

  var lw = markerDef.getLineWidth();
  var bc = markerDef.getBorderColor();

  if (lw || bc) {
    if (! lw)
      lw = "1";
    if (! bc)
      bc = "black";
    
    var stroke = new DvtSolidStroke(bc, 1, lw);
    marker.setStroke(stroke);    
  }

};


/**
 * get a markerDef from the marker list
 * @type DvtPath or DvtContainer (contains a list of DvtPaths)
 */
DvtMarkerUtils.getCustomMarkerInfo = function(context, markerId) {
  var stageId = context.getStage().getId();
  var markerList = DvtMarkerUtils.getMarkerList(stageId);

  if (markerList) {
    return markerList[markerId];
  }
  else {
    return undefined;
  }
};


/**
 * get marker def id
 */
DvtMarkerUtils.getBuiltinMarkerInfo = function(context, markerType) {
  var stageId = context.getStage().getId();
  var markerList = DvtMarkerUtils.getMarkerList(stageId);

  var defId = markerList[markerType];
  // if the marker is not in cache, add it to markerList
  if (! defId) {
    if (markerType) {
      var tmarker = new DvtPath(context, DvtMarkerDef.HUMAN_CMDS, "dvtHuman");
      // cache the dimensions in the shape object
      DvtDisplayableUtils._getDimForced(context, tmarker);
      markerList[markerType] = tmarker;
    }
  }
  return markerList[markerType];
};


/**
 * For internal use only
 */
DvtMarkerUtils.clearCached = function(context) {
  var stageId = context.getStage().getId();
  this._cache[stageId] = undefined;
}



// Copyright (c) 2008, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/*---------------------------------------------------------------------*/
/*  DvtPolygonUtils()       Utility functions for Polygons             */
/*---------------------------------------------------------------------*/

var DvtPolygonUtils = {} ;


/**
 * Returns the bounding box of the supplied polygon coords.
 * @param {Array} aPts an array of consecutive x,y coordinate pairs.
 * @returns {DvtRectangle} the bounding box of the supplied polygon.
 */
DvtPolygonUtils.getDimensions = function(aPts)
{
  if ((! aPts) || (aPts.length=== 0)) {
    return new DvtRectangle() ;
  }

  var minX = Number.MAX_VALUE ;
  var maxX = Number.MIN_VALUE ;
  var minY = Number.MAX_VALUE ;
  var maxY = Number.MIN_VALUE ;

  var len = aPts.length ;
  var x, y ;
  for (var i = 0; i < len; i++) {

     x = aPts[i++];
     y = aPts[i];
     minX = Math.min(minX, x) ;
     maxX = Math.max(maxX, x) ;
     minY = Math.min(minY, y) ;
     maxY = Math.max(maxY, y) ;
  }

  return new DvtRectangle(minX, minY, Math.abs(maxX - minX), Math.abs(maxY - minY)) ;
};



// Copyright (c) 2008, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/*---------------------------------------------------------------------*/
/*  DvtTextUtils()       Utility functions for text                    */
/*---------------------------------------------------------------------*/

var DvtTextUtils = {} ;

/*---------------------------------------------------------------------*/
/*   applyFont()                                                       */
/*---------------------------------------------------------------------*/
DvtTextUtils.applyFont = function(text, font) {
   
   text.setFill(new DvtSolidFill(font.color, font.alpha)) ;
   text.alignBaseline() ;
   
   var style = '';                        //  Handle bold, italic, underline
   if (font.italic)  {
     style = 'font-style:italic; ' ;
   }
   if (font.bold)  {
     style += 'font-weight:bold; ' ;
   }
   if (font.underline)  {
     style += 'text-decoration:underline;' ;
   }
   style += 'font-size:' + font.size+';';
   style += 'font-family:' + font.name + ';' ;

   if (style) {
     style = new DvtCSSStyle(style) ;
     text.setCSSStyle(style) ;
   }
};

DvtTextUtils.formatTextString = function(tooltip)
{
    var fullText = "";
    if (!tooltip)
        return fullText;

    tooltip = tooltip.replace(/\n/g, '<br>'); // replace logical newlines sequences
    var tooltipTextArray = tooltip.split("<br>");        
    if (tooltipTextArray) {
        var shortArray = new Array();
        for (var i=0; i< tooltipTextArray.length; i++) {
            var txt = tooltipTextArray[i];
            if (txt != null && txt != "") {
                shortArray.push(txt);
            }
        }
        for (var i=0; i< shortArray.length; i++) {
            fullText += shortArray[i];
            if (i < shortArray.length - 1) {
                fullText += DvtTextArea.NEW_LINE;
            }
        }
    }
    return fullText;
}
// Copyright (c) 2008, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/*---------------------------------------------------------------------*/
/*  DvtDisplayable         Base object for displayable objects         */
/*---------------------------------------------------------------------*/
/**
 *  Base class for displayable objects.
 *  @extends DvtObj
 *  @class DvtDisplayable is the base class for all displayable objects (derived from {@link DvtDisplayable}).
 *  Must be superclassed  - do not use directly.
 *  <p>Example:<br><br><code>
 *  var line = new DvtLine(context, 10,10, 30, 50) ; &nbsp; &nbsp; ({@link DvtLine} is a descendent
 *  of DvtDisplayable). <br>
 *  <code>
 *  @constructor
 *  @param {DvtContext} context The platform specific context object.
 */
var DvtDisplayable = function (context) {
  this.Init(context);
};

DvtObj.createSubclass(DvtDisplayable, DvtObj, "DvtDisplayable");

/**
  *  Object initializer.
  *  @protected 
  */
DvtDisplayable.prototype.Init = function (context) {
  this._parent = null;       // parent obj
  this._impl.setObj(this);   // point implementation back to the real
  // controlling object.
  this._context = context;

  this._listenerObj = null;  // placeholder for object to store event listeners
  
  //properties for transforms
  //this._translateX = null;
  //this._translateY = null;
  //this._scaleX = null;
  //this._scaleY = null;
  //this._rotation = null;
  this._matrix = null;
  
  this._drawEffects = null;
};

/*---------------------------------------------------------------------*/
/*   Important Getters                                                 */
/*---------------------------------------------------------------------*/

/**
 * Internal DVT toolkit framework use only. Returns the platform specific
 * implementation for this object (such as {@link DvtSvgRect}).
 * @protected
 * @type Object
 */
DvtDisplayable.prototype.getImpl = function () {
  return this._impl;
};

/**
 * Returns the application context.
 * @type DvtContext
 */
DvtDisplayable.prototype.getContext = function () {
  return this._context;
};



/*---------------------------------------------------------------------*/
/*   setClipPath()                                                     */
/*---------------------------------------------------------------------*/
/**
 *  Sets a clipping region for this object.
 *  @param {DvtClipPath}  cp  the DvtClipPath object specifying the clipping region.
 */
DvtDisplayable.prototype.setClipPath = function(cp) {

  this._impl.setClipPath(cp);
};


/**
  *  Set the platform specific implementation.  Dvt internal use only
  */
DvtDisplayable.prototype.setImpl = function (impl) {
  this._impl = impl ;
};


/*---------------------------------------------------------------------*/
/*   get/setPixelHinting()                                             */
/*---------------------------------------------------------------------*/
/**
 * Returns the current pixel hinting state.
 * @type Boolean
 */
DvtDisplayable.prototype.getPixelHinting = function () {
  return this._impl.getPixelHinting();
};

/**
 * Enables/disables pixel hinting.
 * @param {Boolean} id  true if pixel hinting should be interpreted/applied by the
 * implementation platform.
 */
DvtDisplayable.prototype.setPixelHinting = function (bHint) {
  this._impl.setPixelHinting(bHint);
};

/*---------------------------------------------------------------------*/
/*   get/setId()                                                       */
/*---------------------------------------------------------------------*/
/**
 * Returns the id of this object.
 * @type String
 */
DvtDisplayable.prototype.getId = function () {
  return this._impl.getId();
};
/**
 * Sets the id of this object.
 * @param {String} id  The id for the object.
 */
DvtDisplayable.prototype.setId = function (id) {
  this._impl.setId(id);
};


/*---------------------------------------------------------------------*/
/*   get/setParent()                                                   */
/*---------------------------------------------------------------------*/
/**
 * Returns the parent of this object.
 * @type DvtDisplayable
 */
DvtDisplayable.prototype.getParent = function () {
  return this._parent;
};

/**
 * Sets the parent of this object.
 * @param {DvtDisplayable} parent
 */
DvtDisplayable.prototype.setParent = function (parent) {
  this._parent = parent;
};

/**
 * Returns the bounds of the displayable relative to the target coordinate space.  If the target
 * coordinate space is not specified, returns the bounds relative to this displayable.
 * @param {DvtDisplayable} targetCoordinateSpace The displayable defining the target coordinate space.
 * @return {DvtRectangle} The bounds of the displayable relative to the target coordinate space.
 */
DvtDisplayable.prototype.getDimensions = function(targetCoordinateSpace) {
  var bounds = this.getImpl().getDimensions();
  if(!targetCoordinateSpace || targetCoordinateSpace === this)
    return bounds;
  else { // Calculate the bounds relative to the target space
    // First calculate relative to the stage
    var stageP1 = this.localToStage(new DvtPoint(bounds.x, bounds.y));
    var stageP2 = this.localToStage(new DvtPoint(bounds.x + bounds.w, bounds.y + bounds.h));
    
    // Then convert relative to target
    var targetP1 = targetCoordinateSpace.stageToLocal(stageP1);
    var targetP2 = targetCoordinateSpace.stageToLocal(stageP2);
    
    return new DvtRectangle(targetP1.x, targetP1.y, targetP2.x - targetP1.x, targetP2.y - targetP1.y);
  }
};


/*---------------------------------------------------------------------*/
/*   get/setVisible()                                                  */
/*---------------------------------------------------------------------*/
/**
  *  Gets the visibility of this object.
  *  @type {Boolean}
  *  @returns True if the object is visible, else false.
  */
DvtDisplayable.prototype.getVisible = function()
{
   return this._impl.getVisible() ;
};
/**
  *  Enables/disables the visibility of this object.
  *  @param {Boolean}  bVis  True if the object is to be visible, else false if
  *  it is to be hidden.
  */
DvtDisplayable.prototype.setVisible = function(bVis)
{
   this._impl.setVisible(bVis) ;
};


/*---------------------------------------------------------------------*/
/*   Event Handling Support                                            */
/*---------------------------------------------------------------------*/

/**
 * Adds an event listener.
 * @param {string} type the event type
 * @param {function} listener the function to call
 * @param {string} useCapture whether the listener operates in the capture phase
 * @param {object} obj instance of the object the listener is defined on
 */
DvtDisplayable.prototype.addEventListener = function (type, listener, useCapture, obj) {
  // Store a reference to the listener
  var listenersArray = this._getListeners(type, useCapture, true);
  listenersArray.push(listener);
  listenersArray.push(obj);

  // Call the impl so that it can add the actual listener
  this._impl.addListener(type, useCapture);
}

/**
 * Removes an event listener.
 * @param {string} type the event type
 * @param {function} listener the function to call
 * @param {string} useCapture whether the listener operates in the capture phase
 * @param {object} obj instance of the object the listener is defined on
 */
DvtDisplayable.prototype.removeEventListener = function (type, listener, useCapture, obj) {
  // Remove the listener
  var listenersArray = this._getListeners(type, useCapture, false);
  if (listenersArray) {
    for (var i = 0;i < listenersArray.length;i+=2) {
      if (listenersArray[i] === listener && 
           listenersArray[i+1] === obj) {
        listenersArray.splice(i, 2);
        break;
      }
    }
  }

  // Call the impl so that it can remove the actual listener.
  // Note that the array itself is intentionally not removed.
  if (listenersArray && listenersArray.length <= 0)
    this._impl.removeListener(type, useCapture);
}

/**
 * Returns the listeners of the given event type and capture mode.
 * @param {string} type the event type
 * @param {string} useCapture whether the listener operates in the capture phase
 * @param {boolean} createNew whether the array should be created if it doesn't exist
 * @return {array} the mutable Array of listeners
 * @private
 */
DvtDisplayable.prototype._getListeners = function (type, useCapture, createNew) {
  // First find the object where the listener arrays are stored
  if (!this._listenerObj) {
    if (createNew) {
      this._listenerObj = {
      };
    }
    else {
      return null;
    }
  }

  // Then find the array for this event type, creating if necessary 
  var eventKey = type + "_" + (useCapture ? true : false);// for example: "click_true"  
  var listenersArray = this._listenerObj[eventKey];
  if (!listenersArray && createNew) {
    listenersArray = [];
    this._listenerObj[eventKey] = listenersArray;
  }

  return listenersArray;
};

/**
 * Notifies all applicable event listeners of the given event.
 * @param {DvtMouseEvent} event
 * @param {boolean} useCapture whether the listener operates in capture phase
 */
DvtDisplayable.prototype.FireListener = function (event, useCapture) {
  var listenersArray = this._getListeners(event.type, useCapture, false);
  if (listenersArray) {
    for (var i = 0;i < listenersArray.length;i+=2) {
      var obj = listenersArray[i+1];
      if (listenersArray[i]) {
        listenersArray[i].call(obj, event);
      }
    }
  }
};

/*---------------------------------------------------------------------*/
/*   CSS Style Support                                                 */
/*---------------------------------------------------------------------*/

/**
 * Returns the DvtCSSStyle of this object.
 * @type DvtCssStyle
 */ 
DvtDisplayable.prototype.getCSSStyle = function() {

  return this._impl.getCSSStyle() ;
}

/**
 * Sets the DvtCSSStyle of this object.
 * @param {DvtCssStyle} style The DvtCSSStyle of this object.
 */
DvtDisplayable.prototype.setCSSStyle = function(style)
{
  this._impl.setCSSStyle(style) ;
}
    

/**
 * Sets the cursor on this object.
 * @param {String} cursor type
 */
DvtDisplayable.prototype.setCursor = function(cursorType)
{
  this._impl.setCursor(cursorType);
};
    

/**
 * Gets the cursor used on this object.
 * @type {String}
 */
DvtDisplayable.prototype.getCursor = function()
{
  return this._impl.getCursor();
};


/**
 * Sets whether mouse events are enabled on this object.
 * @param {boolean} whether mouse events are enabled
 */
DvtDisplayable.prototype.setMouseEnabled = function(bEnabled)
{
  this._impl.setMouseEnabled(bEnabled);
};
    

/**
 * Gets whether mouse events are enabled on this object.
 * @type {boolean}
 */
DvtDisplayable.prototype.isMouseEnabled = function()
{
  return this._impl.isMouseEnabled();
};



/*---------------------------------------------------------------------*/
/*   get/setAlpha()                                                    */
/*---------------------------------------------------------------------*/
/**
  *  Returns the alpha-channel.
  *  @type number
  */
DvtDisplayable.prototype.getAlpha = function()
{
   return this._impl.getAlpha();
};

/**
  *  Sets the alpha-channel.
  *  @param {number} alpha A value between 0 (invisible) and 1 (opaque).
  */
DvtDisplayable.prototype.setAlpha = function(alpha)
{
   this._impl.setAlpha(alpha);
};

/**  Returns the horizontal translation applied to this container.
  *  @type Number
  *  @returns horizontal translation, in pixels
  */ 
DvtDisplayable.prototype.getTranslateX = function()
{
   //if (this._translateX)
   if (this._matrix)
   {
     //return this._translateX ;
     
     //get the value from the matrix because other 
     //transformations may have changed it
     return this._matrix._decompose()[DvtMatrix._DECOMP_TX];
   }
   
   return 0;
} ;

/**  Set the horizontal translation to apply to this container.
  *  @param {Number} tx   The horizontal translation to apply, in pixels.
  */ 
DvtDisplayable.prototype.setTranslateX = function(tx)
{
   //the matrix is the ultimate source of truth, because
   //it contains all the transform information
   var mat = this.getMatrix().clone();
   var decomp = mat._decompose();
   decomp[DvtMatrix._DECOMP_TX] = tx;
   mat._recompose(decomp);
   this.setMatrix(mat);
   
   //if using the individual transform properties, clear the matrix
   //this._matrix = null;
   
   //this._translateX = tx ;
   //this._ApplyTransform();
} ;

/**  Return the vertical translation applied to this container.
  *  @type Number
  *  @returns vertical translation, in pixels
  */ 
DvtDisplayable.prototype.getTranslateY = function()
{
   //if (this._translateY)
   if (this._matrix)
   {
     //return this._translateY ;
     
     //get the value from the matrix, because other 
     //transformations may have changed it
     return this._matrix._decompose()[DvtMatrix._DECOMP_TY];
   }
   
   return 0;
} ;

/**  Set the vertical translation to apply to this container.
  *  @param {Number} ty   The vertical translation to apply, in pixels.
  */ 
DvtDisplayable.prototype.setTranslateY = function(ty)
{
   //the matrix is the ultimate source of truth, because
   //it contains all the transform information
   var mat = this.getMatrix().clone();
   var decomp = mat._decompose();
   decomp[DvtMatrix._DECOMP_TY] = ty;
   mat._recompose(decomp);
   this.setMatrix(mat);
   
   //if using the individual transform properties, clear the matrix
   //this._matrix = null;
   
   //this._translateY = ty ;
   //this._ApplyTransform();
} ;

/**  Return the horizontal scale applied to this container.
  *  @type Number
  *  @returns horizontal scale
  */ 
DvtDisplayable.prototype.getScaleX = function()
{
   //if (this._scaleX != null)
   if (this._matrix)
   {
     //return this._scaleX ;
     
     //get the value from the matrix, because other 
     //transformations may have changed it
     return this._matrix._decompose()[DvtMatrix._DECOMP_SX];
   }
   
   return 1;
} ;

/**  Set the horizontal scale to apply to this container.
  *  @param {Number} sx   The horizontal scale to apply.
  */ 
DvtDisplayable.prototype.setScaleX = function(sx)
{
   //the matrix is the ultimate source of truth, because
   //it contains all the transform information
   var mat = this.getMatrix().clone();
   var decomp = mat._decompose();
   decomp[DvtMatrix._DECOMP_SX] = sx;
   mat._recompose(decomp);
   this.setMatrix(mat);
   
   //if using the individual transform properties, clear the matrix
   //this._matrix = null;
   
   //this._scaleX = sx ;
   //this._ApplyTransform();
} ;

/**  Return the vertical scale applied to this container.
  *  @type Number
  *  @returns vertical scale
  */ 
DvtDisplayable.prototype.getScaleY = function()
{
   //if (this._scaleY != null)
   if (this._matrix)
   {
     //return this._scaleY ;
     
     //get the value from the matrix, because other 
     //transformations may have changed it
     return this._matrix._decompose()[DvtMatrix._DECOMP_SY];
   }
   
   return 1;
} ;

/**  Set the vertical scale to apply to this container.
  *  @param {Number} sy   The horizontal scale to apply.
  */ 
DvtDisplayable.prototype.setScaleY = function(sy)
{
   //the matrix is the ultimate source of truth, because
   //it contains all the transform information
   var mat = this.getMatrix().clone();
   var decomp = mat._decompose();
   decomp[DvtMatrix._DECOMP_SY] = sy;
   mat._recompose(decomp);
   this.setMatrix(mat);
   
   //if using the individual transform properties, clear the matrix
   //this._matrix = null;
   
   //this._scaleY = sy ;
   //this._ApplyTransform();
} ;

/**  Return the rotation applied to this container.
  *  @type Number
  *  @returns rotation, in radians
  */ 
DvtDisplayable.prototype.getRotation = function()
{
   //if (this._rotation != null)
   if (this._matrix)
   {
     //return this._rotation ;
     
     //get the value from the matrix, because other 
     //transformations may have changed it
     return this._matrix._decompose()[DvtMatrix._DECOMP_R];
   }
   
   return 0;
} ;

/**  Set the rotation to apply to this container.
  *  @param {Number} angleRads   The rotation to apply, in radians.
  */ 
DvtDisplayable.prototype.setRotation = function(angleRads)
{
   //the matrix is the ultimate source of truth, because
   //it contains all the transform information
   var mat = this.getMatrix().clone();
   var decomp = mat._decompose();
   decomp[DvtMatrix._DECOMP_R] = angleRads;
   mat._recompose(decomp);
   this.setMatrix(mat);
   
   //if using the individual transform properties, clear the matrix
   //this._matrix = null;
   
   //this._rotation = angleRads ;
   //this._ApplyTransform();
} ;

/**  Return the transformation matrix applied to this container.
  *  @type DvtMatrix
  *  @returns transformation matrix
  */ 
DvtDisplayable.prototype.getMatrix = function()
{
   if (this._matrix)
   {
     return this._matrix ;
   }
   
   return new DvtMatrix(this.getContext());
} ;

/**  Set the transformation matrix to apply to this container.
  *  When set, the matrix is locked so that it becomes immutable.  
  *  To make changes, clone the matrix, apply changes to it, and then
  *  set the matrix again.
  *  @param {DvtMatrix} mat   The transformation matrix to apply.
  */ 
DvtDisplayable.prototype.setMatrix = function(mat)
{
   //if the matrix is already locked, then it must be attached
   //to a different shape, so don't allow it to be set here
   if (mat.isLocked())
   {
     return;
   }
   
   //if there was already a matrix set, unlock it before releasing it
   if (this._matrix != null)
   {
     this._matrix.__unlock();
   }
   
   //if using the matrix transform property, clear the individual properties
   //this._translateX = null;
   //this._translateY = null;
   //this._scaleX = null;
   //this._scaleY = null;
   //this._rotation = null;
   
   this._matrix = mat ;
   //lock the new matrix
   if (this._matrix)
   {
     this._matrix.__lock();
   }
   this._ApplyTransform();
} ;

/**  
  *  @private
  *  Apply transforms set on this container to the underlying implementation.
  */ 
DvtDisplayable.prototype._ApplyTransform = function()
{
   var mat = null;
   
   if (this._matrix != null)
   {
     mat = this._matrix;
   }
   
   //apply the transforms in the order:
   //1) scale
   //2) rotation
   //3) translation
   
   /*if (this._scaleX != null || this._scaleY != null)
   {
     if (mat == null)
     {
       mat = new DvtMatrix(this.getContext());
     }
     
     mat.scale(this.getScaleX(), this.getScaleY());
   }
   
   if (this._rotation != null)
   {
     if (mat == null)
     {
       mat = new DvtMatrix(this.getContext());
     }
     
     mat.rotate(this.getRotation());
   }
   
   if (this._translateX != null || this._translateY != null)
   {
     if (mat == null)
     {
       mat = new DvtMatrix(this.getContext());
     }
     
     mat.translate(this.getTranslateX(), this.getTranslateY());
   }*/
   
   this._impl.setMatrix(mat) ;
} ;


DvtDisplayable.prototype.getNumDrawEffects = function()
{
  if (!this._drawEffects)
  {
    return 0;
  }
  
  return this._drawEffects.length;
};

DvtDisplayable.prototype.getDrawEffectAt = function(index)
{
  if (!this._drawEffects || 
      index < 0 || 
      index >= this._drawEffects.length)
  {
    return null;
  }
  
  return this._drawEffects[index];
};

DvtDisplayable.prototype.addDrawEffect = function(effect)
{
  if (effect.isLocked())
  {
    return;
  }
  
  if (!this._drawEffects)
  {
    this._drawEffects = [];
  }
  
  //lock the effect
  effect.__lock();
  
  this._drawEffects.push(effect);
  
  this.getImpl().applyDrawEffects(this._drawEffects);
};

DvtDisplayable.prototype.addDrawEffectAt = function(effect, index)
{
  if (effect.isLocked())
  {
    return;
  }
  
  if (!this._drawEffects)
  {
    this._drawEffects = [];
  }
  
  //lock the effect
  effect.__lock();
  
  if (index >= this._drawEffects.length)
  {
    this._drawEffects.push(effect);
  }
  else
  {
    this._drawEffects.splice(index, 0, effect);
  }
  
  this.getImpl().applyDrawEffects(this._drawEffects);
};

DvtDisplayable.prototype.removeDrawEffect = function(effect)
{
  var index = this.getDrawEffectIndex(effect);
  if (index > -1)
  {
    //unlock the effect before removing it
    effect.__unlock();
    
    this._drawEffects.splice(index, 1);
    this.getImpl().applyDrawEffects(this._drawEffects);
  }
};

DvtDisplayable.prototype.removeDrawEffectAt = function(index)
{
  if (this._drawEffects)
  {
    var numEffects = this._drawEffects.length;
    if (index >= 0 && index < numEffects)
    {
      //unlock the effect before removing it
      var effect = this._drawEffects[index];
      effect.__unlock();
      
      this._drawEffects.splice(index, 1);
      this.getImpl().applyDrawEffects(this._drawEffects);
    }
  }
};

DvtDisplayable.prototype.removeAllDrawEffects = function()
{
  if (this._drawEffects)
  {
    var numEffects = this._drawEffects.length;
    for (var index = 0; index < numEffects; index++)
    {
      //unlock the effect before removing it
      var effect = this._drawEffects[index];
      effect.__unlock();
    }
    this._drawEffects = null;
    this.getImpl().applyDrawEffects(this._drawEffects);
  }
};

DvtDisplayable.prototype.getDrawEffectIndex = function(effect)
{
  if (this._drawEffects)
  {
    var numEffects = this._drawEffects.length;
    for (var i = 0; i < numEffects; i++)
    {
      if (effect === this._drawEffects[i])
      {
        return i;
      }
    }
  }
  return -1;
};

DvtDisplayable.prototype.applyDrawEffects = function ()
{
   this.getImpl().applyDrawEffects(this._drawEffects);
}

/**
 * Convert a point from stage coords to local coords.
 * @param {DvtPoint}  point  point in stage coords
 * @type DvtPoint
 */
DvtDisplayable.prototype.stageToLocal = function(point)
{
   return this._impl.stageToLocal(point);
};

/**
 * Convert a point from local coords to stage coords.
 * @param {DvtPoint}  point  point in local coords
 * @type DvtPoint
 */
DvtDisplayable.prototype.localToStage = function(point)
{
   return this._impl.localToStage(point);
};

/**
 * Get an array of objects in the tree from this displayable to the stage.
 * The returned array is ordered with this displayable first and the stage
 * last, like [this, this.getParent(), ... , stage].
 * @type array
 */
DvtDisplayable.prototype.getPathToStage = function()
{
   var displayable = this;
   var array = [];
   while (displayable)
   {
      array.push(displayable);
      displayable = displayable.getParent();
   }
   return array;
};

/*---------------------------------------------------------------------*/
/*    destroy()                                                        */
/*---------------------------------------------------------------------*/
/**
  *    Destroy the displayable.  It should no longer be used or displayed
  */ 
DvtDisplayable.prototype.destroy = function()
{
  //FIX BUG 12875374: Remove all draw effects at once, because removing
  //them one by one results in the remaining ones being reapplied at each
  //iteration.  Since this object is being destroyed, it is most likely 
  //disconnected from the display list.  When the draw effects are applied,
  //they may call getBBox() on the element, which can result in errors in
  //Firefox when the object is disconnected, and the view not being rendered.
  this.removeAllDrawEffects();
};

/**
 * Creates a copy of this displayable wrapped by a new container
 * @type DvtContainer
 */
DvtDisplayable.prototype.createCopy = function() 
{
  var copy = this._impl.createCopy();
  if (!copy)
    copy = new DvtContainer(this.getContext(), "clonedContainer");
  return copy;
}

/**
 * Dispatch event
 * @param {String} eventType
 * @param {String} params Optional parameters used to initialize the event
 */
DvtDisplayable.prototype.dispatchDisplayableEvent = function(eventType, params) 
{
  this._impl.dispatchDisplayableEvent(eventType, params);
}

// Copyright (c) 2008, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/*---------------------------------------------------------------------*/
/* DvtContainer   A container object for shapes and shape derivatives  */
/*---------------------------------------------------------------------*/
/**  A container for shapes, shape derivatives, and objects extended from DvtObj.
  *  @extends DvtDisplayable
  *  @class DvtContainer is a class that is a subclass of {@link DvtDisplayable}.
  *  @constructor  
  *  @param {DvtContext} context  The platform dependent context object (such
  *                               as {@link DvtSvgContext}).
  *  @param {String}     id      Optional id for this object.
  */ 
var DvtContainer = function(context, id)
{
  this.Init(context, id) ; 
};

DvtObj.createSubclass(DvtContainer, DvtDisplayable, "DvtContainer") ;



/*---------------------------------------------------------------------*/
/*   contains()                                                        */
/*---------------------------------------------------------------------*/
/**  Returns true if object is contained by this container.
  *  @param {Object} obj   The object to be searched for.
  *  @param {Boolean} bDeep   An optional boolean specifying whether the search
  *                           is to be shallow or deep.  If omitted (or false
  *                           is specified), a shallow  search of the container's
  *                           direct children is made. If true. the full child tree
  *                           hierachy is searched.
  *  @returns {boolean}  True if object is contained by this container, else false.
  */ 
DvtContainer.prototype.contains = function(obj, bDeep)
{
  var  bRet = false ;

  if (bDeep === undefined) {
    bDeep = false ;
  }

  if (! bDeep) {
     bRet = (this._findChild(obj) >= 0) ;
  }
  else {
    var  iter = this.getIterator(bDeep) ;
    var  o ;
    while (o = iter.getNext()) {
       if (o === obj) {
         bRet = true ;
         break ;
       }
    }
  }

  return bRet ;
} ;



/**
 * @protected
 */
DvtContainer.prototype.Init = function(context, id)
{
  if (! this.getImpl()) {
    this.setImpl(context.getImplFactory().newContainer(id)) ;
  }
  DvtContainer.superclass.Init.call(this, context) ;

  this._arList = null ;    // children
} ;


/*---------------------------------------------------------------------*/
/*   addChild()           Add a child to this container                */
/*---------------------------------------------------------------------*/
/**
  *  Adds the specified object as a child of this container. The object is
  *  added to the end of the child list.  If the object is already a child,
  *  it will be moved to the end of the child list.
  *  @param {DvtObj} obj  The object to be added (must be a descendent of {@link DvtObj}).
  */
DvtContainer.prototype.addChild = function(obj)
{
  if (obj) {
    // Remove the object from its current parent
    var oldParent = obj.getParent();
    if(oldParent)
      oldParent.removeChild(obj);

    //initialize _arList after removing child from parent in case
    //this container was the parent, which could result in removeChild()
    //setting _arList to null if the last child was removed
    if (!this._arList) {
      this._arList = [] ;
    }
    
    // Add the object to this container
    obj.setParent(this) ;
    this._impl.addChild(obj.getImpl()) ;  // perform platform specific add operation 
    this._arList.push(obj) ;
  }
} ;

/**
  *  Adds the specified object as a child of this container at the specified index. Returns
  *  immediately if the index position doesn't already exist in the child list.  If a currently
  *  occupied index is specified, the current child at that position and all subsequent children
  *  are moved one position higher in the list.  If the index equals the number of children, the
  *  object is added to the end of the list.
  *  @param {DvtObj} obj  The object to be added (must be a descendent of {@link DvtObj}).
  *  @param {number} index The index at which to add this object
  */
DvtContainer.prototype.addChildAt = function(obj, index)
{
  // Return immediately if the current index doesn't exist
  if(index > this.getNumChildren())
    return;

  if(obj) {
    // Remove the object from its current parent
    var oldParent = obj.getParent();
    if(oldParent)
      oldParent.removeChild(obj);
  
    // Add the child
    obj.setParent(this) ;
    this._impl.addChildAt(obj.getImpl(), index) ;  // perform platform specific add operation 
    
    if (!this._arList) {
      this._arList = [] ;
    }
    this._arList.splice(index, 0, obj) ;
  }
} ;




/*---------------------------------------------------------------------*/
/*  _findChild()  Return index of specified child obj in the internal  */
/*                list, or -1 if not found.                            */
/*---------------------------------------------------------------------*/
/**
  * Returns index of specified child obj in the internal list, or -1 if not
  * found. 
  * @type DvtObj
  * @private
  */
DvtContainer.prototype._findChild = function(obj)
{
   var  idx = -1 ;

   if (this._arList) {
      var len = this._arList.length ;
      for (var i = 0; i < len; i++) {            // find the obj
         if (this._arList[i] === obj) {
           idx = i ;
           break ;
         }
      }
   }

   return idx ;
} ;



/*---------------------------------------------------------------------*/
/*    getChildAt()                                                     */
/*---------------------------------------------------------------------*/
/**
  *   Returns the child at the specified zero-relative position, or null if
  *   there is no child represented by the position.
  *   @param {number} idx  The zero-relative index to the child object.
  *   @type {DvtObj}
  */
DvtContainer.prototype.getChildAt = function(idx)
{
   var  o = null ;
   
   if (this._arList && (this._arList.length > idx) && (idx >= 0)) {
     o = this._arList[idx] ;
   }

   return o ;
} ;



/*---------------------------------------------------------------------*/
/*    getChildAfter()                                                  */
/*---------------------------------------------------------------------*/
/**
  *   Returns the child after the specified object, or null if it is the last
  *   in the list.
  *   @param {DvtObj} obj  The object whose successor is required.
  *   @type {DvtObj}
  */
DvtContainer.prototype.getChildAfter = function(obj)
{
   var  o = null ;
   var  idx = this._findChild(obj) ;
   
   if ((idx >= 0) && (++idx < this._arList.length)) {
     o = this._arList[idx] ;
   }

   return o ;
} ;



/*---------------------------------------------------------------------*/
/*    getChildBefore()                                                 */
/*---------------------------------------------------------------------*/
/**
  *   Returns the child before the specified object, or null if the is the first
  *   in the list.
  *   @param {DvtObj} obj  The object whose predecessor is required.
  *   @type {DvtObj}
  */
DvtContainer.prototype.getChildBefore = function(obj)
{
   var  o = null ;
   var  idx = this._findChild(obj) ;
   
   if (idx > 0) {
     o = this._arList[--idx] ;
   }

   return o ;
} ;



/*---------------------------------------------------------------------*/
/*    _getChildren()                                                   */
/*---------------------------------------------------------------------*/
/**
  * @private
  * For use by DvtIterator ONLY!  Do not use!!
  * @type Array
  */
DvtContainer.prototype._getChildren = function()
{
   return this._arList ;
} ;


/*---------------------------------------------------------------------*/
/*    getChildIndex()                                                  */
/*---------------------------------------------------------------------*/
/**
  *   Returns the container index of the specified object, or -1 if the object
  *   is not a direct child of the container.
  *   @param {DvtObj} obj  The object whose container index is required.
  *   @type {number}
  */
DvtContainer.prototype.getChildIndex = function(obj)
{
   return  this._findChild(obj) ;
} ;


/*---------------------------------------------------------------------*/
/*    getIterator()                                                    */
/*---------------------------------------------------------------------*/
/**
  *  Returns an interator object for walking the container's tree of children.
  *  @param {Boolean} bDeep  If omitted or set to false, the iterator confines
  *  its search to direct children of the container.  If specified as true,
  *  a deep walk of the container tree is made.
  *  @type DvtIterator
  *
  */
DvtContainer.prototype.getIterator = function(bDeep)
{
   return  new DvtIterator(this._arList, bDeep) ;
} ;



/*---------------------------------------------------------------------*/
/*    getNumChildren()                                                 */
/*---------------------------------------------------------------------*/
/**
  *   Returns the number of direct children of this container
  *   @type number
  */
DvtContainer.prototype.getNumChildren = function()
{
   return (this._arList? this._arList.length : 0) ;
} ;


/*---------------------------------------------------------------------*/
/*    removeChild()                                                    */
/*---------------------------------------------------------------------*/
/**
  *   Removes the specified child object from this container.
  *   @param {DvtObj} obj  The object to be removed.
  */
DvtContainer.prototype.removeChild = function(obj)
{
   var idx = this._findChild(obj) ;    // is child in container

   if (idx !== -1) {
     this._removeObj(obj, idx) ;
   }
} ;


/*---------------------------------------------------------------------*/
/*    removeChildAt()                                                  */
/*---------------------------------------------------------------------*/
/**
  *   Removes the specified child object at the index specfied from this container.
  *   @param {number} idx  The index of the object to be removed.
  *   @returns {DvtObj}  The object removed.
  */
DvtContainer.prototype.removeChildAt = function(idx)
{
   var obj = this.getChildAt(idx) ;

   if (obj) {
     this._removeObj(obj, idx) ;
   }

   return obj ;
} ;


/*---------------------------------------------------------------------*/
/*    removeChildren()                                                 */
/*---------------------------------------------------------------------*/
/**
  *   Removes all child object's from this container.
  */
DvtContainer.prototype.removeChildren = function()
{
   if (this._arList) {
      var ar  = this._arList ;

      while(this.getNumChildren() > 0) {
        this._removeObj(ar[0], 0) ;
      }
   }
} ;



/*---------------------------------------------------------------------*/
/*    _removeObj()                                                     */
/*---------------------------------------------------------------------*/
/**
  *   Removes the specified object from this container.
  *   @param {DvtObj}  obj   The object to be removed.
  *   @param {number}  idx   The index position (zero relative) of the child
  *                          in the container's list of chhildren.
  *    @private
  */ 
DvtContainer.prototype._removeObj = function(obj, idx)
{
   //  obj must be in the container.

   this._impl.removeChild(obj.getImpl()) ;  // perform platform remove
   obj.setParent(null) ;

   this._arList.splice(idx,1) ;             // remove from list
   if (this._arList.length === 0) {
     this._arList = null ;
   }
} ;


/*---------------------------------------------------------------------*/
/*    swap()                                                           */
/*---------------------------------------------------------------------*/
/**
  *    Exchanges the positions of two objects in the container.
  *    DONT USE YET - IN PROGRESS JRM  TDO
  */ 
DvtContainer.prototype.swap = function(obj1, obj2)
{
   //  Both obj's must be in this same container.

   var idx1 = this.getChildIndex(obj1) ;
   var idx2 = this.getChildIndex(obj2) ;

   this._arList[idx1] = obj2 ;        // swap entries in list.
   this._arList[idx2] = obj1 ;

   this._impl.swap(obj1.getImpl(), obj2.getImpl()) ;   // perform platform swap.

} ;

/*---------------------------------------------------------------------*/
/*    destroy()                                                        */
/*---------------------------------------------------------------------*/
/**
  *    Destroy the container.  It should no longer be used or displayed
  */ 
DvtContainer.prototype.destroy = function()
{
    DvtContainer.superclass.destroy.call(this) ;
    var childCount = this.getNumChildren();
    for (var i=0;i<childCount;i++) {
        var child = this.getChildAt(i);      
        child.destroy();
    }
}
// Copyright (c) 2008, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/*-------------------------------------------------------------------------*/
/*  DvtStage()   Contains all objects associated with a specific SVG Root  */
/*-------------------------------------------------------------------------*/
/**
  *  Represents the highest level container under a specific platform DOM element
  *  such as  &lt;svg&gt; or &lt;canvas&gt;.
  *  @extends DvtContainer
  *  @class DvtStage   Represents the highest level container under a specific
  *                    platform DOM element such as  &lt;svg&gt; or &lt;canvas&gt;.
  *  DvtStage should not be used directly, retrieve via the platform context.
  *  <p>
  *  Example for SVG :<br><br>
  *  <code>
  *  context = new DvtSvgContext() ;<br>
  *  stage   = context.getStage();<br>
  *  </code>
  *  @constructor
  */
var  DvtStage = function(context, root, id)
{
  this.Init(context, root, id) ; 
};

DvtObj.createSubclass(DvtStage, DvtContainer, "DvtStage") ;


/*---------------------------------------------------------------------*/
/*  Init()                                                             */
/*---------------------------------------------------------------------*/
/**
  *  Object initializer.
  *  @protected
  */
DvtStage.prototype.Init = function(context, root, id)
{
  if (! this.getImpl()) {
    this.setImpl(context.getImplFactory().newStage(root, id)) ;
  }
  DvtStage.superclass.Init.call(this, context) ;
};
// Copyright (c) 2008, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/*---------------------------------------------------------------------*/
/*   DvtShape              Abstract base class for all shapes          */
/*---------------------------------------------------------------------*/
/**
  * An abstract base class for shapes.  Provides common drawing support
  * for properties such as such as stroke and fill types and colors. DvtShape
  * is intended to be subclassed.
  * @extends DvtContainer
  * @class DvtShape is an abstract base class for displayable shapes and
  * provides common drawing support for properties such as stroke and fill. DvtShape
  * is intended to be subclassed.
  * @constructor
  * @param {DvtContext} context The context object
  */
var  DvtShape = function(context)
{
   this.Init(context) ;
};

DvtObj.createSubclass(DvtShape, DvtContainer, "DvtShape") ;



/*---------------------------------------------------------------------*/
/*   get/setFill()                                                     */
/*---------------------------------------------------------------------*/
/**
  *   Returns the fill object (a derivative of {@link DvtFill}).
  *   @type DvtFill
  *   @returns The fill object or null if no fill has been applied.
  */
DvtShape.prototype.getFill = function()
{
    return this._impl.getFill() ;
};

/**
  *  Sets the fill properties on this shape from the supplied {@link DvtFill}
  *  subclass object. The fill object become immutable at this point (refer
  *  to {@link DvtObj#clone}). 
  *  @param {DvtFill}  fill  A fill object (derivative of {@link DvtFill}).
  *  If null is specified, a transparent fill is applied.
  */
DvtShape.prototype.setFill = function(fill)
{
   this._impl.setFill(fill) ;
   if (fill)
       fill.__lock() ;                // fill object now immutable
   
};


/*---------------------------------------------------------------------*/
/*   get/setStroke()                                                   */
/*---------------------------------------------------------------------*/
/**
  *   Returns the stroke object (a derivative of {@link DvtStroke}).
  *   @type DvtStroke
  *   @returns The stroke object.
  */
DvtShape.prototype.getStroke = function()
{
    return this._impl.getStroke() ;
};

/**
  *  Sets the stroke properties on this shape from the supplied {@link DvtStroke} 
  *  subclass object. The stroke object become immutable at this point (refer to
  *  {@link DvtObj#clone})
  *  @param {DvtStroke}  stroke  A stroke object (derivative of {@link DvtStroke}).
  */
DvtShape.prototype.setStroke = function(stroke)
{
   this._impl.setStroke(stroke) ;
   if (stroke)
   {
     stroke.__lock() ;                // stroke object now immutable
   }

};

/**  Changes the shape to an outline shape format.  Used for legends
  *  markers that represent a hidden state for the associated series risers.
  *  @param {String} color Border color for hollow shape in format of #aarrggbb
  */
DvtShape.prototype.setHollow = function(color)
{
    this._impl.setHollow(color)
};

/**  Returns whether a shape is hollow.
  *  @returns {boolean} True if the shape is hollow
  */
DvtShape.prototype.isHollow = function() {
    return this._impl.isHollow();
}

/*---------------------------------------------------------------------*/
/*    destroy()                                                        */
/*---------------------------------------------------------------------*/
/**
  *    Destroy the shape.  It should no longer be used or displayed
  */ 
DvtShape.prototype.destroy = function()
{
  DvtShape.superclass.destroy.call(this) ;
  this.setFill(null);
  this.setStroke(null);
  this.removeAllDrawEffects();
}
// Copyright (c) 2008, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/*---------------------------------------------------------------------*/
/*    DvtArc                 Base circular or elliptical arc           */
/*---------------------------------------------------------------------*/
/**
  *  Creates an arc (a portion of an ellipse or circle).
  *  @class DvtArc  Creates an arc (a portion of an ellipse or circle).
  *  <p>
  *  Example:<br><br><code>
  *  //  Create an arc from an ellipse centered at (50,50) with radii 100 and<br>
  *  // 200, and starting at angle 40, for an extent of 75.<br><br>
  *  var  arc = new DvtArc(context, 50, 50, 100, 200, 40, 75);<br><br>
  *  //  Create an arc from a circle centered at (50,50) with radii 100<br>
  *  //  starting at angle 40, for an extent of 75.<br><br>
  *  var  arc = new Dvtarc(context, 50, 50, 100, 40, 75);<br>
  *  </code>
  *  @constructor  
  *  @param {DvtContext} context   The platform dependent context object (such
  *                                as {@link DvtSvgContext}).
  *  @param {number} cx  The center x position.
  *  @param {number} cy  The center y position.
  *  @param {number} rx  The horizontal radius of the ellipse/circle.
  *  @param {number} ry  The vertical radius of the ellipse/circle.
  *  @param {number} sa  The starting angle in degrees (following the normal anti-clockwise is positive convention).
  *  @param {number} ae  The angle extent in degrees (following the normal anti-clockwise is positive convention).
  *  @param {String} clos  An optional closure type for the arc. Closure types are {@link DvtArc#OPEN} (the default),
  *                        {@link DvtArc#CHORD} and {@link DvtArc#PIE}.
  *  @param {String} id  Optional ID for the shape (see {@link  DvtDisplayable#setId}).
  */
var  DvtArc = function(context, cx, cy, rx, ry, sa, ae, clos, id)
{
   this.Init(context, cx, cy, rx, ry, sa, ae, clos, id) ;
};

DvtObj.createSubclass(DvtArc, DvtShape, "DvtArc") ;

// Closure types
/** 
  * Closure type - arc is not closed.
  * @type String
  */
DvtArc.OPEN  = "OPEN" ;
/**
  * Closure type - arc is closed to create a segment.
  * @type String
  */
DvtArc.CHORD = "CHORD" ;
/** 
  * Closure type - arc is closed to create a sector.
  * @type String
  */
DvtArc.PIE   = "PIE" ;



/*---------------------------------------------------------------------*/
/*   getAngleStart()                                                   */
/*---------------------------------------------------------------------*/
/**
  *  Returns the start angle of the arc.
  *  @returns {number}  The starting angle (following the normal anti-clockwise
  *  is positive convention).
  */
DvtArc.prototype.getAngleStart = function()
{
   return this._impl.getAngleStart() ;
} ;
/**
  *  Sets the start angle of the arc.
  *  @param {number} sa  The starting angle (following the normal anti-clockwise
  *  is positive convention).
  */
DvtArc.prototype.setAngleStart = function(sa)
{
   this._impl.setAngleStart(sa) ;
} ;


/*---------------------------------------------------------------------*/
/*   getAngleExtent()                                                  */
/*---------------------------------------------------------------------*/
/**
  *  Returns the angle subtended by the arc.
  *  @returns {number}  The angle subtended by the arc (following the normal anti-clockwise
  *  is positive convention).
  */
DvtArc.prototype.getAngleExtent = function()
{
   return this._impl.getAngleExtent() ;
} ;
/**
  *  Sets the angle subtended by the arc.
  *  @param {number} ae  The angle subtended by the arc (following the normal anti-clockwise
  *  is positive convention).
  */
DvtArc.prototype.setAngleExtent = function(ae)
{
   this._impl.setAngleExtent(ae) ;
} ;


/*---------------------------------------------------------------------*/
/*   get/setClosure()                                                  */
/*---------------------------------------------------------------------*/
/**
  *  Returns the closure type of the arc.
  *  @type String
  *  @returns The closure type,  such as {@link DvtArc#OPEN}.
  */
DvtArc.prototype.getClosure = function()
{
   return this._impl.getClosure() ;
} ;

/**
  *  Sets the closure type of the arc.
  *  @param {String} ct   The closure type, such as {@link DvtArc#OPEN}.
  */
DvtArc.prototype.setClosure = function(ct)
{
   this._impl.setClosure(ct) ;
} ;


/*---------------------------------------------------------------------*/
/*   get/setRx()                                                       */
/*---------------------------------------------------------------------*/
/**
  *  Gets the horizontal radius of the ellipse.
  *  @type number
  */
DvtArc.prototype.getRx = function()
{
   return this._impl.getRx() ;
} ;
/**
  *  Sets the horizontal radius of the ellipse.
  *  @param {number} rx  The horizontal radius of the ellipse.
  */
DvtArc.prototype.setRx = function(rx)
{
   this._impl.setRx(rx) ;
} ;


/*---------------------------------------------------------------------*/
/*   get/setRy()                                                       */
/*---------------------------------------------------------------------*/
/**
  *  Gets the vertical radius of the ellipse.
  *  @type number
  */
DvtArc.prototype.getRy = function()
{
   return this._impl.getRy() ;
} ;
/**
  *  Sets the vertical radii of the ellipse.
  *  @param {number} ry  The vertical radius of the ellipse.
  */
DvtArc.prototype.setRy = function(ry)
{
   this._impl.setRy(ry) ;
} ;


/*---------------------------------------------------------------------*/
/*  Init()                                                             */
/*---------------------------------------------------------------------*/
/**
  *  Object initializer.
  */
DvtArc.prototype.Init = function(context, cx, cy, rx, ry, sa, ae, clos, id)
{
  if (! this.getImpl()) {
    this.setImpl(context.getImplFactory().newArc(cx, cy, rx, ry, sa, ae, clos, id)) ;
  }
  DvtArc.superclass.Init.call(this, context) ;

};


/*---------------------------------------------------------------------*/
/*   setArc()                                                          */
/*---------------------------------------------------------------------*/
/**
  *  Defines the position and extent of the arc.
  *  @param {number} sa  The starting angle in degrees (following the normal anti-clockwise is positive convention).
  *  @param {number} ae  The angle extent in degrees (following the normal anti-clockwise is positive convention).
  */
DvtArc.prototype.setArc = function(sa, ae)
{
   this._impl.setArc(sa, ae) ;
} ;


/*---------------------------------------------------------------------*/
/*   Convenience Functions                                             */
/*---------------------------------------------------------------------*/
/**
  *  Sets both the horizontal and vertical radii of the ellipse/circle.
  *  @param {number} rx  The horizontal radius of the ellipse.
  *  @param {number} ry  The vertical radius of the ellipse.
  */
DvtArc.prototype.setRadius = function(rx, ry)
{
   this.setRx(rx);
   this.setRy(ry);
} ;

// Copyright (c) 2008, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/*---------------------------------------------------------------------*/
/*    DvtCircle           Base circular or elliptical shape            */
/*---------------------------------------------------------------------*/
/**
  *  Creates a circular displayable shape.
  *  @extends DvtShape
  *  @class DvtCircle is a platform independent class representing a displayable
  *  circle.
  *  <p>
  *  <b>Example:</b><br><br> <code>
  *  var circle = new DvtCircle(context, 10, 10, 100, 'myCircle') ;<br>
  *  circle.setStroke(new DvtStroke("red", 5)) ;<br>
  *</code>
  *<br>
  *  @constructor
  *  @param {DvtContext} context   The platform dependent context object (such
  *                                as {@link DvtSvgContext}).
  *  @param {number} cx  The center x position.
  *  @param {number} cy  The center y position.
  *  @param {number} r   The radius of the circle.
  *  @param {String} id  Optional ID for the object (see also {@link DvtDisplayable#setId}) 
  */
var  DvtCircle = function(context, cx, cy, r, id)
{
   this.Init(context, cx, cy, r, id) ;
};

DvtObj.createSubclass(DvtCircle, DvtShape, "DvtCircle") ;






/*---------------------------------------------------------------------*/
/*   get/setCx()                                                       */
/*---------------------------------------------------------------------*/
/**
  *    Returns the center x-coordinate.
  *    @type number
  *    @returns The center x-coordinate.
  */
DvtCircle.prototype.getCx = function()
{
   return this._impl.getCx() ;
} ;
/**
  *  Sets the x coordinate of the center.
  *  @param {number} cx  The center x position.
  */

DvtCircle.prototype.setCx = function(cx)
{
   this._impl.setCx(cx) ;
} ;


/*---------------------------------------------------------------------*/
/*   get/setCy()                                                       */
/*---------------------------------------------------------------------*/
/**
  *    Returns the center y-coordinate.
  *    @type number
  *    @returns The center y-coordinate.
  */
DvtCircle.prototype.getCy = function()
{
   return this._impl.getCy() ;
} ;
/**
  *  Sets the y coordinate of the center.
  *  @param {number} cy  The center y position.
  *
  */
DvtCircle.prototype.setCy = function(cy)
{
   this._impl.setCy(cy) ;
} ;

/*---------------------------------------------------------------------*/
/*   get/setRadius()                                                   */
/*---------------------------------------------------------------------*/
/**
  *    Returns the radius of the circle.
  *    @type number
  *    @returns The radius of the circle.
  */
DvtCircle.prototype.getRadius = function()
{
   return this._impl.getRadius() ;
} ;

/**
  *  Sets the radius  of the circle.
  *  @param {number} r   The radius of the circle.
  */
DvtCircle.prototype.setRadius = function(r)
{
   this._impl.setRadius(r) ;
} ;


/*---------------------------------------------------------------------*/
/*  Init()                                                             */
/*---------------------------------------------------------------------*/
/**
  *  Object initializer.
  */
DvtCircle.prototype.Init = function(context, cx, cy, r, id)
{
  if (! this.getImpl()) {
    this.setImpl(context.getImplFactory().newCircle(cx, cy, r, id)) ;
  }

  DvtCircle.superclass.Init.call(this, context) ;
};



/*---------------------------------------------------------------------*/
/*   Convenience Functions                                             */
/*---------------------------------------------------------------------*/
/**
  *  Sets the center position of the circle.
  *  @param {number} cx The center x position
  *  @param {number} cy The center y position
  */
DvtCircle.prototype.setCenter= function(cx,cy)
{
   this.setCx(cx) ;
   this.setCy(cy) ;
} ;
// Copyright (c) 2008, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/*---------------------------------------------------------------------*/
/*    DvtImage               Base image shape                          */
/*---------------------------------------------------------------------*/
/**
  * Creates an image.
  * @extends DvtShape
  * @class DvtImage is a platform independent class representing a displayable
  * image.
  * <p>
  * <b>Example:</b><br><br> <code>
  * var img = new DvtImage(context, "pic.png", 10, 10, 100, 150, 'myImage') ;<br>
  *</code>
  * @constructor  
  * @param {DvtContext} context   The platform dependent context object (such
  *                               as {@link DvtSvgContext}).
 *  @param {String} imgSrc  The image URL.
 *  @param {number} x  The x position of the top left corner of the image.
 *  @param {number} y  The y position of the top left corner of the image.
 *  @param {number} w  The width of the image (optional).
 *  @param {number} h  The height of the image (optional).
 *  @param {String} id Optional ID for the shape (see {@link  DvtDisplayable#setId}).
  */
var DvtImage = function(context, imgSrc, x, y, w, h, id)
{
  this.Init(context, imgSrc, x, y, w, h, id) ;
};

DvtObj.createSubclass(DvtImage, DvtShape, "DvtImage") ;



/*---------------------------------------------------------------------*/
/*   get/setHeight()                                                   */
/*---------------------------------------------------------------------*/
/**
  *  Gets the height of the image.
  *  @returns {number}  The height of the image.
  */
DvtImage.prototype.getHeight = function()
{
  return this._impl.getHeight() ;
} ;

/**
  *  Sets the height of the image.
  *  @param {number} h  The height of the image.
  */
DvtImage.prototype.setHeight = function(h)
{
  this._impl.setHeight(h) ;
} ;

/*---------------------------------------------------------------------*/
/*   getPos()   Returns a DvtPoint for the (x,y) coordinate of the     */
/*              rectangle.                                             */
/*---------------------------------------------------------------------*/

DvtImage.prototype.getPos = function()
{
  return this._impl.getPos() ;
};


/*---------------------------------------------------------------------*/
/*   setPos(x,y)                                                       */
/*---------------------------------------------------------------------*/

DvtImage.prototype.setPos= function(x,y)
{
  this.setX(x) ;
  this.setY(y) ;
};


/*---------------------------------------------------------------------*/
/*   setSrc()                                                          */
/*---------------------------------------------------------------------*/
/**
  *  Sets the src of the image.
  *  @param {String} src  The src of the image.
  *  @returns nothing
  */
DvtImage.prototype.setSrc = function(src)
{
  this._impl.setSrc(src);
} ;



/*---------------------------------------------------------------------*/
/*   get/setX()                                                        */
/*---------------------------------------------------------------------*/
/**
  *  Returns the <code>x</code> coordinate of the image.
  *  @returns {number} the <code>x</code> coordinate of the image.
  */
DvtImage.prototype.getX = function()
{
   return this._impl.getX() ;
} ;

/**
  *  Sets the <code>x</code> coordinate of the top left position of the image.
  *  @param {number} x  The <code>x</code> coordinate of the top left coordinate of the image.
  */
DvtImage.prototype.setX = function(x)
{
  this._impl.setX(x) ;
} ;

/*---------------------------------------------------------------------*/
/*   get/setY()                                                        */
/*---------------------------------------------------------------------*/
/**
  *  Returns the <code>y</code> coordinate of the image.
  *  @returns {number} the <code>y</code> coordinate of the image.
  */
DvtImage.prototype.getY = function(y)
{
  return this._impl.getY() ;
} ;

/**
  *  Sets the <code>y</code> coordinate of the top left position of the image.
  *  @param {number} x  The <code>y</code> coordinate of the top left coordinate of the image.
  */
DvtImage.prototype.setY = function(y)
{
  this._impl.setY(y) ;
} ;


/*---------------------------------------------------------------------*/
/*   get/setWidth()                                                    */
/*---------------------------------------------------------------------*/
/**
  *  Returns the width of the image.
  *  @returns {number} the width of the image.
  */
DvtImage.prototype.getWidth = function()
{
  return this._impl.getWidth() ;
} ;

/**
  *  Sets the width of the image.
  *  @param {number} w  The width of the image.
  */
DvtImage.prototype.setWidth = function(w)
{
  this._impl.setWidth(w) ;
} ;


/*---------------------------------------------------------------------*/
/*  Init()                                                             */
/*---------------------------------------------------------------------*/
/**
  *  Object initializer.
  *  @protected
  */
DvtImage.prototype.Init = function(context, imgSrc, x, y, w, h, id)
{
  if (! this.getImpl()) {
    this.setImpl(context.getImplFactory().newImage(imgSrc, x, y, w, h, id)) ;
  }
  DvtImage.superclass.Init.call(this, context) ;

};

// Copyright (c) 2008, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/*--------------------------------------------------------------------*/
/*   DvtLine                   Base Line shape                        */
/*--------------------------------------------------------------------*/
/**
  *  Creates a line drawn from (x1, y1) to (x2, y2).
  *  @extends DvtShape
  *  @class DvtLine Creates a line drawn from (x1, y1) to (x2, y2).
  *   <p>
  *  Example:<br><br><code>
  *  var line = new DvtLine(context, 10, 10, 100, 150);<br>
  *  </code>
  *  @constructor  
  *  @param {DvtContext} context   The platform dependent context object (such
  *                                as {@link DvtSvgContext}).
  *  @param {number} x1  An x end position of the line.
  *  @param {number} y1  The associated y end point (for x1).
  *  @param {number} x2  The other x end point.
  *  @param {number} y2  The associated y end point (for x2).
  *  @param {String} id  Optional ID for the shape (see {@link  DvtDisplayable#setId}).
  *
  */
var  DvtLine = function(context, x1, y1, x2, y2, id)
{
   this.Init(context, x1, y1, x2, y2, id ) ;
};

DvtObj.createSubclass(DvtLine, DvtShape, "DvtLine") ;


/*-------------------------------------------------------------------------*/
/*   get/setX1()                                                           */
/*-------------------------------------------------------------------------*/
/**
  *  Returns the <code>x1</code> coordinate of the line.
  *  @returns {number} the <code>x1</code> coordinate of the line.
  */
DvtLine.prototype.getX1 = function()
{
   return this._impl.getX1() ;
} ;

/**
  *  Sets the <code>x1</code> coordinate of the line.
  *  @param {number} x1  The <code>x</code> coordinate of the line.
  */
DvtLine.prototype.setX1 = function(x1)
{
   this._impl.setX1(x1) ;
} ;

/*-------------------------------------------------------------------------*/
/*   get/setY1()                                                           */
/*-------------------------------------------------------------------------*/
/**
  *  Returns the <code>y1</code> coordinate of the line.
  *  @returns {number} the <code>y1</code> coordinate of the line.
  */
DvtLine.prototype.getY1 = function()
{
   return this._impl.getY1() ;
} ;

/**
  *  Sets the <code>y1</code> coordinate of the line.
  *  @param {number} y1  The <code>y</code> coordinate of the line.
  */
DvtLine.prototype.setY1 = function(y1)
{
   this._impl.setY1(y1) ;
} ;

/*-------------------------------------------------------------------------*/
/*   get/setX2()                                                           */
/*-------------------------------------------------------------------------*/
/**
  *  Returns the <code>x2</code> coordinate of the line.
  *  @returns {number} the <code>x2</code> coordinate of the line.
  */
DvtLine.prototype.getX2 = function()
{
   return this._impl.getX2() ;
} ;

/**
  *  Sets the <code>x2</code> coordinate of the line.
  *  @param {number} x2  The <code>x</code> coordinate of the line.
  */
DvtLine.prototype.setX2 = function(x2)
{
   this._impl.setX2(x2) ;
} ;

/*-------------------------------------------------------------------------*/
/*   get/setY2()                                                           */
/*-------------------------------------------------------------------------*/
/**
  *  Returns the <code>y2</code> coordinate of the line.
  *  @returns {number} the <code>y2</code> coordinate of the line.
  */
DvtLine.prototype.getY2 = function()
{
   return this._impl.getY2() ;
} ;

/**
  *  Sets the <code>y2</code> coordinate of the line.
  *  @param {number} y2  The <code>y</code> coordinate of the line.
  */
DvtLine.prototype.setY2 = function(y2)
{
   this._impl.setY2(y2) ;
} ;



/*---------------------------------------------------------------------*/
/*  Init()                                                             */
/*---------------------------------------------------------------------*/
/**
  *  Object initializer.
  *  @protected
  */
DvtLine.prototype.Init = function(context, x1, y1, x2, y2, id)
{
  if (! this.getImpl()) {
    this.setImpl(context.getImplFactory().newLine(x1, y1, x2, y2, id)) ;
  }
  DvtLine.superclass.Init.call(this, context) ;

};


// Copyright (c) 2008, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/*---------------------------------------------------------------------*/
/*   DvtMarker                 Marker shape                            */
/*---------------------------------------------------------------------*/
/** 
  *  A marker object for lines, scatter and bubble charts and legend areas.
  *  @class DvtMarker A marker object for lines, scatter and bubble charts and legend areas.
  *  e.g.<br><br><code>
  *  var  marker = new DvtMarker(context, DvtMarker.CIRCLE, 50, 50, 10, 10) ;<br></code>
  *  @extends DvtShape
  *  @constructor
  *  @param {DvtContext} context   The platform dependent context object (such
  *                                as {@link DvtSvgContext}).
  *  @param {number} type The type of the marker (see {@link DvtMarker}).
  *  @param {number} x  The x position of the top left corner of the marker.
  *  @param {number} y  The y position of the top left corner of the marker.
  *  @param {number} w  The width of the marker.
  *  @param {number} h  The height of the marker.
  *  @param {number} sx  Optional The horizontal scale factor of the marker.
  *  @param {number} sy  Optional The vertical scale factor of the marker.
  *  @param {String} id  Optional ID for the shape (see {@link  DvtDisplayable#setId}).
  *
  *  Note: When type is DvtMarker.CUSTOM, id is used as the svg path for the custom marker
  */
var  DvtMarker = function(context, type, x, y, w, h, id, sx, sy)
{
  this.Init(context, type,x, y, w, h, id, sx, sy) ;
};

DvtObj.createSubclass(DvtMarker, DvtShape, "DvtMarker") ;

//  Marker types
//  Note: these marker types are defined in the same order
//        as the definitions in the parser.  Don't change
//        one without changing the other!
/**
  *  No marker shape defined.
  *  @final @type number
  */
DvtMarker.NONE          = -1 ;
/**  A circular marker.
  *  @final @type number
  */
DvtMarker.CIRCLE        = 0 ;
/**  A square marker.
  *  @final  @type number
  */
DvtMarker.SQUARE        = 1 ;
/**  A diamond shaped marker.
  *  @final  @type number
 */
DvtMarker.DIAMOND       = 2 ;
/**  A triangular shaped marker with a vertice at the top.
  *  @final  @type number
  */
DvtMarker.TRIANGLE_UP   = 3 ;
/**  A triangular shaped marker with a vertice at the bottom.
  *  @final  @type number
  */
DvtMarker.TRIANGLE_DOWN = 4 ;
/**  A plus-shaped marker.
  *  @final  @type number
  */
DvtMarker.PLUS          = 5 ;
/**  A human figure shaped marker.
  *  @final  @type number
  */
DvtMarker.HUMAN         = 6 ;

/**  A custom shaped marker.
  *  @final  @type number
  */
DvtMarker.CUSTOM        = 7 ;


/**
 * @protected
 */
DvtMarker.SELECTION_STROKE_COLOR = "#000000";
/**
 * @protected
 */
DvtMarker.SELECTION_STROKE_ALPHA = 1;


/*---------------------------------------------------------------------*/
/*   getSize()                                                         */
/*---------------------------------------------------------------------*/
/**
  *  Returns the greater of the width and height measurement.
  *  @returns {number} the size of the marker.
  */
DvtMarker.prototype.getSize = function()
{
   return this._size;
} ;

/*---------------------------------------------------------------------*/
/*  getType()                                                          */
/*---------------------------------------------------------------------*/
/**
  *  Returns the type of the marker (such as {@link DvtMarker#CIRCLE}).
  *  @returns {number} the type of the marker (such as {@link DvtMarker#CIRCLE}).
  */
DvtMarker.prototype.getType = function()
{
   return  this._impl.getType() ;
} ;

/*---------------------------------------------------------------------*/
/*  Init()                                                             */
/*---------------------------------------------------------------------*/
/**
  *  Object initializer.
  *  @protected
  */
DvtMarker.prototype.Init = function(context, type, x, y, w, h, id, sx, sy)
{
  //BUG FIX #13376761: save initial parameters in case we want to create
  //a copy of this marker
  this._xx = x;
  this._yy = y;
  this._ww = w;
  this._hh = h;
  this._sx = sx ? sx : 1;
  this._sy = sy ? sy : 1;
  
  // Get the marker def
  var etype;
  var markerDef;
  if (type === DvtMarker.CUSTOM) {
    markerDef = DvtMarkerUtils.getCustomMarkerInfo(context, id);
    if (markerDef) {
      // Custom marker is always DvtPath or DvtContainer containing a collection of DvtPaths
      etype = (markerDef instanceof DvtPath ? 'path' : 'g');
      if (! w || ! h) {
        var dim = DvtDisplayableUtils._getDimForced(context, markerDef);
        w = w ? w : dim.w;
        h = h ? h : dim.h;
      }
    }
    // no markerDef found, default to rect
    else {
      type = 1;
    }
  }
  // Create the impl shape
  if (!this.getImpl())
    this.setImpl(context.getImplFactory().newMarker(type, id, etype)) ;
  
  // Superclass should only be set after the impl is created
  DvtMarker.superclass.Init.call(this, context);
  
  if (type === DvtMarker.HUMAN) {
    markerDef = DvtMarkerUtils.getBuiltinMarkerInfo(context, "human");
  }

  // Update the width and height with the scale factors
  var ww = sx ? w*sx : w;
  var hh = sy ? h*sy : h;
  this._size = Math.max(ww, hh);
  
  // Position and size the marker
  this.getImpl().setBounds(x, y, ww, hh, markerDef);

  // Store other params
  this._bSelectable      = false;
  this._bSelected        = false;
  this._bSelecting       = false;
  this._selectionEffects = null;
  this._dataColor        = "#000000";
  this._underlayColor    = "#000000";
  
  //properties related to selection
  this._savedStroke      = null;
  this._savedFill        = null;
  this._bSavedStroke     = false;
  this._bSavedFill       = false;
  this._selectionType    = DvtSelectionEffectUtils.DEFAULT_SEL_TYPE;
  this._selStrokeWidth   = null;
  this._selStrokeColor   = null;
  this._selStrokeAlpha   = null;
};

/**
 *  Returns the x-coord of the marker.
 *  @returns {number} the x-coord of the marker
 */
DvtMarker.prototype.getX = function()
{
   return  this._xx ;
} ;

/**
 *  Returns the y-coord of the marker.
 *  @returns {number} the y-coord of the marker
 */
DvtMarker.prototype.getY = function()
{
   return  this._yy ;
} ;

/**
 *  Returns the width of the marker, before any scale is applied.
 *  @returns {number} the width of the marker
 */
DvtMarker.prototype.getWidth = function()
{
   return  this._ww ;
} ;

/**
 *  Returns the height of the marker, before any scale is applied.
 *  @returns {number} the height of the marker
 */
DvtMarker.prototype.getHeight = function()
{
   return  this._hh ;
} ;

/**
 *  Returns the horizontal scale of the marker.
 *  @returns {number} the horizontal scale of the marker
 */
DvtMarker.prototype.getSx = function()
{
   return  this._sx ;
} ;

/**
 *  Returns the vertical scale of the marker.
 *  @returns {number} the vertical scale of the marker
 */
DvtMarker.prototype.getSy = function()
{
   return  this._sy ;
} ;

/**
 * Converts the specified shape string to its constant value.
 * @param {string} shape The shape string.
 * @return {number} The corresponding constant value.
 */
DvtMarker.convertShapeString = function(shape) {
  if(shape == "circle" || shape == "c")
    return DvtMarker.CIRCLE;
  else if(shape == "square" || shape == "s")
    return DvtMarker.SQUARE;
  else if(shape == "diamond" || shape == "d")
    return DvtMarker.DIAMOND;
  else if(shape == "triangleUp" || shape == "tu")
    return DvtMarker.TRIANGLE_UP;
  else if(shape == "triangleDown" || shape == "td")
    return DvtMarker.TRIANGLE_DOWN;
  else if(shape == "plus" || shape == "p")
    return DvtMarker.PLUS;
  else if(shape == "human" || shape == "h")
    return DvtMarker.HUMAN;
  else
    return DvtMarker.NONE;
}

/**
 * @protected
 * Set the type of selection feedback to show.
 */
DvtMarker.prototype.setSelectionType = function(type)
{
  this._selectionType = type;
};

/**
 * @protected
 * Get the type of selection feedback to show.
 */
DvtMarker.prototype.getSelectionType = function(type)
{
  return this._selectionType;
};

/**
 * @protected
 * Apply any selection effects to this object.
 */
DvtMarker.prototype.ApplySelectionState = function()
{
  switch (this._selectionType)
  {
    case DvtSelectionEffectUtils.SEL_TYPE_STROKE_NO_FILTERS:
      this.ApplySelectingSelectedStroke(true, true, true);
      break;
    case DvtSelectionEffectUtils.SEL_TYPE_STROKE_FILTERS:
    default:
      this.ApplySelectionFilters();
      break;
  }
};

/**
 * @protected
 * Apply any selection filters to this object.
 */
DvtMarker.prototype.ApplySelectionFilters = function()
{
  if (!this._selectionEffects)
  {
    this.UpdateSelectionEffects();
  }
  
  //if (this._bSelectionInitialized)
  //{
    if (this._bSelected)
    {
      if (this._selectionEffects)
      {
        for (var i = 0; i < this._selectionEffects.length; i++)
        {
          var drawEffect = this._selectionEffects[i];
          if (!(drawEffect instanceof DvtShadow) || this._bSelectedShadow)
          {
            DvtSelectionEffectUtils.applyDrawEffect(this, drawEffect);
          }
        }
      }
    }
    else
    {
      this.ClearSelectionEffects();
    }
  //}
};


/**
 * @protected
 * Clear any selection effects.
 */
DvtMarker.prototype.ClearSelectionEffects = function()
{
  if (this._selectionEffects)
  {
    for (var i = 0; i < this._selectionEffects.length; i++)
    {
      this.removeDrawEffect(this._selectionEffects[i]);
    }
  }
};


/**
 * @protected
 * Destroy any selection effects.
 */
DvtMarker.prototype.DestroySelectionEffects = function()
{
  this._selectionEffects = null;
};


/**
 * @protected
 * Update any selection effects.
 */
DvtMarker.prototype.UpdateSelectionEffects = function()
{
  var selColor = "#000000";
  if (this._impl.getUnderlay()) {
    selColor = this._underlayColor;
  } else {
    selColor = this._dataColor; 
  }
  this._selectionEffects = DvtSelectionEffectUtils.createMarkerSelectionEffects(this.getContext(), selColor);
};


/**
 * @protected
 * Apply any mouse hover selection effects to this object.
 */
DvtMarker.prototype.ApplySelectingState = function()
{
  switch (this._selectionType)
  {
    case DvtSelectionEffectUtils.SEL_TYPE_STROKE_NO_FILTERS:
      this.ApplySelectingSelectedStroke(true, true, true);
      break;
    case DvtSelectionEffectUtils.SEL_TYPE_STROKE_FILTERS:
    default:
      this.ApplySelectingStroke();
      break;
  }
};

/**
 * @protected
 */
DvtMarker.prototype.ApplySelectingStroke = function(bAnimated)
{
  this.ApplySelectingSelectedStroke(bAnimated, true);
};

/**
 * @protected
 */
DvtMarker.prototype.ApplySelectingSelectedStroke = function(bAnimated, bApplySelecting, bApplySelected)
{
  var stroke;
  var bSelecting = bApplySelecting && this._bSelecting;
  var bSelected = bApplySelected && this._bSelected;
  
  var bStrokeFill = (this._selectionType === DvtSelectionEffectUtils.SEL_TYPE_STROKE_NO_FILTERS);
  if (bStrokeFill)
  {
    var fill;
    if (bSelected)
    {
      if (!this._bSavedFill)
      {
        fill = new DvtSolidFill("#ffffff", 1);
        this._savedFill = this.getFill();
        this._bSavedFill = true;
        this.setFill(fill);
      }
    }
    else
    {
      if (this._bSavedFill)
      {
        fill = this._savedFill;
        this._savedFill = null;
        this._bSavedFill = false;
        
        this.setFill(fill);
      }
    }
  }
  
  if (bSelecting || bSelected)
  {
    if (!this._bSavedStroke)
    {
      stroke = DvtSelectionEffectUtils.createSelectingStroke(this._dataColor);
      
      //for selection, save the color and alpha before applying
      //the new values
      if (stroke instanceof DvtSolidStroke)
      {
        this._selStrokeColor = stroke.getColor();
        this._selStrokeAlpha = stroke.getAlpha();
        if (bSelected)
        {
          if (bStrokeFill)
          {
            stroke.setColor(this._dataColor);
          }
          else
          {
            stroke.setColor(DvtMarker.SELECTION_STROKE_COLOR);
            stroke.setAlpha(DvtMarker.SELECTION_STROKE_ALPHA);
          }
        }
      }
      
      
      var strokeWidth = stroke.getWidth();
      strokeWidth = this.ScaleStrokeWidth(strokeWidth);
      //save the stroke width so that we can reset it if needed
      this._selStrokeWidth = strokeWidth;
      stroke.setWidth(strokeWidth);
      
      this._savedStroke = this.getStroke();
      this._bSavedStroke = true;
      
      this.setStroke(stroke);
    }
    
    //for selection, set the selected color and alpha values on the stroke;
    //for selecting, restore the original color and alpha values on the stroke
    if (bApplySelecting && bApplySelected)
    {
      if (this._bSelected && this.getStroke() instanceof DvtSolidStroke)
      {
        stroke = this.getStroke().clone();
        if (bStrokeFill)
        {
        if (stroke.getColor() !== this._dataColor)
        {
          stroke.setColor(this._dataColor);
          this.setStroke(stroke);
        }
      }
        else
        {
          if (stroke.getColor() !== DvtMarker.SELECTION_STROKE_COLOR)
          {
            stroke.setColor(DvtMarker.SELECTION_STROKE_COLOR);
            stroke.setAlpha(DvtMarker.SELECTION_STROKE_ALPHA);
            this.setStroke(stroke);
          }
        }
      }
      else if (this._bSelecting && this.getStroke() instanceof DvtSolidStroke)
      {
        stroke = this.getStroke().clone();
        if (stroke.getColor() !== this._selStrokeColor)
        {
          stroke.setColor(this._selStrokeColor);
          stroke.setAlpha(this._selStrokeAlpha);
          this.setStroke(stroke);
        }
      }
    }
    
    if (this._impl.getUnderlay()) {
      var underlayStroke = DvtSelectionEffectUtils.createSelectingStroke(this._underlayColor);
      var underlayStrokeWidth = underlayStroke.getWidth();
      // The stroke width changes with the parent marker's scale
      // This may not be what we wanted and may need to change in the future
      underlayStrokeWidth = this.ScaleStrokeWidth(underlayStrokeWidth);
      if (this.getType() === DvtMarker.HUMAN)
        underlayStrokeWidth *= this.getImpl().getDefaultScale();
      underlayStroke.setWidth(underlayStrokeWidth);
      this._impl.getUnderlay().setStroke(underlayStroke);
    }
    
    //if animating and applying selecting effects, start or stop
    //the animation
    if (bAnimated && bApplySelecting)
    {
      if (this._bSelecting)
      {
        if (!this._selectingAnimator)
        {
          //start the animation if we're currently selecting and 
          //we haven't already started an animation
          this.StartAnimatingStroke();
        }
      }
      else
      {
        //stop the animation if we're not currently selecting
        this.StopSelectingAnimator();
        //need to reset the stroke width because we've stopped
        //the animation in the middle
        this.SetStrokeWidth(this._selStrokeWidth);
      }
    }
  }
  else
  {
    //need to stop animation before restoring old stroke
    if (bAnimated)
    {
      this.StopSelectingAnimator();
    }
    
    stroke = this._savedStroke;
    this._savedStroke = null;
    this._bSavedStroke = false;
    
    this.setStroke(stroke);
    // reset underlay stroke to null
    // if underlay ever comes with original stroke, this need to be modified
    if (this._impl.getUnderlay()) 
    this._impl.getUnderlay().setStroke(null);
  }
};

/**
 * @protected
 */
/*DvtMarker.prototype.ApplySelectingAnimatedScale = function()
{
  if (this._bSelecting)
  {
    this._savedMatrix = this.getMatrix().clone();
    
    this.StartAnimatingScale();
  }
  else
  {
    this.StopSelectingAnimator();
    
    this.setMatrix(this._savedMatrix);
  }
};*/

/**
 * @protected
 */
DvtMarker.prototype.StartAnimatingStroke = function()
{
  if (!this._bSelecting)
  {
    return;
  }
  
  var playable1 = new DvtCustomAnimation(this.getContext(), null, 1);
  var anim1 = playable1.getAnimator();
  anim1.addProp(DvtAnimator.TYPE_NUMBER, this, this.GetStrokeWidth, this.SetStrokeWidth, this.getStroke().getWidth() * 3);
  
  var playable2 = new DvtCustomAnimation(this.getContext(), null, 1);
  var anim2 = playable2.getAnimator();
  anim2.addProp(DvtAnimator.TYPE_NUMBER, this, this.GetStrokeWidth, this.SetStrokeWidth, this.getStroke().getWidth());
  
  var seqPlayable = new DvtSequentialPlayable(this.getContext(), playable1, playable2);
  seqPlayable.setOnEnd(this.StartAnimatingStroke, this);
  
  this._selectingAnimator = seqPlayable;
  seqPlayable.play();
};

/**
 * @protected
 */
/*DvtMarker.prototype.StartAnimatingScale = function()
{
  if (!this._bSelecting)
  {
    return;
  }
  
  var newMat = this.getMatrix().clone();
  var dims = this.getDimensions();
  //dims.w *= this.getScaleX();
  //dims.h *= this.getScaleY();
  newMat.translate(-dims.w / 2, -dims.h / 2);
  newMat.scale(2);
  newMat.translate(dims.w / 2, dims.h / 2);
  
  //this.setMatrix(newMat);
  //return;
  
  var playable1 = new DvtCustomAnimation(this.getContext(), null, 1);
  var anim1 = playable1.getAnimator();
  anim1.addProp(DvtAnimator.TYPE_MATRIX, this, this.getMatrix, this.setMatrix, newMat);
  
  var playable2 = new DvtCustomAnimation(this.getContext(), null, 1);
  var anim2 = playable2.getAnimator();
  anim2.addProp(DvtAnimator.TYPE_MATRIX, this, this.getMatrix, this.setMatrix, this.getMatrix().clone());
  
  var seqPlayable = new DvtSequentialPlayable(this.getContext(), playable1, playable2);
  seqPlayable.setOnEnd(this.StartAnimatingScale, this);
  
  this._selectingAnimator = seqPlayable;
  seqPlayable.play();
};*/

/**
 * @protected
 */
DvtMarker.prototype.StopSelectingAnimator = function()
{
  if (this._selectingAnimator)
  {
    this._selectingAnimator.stop();
    this._selectingAnimator = null;
  }
};

/**
 * @protected
 */
DvtMarker.prototype.SetStrokeWidth = function(sw)
{
  var stroke = this.getStroke();
  if (stroke)
  {
    stroke = stroke.clone();
    stroke.setWidth(sw);
    this.setStroke(stroke);
  }
};

/**
 * @protected
 */
DvtMarker.prototype.GetStrokeWidth = function()
{
  var stroke = this.getStroke();
  if (stroke)
  {
    return stroke.getWidth();
  }
  return 0;
};


/**
 * @protected
 */
DvtMarker.prototype.ScaleStrokeWidth = function(strokeWidth)
{
  //scale the stroke width inversely proportional to the marker scale
  //so that the stroke width appears to be the same for all markers
  var scaleX = this.getScaleX();
  var scaleY = this.getScaleY();
  var scale = Math.min(scaleX, scaleY);
  //in SVG, the marker may have a default scale used to initially force
  //it to the reference size, so that scale needs to be taken into account
  //when inversely scaling the stroke
  if (this.getContext().isPlatformSvg())
  {
    var defScale = this.getImpl().getDefaultScale();
    scale *= defScale;
  }
  strokeWidth /= scale;
  return strokeWidth;
};


/**
 * Show the selection hover effect.
 */
DvtMarker.prototype.showHoverEffect = function()
{
  this.SetSelectionMouseOver(true);
};


/**
 * Hide the selection hover effect.
 */
DvtMarker.prototype.hideHoverEffect = function()
{
  this.SetSelectionMouseOver(false);
};


/**
 * Determine if the selection hover effect is shown.
 * 
 * @type boolean
 */
DvtMarker.prototype.isHoverEffectShown = function()
{
  return this._bSelecting;
};


/**
 * @protected
 * Set whether the selection mouse hover effect is shown.
 * 
 * @param {boolean}  bOver  true if the mouse is over the object,
 *        false otherwise
 */
DvtMarker.prototype.SetSelectionMouseOver = function(bOver)
{
  if (this._bSelecting != bOver)
  {
    this._bSelecting = bOver;
    
    this.ApplySelectingState();
  }
};


/**
 * Determine whether this object is selected.
 * 
 * @type boolean
 */
DvtMarker.prototype.isSelected = function()
{
  return this._bSelected;
};


/**
 * @protected
 * Set whether the selection effect is shown.
 * 
 * @param  {boolean}  bSel  true if the object is selected,
 *        false otherwise
 */
DvtMarker.prototype.SetSelected = function(bSel)
{
  this.setSelected(bSel);
};


/**
 * Set whether the selection effect is shown.
 * 
 * @param  {boolean}  bSel  true if the object is selected,
 *        false otherwise
 */
DvtMarker.prototype.setSelected = function(bSel)
{
  if (this._bSelected != bSel)
  {
    this._bSelected = bSel;
    
    this.ApplySelectionState();
  }
};


/**
 * Set whether this object is selectable.
 * 
 * @param {boolean}  bSelectable  true to make selectable, false otherwise
 */
DvtMarker.prototype.setSelectable = function(bSelectable)
{
  this._bSelectable = bSelectable;
  
  if (this._bSelectable)
  {
    this.setCursor(DvtSelectionEffectUtils.getSelectingCursor());
  }
  else
  {
    this.setCursor(null);
  }
};


/**
 * Determine whether this object is selectable.
 * 
 * @type boolean
 */
DvtMarker.prototype.isSelectable = function()
{
  return this._bSelectable;
};


/**
 * Set the data color to use as a base for selection colors.
 * 
 * @param {string}  dataColor  data color to use as a base for selection colors
 */
DvtMarker.prototype.setDataColor = function(dataColor)
{
  this._dataColor = dataColor;
};


/**
 * Get the data color used as a base for selection colors.
 * 
 * @type string
 */
DvtMarker.prototype.getDataColor = function()
{
  return this._dataColor;
};

/**  Sets the underlay for markers
 *  @param {string} ut underlay type
 *  @param {string} uc fill color of the underlay
 *  @param {number} ua fill alpha of the underlay
 */
DvtMarker.prototype.setUnderlay = function(type, color, alpha)
{
   this._impl.setUnderlay(type, color, alpha);
   this._underlayColor = color;
};

/**
  *  Enables/disables the visibility of a marker underlay.
  *  @param {Boolean}  bVis  True if the object is to be visible, else false if
  *  it is to be hidden.
  */
DvtMarker.prototype.setUnderlayVisible = function (bVis) {
  var underlay = this._impl.getUnderlay();
  if (underlay)
    underlay.setVisible(bVis);
}

/**  Changes the shape to an outline shape format.  Used for legend
  *  markers that represent a hidden state for the associated series risers.
  *  @param {String} color Border color for hollow shape in format of #aarrggbb
  *  @override
  */
DvtMarker.prototype.setHollow = function(color)
{
    //scale the stroke width inversely proportional to the marker scale
    //so that the stroke width appears to be the same for all markers
    var scaleX = this.getScaleX();
    var scaleY = this.getScaleY();
    var scale = Math.min(scaleX, scaleY);
    var strokeWidth = this.GetStrokeWidth();
    strokeWidth = (strokeWidth ? strokeWidth : 1) / scale;
    //save the stroke width so that we can reset it if needed
    this._impl.setHollow(color, strokeWidth)
};

/**  Adds reference for legend text to marker
  *  @param {DvtText} text Legend text
  */
DvtMarker.prototype.setText = function(text)
{
    this._markerText = text;
}

/**  Adds reference for legend text to marker
  *  @param {number} alpha Opacity of object
  *  @override
  */
DvtMarker.prototype.setAlpha = function(alpha) {
    DvtMarker.superclass.setAlpha.call(this, alpha);
    if (this._markerText)
        this._markerText.setAlpha(alpha);
}

/**
  *  Enables/disables the visibility of marker and text if reference exists.
  *  @param {Boolean}  bVis  True if the object is to be visible, else false if
  *  it is to be hidden.
  *  @override
  */
DvtMarker.prototype.setVisible = function(bVis)
{
  DvtMarker.superclass.setVisible.call(this, bVis);
  if (this._markerText) 
      this._markerText.setVisible(bVis);
}



// Copyright (c) 2008, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/*---------------------------------------------------------------------*/
/*    DvtOval                 Base elliptical shape                    */
/*---------------------------------------------------------------------*/
/**
  *  Creates an elliptical shape.
  *  @extends DvtCircle
  *  @class DvtOval  Creates an elliptical shape.
  *  <p>
  *  Example:<br><br><code>
  *  var  oval = new DvtOval(context, 50, 50, 100, 200);<br>
  *  </code>
  *  @constructor  
  *  @param {DvtContext} context   The platform dependent context object (such
  *                                as {@link DvtSvgContext}).
  *  @param {number} cx  The center x position.
  *  @param {number} cy  The center y position.
  *  @param {number} rx  The horizontal radius of the ellipse.
  *  @param {number} ry  The vertical radius of the ellipse.
  *  @param {String} id  Optional ID for the shape (see {@link  DvtDisplayable#setId}).
  */
var  DvtOval = function(context, cx, cy, rx, ry, id)
{
   this.Init(context, cx, cy, rx, ry, id) ;
};

DvtObj.createSubclass(DvtOval, DvtCircle, "DvtOval") ;


/*---------------------------------------------------------------------*/
/*   get/setRx()                                                       */
/*---------------------------------------------------------------------*/
/**
  *  Gets the horizontal radius of the ellipse.
  *  @type number
  */
DvtOval.prototype.getRx = function()
{
   return this._impl.getRx() ;
} ;
/**
  *  Sets the horizontal radius of the ellipse.
  *  @param {number} rx  The horizontal radius of the ellipse.
  */
DvtOval.prototype.setRx = function(rx)
{
   this._impl.setRx(rx) ;
} ;


/*---------------------------------------------------------------------*/
/*   get/setRy()                                                       */
/*---------------------------------------------------------------------*/
/**
  *  Gets the vertical radius of the ellipse.
  *  @type number
  */
DvtOval.prototype.getRy = function()
{
   return this._impl.getRy() ;
} ;
/**
  *  Sets the vertical radii of the ellipse.
  *  @param {number} ry  The vertical radius of the ellipse.
  */
DvtOval.prototype.setRy = function(ry)
{
   this._impl.setRy(ry) ;
} ;


/*---------------------------------------------------------------------*/
/*  Init()                                                             */
/*---------------------------------------------------------------------*/
/**
  *  Object initializer.
  *  @protected
  */
DvtOval.prototype.Init = function(context, cx, cy, rx, ry, id)
{
  if (! this.getImpl()) {
    this.setImpl(context.getImplFactory().newOval(cx, cy, rx, ry, id)) ;
  }
  DvtOval.superclass.Init.call(this, context) ;
};



/*---------------------------------------------------------------------*/
/*   Convenience Functions                                             */
/*---------------------------------------------------------------------*/
/**
  *  Sets both the horizontal and vertical radii of the ellipse.
  *  @param {number} rx  The horizontal radius of the ellipse.
  *  @param {number} ry  The vertical radius of the ellipse.
  */
DvtOval.prototype.setRadius = function(rx, ry)
{
   this.setRx(rx);
   this.setRy(ry);
} ;

// Copyright (c) 2008, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/*---------------------------------------------------------------------*/
/*   DvtPath                    Base Path shape                        */
/*---------------------------------------------------------------------*/
/**
  *  Creates a shape using SVG path commands.
  *  @extends DvtShape
  *  @class DvtPath  Creates an arbitrary shape using SVG path commands.
  *  @constructor
  *  @param {DvtContext} context  The platform dependent context object (such
  *                               as {@link DvtSvgContext}).
  *  @param {Object} cmds  Optional string of SVG path commands (see comment for
  *                        {@link DvtPath#setCmds}), or an array containing
  *                        consecutive command and coordinate entries (see comment
  *                        for {@link DvtPath#setCommands}).
  * @param {String} id  Optional ID for the shape (see {@link  DvtDisplayable#setId}).
  */
var  DvtPath = function(context, cmds, id)
{
   this.Init(context, cmds, id) ;
};

DvtObj.createSubclass(DvtPath, DvtShape, "DvtPath") ;


/*---------------------------------------------------------------------*/
/*    get/setCmds()                                                    */
/*---------------------------------------------------------------------*/
/**
  *  Gets the path from a string of SVG commands sequences. See also {@link DvtPath#setCommands}.
  *  @type {String} cmds A string containing the SVG commands sequences.
  */
DvtPath.prototype.getCmds = function()
{
   return this._impl.getCmds();
} ;
/**
  *  Sets the path from a string of SVG command sequences. See also {@link DvtPath#setCommands}.
  *  @param {String} cmds A string containing SVG command sequences.
  */
DvtPath.prototype.setCmds = function(cmds)
{
   this._impl.setCmds(cmds) ;
} ;


/*---------------------------------------------------------------------*/
/*   get/setCommands()                                                 */
/*---------------------------------------------------------------------*/
/**
  *  Gets the array of consecutive SVG path command sequences supplied by
  *  the last setCommands().
  *  @type Array  An array of commands and coordinates.
  */
DvtPath.prototype.getCommands = function()
{
   return this._impl.getCommands() ;
} ;

/**
  *  Sets the path from an array of consecutive SVG path
  *  command sequences. See also {@link DvtPath#setCmds}.
  *  @param {Array} ar  An array of commands and coordinates.
  */
DvtPath.prototype.setCommands = function(ar)
{
   this._impl.setCommands(ar) ;
} ;


/*---------------------------------------------------------------------*/
/*  Init()                                                             */
/*---------------------------------------------------------------------*/
/**
  *  Object initializer.
  *  @protected
  */
DvtPath.prototype.Init = function(context, cmds, id)
{
  if (! this.getImpl()) {
    this.setImpl(context.getImplFactory().newPath(cmds, id)) ;
  }
  DvtPath.superclass.Init.call(this, context) ;

};

// Copyright (c) 2008, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/*---------------------------------------------------------------------*/
/*   DvtPolygon                Base Polygon shape                      */
/*---------------------------------------------------------------------*/
/**
  * Creates a polygon from an array of consecutive (x,y) coordinates.
  * @extends DvtShape
  * @constructor  
  * @param {DvtContext} context   The platform dependent context object (such
  *                               as {@link DvtSvgContext}).
  * @param {Array} ar  An array of consecutive x,y coordinate pairs.
  * @param {String} id  Optional ID for the shape (see {@link  DvtDisplayable#setId}).
  */
var  DvtPolygon = function(context, arPoints, id)
{
   this.Init(context, arPoints, id) ;
};

DvtObj.createSubclass(DvtPolygon, DvtShape, "DvtPolygon") ;



/*---------------------------------------------------------------------*/
/*   get/setPoints()                                                   */
/*---------------------------------------------------------------------*/
/**
  *  Returns the coordinates of the polygon vertices.
  *  @type Array
  */
DvtPolygon.prototype.getPoints = function()
{
   return this._impl.getPoints() ;
} ;

/**
  *   Sets the polygon points from an array of x,y coordinate pairs.
  *   @param {Array} arPoints  An array of x, y pairs of coordinates.
  */
DvtPolygon.prototype.setPoints = function(arPoints)
{
   this._impl.setPoints(arPoints) ;
} ;



/*---------------------------------------------------------------------*/
/*  Init()                                                             */
/*---------------------------------------------------------------------*/
/**
  *  Object initializer.
  *  @protected
  */
DvtPolygon.prototype.Init = function(context, arPoints, id)
{
  if (! this.getImpl()) {
    this.setImpl(context.getImplFactory().newPolygon(arPoints, id)) ;
  }
  DvtPolygon.superclass.Init.call(this, context) ;
};


// Copyright (c) 2008, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/*--------------------------------------------------------------------*/
/*   DvtPolyline             Base Polyline shape                      */
/*--------------------------------------------------------------------*/
/**
  *  Creates a shape of joined lines whose vertices are specified by
  *  an array of point coordinates.
  *  @extends DvtShape
  *  @constructor  
  *  @param {DvtContext} context   The platform dependent context object (such
  *                                as {@link DvtSvgContext}).
  *  @param {Array} arPoints   An array of consecutive x,y coordinate pairs.
  *  @param {String} id  Optional ID for the shape (see {@link  DvtDisplayable#setId}).
  *  @returns {DvtPolyline} A new DvtPolyline object.
  */
var  DvtPolyline = function(context, arPoints, id)
{
   this.Init(context, arPoints, id) ;
};

DvtObj.createSubclass(DvtPolyline, DvtShape, "DvtPolyline") ;



/*---------------------------------------------------------------------*/
/*   get/setPoints()                                                   */
/*---------------------------------------------------------------------*/

DvtPolyline.prototype.getPoints = function()
{
   return this._impl.getPoints() ;
} ;

/**
 *  Sets the points for the line.
 *  e.g. for single line    myLine.setPoints(x1,y1,x2,y2)
 *
 *       for polyline       setPoints( [x1,y1,x2,y2,x3,y3,x4,y4, . . .])
 */
DvtPolyline.prototype.setPoints = function(array)
{
   this._impl.setPoints(array) ;
} ;


/*---------------------------------------------------------------------*/
/*  Init()                                                             */
/*---------------------------------------------------------------------*/
/**
  *  Object initializer.
  *  @protected
  */
DvtPolyline.prototype.Init = function(context, arPoints, id)
{
  if (! this.getImpl()) {
    this.setImpl(context.getImplFactory().newPolyline(arPoints, id)) ;
  }
  DvtPolyline.superclass.Init.call(this, context) ;
};

// Copyright (c) 2008, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/*---------------------------------------------------------------------*/
/*    DvtRect               Base rectangular shape                     */
/*---------------------------------------------------------------------*/
/**
  *  Creates a rectangular displayable shape.
  *  @extends DvtShape
  *  @class DvtRect is a platform independent class representing a displayable
  *  rectangle.
  *  <p>
  *  <b>Example:</b><br><br> <code>
  *  var rect = new DvtRect(context, 10, 10, 100, 150, 'myRect') ;<br>
  *  rect.setStroke(new DvtStroke("red", 5)) ;<br>
  *<br>
  *  // Rounded rectangle<br><br>
  *  var rect = new DvtRect(context, 10, 10, 100, 150) ;<br>
  *  rect.setCornerRadius(20) ;<br>
  *</code>
  *  @constructor  
  *  @param {DvtContext} context   The platform dependent context object (such
  *                                as {@link DvtSvgContext}).
  *  @param {number} x  The x position of the top left corner of the rectangle.
  *  @param {number} y  The y position of the top left corner of the rectangle.
  *  @param {number} w  The width of the rectangle.
  *  @param {number} h  The height of the rectangle.
  *  @param {String} id  Optional ID for the shape (see {@link  DvtDisplayable#setId}).
  */
var  DvtRect = function(context, x, y, w, h,id)
{
   this.Init(context, x, y, w, h, id) ;
};

DvtObj.createSubclass(DvtRect, DvtShape, "DvtRect") ;



/*---------------------------------------------------------------------*/
/*   get/setX()                                                        */
/*---------------------------------------------------------------------*/
/**
  *  Returns the <code>x</code> coordinate of the rectangle.
  *  @returns {number} the <code>x</code> coordinate of the rectangle.
  */
DvtRect.prototype.getX = function()
{
   return this._impl.getX() ;
} ;

/**
  *  Sets the <code>x</code> coordinate of the top left position of the rectangle.
  *  @param {number} x  The <code>x</code> coordinate of the top left coordinate of the rectangle.
  */
DvtRect.prototype.setX = function(x)
{
   this._impl.setX(x) ;
} ;

/*---------------------------------------------------------------------*/
/*   get/setY()                                                        */
/*---------------------------------------------------------------------*/
/**
  *  Returns the <code>y</code> coordinate of the rectangle.
  *  @returns {number} the <code>y</code> coordinate of the rectangle.
  */
DvtRect.prototype.getY = function(y)
{
   return this._impl.getY() ;
} ;

/**
  *  Sets the <code>y</code> coordinate of the top left position of the rectangle.
  *  @param {number} y  The <code>y</code> coordinate of the top left coordinate of the rectangle.
  */
DvtRect.prototype.setY = function(y)
{
   this._impl.setY(y) ;
} ;


/*---------------------------------------------------------------------*/
/*   get/setWidth()                                                    */
/*---------------------------------------------------------------------*/
/**
  *  Returns the width of the rectangle.
  *  @returns {number} the width of the rectangle.
  */
DvtRect.prototype.getWidth = function()
{
   return this._impl.getWidth() ;
} ;

/**
  *  Sets the width of the rectangle.
  *  @param {number} w  The width of the rectangle.
  */
DvtRect.prototype.setWidth = function(w)
{
   this._impl.setWidth(w) ;
} ;


/*---------------------------------------------------------------------*/
/*   setHeight()                                                       */
/*---------------------------------------------------------------------*/
/**
  *  Gets the height of the rectangle.
  *  @returns {number}  The height of the rectangle.
  */
DvtRect.prototype.getHeight = function()
{
   return this._impl.getHeight() ;
} ;

/**
  *  Sets the height of the rectangle.
  *  @param {number} h  The height of the rectangle.
  */
DvtRect.prototype.setHeight = function(h)
{
   this._impl.setHeight(h) ;
} ;

/*---------------------------------------------------------------------*/
/*   get/setRx()                                                       */
/*---------------------------------------------------------------------*/
/**
  *  Gets the horizontal radius of the rounded corners, if any.
  *  @type number
  */
DvtRect.prototype.getRx = function()
{
   return this._impl.getRx() ;
} ;

/**
  *  Sets the horizontal radius of the rounded corners.
  *  @param {number} rx  The horizontal radius of the rounded corners.
  */
DvtRect.prototype.setRx = function(rx)
{
   this._impl.setRx(rx) ;
} ;

/*---------------------------------------------------------------------*/
/*   get/setRy()                                                       */
/*---------------------------------------------------------------------*/
/**
  *  Gets the vertical radius of the rounded corners, if any.  If not specified, 
  *  the vertical radius defaults to be the same as the horizontal radius.
  *  @type number
  */
DvtRect.prototype.getRy = function()
{
   return this._impl.getRy() ;
} ;
/**
  *  Sets the vertical radius of the rounded corners.  If not specified, the 
  *  vertical radius defaults to be the same as the horizontal radius.
  *  @param {number} ry  The vertical radius of the rounded corners.
  */
DvtRect.prototype.setRy = function(ry)
{
   this._impl.setRy(ry) ;
} ;


/*---------------------------------------------------------------------*/
/*  Init()                                                             */
/*---------------------------------------------------------------------*/
/**
  *  Object initializer.
  *  @protected
  */
DvtRect.prototype.Init = function(context, x, y, w, h, id)
{
  if (! this.getImpl()) {
    this.setImpl(context.getImplFactory().newRect(x, y, w, h, id)) ;
  }
  DvtRect.superclass.Init.call(this, context) ;

};


/*---------------------------------------------------------------------*/
/*   Convenience Functions                                             */
/*---------------------------------------------------------------------*/

/**
  *  Sets the top left position of the rectangle.
  *  @param {number} x  The <code>x</code> coordinate of the top left coordinate of the rectangle.
  *  @param {number} y  The <code>y</code> coordinate of the top left coordinate of the rectangle.
  */
DvtRect.prototype.setPos = function(x,y)
{
   this.setX(x) ;
   this.setY(y) ;
};

/**
  *  Sets the corner radius value(s) to create rounded corners.
  *  @param {number} rx  The horizontal (x) radius.
  *  @param {number} ry  Optional: The vertical (y) radius. if omitted the rx
  *                      value is used.
  */
DvtRect.prototype.setCornerRadius = function(rx, ry)
{
   this.setRx(rx);
   this.setRy(ry);
} ;

/**
  *  Sets the position and size of the rectangle.
  *  May be specified as individual values or using a DvtRectangle object.
  *  <p>
  *  Example<br><br><code>
  *  rect.setRect(10, 10, 50, 100) ; &nbsp;  or<br>
  *  <br>
  *  rect.setRect(myRect) ; &nbsp; &nbsp;  where myRect = new DvtRectangle(10, 10, 50, 100);<br>
  *
  *  @param {number} x  The x position of the top left corner of the rectangle.
  *  @param {number} y  The y position of the top left corner of the rectangle.
  *  @param {number} w  The width of the rectangle.
  *  @param {number} h  The height of the rectangle.
  */
DvtRect.prototype.setRect = function(x,y,w,h)
{
   if (x instanceof DvtRectangle) {
     this.setPos(x.x, x.y) ;
     this.setWidth(x.w) ;
     this.setHeight(x.h) ;
   }
   else {
     this.setPos(x,y) ;
     this.setWidth(w) ;
     this.setHeight(h) ;
   }
} ;
// Copyright (c) 2008, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/*---------------------------------------------------------------------*/
/*   DvtText                   Text "shape"                            */
/*---------------------------------------------------------------------*/
/**
 * Creates an instance of DvtText.
 * @extends  DvtShape
 * @class DvtText
 * @constructor
 * @param {DvtContext} context   The platform dependent context object (such
 *                               as {@link DvtSvgContext}).
 * @param {number} x  
 * @param {number} y  
 * @param {String} text  Text to be displayed.
 * @param {String} id  Optional ID for the shape (see {@link  DvtDisplayable#setId}).
 */
var  DvtText = function(context, text, x, y, id)
{
  this.Init(context,  text, x, y, id) ;
};

DvtObj.createSubclass(DvtText, DvtShape, "DvtText") ;

DvtText._TRUNCATION_INCR = 1; // Increment in chars to truncate by
DvtText._TRUNCATION_MIN_LENGTH = 1; // Minimum length of truncated text


DvtText.ELLIPSIS = "...";


/*---------------------------------------------------------------------*/
/*  Init()                                                             */
/*---------------------------------------------------------------------*/
/**
  *  Object initializer.
  *  @protected
  */
DvtText.prototype.Init = function(context, text, x, y, id)
{
  if (! this.getImpl()) {
    this.setImpl(context.getImplFactory().newText(text, x, y, id)) ;
  }
  DvtText.superclass.Init.call(this, context) ;

  this._Ctx = context ;

  this._maxw = -1;
  this._bHtmlText = false;

  //flag indicating whether text is truncated
  this._bTruncated = false;
  this._inProcess = false;

  //default origin to top left corner
  this.alignTop();

  // ellipsis width
  this._eWidth = undefined;

  // for defer truncation
  this._defTrunc = false;
  this._setCachedDims(undefined);
  
  // for legend text to keep track of whether associated legend marker is hollow
  this._bHollow = false;

};


/**
 * Returns the text string for this text object.
 * @return {string} the text string
 */ 
DvtText.prototype.getTextString = function() {

  return this._impl.getTextString() ;
} ;


/**
 * Sets the text angle. See also {@link DvtText#setRotatePoint}.
 * @param {number} a the angle in degrees. Positive angle rotate counter-clockwise.
 */
DvtText.prototype.setAngle = function(a)
{
  this._impl.setAngle(a) ;
}; 


/**
 * Sets the rotation point for angle text (see {@link DvtText#setAngle}).
 * @param {number} cx the rotation point x-coordinate.
 * @param {number} cy the rotation point y-coordinate.
 */
DvtText.prototype.setRotatePoint = function(cx, cy)
{
  this._impl.setRotatePoint(cx, cy) ;
}; 


/**
 * Sets the text string for this text object.
 * @param {string} textStr the text string
 */
DvtText.prototype.setTextString = function(txt)
{
  this._text = txt;
  this._impl.setTextString(txt) ;
  this._setCachedDims(undefined);
} ;

/**
 * Gets the x position for this text object.
 * @returns {number}  the x position.
 */
DvtText.prototype.getX = function()
{
  return this._impl.getX() ;
}; 
/**
 * Sets the x position for this text object.
 * @param {number} x the x position
 */
DvtText.prototype.setX = function(x)
{
  this._impl.setX(x) ;
}; 


/**
 * Gets the y position for this text object.
 * @returns {number}  the y position.
 */
DvtText.prototype.getY = function()
{
  return this._impl.getY() ;
}; 
/**
 * Sets the y position for this text object.
 * @param {number} y the y position
 */
DvtText.prototype.setY = function(y)
{
  this._impl.setY(y) ;
};


/**
 * Sets the font size.
 * @param {number} fontSize the font size
 */
DvtText.prototype.setFontSize = function(fontSize)
{
  this._impl.setFontSize(fontSize);
  this._setCachedDims(undefined);
};


// TODO JSDOC Not sure how to expose these, so this is temporary
DvtText.prototype.alignStart = function() {
  this._impl.alignStart();
}

// TODO JSDOC Not sure how to expose these, so this is temporary
DvtText.prototype.alignMiddle = function() {
  this._impl.alignMiddle();
}

// TODO JSDOC Not sure how to expose these, so this is temporary
DvtText.prototype.alignEnd = function() {
  this._impl.alignEnd();
}

// TODO JSDOC Not sure how to expose these, so this is temporary
DvtText.prototype.alignTop = function() {
  this._impl.alignTop();
};

// TODO JSDOC Not sure how to expose these, so this is temporary
DvtText.prototype.alignCenter = function() {
  this._impl.alignCenter();
};

// TODO JSDOC Not sure how to expose these, so this is temporary
DvtText.prototype.alignBottom = function() {
  this._impl.alignBottom();
};

// TODO JSDOC Not sure how to expose these, so this is temporary
DvtText.prototype.alignBaseline = function() {
  this._impl.alignBaseline();
};


/**
 * Truncates this text element to fit within the available space.  Returns
 * null if the text can't fit.
 * @param parent {DvtContainer} element used temporarily for calculating the bounds of the text, must be connected.
 * @param {number} availWidth the available width
 * @param {number} availHeight the available height
 * @return {DvtText} this text element, truncated to fit in the given space.  
 */
DvtText.prototype.truncateToSpace = function(parent, availWidth, availHeight) {
  // Temporarily add the child so that metrics may be obtained
  parent.addChild(this);
  
  // Hide the text if it won't fit
  var dims = this.getDimensions();
  var width = dims.w;
  var height = dims.h;
  
  // If not enough height, return null
  if(height > availHeight) {
    parent.removeChild(this);
    return null;
  }
  
  // If we need to truncate, estimate to reduce calls to getDimensions() which is expensive
  if (width > availWidth) {
  // Determine avg pixels per char
    var text = this.getTextString();
    var numChars = text.length;
    var avgPixel = width/numChars;
    var maxNumChars = Math.floor(availWidth/avgPixel) - 1; //fudge factor for ellipsis width
    var textStr = text.substring(0, maxNumChars);
      
    while(width > availWidth && textStr.length >= DvtText._TRUNCATION_MIN_LENGTH) {
      // Update the text element and recalc size
      this.setTextString(textStr + "...");
      width = this.getDimensions().w;
      
      // Truncate 1 chars at a time
      textStr = textStr.substring(0, textStr.length - DvtText._TRUNCATION_INCR);
    }
  }
  
  // Remove the child since metrics are calc'ed
  parent.removeChild(this);
  
  if(width > availWidth) {
    return null; // not enough space, don't return a text element
  }
  else {
    return this;
  }
};

/**
 * Truncates the given text element to fit within the available space.  Returns
 * null if the text node can't fit.
 * @param parent {DvtContainer} element used temporarily for calculating the bounds of the text, must be connected.
 * @param {function} callback the callback function that takes a bbox and returns true if the text fits
 * @param {object} cbArgs the arguments to pass the callback, after the bbox
 * @return {DvtText} the text element, truncated to fit in the given space.  
 */
DvtText.prototype.truncateToCallback = function(parent, callback, cbArgs) {
  // Temporarily add the child so that metrics may be obtained
  parent.addChild(this);
  
  // If the text doesn't fit, attempt to truncate
  var dims = this.getDimensions();
  var textStr = DvtText._getInitialTruncation(this.getTextString());
  while(!callback(dims, cbArgs) && textStr.length >= DvtText._TRUNCATION_MIN_LENGTH) {
    // Update the text element and recalc size
    this.setTextString(textStr + "...");
    dims = this.getDimensions();
    
    // Truncate 1 chars at a time
    textStr = textStr.substring(0, textStr.length - DvtText._TRUNCATION_INCR);
  }
  
  // Remove the child since metrics are calc'ed
  parent.removeChild(this);
  
  if(!callback(dims, cbArgs)) {
    return null; // not enough space, don't return a text element
  }
  else {
    return this;
  }
};

/**
 * Helper function that returns the initial truncation for the given string.
 */
DvtText._getInitialTruncation = function(textStr) {
  var newLength = Math.max(1, textStr.length - 3); // Keep at least 1 char
  return textStr.substring(0, newLength); 
};


/**
 * Set the maximum width allowed for this text field.  
 * If this text field is longer than the maxWidth,
 * the text will be truncated.
 * 
 * @param mw maximum width
 */
DvtText.prototype.setMaxWidth = function(mw) {
  this._maxw = mw;

  if (mw > 0)
    this._ProcessText();
}

/**
 * Gets the text string for this object.
 * @return {string} the text string
 */
DvtText.prototype.getText = function() {
  return this._text;
}

/**
 * Sets the text string for this text object.
 * @param {array} single line text or multiline text
 * @param {array} dimList Optional dimensions of multilines
 */
DvtText.prototype._setTextWithSize = function(text, dimList) {
  this._impl.setText(text, dimList);
}

/**
 * Sets the TruncateAt for this text object.
 * @param {number} truncateAt
 */
DvtText.prototype.setTruncateAt = function(truncateAt) {
  this._truncateAt = truncateAt;

  // reset the text
  this.DoSetText(this.getText());
}

/**
 * Gets the TruncateAt for this text object.
 * @return {number} truncateAt
 */
DvtText.prototype.getTruncateAt = function() {
  return this._truncateAt;
}

/**
 * Sets the text string for this object.
 * @param {string} text the text string
 */
DvtText.prototype.DoSetText = function(text) {
  //handle "truncate at" if specified
  text = this.DoTruncateAt(text, this.getTruncateAt());

  this._setCachedDims(undefined);
  this._setText(text);
  if (text)
    this._ProcessText();
};

/**
 * Truncate text at number of character specified
 * @param text text being truncated
 * @param {number} truncateAt
 * @return (String) truncated text
 */
DvtText.prototype.DoTruncateAt = function(text, truncateAt) {
  this._bTruncated = false;

  if (truncateAt && text && text.length > truncateAt) {
    text = text.substr(0, Math.max(truncateAt - 3, 0)) + "...";
    this._bTruncated = true;
  }

  return text;
}
    
/**
 * Determine if the text has been truncated.
 * @return true if text has been truncated, false if not
 */
DvtText.prototype.isTruncated = function() {
  return this._bTruncated;
}
    
/**
 * Is truncation enabled?
 * @return true if truncation is enabled, false if not
 */
DvtText.prototype.isTruncationEnabled = function() {
  //Note: no truncation on html text, because that's harder
  return (this._maxw > 0) && (! this._bHtmlText);
}
    
/**
 * Sets the text string for this text object.
 * It also performs word wrapping or truncation if enabled
 * @param {string} text the text string
 */
DvtText.prototype.setText = function(text) {
  // save the original text
  this._text = text;
  this.DoSetText(text);
}

/**
 * Sets the text string for this text object.
 * @param {array} single line text or multiline text
 */
DvtText.prototype._setText = function(text) {
  this._impl.setText(text);
}

/**
 * Gets the text string for this text object.
 * @return {string} the text string
 */
DvtText.prototype._getText = function() {
  return this._impl.getText();
}

/**
 * perform truncation if enabled
 * @param value text being set
 */
DvtText.prototype.setCSSStyle = function(style) {
  this._eWidth = undefined;
  this._setCachedDims(undefined);
  DvtText.superclass.setCSSStyle.call(this, style);
  this._ProcessText();
}

/**
 * Performs truncation.
 */
DvtText.prototype._ProcessText = function() {
  if (this.isTruncationEnabled() && ! this._inProcess) {
    this._inProcess = true;
    this._TruncateText();
    this._inProcess = false;
  }
}

/**
 * Check whether the text being shown needs to be truncated,
 * and truncate it if so.  
 */
DvtText.prototype._TruncateText = function() {
  this._bTruncated = false;

  if (this.isTruncationEnabled()) {
    var newtext = this._truncateLine(this._maxw);
    if (newtext) {
      this._bTruncated = true;
      this._setText(newtext);
    }
  }
}

//the maximum width allowed for a line of text
DvtText.prototype._truncateLine = function(maxLineWidth) {
  //indicating whether text is truncated
  var bTruncated = false;

  var dim = this.getCachedDims();

  //truncate this line if its width > the max line width
  if (dim.w > maxLineWidth) {
    bTruncated = true;

    // defer text truncation
    if (this._defTrunc) {
      this._bTruncated = true;
      return null;
    }

    //remove the ellipsis length
    maxLineWidth -= this._getEllipsisWidth();

    var lineText = this._getText();
    var high = lineText.length;
    var mid;
    var low = 0;

    while (low + 1 < high) {
      mid = Math.floor((low + high) / 2);

      //replace the original text with the truncated text
      this._setText(lineText.substring(0, mid));

      //check whether the newly truncated text fits
      dim = this.getDimensions();
      this._setCachedDims(dim);

      if (dim.w > maxLineWidth)
        high = mid;
      else
        low = mid;
    }
    if (low != mid)
      this._setText(lineText.substring(0, low));
  }
  return bTruncated? this._getText() + DvtText.ELLIPSIS : null;
}


DvtText.prototype.CreateTextField = function(text, x, y, id) {
  var obj = new DvtText(this._Ctx, null, x, y, id);
  if (text) {
    obj.setText(text);
  }
  return obj;
}

DvtText.prototype._GetTempTextField = function() {
  if (this._ttf === undefined) {
    var tmp = this.CreateTextField(undefined, 0, 0, this.getId() + "__tmp");
    tmp.setCSSStyle(this.getCSSStyle());

    // Temporarily add to the DOM so that metrics may be obtained
    if (this.getParent()) {
      this.getParent().addChild(tmp);
    }
    this._ttf = tmp;
  }
  return this._ttf;
}

// remove the temporary text field
DvtText.prototype._RemoveTempTextField = function() {
  if (this._ttf) {
    if (this.getParent()) {
      this.getParent().removeChild(this._ttf);
    }
    this._ttf = undefined;
  }
}

DvtText.prototype._getEllipsisWidth = function() {
  if (this._eWidth === undefined) {
    var style = this.getCSSStyle();

    //perf: if ellipsisWidth in DvtCSSStyle, use it
    if (style && style["ellipsisWidth"]) {
      this._eWidth = style["ellipsisWidth"];
    }
    else {
      var tmptf = this._GetTempTextField();

      tmptf._setText(DvtText.ELLIPSIS) ;
      this._eWidth = tmptf.getDimensions().w;

      // remove the temporary text field
      this._RemoveTempTextField();

      //perf: cache ellipsisWidth in DvtCSSStyle
      //if more texts have the same DvtCSSStyle, 
      //we dont need to getDimensions for ellipsis again
      if (style) {
        style["ellipsisWidth"] = this._eWidth;
      }
    }
  }
  return this._eWidth;
}


DvtText.prototype.getCachedDims = function() {
  var dim = DvtDisplayableUtils._getDimForced(null, this);
  if (! dim) {
    dim = DvtText.superclass.getDimensions.call(this);
    this._setCachedDims(dim);
  }
  return dim;
}

DvtText.prototype._setCachedDims = function(val) {
  DvtDisplayableUtils._setDimForced(this, val);
}


/**
 * set defer text truncation flag
 * if it's not defer, truncate text
 */
DvtText.prototype.truncateText = function(deferFlag) {
  this._defTrunc = deferFlag;
  if (! deferFlag) {
    this._ProcessText();
  }
}

/**
 * Truncate texts for an array of DvtText.
 * @param {array} textFields 
 */
DvtText.truncateTexts = function(textFields) {

  var highs = [];
  var mids = [];
  var lows = [];
  var strings = [];
  var maxWidths = [];

  //indicating whether text is truncated
  var bTruncated = false;
  var bMore;
  var dim;

  var i;
  var len = textFields.length;
  for (i = 0; i < len; i++) {
    strings[i] = textFields[i]._getText();
    lows[i] = 0;
    if (! strings[i]) {
      strings[i] = "";
    }
    highs[i] = strings[i].length;
    maxWidths[i] = textFields[i]._maxw - textFields[i]._getEllipsisWidth();
  }

  do {
    for (i = 0; i < len; i++) {
      // done with truncation for this text
      if (lows[i] + 1 >= highs[i]) {
        if (lows[i] != mids[i]) {
          textFields[i]._setText(strings[i].substring(0, lows[i]));
          mids[i] = lows[i];
        }
        continue;
      }
      mids[i] = Math.floor((lows[i] + highs[i]) / 2);
      
      //replace the original text with the truncated text
      textFields[i]._setText(strings[i].substring(0, mids[i]));
    }

    bMore = false;

    for (i = 0; i < len; i++) {
      // done with truncation for this text
      if (lows[i] + 1 >= highs[i]) {
        continue;
      }
      //check whether the newly truncated text fits
      dim = textFields[i].getDimensions();
      DvtDisplayableUtils._setDimForced(textFields[i], dim);

      if (dim.w > maxWidths[i])
        highs[i] = mids[i];
      else
        lows[i] = mids[i];

      // are we all done?
      if (lows[i] < highs[i]) {
        bMore = true;
      }
    }

  } while (bMore)

  for (i = 0; i < len; i++) {
    textFields[i]._setText(strings[i].substring(0, mids[i]) + DvtText.ELLIPSIS);
  }

}

/**
  *  @override
  */
DvtText.prototype.getDimensions = function(targetCoordinateSpace) {
  var dim = DvtText.superclass.getDimensions.call(this, targetCoordinateSpace);
  if (this.isTruncated() && this._defTrunc && ! this._dim) {
    dim.w = this._maxw;
  }
  return dim;
}


// Copyright (c) 2008, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/*---------------------------------------------------------------------*/
/*   DvtTextArea                   TextArea "shape"                    */
/*---------------------------------------------------------------------*/
/**
 * Creates an instance of DvtTextArea.
 * @extends  DvtText
 * @class DvtTextArea
 * @constructor
 * @param {DvtContext} context   The platform dependent context object (such
 *                               as {@link DvtSvgContext}).
 * @param {number} x the x position
 * @param {number} y the y position
 * @param {String} id  Optional ID for the shape (see {@link  DvtDisplayable#setId}).
 */
var DvtTextArea = function(context, x, y, id) {
  this.Init(context, x, y, id) ;
};

DvtObj.createSubclass(DvtTextArea, DvtText, "DvtTextArea") ;

DvtTextArea.NEW_LINE = "\n";


DvtTextArea.TRIM_TRAILING_REGEXP = /\s+$/;


/**
 * Initializes this instance of DvtTextArea.
 */
DvtTextArea.prototype.Init = function(context, x, y, id) {

  if (! this.getImpl()) {
    this.setImpl(context.getImplFactory().newTextArea(x, y, id)) ;
  }
  DvtTextArea.superclass.Init.call(this, context) ;

  this._bWordWrap = true;
  
  // the maximum number of lines to be displayed in the text area
  this._maxLines = -1;
  
  this._numLines = 1;
  
  this._bTruncated = false;

};



/**
 * Returns the number of lines displayed for this textArea object.
 * @return {number} the number of lines displayed
 */
DvtTextArea.prototype.getNumLines = function() {
  if(this.isWrappingEnabled()) 
    return this._numLines;  
  else
    return 1;
};



/**
 * Returns the amount of vertical space, in pixels, between lines
 * @return {number} the amount of vertical space (called leading) between lines
 */
DvtTextArea.prototype.getLeading = function() {
  return this._impl.getLeading();
};

/**
 * Sets the amount of vertical space, in pixels, between lines
 * @param {number} leading amount of vertical space, in pixels, between lines
 */
DvtTextArea.prototype.setLeading = function(leading) {
  this._impl.setLeading(leading);
};



/**
 * Returns the maximum number of lines that can be displayed for this textArea object.
 * @return {number} the maximum number of lines to be displayed
 */
DvtTextArea.prototype.getMaxLines = function() {
  return this._maxLines;
};

/**
 * Sets the maximum number of lines that can be displayed for this textArea object.
 * @param {number} maxLines the maximum number of lines to be displayed
 */
DvtTextArea.prototype.setMaxLines = function(maxLines) {
  this._maxLines = maxLines;
};


/**
 *  @override
 */
DvtTextArea.prototype.DoSetText = function(text) {
  //handle "truncate at" if specified
  text = this.DoTruncateAt(text, this.getTruncateAt());

  var lines;
  text = text || "";
  if (text) {
    this._setText(text);
    lines = text.split(DvtTextArea.NEW_LINE);
  }
  //TODO: Keep the original text??
  this._lines = lines;
  this._ProcessText();
};

/**
 * Set whether this text field should wrap words.
 * 
 * @param b true to wrap words, false otherwise
 */
DvtTextArea.prototype.setWordWrap = function(wrap) {
  this._bWordWrap = wrap;
};

/**
 * Determine whether this text field wraps words.
 * 
 * @return true if words are wrapped, false otherwise
 */
DvtTextArea.prototype.isWordWrap = function() {
  return this._bWordWrap;
};

/**
 * Is wrapping enabled?
 * @return true if truncation is enabled, false if not
 */
DvtTextArea.prototype.isWrappingEnabled = function() {
  //Note: no wrapping on html text, because that's harder
  return this.isWordWrap() && this._maxw > 0 && ! this._bHtmlText && this._lines;
};

/**
 * @override
 * Performs wrapping
 */
DvtTextArea.prototype._ProcessText = function() {
  if (! this._inProcess) {
    this._inProcess = true;
    if (this.isWrappingEnabled()) {
      this._wrapText();
    }
    else if (this.isTruncationEnabled()) {
      this._TruncateText();
    }
    this._inProcess = false;
  }
}


/**
 * Check whether the text being shown needs to be wrapped,
 * and wrap it if so.  
 */
DvtTextArea.prototype._wrapText = function() {
  //the maximum width allowed for a line of text
  var maxLineWidth = this._maxw;

  var lines = DvtArrayUtils.copy(this._lines);
  var numLines = lines.length;
  var tmptf = this._GetTempTextField();
  var newTexts = [];
  var remainder;
  var dim;
  var max_hh = 0;
  var max_ww = 0;
  var preWrappedString;
  var truncateNonWrappedString = false;
  var maxOut = false;
  var dimList = [];

  //loop over all the lines and wrap each independently
  //end the loop once we've processed all lines, or have reached
  //the maximum number of lines to display
  for (var lineIndex = 0; lineIndex < numLines; lineIndex++) {
    tmptf._setText(lines[lineIndex]);
    dim = tmptf.getDimensions();

    // need word wrap if text width > max width
    if (dim.w > maxLineWidth) {
      preWrappedString = tmptf._getText();
      remainder = DvtTextArea._wrapLine(maxLineWidth, tmptf);

      //include the remainder of the line as a new next line in the text
      if (remainder) {
        lines.splice(lineIndex + 1, 0, remainder);
        //increment line count
        numLines++;
        
        // BUGFIX 12724589 and 12780962
        // if we couldn't wrap this string, then truncate it
        if(preWrappedString == remainder)
        {
          truncateNonWrappedString = true;
        }
      }
    }

    // exit the loop if we've reached the maximum number of lines to display 
    // or if the line is too long to wrap, thus requiring us to truncate it
    if( ((this._maxLines != -1) && (lineIndex == this._maxLines-1)) || truncateNonWrappedString)
    {
      if((this._maxLines < numLines) || truncateNonWrappedString) {
        var s = tmptf._getText();
        // trim trailing whitespace and truncate if necessary
        s = s.replace(DvtTextArea.TRIM_TRAILING_REGEXP, "");
        tmptf.setText(s + DvtText.ELLIPSIS);
        tmptf.setMaxWidth(maxLineWidth);
        this._bTruncated = true;
      } 
      maxOut = true;
    }

    newTexts.push(tmptf._getText());

    // keep dimension for each line
    dim = tmptf.getDimensions();
    dimList.push(new DvtRectangle(dim.x, dim.y, dim.w, dim.h));

    max_hh = Math.max(dim.h, max_hh);
    max_ww = Math.max(dim.w, max_ww);

    if (maxOut)
      break;
  }

  //TODO: call API
  //peformance: need in DvtSvgTextArea
  this._maxh = max_hh;
  this._maxw = max_ww;


  // remove the temporary text field
  this._RemoveTempTextField();

  //replace the original text with the wrapping text
  this._setTextWithSize(newTexts, (dimList.length === 0)? undefined : dimList);
  this._numLines = newTexts.length;
};


/**
 * @private
 * Check whether the text being shown needs to be wrapped,
 * and wrap it if so.  
 * return remainder if wrap
 */
DvtTextArea._wrapLine = function(maxLineWidth, textField) {
  var lineText = textField._getText();
  var newLineText;
  var remainder;
  var ww;

  //test wrapping word by word to find where
  //we need to wrap to make the string fit in the allowed width; 
  var wordOffsets = DvtTextArea._breakWords(lineText);
  if (wordOffsets.length > 1) {
    var i;
    for (i = 0; i < wordOffsets.length - 1; i++) {
      //add one word to the line
      if (i < wordOffsets.length) {
        newLineText = lineText.substring(0, wordOffsets[i + 1].index);
      }
      else {
        newLineText = lineText.substring(0, wordOffsets[i].length);
      }
      //replace the original text with the truncated text
      textField._setText(newLineText);

      //re-apply TextFormat after modifying text 
      //check whether the newly truncated text fits
      ww = textField.getDimensions().w;
      if (ww > maxLineWidth)
        break;
    }
    //after the above loop 'i' will be the index of the
    //first word in the remainder of the line, so the 
    //last word that fits in the line is i-1
    if (i > 0) {
      var s = lineText.substring(0, wordOffsets[i].index);
      // trim off trailing whitespace so that we can properly do left or right alignment
      s = s.replace(DvtTextArea.TRIM_TRAILING_REGEXP, "");
      textField._setText(s);

      remainder = lineText.substring(wordOffsets[i].index); 
    }
    else if (wordOffsets.length > 1) {
      remainder = lineText.substring(wordOffsets[i + 1].index); 
    }
  }
  else {
    // BUGFIX 12724589 and 12780962
    // we fall into this case if the original string was one long word.
    // in this case, we couldn't wrap the line, and should return the
    // original line of text as the remainder
    remainder = lineText;
  }

  return remainder;
};

/**
 * @private
 */
DvtTextArea._breakWords = function(text) {
  if (DvtTextArea._word_regexp === undefined) {
    DvtTextArea._word_regexp = new RegExp("\\S+", "g");
  }
  var wordOffsets = [];
  var result;
  while ((result = DvtTextArea._word_regexp.exec(text)) !== null) {
    wordOffsets.push({index: result.index,
                      length: result[0].length
                     });
  }
  return wordOffsets;
};


/**
 * Get the maximum text height
 * @type {number} maximum height
 */
DvtTextArea.prototype._getMaxTextHeight = function() {
  return this._maxh;
}

/**
 * Get the maximum text width
 * @type {number} maximum width
 */
DvtTextArea.prototype._getMaxTextWidth = function() {
  return this._maxw;
}

/**
 * @override
 */
DvtTextArea.prototype.isTruncated = function() {
    // Since truncation can happen in DvtTextArea._wrapText() and DvtText._TruncateText() need to check both
    return this._bTruncated || DvtTextArea.superclass.isTruncated.call(this);
}

// Copyright (c) 2008, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/*-------------------------------------------------------------------------*/
/*   DvtTextFormatted                   TextFormatted "shape"              */
/*-------------------------------------------------------------------------*/
/**
 * Creates an instance of DvtTextFormatted.
 * @extends  DvtShape
 * @class DvtTextFormatted
 * @constructor
 * @param {DvtContext} context   The platform dependent context object (such
 *                               as {@link DvtSvgContext}).
 * @param x {number} x the x position
 * @param y {number} y the y position
 * @param {String} id  Optional ID for the shape (see {@link  DvtDisplayable#setId}).
 */
var DvtTextFormatted = function(context, x, y, id) {
  this.Init(context, x, y, id) ;
};

DvtObj.createSubclass(DvtTextFormatted, DvtText, "DvtTextFormatted") ;



/**
 * Initializes this instance of DvtTextFormatted.
 */
DvtTextFormatted.prototype.Init = function(context, x, y, id) {

  if (! this.getImpl()) {
    this.setImpl(context.getImplFactory().newTextFormatted(x, y, id)) ;
  }
  DvtTextFormatted.superclass.Init.call(this, context);

};


/**
 * Returns the textFormatted string for this textFormatted object.
 * @return {string} the textFormatted string
 */
DvtTextFormatted.prototype.getText = function() {
  return this._impl.getText();
};

/**
 * Sets the textFormatted string for this textFormatted object.
 * @param {string} textFormattedStr the textFormatted string
 */
DvtTextFormatted.prototype.setText = function(text) {
  this._impl.setText(text);

};


// Copyright (c) 2011, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/**
  *  Creates a selectable shape using SVG path commands.
  *  @extends DvtArc
  *  @class DvtSelectableArc  Creates an arbitrary shape using SVG path commands.
  *  @constructor
  *  @param {DvtContext} context   The platform dependent context object (such
  *                                as {@link DvtSvgContext}).
  *  @param {number} cx  The center x position.
  *  @param {number} cy  The center y position.
  *  @param {number} rx  The horizontal radius of the ellipse.
  *  @param {number} ry  The vertical radius of the ellipse.
  *  @param {number} sa  The starting angle in degrees (following the normal anti-clockwise is positive convention).
  *  @param {number} ae  The angle extent in degrees (following the normal anti-clockwise is positive convention).
  *  @param {String} clos  An optional closure type for the arc. Closures are "OPEN" (the default), "SEGMENT", and "CHORD".
  *  @param {String} id  Optional ID for the shape (see {@link  DvtDisplayable#setId}).
  */
var  DvtSelectableArc = function(context, cx, cy, rx, ry, sa, ae, clos, id)
{
   this.Init(context, cx, cy, rx, ry, sa, ae, clos, id) ;
};

DvtObj.createSubclass(DvtSelectableArc, DvtArc, "DvtSelectableArc") ;

/**
  *  Object initializer.
  *  @protected
  */
DvtSelectableArc.prototype.Init = function(context, cx, cy, rx, ry, sa, ae, clos, id)
{
  DvtSelectableArc.superclass.Init.call(this, context, cx, cy, rx, ry, sa, ae, clos, id) ;
  //properties related to selection
  this._bSelected = false;
  this._bSelecting = false;
  this._selectionEffects = null;
  this._bSelectedShadow = true;
  this._dataColor = "#000000";
  
  this._savedStroke = null;
  this._bSavedStroke = false;
  this._relatedLogicalObjects = null;
  this._applyStrokeTimer  = null;
  
  this._bZorder = true;
  this._zOrderManager = null;

  this._selectionType    = DvtSelectionEffectUtils.DEFAULT_SEL_TYPE;
}

/**
 * @protected
 * Apply any selection effects to this object.
 */
DvtSelectableArc.prototype.ApplySelectionState = function()
{
  DvtSelectionEffectUtils.applySelectionState(this, this._dataColor);
};

/**
 * @protected
 * Apply any mouse hover selection effects to this object.
 */
DvtSelectableArc.prototype.ApplySelectingState = function()
{
  DvtSelectionEffectUtils.applySelectingState(this, this._dataColor);
};


/**
 * Show the selection hover effect.
 */
DvtSelectableArc.prototype.showHoverEffect = function()
{
  this.SetSelectionMouseOver(true);
};


/**
 * Hide the selection hover effect.
 */
DvtSelectableArc.prototype.hideHoverEffect = function()
{
  this.SetSelectionMouseOver(false);
};


/**
 * Determine if the selection hover effect is shown.
 * 
 * @type boolean
 */
DvtSelectableArc.prototype.isHoverEffectShown = function()
{
  return this._bSelecting;
};


/**
 * @protected
 * Set whether the selection mouse hover effect is shown.
 * 
 * @param bOver {boolean}  bOver  true if the mouse is over the object,
 *        false otherwise
 */
DvtSelectableArc.prototype.SetSelectionMouseOver = function(bOver)
{
  this.SetSelectionMouseOverSelf(bOver);

  //set selection on related parts of this marker also
  if (this._relatedLogicalObjects)
  {
    for (var i = 0; i < this._relatedLogicalObjects.length; i++)
    {
      if (this._relatedLogicalObjects[i].SetSelectionMouseOverSelf)
      {
        this._relatedLogicalObjects[i].SetSelectionMouseOverSelf(bOver);
      }
    }
  }
}

/**
 * @protected
 * Set whether the selection mouse hover effect is shown.
 * 
 * @param bOver {boolean}  bOver  true if the mouse is over the object,
 *        false otherwise
 */
DvtSelectableArc.prototype.SetSelectionMouseOverSelf = function(bOver)
{
  if (this._bSelecting != bOver)
  {
    this._bSelecting = bOver;
    if (this._bZorder)
    {   
      if (this._bSelecting && this._zOrderManager)
      {
        this._zOrderManager.bringToFrontOfSelection(this);
      }
      else if (!this._bSelected)
      {
        this._zOrderManager.pushToBackOfSelection(this);
      }
    }
    this.ApplySelectingState();
  }
};


/**
 * Determine whether this object is selected.
 * 
 * @type boolean
 */
DvtSelectableArc.prototype.isSelected = function()
{
  return this._bSelected;
};

/**
 * Set whether the selection effect is shown.
 * 
 * @param bOver {boolean}  bSel  true if the object is selected,
 *        false otherwise
 */
DvtSelectableArc.prototype.setSelected = function(bSel)
{
  this.SetSelectedSelf(bSel);

  //set selection on related parts of this marker also
  if (this._relatedLogicalObjects)
  {
    for (var i = 0; i < this._relatedLogicalObjects.length; i++)
    {
      if (this._relatedLogicalObjects[i].SetSelectedSelf)
      {
        this._relatedLogicalObjects[i].SetSelectedSelf(bSel);
      }
    }
  }
};

/**
 * @protected
 * Set whether the selection effect is shown.
 * 
 * @param bOver {boolean}  bSel  true if the object is selected,
 *        false otherwise
 */
DvtSelectableArc.prototype.SetSelectedSelf = function(bSel)
{
  if (this._bSelected != bSel)
  {
    this._bSelected = bSel;
    if (this._bZorder)
    {
      if (this._bSelected && this._zOrderManager)
      {
        this._zOrderManager.bringToFrontOfSelection(this);
      }
      else if (!this._bSelecting && this._zOrderManager)
      {
        this._zOrderManager.pushToBackOfSelection(this);
      }
    }
    this.ApplySelectionState();
  }
};

/**
 * Add a related object of this det object.
 *
 * @param {DvtDisplayable} displayable A DvtDisplayable object related to this one
 */
DvtSelectableArc.prototype.addRelatedObject = function(displayable)
{
  if (!this._relatedLogicalObjects)
    this._relatedLogicalObjects = [];

  this._relatedLogicalObjects.push(displayable);
};


/**
 * Set whether a drop shadow is shown when this object is selected.
 *
 * @param {boolean}  bShadow  true if a selection drop shadow should be shown,
 *        false if not
 */
DvtSelectableArc.prototype.setSelectedShadow = function(bShadow)
{
  this._bSelectedShadow = bShadow;
};

/**
 * Set the _dataColor.
 *
 * @param {string}  clr  the color to set
 */
DvtSelectableArc.prototype.setDataColor = function(clr)
{
  this._dataColor = clr;
};

/**
 * Sets whether the z order of an object should be adjusted for selection.
 *
 * @param {boolean}  yesNo true if zorder is to change
 */
DvtSelectableArc.prototype.setZorder = function(yesNo)
{
  this._bZorder = yesNo;
};

DvtSelectableArc.prototype.setZOrderManager = function(manager) 
{
  this._zOrderManager = manager;
}

// Copyright (c) 2011, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/** 
  *  A marker object for selectable invisible markers.
  *  @class DvtSelectableLineMarker A marker object for selectable scatter and bubble charts.
  *  e.g.<br><br><code>
  *  var  marker = new DvtSelectableLineMarker(context, DvtSelectableLineMarker.CIRCLE, 50, 50, 10, 10) ;<br></code>
  *  @extends DvtMarker
  *  @constructor
  *  @param {DvtContext} context   The platform dependent context object (such
  *                                as {@link DvtSvgContext}).
  *  @param {number} type The type of the marker (see {@link DvtMarker}).
  *  @param {number} x  The x position of the top left corner of the marker.
  *  @param {number} y  The y position of the top left corner of the marker.
  *  @param {number} w  The width of the marker.
  *  @param {number} h  The height of the marker.
  *  @param {String} id  Optional ID for the shape (see {@link  DvtDisplayable#setId}).
  */
var  DvtSelectableLineMarker = function(context, type, x, y, w, h, id)
{
   this.Init(context, type,x, y, w, h, id) ;
};

DvtObj.createSubclass(DvtSelectableLineMarker, DvtMarker, "DvtSelectableLineMarker") ;



/*---------------------------------------------------------------------*/
/*  Init()                                                             */
/*---------------------------------------------------------------------*/
/**
  *  Object initializer.
  *  @protected
  */
DvtSelectableLineMarker.prototype.Init = function(context, type, x, y, w, h, id)
{
  DvtSelectableLineMarker.superclass.Init.call(this, context, type, x, y, w, h, id) ;
  
  //For Selection
  this._savedFill = null;
  this._bSavedFill = false;
  this._bSavedStroke = false;
  
  this._zOrderManager = null;
};

/**
 * @protected
 * Apply selection effects to line markers on line, area, combo, pareto, and radar graphs.
 */
DvtSelectableLineMarker.prototype.ApplySelectingSelectionState = function() 
{
  var stroke;
  var fill;
  
  if (this._bSelected) 
  {
    if (this._zOrderManager)
      this._zOrderManager.bringToFrontOfSelection(this);
    //Selection stroke is black
    stroke = DvtSelectionEffectUtils.createSelectingStroke("#000000"); 
    var strokeWidth = stroke.getWidth();
    strokeWidth = this.ScaleStrokeWidth(strokeWidth);
    stroke.setWidth(strokeWidth);
    //No Selection fill for invisible markers
    fill = new DvtSolidFill("#000000", 0.001);
      
    if (!this._bSelecting) 
    {
      //This is for pre-selected case, we need to save the original stroke and fill
      //without mouse over event
      this.SaveStrokeAndFill();
    }
  } 
  else 
  {
    if (this._bSelecting) 
    {
      if (this._zOrderManager)
        this._zOrderManager.bringToFrontOfSelection(this);
      //Selecting stroke is a lighter version of the data color
      stroke = DvtSelectionEffectUtils.createSelectingStroke(this._dataColor);
      var strokeWidth = stroke.getWidth();
      strokeWidth = this.ScaleStrokeWidth(strokeWidth);
      stroke.setWidth(strokeWidth);
      fill = new DvtSolidFill("#000000", 0.001);
      this.SaveStrokeAndFill();
    } 
    else 
    {
      if (this._zOrderManager)
        this._zOrderManager.pushToBackOfSelection(this);
      stroke = this._savedStroke;
      fill = this._savedFill;
      this._savedStroke = null;
      this._savedFill = null
      this._bSavedStroke = false;
      this._bSavedFill = false;
    }
  }
  this.setStroke(stroke);
  this.setFill(fill);
}

/**
 * @protected
 * Helper function to save the original stroke and fill
 */
DvtSelectableLineMarker.prototype.SaveStrokeAndFill = function() 
{
  if (!this._bSavedStroke) 
  {
    this._savedStroke = this.getStroke();
    this._bSavedStroke = true;
  }
      
  if (!this._bSavedFill) 
  {
    this._savedFill = this.getFill();  
    this._bSavedFill = true;
  } 
}

/**
 * @override
 */
DvtSelectableLineMarker.prototype.ApplySelectingState = function()
{
  this.ApplySelectingSelectionState();
};

/**
 * @override
 */
DvtSelectableLineMarker.prototype.ApplySelectionState = function()
{
   this.ApplySelectingSelectionState();
};

DvtSelectableLineMarker.prototype.setZOrderManager = function(manager) 
{
  this._zOrderManager = manager;
}
// Copyright (c) 2011, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/**
  *  Creates a selectable shape using SVG path commands.
  *  @extends DvtPath
  *  @class DvtSelectablePath  Creates an arbitrary shape using SVG path commands.
  *  @constructor
  *  @param {DvtContext} context  The platform dependent context object (such
  *                               as {@link DvtSvgContext}).
  *  @param {Object} cmds  Optional string of SVG path commands (see comment for
  *                        {@link DvtPath#setCmds}), or an array containing
  *                        consecutive command and coordinate entries (see comment
  *                        for {@link DvtPath#setCommands}).
  * @param {String} id  Optional ID for the shape (see {@link  DvtDisplayable#setId}).
  */
var  DvtSelectablePath = function(context, cmds, id)
{
   this.Init(context, cmds, id) ;
};

DvtObj.createSubclass(DvtSelectablePath, DvtPath, "DvtSelectablePath") ;

/**
  *  Object initializer.
  *  @protected
  */
DvtSelectablePath.prototype.Init = function(context, cmds, id)
{
  DvtSelectablePath.superclass.Init.call(this, context, cmds, id) ;
  
  this._bSelected = false;
  this._bSelecting = false;
  this._selectionEffects = null;
  this._bSelectedShadow = true;
  this._dataColor = "#000000";
  
  //properties related to selection
  this._savedStroke = null;
  this._bSavedStroke = false;
  this._relatedLogicalObjects = null;
  this._applyStrokeTimer = null;
  
  this._bZorder = true;
  this._zOrderManager = null;
  this._selectionType    = DvtSelectionEffectUtils.DEFAULT_SEL_TYPE;
};

/**
 * @protected
 * Apply any selection effects to this object.
 */
DvtSelectablePath.prototype.ApplySelectionState = function()
{
  DvtSelectionEffectUtils.applySelectionState(this, this._dataColor);
};

/**
 * @protected
 * Apply any mouse hover selection effects to this object.
 */
DvtSelectablePath.prototype.ApplySelectingState = function()
{
  DvtSelectionEffectUtils.applySelectingState(this, this._dataColor);
};


/**
 * Show the selection hover effect.
 */
DvtSelectablePath.prototype.showHoverEffect = function()
{
  this.SetSelectionMouseOver(true);
};


/**
 * Hide the selection hover effect.
 */
DvtSelectablePath.prototype.hideHoverEffect = function()
{
  this.SetSelectionMouseOver(false);
};


/**
 * Determine if the selection hover effect is shown.
 * 
 * @type boolean
 */
DvtSelectablePath.prototype.isHoverEffectShown = function()
{
  return this._bSelecting;
};


/**
 * @protected
 * Set whether the selection mouse hover effect is shown.
 * 
 * @param bOver {boolean}  bOver  true if the mouse is over the object,
 *        false otherwise
 */
DvtSelectablePath.prototype.SetSelectionMouseOver = function(bOver)
{
  this.SetSelectionMouseOverSelf(bOver);

  //set selection on related parts of this marker also
  if (this._relatedLogicalObjects)
  {
    for (var i = 0; i < this._relatedLogicalObjects.length; i++)
    {
      if (this._relatedLogicalObjects[i].SetSelectionMouseOverSelf)
      {
        this._relatedLogicalObjects[i].SetSelectionMouseOverSelf(bOver);
      }
    }
  }
}

/**
 * @protected
 * Set whether the selection mouse hover effect is shown.
 * 
 * @param bOver {boolean}  bOver  true if the mouse is over the object,
 *        false otherwise
 */
DvtSelectablePath.prototype.SetSelectionMouseOverSelf = function(bOver)
{
  if (this._bSelecting != bOver)
  {
    this._bSelecting = bOver;
    if (this._bZorder)
    {
      if (this._bSelecting && this._zOrderManager) {
        this._zOrderManager.bringToFrontOfSelection(this);
      }
      else if (!this._bSelected && this._zOrderManager) {
        this._zOrderManager.pushToBackOfSelection(this);
      }
    }
    this.ApplySelectingState();
  }
};


/**
 * Determine whether this object is selected.
 * 
 * @type boolean
 */
DvtSelectablePath.prototype.isSelected = function()
{
  return this._bSelected;
};

/**
 * Set whether the selection effect is shown.
 * 
 * @param bOver {boolean}  bSel  true if the object is selected,
 *        false otherwise
 */
DvtSelectablePath.prototype.setSelected = function(bSel)
{
  this.SetSelectedSelf(bSel);

  //set selection on related parts of this marker also
  if (this._relatedLogicalObjects)
  {
    for (var i = 0; i < this._relatedLogicalObjects.length; i++)
    {
      if (this._relatedLogicalObjects[i].SetSelectedSelf)
      {
        this._relatedLogicalObjects[i].SetSelectedSelf(bSel);
      }
    }
  }
};

/**
 * @protected
 * Set whether the selection effect is shown.
 * 
 * @param bOver {boolean}  bSel  true if the object is selected,
 *        false otherwise
 */
DvtSelectablePath.prototype.SetSelectedSelf = function(bSel)
{
  if (this._bSelected != bSel) {
    this._bSelected = bSel;
    if (this._bZorder)
    {
      if (this._bSelected && this._zOrderManager) {
        this._zOrderManager.bringToFrontOfSelection(this);
      }
      else if (!this._bSelecting && this._zOrderManager) {
        this._zOrderManager.pushToBackOfSelection(this);
      }
    }
    this.ApplySelectionState();
  }
};

/**
 * Add a related object of this det object.
 *
 * @param {DvtDisplayable} displayable A DvtDisplayable object related to this one
 */
DvtSelectablePath.prototype.addRelatedObject = function(displayable)
{
  if (!this._relatedLogicalObjects)
  {
    this._relatedLogicalObjects = [];
  }

  this._relatedLogicalObjects.push(displayable);
};


/**
 * Set whether a drop shadow is shown when this object is selected.
 *
 * @param {boolean}  bShadow  true if a selection drop shadow should be shown,
 *        false if not
 */
DvtSelectablePath.prototype.setSelectedShadow = function(bShadow)
{
  this._bSelectedShadow = bShadow;
};

/**
 * Set the _dataColor.
 *
 * @param {string}  clr  the color to set
 */
DvtSelectablePath.prototype.setDataColor = function(clr)
{
  this._dataColor = clr;
};

/**
 * Sets whether the z order of an object should be adjusted for selection.
 *
 * @param {boolean}  yesNo true if zorder is to change
 */
DvtSelectablePath.prototype.setZorder = function(yesNo)
{
  this._bZorder = yesNo;
};

DvtSelectablePath.prototype.setZOrderManager = function(manager) 
{
  this._zOrderManager = manager;
}
/**
  * Creates a selectable polygon from an array of consecutive (x,y) coordinates.
  * @extends DvtPolygon
  * @constructor  
  * @param {DvtContext} context   The platform dependent context object (such
  *                               as {@link DvtSvgContext}).
  * @param {Array} ar  An array of consecutive x,y coordinate pairs.
  * @param {String} id  Optional ID for the shape (see {@link  DvtDisplayable#setId}).
  */
var  DvtSelectablePolygon = function(color, context, arPoints, id)
{
   this.Init(color, context, arPoints, id) ;
}

DvtObj.createSubclass(DvtSelectablePolygon, DvtPolygon, "DvtSelectablePolygon") ;

/**
  *  Object initializer.
  *  @protected
  */
DvtSelectablePolygon.prototype.Init = function(context, arPoints, id)
{
  DvtSelectablePolygon.superclass.Init.call(this, context, arPoints, id) ;
  
  this._dataColor = "#000000";
  this._bSelected = false;
  this._bSelecting = false;
  this._selectionEffects = null;
  this._bSelectedShadow = true;
  
  //properties related to selection
  this._savedStroke = null;
  this._bSavedStroke = false;
  this._relatedLogicalObjects = null;
  this._applyStrokeTimer = null;
  
  this._bZorder = true;
  this._zOrderManager = null;  
  this._selectionType    = DvtSelectionEffectUtils.DEFAULT_SEL_TYPE;
}

/**
 * @protected
 * Apply any selection effects to this object.
 */
DvtSelectablePolygon.prototype.ApplySelectionState = function()
{
  DvtSelectionEffectUtils.applySelectionState(this, this._dataColor);
}


/**
 * @protected
 * Apply any mouse hover selection effects to this object.
 */
DvtSelectablePolygon.prototype.ApplySelectingState = function()
{
  DvtSelectionEffectUtils.applySelectingState(this, this._dataColor);
}


/**
 * Show the selection hover effect.
 */
DvtSelectablePolygon.prototype.showHoverEffect = function()
{
  this.SetSelectionMouseOver(true);
};


/**
 * Hide the selection hover effect.
 */
DvtSelectablePolygon.prototype.hideHoverEffect = function()
{
  this.SetSelectionMouseOver(false);
};


/**
 * Determine if the selection hover effect is shown.
 * 
 * @type boolean
 */
DvtSelectablePolygon.prototype.isHoverEffectShown = function()
{
  return this._bSelecting;
}

/**
 * @protected
 * Set whether the selection mouse hover effect is shown.
 * 
 * @param bOver {boolean}  bOver  true if the mouse is over the object,
 *        false otherwise
 */
DvtSelectablePolygon.prototype.SetSelectionMouseOver = function(bOver)
{
  this.SetSelectionMouseOverSelf(bOver);

  //set selection on related parts of this marker also
  if (this._relatedLogicalObjects)
  {
    for (var i = 0; i < this._relatedLogicalObjects.length; i++)
    {
      if (this._relatedLogicalObjects[i].SetSelectionMouseOverSelf)
      {
        this._relatedLogicalObjects[i].SetSelectionMouseOverSelf(bOver);
      }
    }
  }
}

/**
 * @protected
 * Set whether the selection mouse hover effect is shown.
 * 
 * @param bOver {boolean}  bOver  true if the mouse is over the object,
 *        false otherwise
 */
DvtSelectablePolygon.prototype.SetSelectionMouseOverSelf = function(bOver)
{
  if (this._bSelecting != bOver)
  {
    this._bSelecting = bOver;
    if (this._bZorder)
    {
      if (this._bSelecting && this._zOrderManager)
      {
        this._zOrderManager.bringToFrontOfSelection(this);
      }
      else if (!this._bSelected && this._zOrderManager)
      {
        this._zOrderManager.pushToBackOfSelection(this);
      }
    }
    this.ApplySelectingState();
  }
};

/**
 * Determine whether this object is selected.
 * 
 * @type boolean
 */
DvtSelectablePolygon.prototype.isSelected = function()
{
  return this._bSelected;
}

/**
 * Set whether the selection effect is shown.
 * 
 * @param bOver {boolean}  bSel  true if the object is selected,
 *        false otherwise
 */
DvtSelectablePolygon.prototype.setSelected = function(bSel)
{
  this.SetSelectedSelf(bSel);

  //set selection on related parts of this marker also
  if (this._relatedDetObjects)
  {
    for (var i = 0; i < this._relatedDetObjects.length; i++)
    {
      if (this._relatedDetObjects[i].SetSelectedSelf)
      {
        this._relatedDetObjects[i].SetSelectedSelf(bSel);
      }
    }
  }
}

/**
 * @protected
 * Set whether the selection effect is shown.
 * 
 * @param bOver {boolean}  bSel  true if the object is selected,
 *        false otherwise
 */
DvtSelectablePolygon.prototype.SetSelectedSelf = function(bSel)
{
  if (this._bSelected != bSel)
  {
    this._bSelected = bSel;
    if (this._bZorder)
    {
      if (this._bSelected && this._zOrderManager)
      {
        this._zOrderManager.bringToFrontOfSelection(this);
      }
      else if (!this._bSelecting && this._zOrderManager)
      {
        this._zOrderManager.pushToBackOfSelection(this);
      }
    }
    this.ApplySelectionState();
  }
}

/**
 * Add a related object of this logical object.
 *
 * @param {DvtDisplayable} displayable A DvtDisplayable object related to this one
 */
DvtSelectablePolygon.prototype.addRelatedObject = function(displayable)
{
  if (!this._relatedLogicalObjects)
  {
    this._relatedLogicalObjects = [];
  }

  this._relatedLogicalObjects.push(displayable);
}


/**
 * Set whether a drop shadow is shown when this object is selected.
 *
 * @param {boolean}  bShadow  true if a selection drop shadow should be shown,
 *        false if not
 */
DvtSelectablePolygon.prototype.setSelectedShadow = function(bShadow)
{
  this._bSelectedShadow = bShadow;
}

/**
 * Set the _dataColor.
 *
 * @param {string}  clr  the color to set
 */
DvtSelectablePolygon.prototype.setDataColor = function(clr)
{
  this._dataColor = clr;
}

/**
 * Sets whether the z order of an object should be adjusted for selection.
 *
 * @param {boolean}  yesNo true if zorder is to change
 */
DvtSelectablePolygon.prototype.setZorder = function(yesNo)
{
  this._bZorder = yesNo;
}

DvtSelectablePolygon.prototype.setZOrderManager = function(manager) 
{
  this._zOrderManager = manager;
}
/**
 * Style Utilities 
 * @class DvtStyleUtils 
 * @constructor
 */
var DvtStyleUtils = function() {
};


/**
 * get computed style applied to the specified element
 * Note: 
 * IE may return style value in % or "em" unit if it was specfied that way in the css style
 * while oher browser returns the equiv value in pixel
 * @param {DOM Element} element
 * @param {CSSStyleDeclaration} style

DvtStyleUtils.getComputedStyle = function(element) {
  if (! element)
    return null;

  var style;
  // if not IE
  if (document.defaultView && document.defaultView.getComputedStyle) {
    style = document.defaultView.getComputedStyle(element, null);
  }
  // if IE
  else if (element.currentStyle) {
    style = element.currentStyle;
  }
  else {
    style = element.style;
  }
  return new DvtCSSStyle(style);
}
 */


/**
 * @private
 * key: component type name
 * val: component short name 
 */
DvtStyleUtils._AfComponentMap = {
  DvtAfLink : "afl",
  DvtAfCommandButton : "cb",
  DvtAfCommandImageLink : "cil",
  DvtAfCommandLink : "cl",
  DvtAfGoButton : "gb",
  DvtAfGoLink : "gl",
  DvtAfImage : "i",
  DvtAfPanelFormLayout : "pfl",
  DvtAfPanelGroupLayout : "pgl",
  DvtAfPanelLabelAndMessage : "plm",
  DvtAfSeparator : "se"
};


DvtStyleUtils.getTagSkinKeyMap = function () {
  /*
   * This map is only created when we run in local mode
   * key: component short name 
   * val: list of selectors
   */
  if (DvtStyleUtils._tagSkinKey === undefined) {
    var tagSkinKeyMap = {};

    tagSkinKeyMap["cil"] = ("af_commandImageLink,af_commandImageLink_image,af_commandImageLink_text,af_commandImageLink.p_AFDisabled").split(",");
    tagSkinKeyMap["afl"] = ("af_link,af_link_image,af_link_text,af_link.p_AFDisabled").split(",");

    tagSkinKeyMap["cl"] = ("af_commandLink,af_commandLink.p_AFDisabled").split(",");
    tagSkinKeyMap["gl"] = ("af_goLink,af_goLink.p_AFDisabled").split(",");
    tagSkinKeyMap["i"] = ("af_image").split(",");
    tagSkinKeyMap["se"] = ("af_separator").split(",");

    tagSkinKeyMap["pfl"] = (",AFPanelFormLayoutContentCell,af_panelFormLayout_label-cell").split(",");
    tagSkinKeyMap["pgl"] = ("af_panelGroupLayout").split(",");
    tagSkinKeyMap["plm"] = (",af_panelLabelAndMessage_label,af_panelLabelAndMessage_content-cell").split(",");


    tagSkinKeyMap["cb"] = ("af_commandButton,af_commandButton_icon-style,af_commandButton.p_AFDisabled").split(",");
    tagSkinKeyMap["gb"] = ("af_goButton,af_goButton_icon-style,af_goButton.p_AFDisabled").split(",");


    DvtStyleUtils._tagSkinKeyMap = tagSkinKeyMap;
  }
  return DvtStyleUtils._tagSkinKeyMap;
};

/**
 * This method is called when parsing the st(tag, skin keys) block
 *
 * <st cb="x7i,xg2,x7i.p_AFDisabled" cil="xg8,x122,x11y,xg8.p_AFDisabled" cl="xg9,xg9.p_AFDisabled"
 *     gb="af_commandButton,xg4,af_commandButton.p_AFDisabled" gl="xgo,xgo.p_AFDisabled" i="xit"
 *     pfl="x19,xrf,x4y,x4w" pgl="x1a" plm=",af_panelLabelAndMessage_label," se="xy8"/>
 *
 * Ex: DvtStyleUtils.setTagSkinKeyMap(stElement.attributes);
 */
DvtStyleUtils.setTagSkinKeyMap = function (attrMap) {
  if (attrMap && attrMap.length > 0) {
    var tagSkinKeyMap = {};
    var selList = "";
    for (var i = 0; i < attrMap.length; i++) {
      var compSels = attrMap[i];
      if (compSels.name && compSels.value !== undefined) {
        var tmpSels = compSels.value.split(",");
        tagSkinKeyMap[compSels.name] = tmpSels;

        for (var j = 0; j < tmpSels.length; j++) {
          selList += tmpSels[j] + " ";
        }
      }
    }
    DvtStyleUtils._tagSkinKey = tagSkinKeyMap;

    //TODO: getStyleMap from styleSheets
    //this._styleMap = AdfDhtmlCommonFlash.getAllStyles(selList);
  }
};

DvtStyleUtils.getStyleMap = function () {
  if (this._styleMap) {
  }
  /*
   * This map is only created when we run in local mode
   * key: selector
   * val: list of styles
   */
  else if (this.isLocal()) {
    var styleMap = {};
    //image
    styleMap["af_image"] = new DvtCSSStyle("border:0px");

    //commandLink
    styleMap["af_commandLink"] = new DvtCSSStyle("font-family:Tahoma,Verdana,Arial,Helvetica,FreeSans,sans-serif;font-weight:normal;font-size:11px;color:#003286;text-decoration:none");
    styleMap["af_commandLink.p_AFDisabled"] = new DvtCSSStyle("text-decoration:none;cursor:default;color:#8e98af");

    //goLink
    styleMap["af_goLink"] = new DvtCSSStyle("font-family:Tahoma,Verdana,Arial,Helvetica,FreeSans,sans-serif;font-weight:normal;font-size:11px;color:#003286;text-decoration:none");
    styleMap["af_goLink.p_AFDisabled"] = new DvtCSSStyle("text-decoration:none;cursor:default;color:#8e98af");

    //commandImageLink
    styleMap["af_commandImageLink"] = new DvtCSSStyle("font-family:Tahoma,Verdana,Arial,Helvetica,FreeSans,sans-serif;font-weight:normal;font-size:11px;white-space:nowrap;text-decoration:none");
    styleMap["af_commandImageLink_image"] = new DvtCSSStyle("border:none;vertical-align:middle;display:inline");
    styleMap["af_commandImageLink_text"] = new DvtCSSStyle("color:#003286;margin-left:3px;text-decoration:none");
    styleMap["af_commandImageLink.p_AFDisabled"] = new DvtCSSStyle("text-decoration:none;cursor:default;color:#8e98af");

    //link
    styleMap["af_link"] = new DvtCSSStyle("font-family:Tahoma,Verdana,Arial,Helvetica,FreeSans,sans-serif;font-weight:normal;font-size:11px;white-space:nowrap;text-decoration:none");
    styleMap["af_link_image"] = new DvtCSSStyle("border:none;vertical-align:middle;display:inline");
    styleMap["af_link_text"] = new DvtCSSStyle("color:#003286;margin-left:3px;text-decoration:none");
    styleMap["af_link.p_AFDisabled"] = new DvtCSSStyle("text-decoration:none;cursor:default;color:#8e98af");

    //panelLabelAndMessage
    styleMap["af_panelLabelAndMessage_label"] = new DvtCSSStyle("font-family:Tahoma,Verdana,Arial,Helvetica,FreeSans,sans-serif;font-size:11px;" + DvtStyleUtils._getTextAlignAttr(true) + ";color:#755600;padding:0px 6px 0px 0px;font-weight:normal");

    //panelFormLayout
    styleMap["AFPanelFormLayoutContentCell"] = new DvtCSSStyle("padding-left:8px;padding-right:0px;" + DvtStyleUtils._getTextAlignAttr(false) + ";font-family:Tahoma,Verdana,Arial,Helvetica,FreeSans,sans-serif;vertical-align:top;padding-top:2px;padding-bottom:0px;padding:1px 0 0 2px");
    styleMap["af_panelFormLayout_label-cell"] = new DvtCSSStyle("padding:0px 6px 0px 0px;padding-left:8px;padding-right:0px;" + DvtStyleUtils._getTextAlignAttr(true) + ";padding-top:3px;padding-bottom:1px");

    //commandButton
    styleMap["af_commandButton"] = new DvtCSSStyle("font-family:Tahoma,Verdana,Arial,Helvetica,FreeSans,sans-serif;font-weight:normal;font-size:11px;color:#003D5B;border-color:transparent;border-style:solid;border-width:1px;border-top-color:#E0E3E8;border-right-color:#606974;border-bottom-color:#606974;border-left-color:#E0E3E8;background-position:top center;background-repeat:repeat-x;background-color:#CCD6E8;background-image:-webkit-linear-gradient(top, #FFFFFF, #CCD6E8);text-decoration:none;white-space:nowrap;margin:0px;padding-top:1px;padding-bottom:3px;padding:1px 1px 0px 2px;padding-left:9px;padding-right:9px");
    styleMap["af_commandButton_icon-style"] = new DvtCSSStyle("border-width:0px;padding-left:0px;padding-right:0px;padding-bottom:1px;padding-top:1px;vertical-align:-30%");
    styleMap["af_commandButton.p_AFDisabled"] = new DvtCSSStyle("color:#6e7587;border-style:solid;border-width:1px;border-color:#9297A6;border-top-color:#E0E3E8;border-right-color:#B3BFC5;border-bottom-color:#B3BFC5;border-left-color:#E0E3E8;background-color:#DBE0EA;background-image:none");

    //goButton
    styleMap["af_goButton"] = new DvtCSSStyle("font-family:Tahoma,Verdana,Arial,Helvetica,FreeSans,sans-serif;font-weight:normal;font-size:11px;color:#003D5B;border-color:transparent;border-style:solid;border-width:1px;border-top-color:#E0E3E8;border-right-color:#606974;border-bottom-color:#606974;border-left-color:#E0E3E8;background-position:top center;background-repeat:repeat-x;background-color:#CCD6E8;background-image:-webkit-linear-gradient(top, #FFFFFF, #CCD6E8);text-decoration:none;white-space:nowrap;margin:0px;padding-top:1px;padding-bottom:3px;padding:1px 1px 0px 2px;padding-left:9px;padding-right:9px");
    styleMap["af_goButton_icon-style"] = new DvtCSSStyle("border-width:0px;padding-left:0px;padding-right:0px;padding-bottom:1px;padding-top:1px;vertical-align:-30%");
    styleMap["af_goButton.p_AFDisabled"] = new DvtCSSStyle("color:#6e7587;border-style:solid;border-width:1px;border-color:#9297A6;border-top-color:#E0E3E8;border-right-color:#B3BFC5;border-bottom-color:#B3BFC5;border-left-color:#E0E3E8;background-color:#DBE0EA;background-image:none");

    //separator
    styleMap["af_separator"] = new DvtCSSStyle("margin-top:3px;margin-bottom:3px;border-left:0px;border-right:0px;border-top:1px solid #ADB6C7;border-bottom:1px solid #FFFFFF");

    this._styleMap = styleMap;
  }
  else {
    this._styleMap = {};
  }
  return this._styleMap;
};

/**
 * Get text-align based on reading direction.
 * 
 * @return CSS "key:val" string for text-align attribute
 */
DvtStyleUtils._getTextAlignAttr = function(rightAlign) {
  if (DvtStyleUtils.isLocaleR2L()) {
    return rightAlign? "text-align:left" : "text-align:right";
  }
  else {
    return rightAlign? "text-align:right" : "text-align:left";
  }
};
    
/**
 * Get background-position based on reading direction.
 * 
 * @return CSS "key:val" string for background-position attribute
 */
DvtStyleUtils.getBackgroundPositionAttr = function() {
  if (DvtStyleUtils.isLocaleR2L())
    return "background-position:right bottom";
  else
    return "background-position:left bottom";
};


/**
 * @param {String} typeName AF component type name
 * @return an array of DvtCSSStyle objects for the specified component
 */
DvtStyleUtils.getDefaultCSSStyle = function(typeName) {
  var styleList = [];
  var shortName = DvtStyleUtils._AfComponentMap[typeName];
  if (shortName) {
    var skinMap = DvtStyleUtils.getTagSkinKeyMap();
    var selectors = skinMap[shortName];
    var styleMap = DvtStyleUtils.getStyleMap();
    if (selectors && selectors.length > 0 && styleMap) {
      for (var i = 0; i < selectors.length; i++) {
        var sel = selectors[i];
        if (sel && styleMap[sel]) {
          styleList.push(styleMap[sel]);
        }
        else {
          styleList.push(new DvtCSSStyle());
        }
      }
    }
  }

  return styleList;
};

DvtStyleUtils.isLocaleR2L = function() {
  return DvtAgent.getAgent().isRightToLeft();
};

//TODO: need to get this from the framework
DvtStyleUtils.isLocal = function() {
  return true;
};


// clone a list of DvtCSSStyle objects
DvtStyleUtils.cloneStyles = function(styleList) {
  var newList = [];
  if (styleList && styleList.length > 0) {
    for (var i = 0; i < styleList.length; i++) {
      newList.push(styleList[i].clone());
    }
  }
  return newList;
};


/**
 * Represents a set of CSS styles.
 * @param {String} style inlineStyle
 */
var DvtCSSStyle = function(style) {
  this.Init(style);
};

/**
 * @private
 * Only contain css style we support
 */
DvtCSSStyle._attrs = ["background-color", 
                      "background-image", 
                      "background-repeat", 
                      "background-position", 

                      "border",
                      "border-top",
                      "border-bottom",
                      "border-left",
                      "border-right",

                      "border-color",
                      "border-top-color",
                      "border-bottom-color",
                      "border-left-color",
                      "border-right-color",
                      "border-width",
                      "border-top-width",
                      "border-bottom-width",
                      "border-left-width",
                      "border-right-width",
                      "border-style",
                      "border-top-style",
                      "border-bottom-style",
                      "border-left-style",
                      "border-right-style",

                      "padding",
                      "padding-top",
                      "padding-bottom",
                      "padding-left",
                      "padding-right",

                      "margin",
                      "margin-top",
                      "margin-bottom",
                      "margin-left",
                      "margin-right",

                      "color",
                      "font-family",
                      "font-size",
                      "font-style",
                      "font-weight",

                      "text-align",
                      "text-decoration",

                      "height",
                      "width",
                      
                      "-tr-outer-color",
                      "-tr-inner-color"
                     ];



/*
 * A list of css styles apply to this text object.
 * note: svg does not recognize the "color" attribute, use "fill" instead

DvtCSSStyle._textAttrs = 
[
  "color",
  "font-family",
  "font-size",
  "font-style",
  "font-weight",
  "text-align",
  "text-decoration",
];
 */


// CSS attributes supported

// Background Properties
DvtCSSStyle.BACKGROUND_COLOR = "background-color";
DvtCSSStyle.BACKGROUND_IMAGE = "background-image";
DvtCSSStyle.BACKGROUND_REPEAT = "background-repeat";
DvtCSSStyle.BACKGROUND_POSITION = "background-position";

// Border Properties
DvtCSSStyle.BORDER = "border";
DvtCSSStyle.BORDER_TOP = "border-top";
DvtCSSStyle.BORDER_BOTTOM = "border-bottom";
DvtCSSStyle.BORDER_LEFT = "border-left";
DvtCSSStyle.BORDER_RIGHT = "border-right";

DvtCSSStyle.BORDER_WIDTH = "border-width";
DvtCSSStyle.BORDER_TOP_WIDTH = "border-top-width";
DvtCSSStyle.BORDER_BOTTOM_WIDTH = "border-bottom-width";
DvtCSSStyle.BORDER_LEFT_WIDTH = "border-left-width";
DvtCSSStyle.BORDER_RIGHT_WIDTH = "border-right-width";

DvtCSSStyle.BORDER_COLOR = "border-color";
DvtCSSStyle.BORDER_TOP_COLOR = "border-top-color";
DvtCSSStyle.BORDER_BOTTOM_COLOR = "border-bottom-color";
DvtCSSStyle.BORDER_LEFT_COLOR = "border-left-color";
DvtCSSStyle.BORDER_RIGHT_COLOR = "border-right-color";

// Margin Properties
DvtCSSStyle.MARGIN = "margin";
DvtCSSStyle.MARGIN_TOP = "margin-top";
DvtCSSStyle.MARGIN_BOTTOM = "margin-bottom";
DvtCSSStyle.MARGIN_LEFT = "margin-left";
DvtCSSStyle.MARGIN_RIGHT = "margin-right";

// Padding Properties
DvtCSSStyle.PADDING = "padding";
DvtCSSStyle.PADDING_TOP = "padding-top";
DvtCSSStyle.PADDING_BOTTOM = "padding-bottom";
DvtCSSStyle.PADDING_LEFT = "padding-left";
DvtCSSStyle.PADDING_RIGHT = "padding-right";

// Font Properties
DvtCSSStyle.COLOR = "color";
DvtCSSStyle.FONT_FAMILY = "font-family";
DvtCSSStyle.FONT_SIZE = "font-size";
DvtCSSStyle.FONT_STYLE = "font-style";
DvtCSSStyle.FONT_WEIGHT = "font-weight";
DvtCSSStyle.TEXT_DECORATION = "text-decoration";
DvtCSSStyle.TEXT_ALIGN = "text-align";


// Size Properties
DvtCSSStyle.HEIGHT = "height";
DvtCSSStyle.WIDTH = "width";


//value for background-image
DvtCSSStyle.NONE = "none";

//values for background-repeat
DvtCSSStyle.NO_REPEAT = "no-repeat";
DvtCSSStyle.REPEAT = "repeat";
DvtCSSStyle.REPEAT_X = "repeat-x";
DvtCSSStyle.REPEAT_Y = "repeat-y";
        
//value for margin
DvtCSSStyle.AUTO = "auto";
DvtCSSStyle.AUTO_MARGIN = "8";

// AFInstructionText is used as the default css style
// for outputText and formattedOutputText
DvtCSSStyle.AF_DEFAULT_FONT = "AFInstructionText";

DvtCSSStyle.DEFAULT_FONT_FAMILY = "Tahoma, Verdana, Helvetica, sans-serif";
DvtCSSStyle.DEFAULT_FONT_SIZE = "11";


// Special values for font size
DvtCSSStyle.SpFontSizeMap = {
  "xx-small" : "9",
  "x-small" : "10",
  "small" : "13",
  "medium" : "16",
  "large" : "18",
  "x-large" : "24",
  "xx-large" : "32"
};


// Special values for width
DvtCSSStyle.SpWidthMap = {
  thin : "2",
  medium : "4",
  thick : "6"
};


// Basic color keywords
DvtCSSStyle.SpColorMap = {
  aqua : "#00FFFF",
  black : "#000000",
  blue : "#0000FF",
  white : "#FFFFFF",
  fuchsia : "#FF00FF",
  gray : "#848284",
  lime : "#00FF00",
  maroon : "#840000",
  green : "#008200",
  navy : "#000084",
  olive : "#848200",
  red : "#FF0000",
  silver : "#C6C3C6",
  teal : "#008284",
  yellow : "#FFFF00",
  purple : "#800080",

  // for testing used
  cyan : "#D2B48C",
  goldenrod : "#DAA520",
  lightblue : "#ADD8E6",
  lightyellow : "#FFFFE0",
  orange : "#FFA500",
  paleGoldenRod : "#EEE8AA",
  paleturquoise : "#AFEEEE",
  peachpuff : "#FFDAB9",
  pink : "#FFC0CB",
  tan : "#D2B48C",
  thistle : "#D8BFD8",

  transparent : "#00FFFFFF"
};


// numeric attributes List
DvtCSSStyle._numericAttrsList = [
  DvtCSSStyle.WIDTH,
  DvtCSSStyle.HEIGHT,
  DvtCSSStyle.BORDER_WIDTH,
  DvtCSSStyle.BORDER_TOP_WIDTH,
  DvtCSSStyle.BORDER_BOTTOM_WIDTH,
  DvtCSSStyle.BORDER_LEFT_WIDTH,
  DvtCSSStyle.BORDER_RIGHT_WIDTH,
  
  DvtCSSStyle.MARGIN,
  DvtCSSStyle.MARGIN_TOP,
  DvtCSSStyle.MARGIN_BOTTOM,
  DvtCSSStyle.MARGIN_LEFT,
  DvtCSSStyle.MARGIN_RIGHT,

  DvtCSSStyle.PADDING,
  DvtCSSStyle.PADDING_TOP,
  DvtCSSStyle.PADDING_BOTTOM,
  DvtCSSStyle.PADDING_LEFT,
  DvtCSSStyle.PADDING_RIGHT
];

/**
 * Parse an inline style String and turn it into a DvtCSSStyle.
 * @param {String} style inlineStyle
 */
DvtCSSStyle.prototype.Init = function(style) {
  this.parseInlineStyle(style);
};

/**
 * Parse an inlineStyle string into a set of CSS styles and merge the results to this style object.
 * @param {String} style inlineStyle
 */
DvtCSSStyle.prototype.parseInlineStyle = function(style) {
  if (style && style.length > 0) {
    var a = style.split(";");
    var s;
    var colonIndex;
    var attrName;
    var attrVal;
    for (var i = 0; i < a.length; i++) {
      s = a[i];
      if (s && s.length > 0) {
        //find the first colon instead of using String.split because
        //there may be other colons in the string, for instance in
        //a fully qualified background-image url (http://some.server.com/...)
        colonIndex = s.indexOf(":");
        if (colonIndex > -1) {
          attrName = DvtStringUtils.trim(s.substring(0, colonIndex));
          attrVal = DvtStringUtils.trim(s.substring(colonIndex + 1));
              
          if (attrName && attrName.length > 0 &&
              attrVal && attrVal.length > 0) {

            this.setCSSStyle(attrName, attrVal);
          }
        }
      }
    }
  }
};

/**
 * Set a CSS style. For example: key="font-size" val="11px"
 * @param {String} key css style name
 * @param {String} val css style value
 */
DvtCSSStyle.prototype.setCSSStyle = function(key, val) {

  switch (key) {
  case "background-repeat" : 
    this.setBackgroundRepeat(key, val);
    break;
  case "color" :
  case "background-color" :
  case "border-top-color" :
  case "border-bottom-color" :
  case "border-left-color" :
  case "border-right-color" : 
    this.setColorString(key, val);
    break;

  case "border-top" :
  case "border-bottom" :
  case "border-left" :
  case "border-right" :
    this.setBorderSide(key, val);
    break;

  case "border" : 
    this.setBorderShorthand(key, val);
    break;
  case "border-color" :
    this.setBorderColorShorthand(key, val);
    break;
  case "border-width" : 
    this.setBorderWidthShorthand(key, val);
    break;
  case "padding" :
    this.setPaddingShorthand(key, val);
    break;
  case "margin" :
    this.setMarginShorthand(key, val);
    break;
  case "font-family" :
    this._setFontFamily(key, val);
    break;
  case "font-size" :
    this._setFontSize(key, val);
    break;
  default:
    this.setStyle(key, val);
    break;
  }

};


DvtCSSStyle.prototype._setFontFamily = function(key, val) {
    this[key] = val;
};

DvtCSSStyle.prototype._setFontSize = function(key, val) {
  var fsize = DvtStringUtils.trim(val);
  var specSize = DvtCSSStyle.SpFontSizeMap[fsize];
  if (specSize) {
    this[key] = (String(specSize) + "px");
  }
  else {
    this[key] = isNaN(parseFloat(fsize)) ? (DvtCSSStyle.DEFAULT_FONT_SIZE + "px") : fsize;
  }
};


/**
 * @param key is a shorthand for the four border properties: top, right, bottom and left border, respectively. 
 * @param val may contain up to 4 border-width values. 
 */
DvtCSSStyle.prototype.setBorderWidthShorthand = function(key, val) {
  var bwArray = val.split(" ");
  var bWidth = null;

  switch (bwArray.length) {
  case 1:
    this[key] = DvtCSSStyle._getBorderWidth(bwArray[0]);
    // remove other border widths
    delete this[DvtCSSStyle.BORDER_TOP_WIDTH];
    delete this[DvtCSSStyle.BORDER_BOTTOM_WIDTH];
    delete this[DvtCSSStyle.BORDER_RIGHT_WIDTH];
    delete this[DvtCSSStyle.BORDER_LEFT_WIDTH];
    break;

  case 2:
    bWidth = DvtCSSStyle._getBorderWidth(bwArray[0]);
    this.setStyle(DvtCSSStyle.BORDER_TOP_WIDTH, bWidth);
    this.setStyle(DvtCSSStyle.BORDER_BOTTOM_WIDTH, bWidth);

    bWidth = DvtCSSStyle._getBorderWidth(bwArray[1]);
    this.setStyle(DvtCSSStyle.BORDER_LEFT_WIDTH, bWidth);
    this.setStyle(DvtCSSStyle.BORDER_RIGHT_WIDTH, bWidth);
    break;

  case 3:
    this.setStyle(DvtCSSStyle.BORDER_TOP_WIDTH, DvtCSSStyle._getBorderWidth(bwArray[0]));
    bWidth = DvtCSSStyle._getBorderWidth(bwArray[1]);
    this.setStyle(DvtCSSStyle.BORDER_LEFT_WIDTH, bWidth);
    this.setStyle(DvtCSSStyle.BORDER_RIGHT_WIDTH, bWidth);
    this.setStyle(DvtCSSStyle.BORDER_BOTTOM_WIDTH, DvtCSSStyle._getBorderWidth(bwArray[2]));
    break;

  case 4:
    this.setStyle(DvtCSSStyle.BORDER_TOP_WIDTH, DvtCSSStyle._getBorderWidth(bwArray[0]));
    this.setStyle(DvtCSSStyle.BORDER_RIGHT_WIDTH, DvtCSSStyle._getBorderWidth(bwArray[1]));
    this.setStyle(DvtCSSStyle.BORDER_BOTTOM_WIDTH, DvtCSSStyle._getBorderWidth(bwArray[2]));
    this.setStyle(DvtCSSStyle.BORDER_LEFT_WIDTH, DvtCSSStyle._getBorderWidth(bwArray[3]));
    break;

  case 0:
  default:
    break;
  }
};


/**
 * @private
 * #param val contain only one borderWidth value
 */
DvtCSSStyle._getBorderWidth = function(val) {

  var bwidth = DvtStringUtils.trim(val);
  var specSize = DvtCSSStyle.SpWidthMap[bwidth];
  if (! specSize) {
    specSize = isNaN(parseFloat(bwidth)) ? "0px" : bwidth;
  }

  return specSize;
};


// border-top, border-right, border-bottom and border-left shorthand property 
// can specify width, style, and color in any order and separated by spaces
// ex: border-bottom:#797975 1px solid
//ex: border-top:1px solid rgb(185, 185, 180)

DvtCSSStyle.prototype.setBorderSide = function(key, val) {
  var borderArray = val.split(" ");
  var borderVal = null;
  var noBorder = false;
  var key1;

  for (var i = 0; i < borderArray.length; i++) {
    borderVal = borderArray[i];
    key1 = key;

    //rgb border color
    if (borderVal.indexOf("rgb") == 0) {
      for (var k = i + 1; k < borderArray.length; k++) {
        borderVal += borderArray[k];
        i++;
        if (borderArray[k].indexOf(")") != -1)
          break;
      }
      if (! DvtStringUtils.endsWith(key, "-" + DvtCSSStyle.COLOR))
        key1 = key + "-" + DvtCSSStyle.COLOR;
      this.setStyle(key1, borderVal);
    }
    //border color
    else if (DvtCSSStyle.isColorVal(borderVal)) {
      if (! DvtStringUtils.endsWith(key, "-" + DvtCSSStyle.COLOR))
        key1 = key + "-" + DvtCSSStyle.COLOR;
      this.setStyle(key1, DvtCSSStyle.parseHexColor(borderVal));
    }
    //border width
    else if (DvtCSSStyle.isBorderWidthVal(borderVal)) {
      if (! DvtStringUtils.endsWith(key, "-" + DvtCSSStyle.WIDTH))
        key1 = key + "-" + DvtCSSStyle.WIDTH;
      this.setStyle(key1, borderVal);
    }
    //we don't currently handle border style, but if it's none, set width=0
    else if (val == "none")
      noBorder = true;
  }

  if (noBorder) {
    this.setStyle(key + "-" + DvtCSSStyle.WIDTH, "0");
  }
};


// get margin-top, margin-right, margin-bottom and margin-left
DvtCSSStyle.prototype.getMarginTop = function() {
  return this._getSideWidth(DvtCSSStyle.MARGIN_TOP, DvtCSSStyle.MARGIN);
};

DvtCSSStyle.prototype.getMarginRight = function() {
  return this._getSideWidth(DvtCSSStyle.MARGIN_RIGHT, DvtCSSStyle.MARGIN);
};

DvtCSSStyle.prototype.getMarginBottom = function() {
  return this._getSideWidth(DvtCSSStyle.MARGIN_BOTTOM, DvtCSSStyle.MARGIN);
};

DvtCSSStyle.prototype.getMarginLeft = function() {
  return this._getSideWidth(DvtCSSStyle.MARGIN_LEFT, DvtCSSStyle.MARGIN);
};

// get border-top-width, border-right-width, border-bottom-width and border-left-width
DvtCSSStyle.prototype.getBorderTopWidth = function() {
  return this._getSideWidth(DvtCSSStyle.BORDER_TOP_WIDTH, DvtCSSStyle.BORDER_WIDTH);
};

DvtCSSStyle.prototype.getBorderRightWidth = function() {
  return this._getSideWidth(DvtCSSStyle.BORDER_RIGHT_WIDTH, DvtCSSStyle.BORDER_WIDTH);
};

DvtCSSStyle.prototype.getBorderBottomWidth = function() {
  return this._getSideWidth(DvtCSSStyle.BORDER_BOTTOM_WIDTH, DvtCSSStyle.BORDER_WIDTH);
};

DvtCSSStyle.prototype.getBorderLeftWidth = function() {
  return this._getSideWidth(DvtCSSStyle.BORDER_LEFT_WIDTH, DvtCSSStyle.BORDER_WIDTH);
};

DvtCSSStyle.prototype.getBorderWidth = function() {
  var bwidth = this.getStyle(DvtCSSStyle.BORDER_WIDTH);
  if (bwidth) {
    return bwidth;
  }
  bwidth = this.getStyle(DvtCSSStyle.BORDER_TOP_WIDTH);
  if (bwidth) {
    return bwidth;
  }
  bwidth = this.getStyle(DvtCSSStyle.BORDER_RIGHT_WIDTH);
  if (bwidth) {
    return bwidth;
  }
  bwidth = this.getStyle(DvtCSSStyle.BORDER_BOTTOM_WIDTH);
  if (bwidth) {
    return bwidth;
  }
  bwidth = this.getStyle(DvtCSSStyle.BORDER_LEFT_WIDTH);
  if (bwidth) {
    return bwidth;
  }
  return 0;
};

// get padding-top, padding-right, padding-bottom and padding-left
DvtCSSStyle.prototype.getPaddingTop = function() {
  return this._getSideWidth(DvtCSSStyle.PADDING_TOP, DvtCSSStyle.PADDING);
};

DvtCSSStyle.prototype.getPaddingRight = function() {
  return this._getSideWidth(DvtCSSStyle.PADDING_RIGHT, DvtCSSStyle.PADDING);
};

DvtCSSStyle.prototype.getPaddingBottom = function() {
  return this._getSideWidth(DvtCSSStyle.PADDING_BOTTOM, DvtCSSStyle.PADDING);
};

DvtCSSStyle.prototype.getPaddingLeft = function() {
  return this._getSideWidth(DvtCSSStyle.PADDING_LEFT, DvtCSSStyle.PADDING);
};

// width and height
DvtCSSStyle.prototype.getWidth = function() {
  return this.width;
};

DvtCSSStyle.prototype.getHeight = function() {
  return this.height;
};


// convert a string to an integer , default to zero
DvtCSSStyle.toInteger = function(val) {
  return (val) ? parseInt(val) : 0;
};

/**
 * Determine if the given style can be inherited.
 * 
 * @return true if the style can be inherited from an ancestor,
 *         false if not
 */
DvtCSSStyle.isInheritable = function(key) {
  switch (key) {
  case DvtCSSStyle.COLOR:
  case DvtCSSStyle.FONT_FAMILY:
  case DvtCSSStyle.FONT_SIZE:
  case DvtCSSStyle.FONT_STYLE:
  case DvtCSSStyle.FONT_WEIGHT:
  case DvtCSSStyle.TEXT_ALIGN:
    return true;

  default:
    return false;
  }
};


// val is a string contains up to 4 rgb colors, ex:
// border-color: rgb(221, 221, 216) rgb(185, 185, 132) rgb(121, 121, 117)
DvtCSSStyle.prototype.setBorderColorShorthand = function(key, val) {
  var bcArray = DvtCSSStyle.parseBorderColorString(key, val);
  var bcolor;

  switch (bcArray.length) {
  case 1:
    this.setColor(key, bcArray[0]);
    delete this[DvtCSSStyle.BORDER_TOP_COLOR];
    delete this[DvtCSSStyle.BORDER_BOTTOM_COLOR];
    delete this[DvtCSSStyle.BORDER_RIGHT_COLOR];
    delete this[DvtCSSStyle.BORDER_LEFT_COLOR];
    break;

  case 2:
    bcolor = bcArray[0];
    this.setColor(DvtCSSStyle.BORDER_TOP_COLOR, bcolor);
    this.setColor(DvtCSSStyle.BORDER_BOTTOM_COLOR, bcolor);

    bcolor = bcArray[1];
    this.setColor(DvtCSSStyle.BORDER_LEFT_COLOR, bcolor);
    this.setColor(DvtCSSStyle.BORDER_RIGHT_COLOR, bcolor);
    break;

  case 3:
    this.setColor(DvtCSSStyle.BORDER_TOP_COLOR, bcArray[0]);
    bcolor = bcArray[1];
    this.setColor(DvtCSSStyle.BORDER_LEFT_COLOR, bcolor);
    this.setColor(DvtCSSStyle.BORDER_RIGHT_COLOR, bcolor);
    this.setColor(DvtCSSStyle.BORDER_BOTTOM_COLOR, bcArray[2]);
    break;

  case 4:
    this.setColor(DvtCSSStyle.BORDER_TOP_COLOR, bcArray[0]);
    this.setColor(DvtCSSStyle.BORDER_RIGHT_COLOR, bcArray[1]);
    this.setColor(DvtCSSStyle.BORDER_BOTTOM_COLOR, bcArray[2]);
    this.setColor(DvtCSSStyle.BORDER_LEFT_COLOR, bcArray[3]);
    break;

  case 0:
  default:
    break;
  }
};


// val is a string contains up to 4 padding sizes, ex:
// padding: 2px 9px 1px
DvtCSSStyle.prototype.setPaddingShorthand = function(key, val) {
  var padArray = val.split(" ");
  var padding = null;

  switch (padArray.length) {
  case 1:
    this.setStyle(key, this._getPercent(padArray[0]));
    delete this[DvtCSSStyle.PADDING_TOP];
    delete this[DvtCSSStyle.PADDING_BOTTOM];
    delete this[DvtCSSStyle.PADDING_RIGHT];
    delete this[DvtCSSStyle.PADDING_LEFT];
    break;

  case 2:
    padding = this._getPercent(padArray[0]);
    this.setStyle(DvtCSSStyle.PADDING_TOP, padding);
    this.setStyle(DvtCSSStyle.PADDING_BOTTOM, padding);

    padding = this._getPercent(padArray[1]);
    this.setStyle(DvtCSSStyle.PADDING_LEFT, padding);
    this.setStyle(DvtCSSStyle.PADDING_RIGHT, padding);
    break;

  case 3:
    this.setStyle(DvtCSSStyle.PADDING_TOP, this._getPercent(padArray[0]));
    padding = this._getPercent(padArray[1]);
    this.setStyle(DvtCSSStyle.PADDING_LEFT, padding);
    this.setStyle(DvtCSSStyle.PADDING_RIGHT, padding);
    this.setStyle(DvtCSSStyle.PADDING_BOTTOM, this._getPercent(padArray[2]));
    break;

  case 4:
    this.setStyle(DvtCSSStyle.PADDING_TOP, this._getPercent(padArray[0]));
    this.setStyle(DvtCSSStyle.PADDING_RIGHT, this._getPercent(padArray[1]));
    this.setStyle(DvtCSSStyle.PADDING_BOTTOM, this._getPercent(padArray[2]));
    this.setStyle(DvtCSSStyle.PADDING_LEFT, this._getPercent(padArray[3]));
    break;

  case 0:
  default:
    break;
  }
};

// val is a string contains up to 4 margin sizes, ex:
// margin: 2px 9px 1px
//TODO: margin can be negative numbers and in CM
DvtCSSStyle.prototype.setMarginShorthand = function(key, val) {
  var padArray = val.split(" ");
  var margin = null;

  switch (padArray.length) {
  case 1:
    this.setStyle(key, this._getMargin(padArray[0]));
    delete this[DvtCSSStyle.MARGIN_TOP];
    delete this[DvtCSSStyle.MARGIN_BOTTOM];
    delete this[DvtCSSStyle.MARGIN_RIGHT];
    delete this[DvtCSSStyle.MARGIN_LEFT];
    break;

  case 2:
    margin = this._getMargin(padArray[0]);
    this.setStyle(DvtCSSStyle.MARGIN_TOP, margin);
    this.setStyle(DvtCSSStyle.MARGIN_BOTTOM, margin);

    margin = this._getMargin(padArray[1]);
    this.setStyle(DvtCSSStyle.MARGIN_LEFT, margin);
    this.setStyle(DvtCSSStyle.MARGIN_RIGHT, margin);
    break;

  case 3:
    this.setStyle(DvtCSSStyle.MARGIN_TOP, this._getMargin(padArray[0]));
    margin = this._getMargin(padArray[1]);
    this.setStyle(DvtCSSStyle.MARGIN_LEFT, margin);
    this.setStyle(DvtCSSStyle.MARGIN_RIGHT, margin);
    this.setStyle(DvtCSSStyle.MARGIN_BOTTOM, this._getMargin(padArray[2]));
    break;

  case 4:
    this.setStyle(DvtCSSStyle.MARGIN_TOP, this._getMargin(padArray[0]));
    this.setStyle(DvtCSSStyle.MARGIN_RIGHT, this._getMargin(padArray[1]));
    this.setStyle(DvtCSSStyle.MARGIN_BOTTOM, this._getMargin(padArray[2]));
    this.setStyle(DvtCSSStyle.MARGIN_LEFT, this._getMargin(padArray[3]));
    break;

  case 0:
  default:
    break;
  }
};

//TODO: auto size defined by browsers
DvtCSSStyle.prototype._getMargin = function(val) {
  var margin = DvtStringUtils.trim(val);
  if (DvtCSSStyle.AUTO == margin)
    return DvtCSSStyle.AUTO_MARGIN;
  else
    return this._getPercent(margin);
};



DvtCSSStyle.prototype._getPercent = function(val) {
  return DvtStringUtils.trim(val);
};


DvtCSSStyle.prototype.setBorderShorthand = function(key, val) {
  /*
   * "border" Shorthand property can specify width, style, and color
   * separated by spaces, which are applied to all 4 border sides
   * ex: "1px solid rgb(185, 185, 180)"
   */
  var borderArray = val.split(" ");
  var borderVal = null;
  var noBorder = false;

  for (var i = 0; i < borderArray.length; i++) {
    borderVal = borderArray[i];

    //rgb border color
    if (borderVal.indexOf("rgb") == 0) {
      for (var k = i + 1; k < borderArray.length; k++) {
        borderVal += borderArray[k];
        i++;
        if (borderArray[k].indexOf(")") != -1)
          break;
      }
      this.setBorderColorShorthand(DvtCSSStyle.BORDER_COLOR, borderVal);
    }

    //border color
    else if (DvtCSSStyle.isColorVal(borderVal))
      this.setBorderColorShorthand(DvtCSSStyle.BORDER_COLOR, borderVal);

    //border width
    else if (DvtCSSStyle.isBorderWidthVal(borderVal))
      this.setBorderWidthShorthand(DvtCSSStyle.BORDER_WIDTH, borderVal);

    //we don't currently handle border style, but if it's none, set width=0
    else if (val == "none")
      noBorder = true;

  }

  if (noBorder) {
    this.setBorderWidthShorthand(DvtCSSStyle.BORDER_WIDTH, "0");
  }
};


DvtCSSStyle.prototype.setBackgroundRepeat = function(key, val) {
  var nval = val.toLowerCase();
  var a = val.split(" ");

  // Bug 10080044 - buttons look broken on safari
  // in Safari button -> background-repeat: repeat no-repeat 
  if (a.length == 2) {
    // both repeat or no_repeat
    if (a[0] == a[1])
      val = a[0];
    else if (a[0] == DvtCSSStyle.REPEAT && a[1] == DvtCSSStyle.NO_REPEAT)
      val = DvtCSSStyle.REPEAT_X;
    if (a[0] == DvtCSSStyle.NO_REPEAT && a[1] == DvtCSSStyle.REPEAT)
      val = DvtCSSStyle.REPEAT_Y;
  }
  this[key] = val;
};


/**
 * set a color attribute
 * 
 * @param {string} key color attribute
 * @param {string} val is a string in color keyword or a numeric value in #AARRGGBB or #RRGGBB format
 */
DvtCSSStyle.prototype.setColorString = function(key, val) {
  var color = DvtCSSStyle._toColorVal(val);
  this[key] = color ? color : val;
};


/**
 * If the given string is a color keyword, return its color value
 * 
 * @param s string that may specify a color keyword
 * @return color value if the string is a color keyword.
 */
DvtCSSStyle._toColorVal = function(val) {

  val = DvtStringUtils.trim(val);

  // color name?
  var color = DvtCSSStyle.SpColorMap[val];
  if (color) {
    return color;
  }
  return null;
};
    
DvtCSSStyle.prototype.getStyle = function(key) {
  return this[key];
};

DvtCSSStyle.prototype.setStyle = function(key, val) {
  this[key] = val;
};

DvtCSSStyle.prototype.setColor = function(key, val) {
  this[key] = val;
}


/**
 * @private
 * @param value a number with unit
 */
DvtCSSStyle.isValueInEM = function(value) {
  return value.toLowerCase().indexOf("em") >= 0;
}

/**
 * @private
 * @param key its value is a number with unit
 * @param fontSize (string) a number with unit
 *
 */
DvtCSSStyle.prototype._resolveEMx = function(key, fontSize) {
  var value = this.getStyle(key);

  if (value && DvtCSSStyle.isValueInEM(value)) {
    // if value is in EM unit, convert it to px so value no longer in EM
    if (fontSize) {
      this.setStyle(key, 
                    String(parseFloat(value) * parseFloat(fontSize)) + "px");
      return true;
    }
    return false;
  }
  return true;
};


/**
 * @return font size if is a font size is specified and not in relative length unit(em)
 * otherwise return null
 */
DvtCSSStyle.prototype.getAbsoluteFontSize = function() {
  // get the current font size
  var fontSize = this.getFontSize();
  if (fontSize && ! DvtCSSStyle.isValueInEM(fontSize)) {
    return fontSize;
  }
  return null;
};


/**
 * @param {string} fontSize to be used in resolving em if no fontSize specified in this css style
 */
DvtCSSStyle.prototype.resolveEM = function(fontSize) {

  // try to resolved em unit with the current font size
  var myFontSize = this.getFontSize();

  if (myFontSize) {
    // FONT_SIZE value is in "em" 
    if (DvtCSSStyle.isValueInEM(myFontSize)) {
      // resolve fontSize and use this new fontSize value
      this._resolveEMx(DvtCSSStyle.FONT_SIZE, fontSize);
    }
    // FONT_SIZE value is NOT in "em", use new fontSize value
    else {
      fontSize = myFontSize;
    }
  }

  var numList = DvtCSSStyle._numericAttrsList;
  for (var i = 0; i < numList.length; i++) {
    if (! this._resolveEMx(numList[i], fontSize)) {
      return false;
    }
  }
  return true;
};


/**
 * return a copy of this object
 */
DvtCSSStyle.prototype.clone = function() {
  var css = new DvtCSSStyle();
  for (var i = 0; i < DvtCSSStyle._attrs.length; i++) {
    var key = DvtCSSStyle._attrs[i];

    if (this[key])
      css[key] = this[key];
  }
  return css;
};

/**
 * Merge the properties of the given CSSStyle into this one.
 * 
 * @param style properties to merge into this CSSStyle
 */
DvtCSSStyle.prototype.merge = function(style) {
  for (var i = 0; i < DvtCSSStyle._attrs.length; i++) {
    var key = DvtCSSStyle._attrs[i];
    if (style[key])
      this[key] = style[key];
  }
  return this;
};

/**
 * Merge the properties of the given CSSStyle under this one.
 * 
 * @param style properties to merge under this CSSStyle
 */
DvtCSSStyle.prototype.mergeUnder = function(style) {
  for (var i = 0; i < DvtCSSStyle._attrs.length; i++) {
    var key = DvtCSSStyle._attrs[i];

    if (! this[key] && style[key])
      this[key] = style[key];
  }
  return this;
};



/**
 * Convenience method for getting only styles specified in the list
 * and convert them to a string
 * 
 * @param {array} attrs an array of style properties of interest
 * @return {string} an inlineStyle in string
 */
DvtCSSStyle.prototype.toInlineStyle = function(attrs) {
  var strBuf = "";
  for (var i = 0; i < attrs.length; i++) {
    var key = attrs[i];

    if (this[key] !== undefined)
      strBuf += key + ":" + this[key] + "; ";
  }
  return strBuf;
};

DvtCSSStyle.prototype.toString = function() {
  return this.toInlineStyle(DvtCSSStyle._attrs);
};



DvtCSSStyle.prototype.getBackgroundImage = function() {
  var ret = this[DvtCSSStyle.BACKGROUND_IMAGE];

  var startx;
  var endx;
      
  //strip off the 'url(' and ')'
  if (ret) {
    startx = ret.indexOf("url(");
    endx = ret.lastIndexOf(")");
    if ((startx == 0) && (endx == (ret.length - 1))) {
      ret = ret.substring(4, endx);
    }
  }
      
  //strip off single or double quotes
  if (ret) {
    startx = ret.indexOf("'");
    endx = ret.lastIndexOf("'");
    if ((startx == 0) && (endx == (ret.length - 1))) {
      ret = ret.substring(1, endx);
    }
    else {
      startx = ret.indexOf("\"");
      endx = ret.lastIndexOf("\"");
      if ((startx == 0) && (endx == (ret.length - 1))) {
        ret = ret.substring(1, endx);
      }
    }
  }
      
  return ret;
};
  	
/**
 * Determine if the given string specifies a color value.
 * 
 * @param s string that may specify a color value
 * 
 * @return true if the string specifies a color value, false otherwise
 */
DvtCSSStyle.isColorVal = function(val) {
  val = DvtStringUtils.trim(val);

  if (val.indexOf("rgb") == 0 ||
      val.indexOf("#") == 0)
    return true;

  // color name?
  var color = DvtCSSStyle.SpColorMap[val];
  if (color) {
    return true;
  }
  return false;
};


/**
 * @private
 * #param val contain only one borderWidth value
 */
DvtCSSStyle.isBorderWidthVal = function(val) {

  var bwidth = DvtStringUtils.trim(val);
  if (DvtCSSStyle.SpWidthMap[bwidth])
    return true;

  return ! isNaN(parseFloat(bwidth));
};

// val is a string contains up to 4 rgb colors, ex:
// border-color: rgb(221, 221, 216) rgb(185, 185, 132) rgb(121, 121, 117)
DvtCSSStyle.parseBorderColorString = function(key, val) {

  var val = DvtStringUtils.trim(val);
  var cArray = [];
  while (val != null && val.length > 0) {
    val = DvtCSSStyle.parseBorderColor(val, cArray);
  }
  return cArray;
};


DvtCSSStyle.parseBorderColor = function(val, cArray) {
  val = DvtStringUtils.ltrim(val);
  var strLen = val.length;
  var endIndex = -1;
  var colorObj;

  if (! val) {
    return val;
  }
  // rgb format?
  if (val.indexOf("rgb") == 0) {
    colorObj = val;

    if (colorObj) {
      endIndex = val.indexOf(")") + 1;
    }
  }

  // color name?
  else {
    endIndex = val.indexOf(" ");
    if (endIndex == -1)
      endIndex = strLen;
    var singleColor = val.slice(0, endIndex);

    colorObj = DvtCSSStyle._toColorVal(singleColor);

    // hex color
    if (! colorObj) {
      colorObj = DvtCSSStyle.parseHexColor(singleColor);
    }
  }
      
  if (colorObj) {
    cArray.push(colorObj);
    val = val.slice(endIndex);
  }
  return val;
}

// val is a string in #AARRGGBB or #RRGGBB format
DvtCSSStyle.parseHexColor = function(s) {
  var n ;
  var colorObj;
  if (s && s.length > 0) {
    var bHasAlpha  = (s.length > 7) ;
    n = Number("0x" + s.substring(1)) ;
    if (isNaN(n)) {
      n = 0 ;                   // assume black if we didn't get a valid numeric string
    }
    if (bHasAlpha) {
      var x = "#"+s.substring(3);
      colorObj = x;
    }
    else {
      colorObj = s;
    }
  }
  return colorObj;
}
    


// get padding-top, padding-right, padding-bottom and padding-left
// get border-top-width, border-right-width, border-bottom-width and border-left=width
// get margin-top, margin-right, margin-bottom and margin-left
//TODO: percent
DvtCSSStyle.prototype._getSideWidth = function(key, shortKey) {
  var side = this.getStyle(key);
  if (! side) {
    side = this.getStyle(shortKey);
  }
  return DvtCSSStyle.toInteger(side);
}

DvtCSSStyle.createDefaultTextStyle = function() {
  var style = new DvtCSSStyle();

  // Default to Tomoha font family
  style.setStyle(DvtCSSStyle.FONT_FAMILY, DvtCSSStyle.DEFAULT_FONT_FAMILY);

  // Default to 11px
  style.setStyle(DvtCSSStyle.FONT_SIZE, DvtCSSStyle.DEFAULT_FONT_SIZE + "px");

  // Default to black
  style.setStyle(DvtCSSStyle.COLOR, "black");

  return style;
}

DvtCSSStyle.prototype.getFontSize = function() {
  return this.getStyle(DvtCSSStyle.FONT_SIZE);
}

// Returns a CSSStyle object as a merge of the array
DvtCSSStyle.mergeStyles = function(styleArray) {
    var style = new DvtCSSStyle();
    if (styleArray) {
        for (var i=0; i<styleArray.length;i++) {
            style.merge(styleArray[i]);
        }
    }
    return style;    
}
/**
 * Context Menu Item property bag.
 * @param {DvtContextMenuSelectEvent} event  The event to fire in response to selection of this menu item.
 * @param {string} text The text of the context menu item.
 * @param {boolean} disabled True if this context menu item is disabled.
 * @param {boolean} sepBefore True if a separator should appear before this menu item.
 * @class
 * @constructor
 */
var DvtContextMenuItem = function(event, text, disabled, sepBefore) {
  this._event = event;
  this._text = text;
  this._disabled = disabled;
  this._sepBefore = sepBefore;
}

DvtObj.createSubclass(DvtContextMenuItem, DvtObj, "DvtContextMenuItem");

/**
 * Returns the event to fire in response to selection of this menu item.
 * @return {DvtContextMenuSelectEvent} The event to fire in response to selection of this menu item.
 */
DvtContextMenuItem.prototype.getEvent = function() {
  return this._event;
}

/**
 * Returns the text of the context menu item.
 * @return {string} The text of the context menu item.
 */
DvtContextMenuItem.prototype.getText = function() {
  return this._text;
}

/**
 * Returns true if this context menu item is disabled.
 * @return {string} True if this context menu item is disabled.
 */
DvtContextMenuItem.prototype.isDisabled = function() {
  return this._disabled;
}

/**
 * Returns true if a separator should appear before this menu item.
 * @return {string} True if a separator should appear before this menu item.
 */
DvtContextMenuItem.prototype.hasSeparatorBefore = function() {
  return this._sepBefore;
}
/**
 * ShowPopupBehavior property bag.
 * @param {string} popupId The id of the popup that will be fired.
 * @param {string} triggerType The interaction type that triggers the popup.
 * @param {string} alignId The id of the object that the popup will be aligned to.
 * @param {string} align  The alignment position for the popup.
 * @class
 * @constructor
 */
var DvtShowPopupBehavior = function(popupId, triggerType, alignId, align) {
  this._popupId = popupId;
  this._triggerType = triggerType;
  this._alignId = alignId;
  this._align = align;
}

DvtObj.createSubclass(DvtShowPopupBehavior, DvtObj, "DvtShowPopupBehavior");

DvtShowPopupBehavior.TRIGGER_TYPE_ACTION = "action";
DvtShowPopupBehavior.TRIGGER_TYPE_CLICK = "click";
DvtShowPopupBehavior.TRIGGER_TYPE_CONTEXT_MENU = "contextMenu";
DvtShowPopupBehavior.TRIGGER_TYPE_MOUSE_HOVER = "mouseHover";

DvtShowPopupBehavior.ALIGN_AFTER_START = "afterStart";
DvtShowPopupBehavior.ALIGN_AFTER_END = "afterEnd";
DvtShowPopupBehavior.ALIGN_BEFORE_START = "beforeStart";
DvtShowPopupBehavior.ALIGN_BEFORE_END = "beforeEnd";
DvtShowPopupBehavior.ALIGN_END_AFTER = "endAfter";
DvtShowPopupBehavior.ALIGN_END_BEFORE = "endBefore";
DvtShowPopupBehavior.ALIGN_START_AFTER = "startAfter";
DvtShowPopupBehavior.ALIGN_START_BEFORE = "startBefore";
DvtShowPopupBehavior.ALIGN_OVERLAP = "overlap";

/**
 * Creates and returns a new instance of DvtShowPopupBehavior with properties parsed from
 * the specified DvtXmlNode.
 * @param {DvtXmlNode} xmlNode The xml node containing properties for the new instance.
 * @return {DvtShowPopupBehavior}
 */
DvtShowPopupBehavior.newInstance = function(xmlNode) {
  var popupId = xmlNode.getAttribute("popupId");
  var triggerType = xmlNode.getAttribute("triggerType");
  var alignId = xmlNode.getAttribute("alignId");
  var align = xmlNode.getAttribute("align");
  return new DvtShowPopupBehavior(popupId, triggerType, alignId, align);
}

/**
 * Returns the id of the popup that will be fired by this instance.
 * @return {string} The id of the popup that will be fired.
 */
DvtShowPopupBehavior.prototype.getPopupId = function() {
  return this._popupId;
}

/**
 * Returns the interaction type that triggers the popup.
 * @return {string} The the interaction type that triggers the popup.
 */
DvtShowPopupBehavior.prototype.getTriggerType = function() {
  return this._triggerType;
}

/**
 * Returns the id of the object that the popup will be aligned to.
 * @return {string} The id of the object that the popup will be aligned to.
 */
DvtShowPopupBehavior.prototype.getAlignId = function() {
  return this._alignId;
}

/**
 * Returns the alignment position for the popup.
 * @return {string} The alignment position for the popup.
 */
DvtShowPopupBehavior.prototype.getAlign = function() {
  return this._align;
}
/*--------------------------------------------------------------------*/
/*   DvtMagnifyLens              Magnify lens component                 */
/*--------------------------------------------------------------------*/
/**
  *  Magnify lens component.
  *  @extends DvtContainer
  *  @class DvtMagnifyLens  Creates a magnify lens component.
  *  @constructor  
  *  @param {DvtContext} context The context object
  */
var   DvtMagnifyLens = function(context)
{
    this.Init(context);
}  

DvtObj.createSubclass(DvtMagnifyLens, DvtContainer, "DvtMagnifyLens");

DvtMagnifyLens.DEFAULT_BACKGROUND_COLOR = "#ffffff";

DvtMagnifyLens.prototype.Init = function(context) {

   this._context = context;
   this._lensBorderWidth = 2;
   this._backgroundFill = new DvtSolidFill(DvtMagnifyLens.DEFAULT_BACKGROUND_COLOR, 1);
   this._rimFillColor = "black";
   if (! this.getImpl()) {
     this.setImpl(context.getImplFactory().newContainer("maglens")) ;
   }
   DvtMagnifyLens.superclass.Init.call(this, context) ;

   this._zoomFactor = 3;
   this._zoomSize = 91;
   this._shiftValue = 0.5;
   this.setMouseEnabled(false);
   
   this.setTranslateX(this._lensBorderWidth);
   this.setTranslateY(this._lensBorderWidth);
   this._dirty = true;

}

DvtMagnifyLens.prototype.isDirty = function() 
{    
    return this._dirty;
}

DvtMagnifyLens.prototype.setDirty = function(dirty) 
{
    this._dirty = dirty;
}

DvtMagnifyLens.prototype.setZoomFactor = function(zoomFactor) 
{
    this._zoomFactor = zoomFactor;
}

DvtMagnifyLens.prototype.setSize = function(size) 
{
    this._zoomSize = size;
}

DvtMagnifyLens.prototype.setBackgroundFill = function(fill) 
{
    this._backgroundFill = fill;
}

DvtMagnifyLens.prototype.setRimFillColor = function(color) 
{
    this._rimFillColor = color;
}

DvtMagnifyLens.prototype.getSize = function() 
{
    return this._zoomSize + this._lensBorderWidth*2;
}

DvtMagnifyLens.prototype.initialize = function() 
{
   // TODO: in the future initialize all objects in the constructor, and change properties here
   if (this._initialized) {
        return;
   }
   this._initialized = true;

   var zoomSize = this._zoomSize;
   var context = this._context;
   
   var clipContainer = new DvtContainer(context, "clipContainer");
   var clipPath = new DvtClipPath("thisclippath");
   
   var clipObj  = {} ;
   clipObj.type = DvtClipPath.ELLIPSE ;
   clipObj.cx    = zoomSize/2 ;
   clipObj.cy    = zoomSize/2 ;
   clipObj.rx    = zoomSize/2 ;
   clipObj.ry    = zoomSize/2 ;

   // TODO: add non-private methods to clip path to handle circles
   clipPath._addRegion(clipObj);
   
   this.getImpl().addClipPath(clipPath, context);
   
   this._magClipPath = clipPath;
   this._magClipContainer = clipContainer;
   
   this._magClipContainer.setClipPath(this._magClipPath);

   var zoomBack = new DvtCircle(context, zoomSize/2, zoomSize/2, zoomSize/2 - this._lensBorderWidth/2);
   zoomBack.setMouseEnabled(false);
   //zoomBack.setStroke(new DvtSolidStroke(this._borderColor, 1, this._lensBorderWidth));
   clipContainer.addChild(zoomBack);
   //var fakeLine = new DvtRect(context, zoomSize/2 - 2, 0, 4, zoomSize);
   //fakeLine.setFill(this._backgroundFill);
   //fakeLine.setMouseEnabled(false);
   //this._fakeLine = fakeLine;
   //clipContainer.addChild(fakeLine);

   clipContainer.setAlpha(1);
   this._view = clipContainer;
   this.addChild(clipContainer);

   var circleBack = new DvtCircle(this.getContext(), zoomSize/2, zoomSize/2, zoomSize/2 + this._lensBorderWidth);
   circleBack.setFill(new DvtSolidFill(this._rimFillColor, 1));
   //circleBack.setFill(new DvtLinearGradientFill(45, [this._rimFillColor, '#CFCFCF'], [1, 0.75])); 
   circleBack.setMouseEnabled(false);
   this.addChildAt(circleBack, 0);

}

DvtMagnifyLens.prototype.UpdatePosition = function(x, y) 
{
    var zoomSize = this._zoomSize;
    var content = this._content;
    if (content) {
        var scaleFactor = this._zoomFactor;
        content.setTranslateX(-(x)*scaleFactor + zoomSize/2);
        content.setTranslateY(-y*scaleFactor + zoomSize*this._shiftValue);
    }
}

DvtMagnifyLens.prototype.getRootDisplayable = function() 
{
    return this;
}

DvtMagnifyLens.prototype.GetMagnifyContent = function(container) 
{
   return container.createCopy();
}

DvtMagnifyLens.prototype.getDisplayWidth = function() {
   return this._zoomSize + 2*this._lensBorderWidth;
}

DvtMagnifyLens.prototype.getDisplayHeight = function() {
   return this._zoomSize + 2*this._lensBorderWidth;
}

DvtMagnifyLens.prototype.clearContent = function() {
   var clonedContainer = this._content;
   if (clonedContainer) {
        this._view.removeChild(clonedContainer);
   }
}

DvtMagnifyLens.prototype.updateMagnifyContent = function(container) 
{
   this.clearContent();
   var clonedContainer = this.GetMagnifyContent(container);
   clonedContainer.setScaleX( this._zoomFactor);
   clonedContainer.setScaleY( this._zoomFactor);
   this._content = clonedContainer;

   var originalSize = container.getDimensions();
   var fixedBack = new DvtRect(this.getContext(), originalSize.x, originalSize.y, originalSize.w, originalSize.h);
   fixedBack.setFill(new DvtSolidFill("white", 1));
   clonedContainer.addChildAt(fixedBack, 0);
   fixedBack.setMouseEnabled(false);

   this._view.addChildAt(clonedContainer, 0);
   this._view.setMouseEnabled(false);
   clonedContainer.setMouseEnabled(false);

}
/**
 * Drag recognizer
 * @class DvtDragRecognizer
 * @constructor
 */
var DvtDragRecognizer = function () {};

DvtObj.createSubclass(DvtDragRecognizer, DvtObj, "DvtDragRecognizer");

/**
 * Notifies the component that a drag may have started.
 */
DvtDragRecognizer.prototype.prepDrag = function () {
  // subclasses should override
}

/**
 * Notifies the component that a drag has been aborted.
 */
DvtDragRecognizer.prototype.abortPrep = function () {
  // subclasses should override
}

/**
 * Returns true if the component allows drag. This function gives the peer the
 * chance to prevent a drag.  All other conditions for a drag
 * must be satisfied even if the peer returns true.
 */
DvtDragRecognizer.prototype.recognizeDrag = function () {
  return true; // subclasses should override
}
/**
 * Drag source event handler.
 * @param {DvtContext} context
 * @class DvtDragSource
 * @constructor
 */
var DvtDragSource = function (context) {
  this.Init(context);
};

DvtObj.createSubclass(DvtDragSource, DvtObj, "DvtDragSource");

// Margin to add to drag feedback bounds to minimize clipping
DvtDragSource.DRAG_FEEDBACK_MARGIN = 2;

/**
 * @param {DvtContainer} container
 * @param {DvtContext} context
 */
DvtDragSource.prototype.Init = function(context) {
    this._context = context;
    
    // current draggable object under the mouse pointer
    this._dragCandidate = null;
    
    // object being dragged
    this._dragObj = null;
    this._dragCoords = null;
} ;

/**
 * Returns the current drag candidate object.
 */
DvtDragSource.prototype.getDragCandidate = function () {
  return this._dragCandidate;
}

/**
 * Sets the specified object as the current drag candidate, if it supports the DvtDraggable interface.
 * @param {object} obj 
 */
DvtDragSource.prototype.setDragCandidate = function (obj) {
  // a DnD candidate object must support all DvtDraggable methods
  if (obj && obj.isDragAvailable && obj.getDragTransferable)
    this._dragCandidate = obj;
  else
    this._dragCandidate = null;
}

/**
 * If there are any drag candidate, returns the client id of the drag component.
 * Otherwise returns null.
 */
DvtDragSource.prototype.isDragAvailable = function (clientIds) {
  if (this._dragCandidate != null) {
    return this._dragCandidate.isDragAvailable(clientIds);
  }
  return null;
};


/**
 * If there are a drag candidate, return the dragTransferable object.
 */
DvtDragSource.prototype.getDragTransferable = function (mouseX, mouseY) {
  // if there's anything to drag
  if (this._dragCandidate) {
    // store the dragObj and current mouse coords
    this._dragObj = this._dragCandidate;
    this._dragCoords = {
      x : mouseX, y : mouseY
    };

    return this._dragCandidate.getDragTransferable(mouseX, mouseY);
  }
  return null;
};

/**
 * Returns the feedback for the drag operation.
 */
DvtDragSource.prototype.getDragOverFeedback = function (mouseX, mouseY) {
  // Hide the tooltip, since this is the last hook before the drag feedback is created
  this._context.getTooltipManager().hideTooltip();

  // Return the drag feedback
  var dragObj = this.getDragObject();
  if (dragObj && dragObj.getDragFeedback)
    return dragObj.getDragFeedback(mouseX, mouseY);
  else 
    return null;
}

/**
 * Returns component specific context for the drag.
 */
DvtDragSource.prototype.getDragContext = function (mouseX, mouseY) {
  if (this._dragObj && this._dragObj.getDragContext) {
    return this._dragObj.getDragContext(mouseX, mouseY);
  }
  return null;
}

/**
 * Returns the object currently being dragged.
 */
DvtDragSource.prototype.getDragObject = function() {
    return this._dragObj;
}

/**
 * Returns the coordinates where the current drag was initiated.
 */
DvtDragSource.prototype.getDragCoords = function () {
  return this._dragCoords;
}

/**
 * Return the offset to use for the drag feedback.
 */
DvtDragSource.prototype.getDragOffset = function (mouseX, mouseY) {
  var offset = null;
  var feedback = this.getDragOverFeedback(mouseX, mouseY);
  if(feedback) {
    var bounds = DvtDnDUtils.getDragFeedbackBounds(feedback, this._context.getStage());
    if (bounds) {
      offset = {};
      offset.x = mouseX - bounds.x;
      offset.y = mouseY - bounds.y;
      offset.x += DvtDragSource.DRAG_FEEDBACK_MARGIN;
      offset.y += DvtDragSource.DRAG_FEEDBACK_MARGIN;
    }
  }
  return offset;
}

/**
 * Returns the offset from the mouse pointer where the drag is considered to be located.
 * @param {number} xOffset A suggested offset, usually the center of the drag feedback.
 * @param {number} yOffset A suggested offset, usually the center of the drag feedback.
 * @return {object}
 */
DvtDragSource.prototype.getPointerOffset = function (xOffset, yOffset) {
  // Default implementation does not apply an offset, mouse position is used instead
  return {x: 0, y: 0};
}

/**
 * Called when a drag is started.
 */
DvtDragSource.prototype.initiateDrag = function () {
  // On touch devices, when a drag is initiated, immediately cancel any touch and hold
  if(DvtAgent.getAgent().isTouchDevice() && this._context) 
    this._context.getTouchManager().cancelTouchHold();
}

/**
 * Clean up after the drag is completed.
 */
DvtDragSource.prototype.dragDropEnd = function () {
  this._dragCandidate = null;
  this._dragObj = null;
  this._dragCoords = null;
}
/**
 * Drop target event handler.
 * @class DvtDropTarget
 * @constructor
 */
var DvtDropTarget = function() {};

DvtObj.createSubclass(DvtDropTarget, DvtObj, "DvtDropTarget");

/**
 * If a drop is possible at these mouse coordinates, returns the client id
 * of the drop component. Returns null if drop is not possible.
 */
DvtDropTarget.prototype.acceptDrag = function(mouseX, mouseY, clientIds) {
  return null; // subclasses should override
}

/**
 * Paints drop site feedback as a drag enters the drop site.
 */
DvtDropTarget.prototype.dragEnter = function() {
  // subclasses should override
}

/**
 * Cleans up drop site feedback as a drag exits the drop site.
 */
DvtDropTarget.prototype.dragExit = function() {
  // subclasses should override
}

/**
 * Returns the object representing the drop site. This method is called when a valid
 * drop is performed.
 */
DvtDropTarget.prototype.getDropSite = function(mouseX, mouseY) {
  return null; // subclasses should override
}
/*
 * DvtButton
 */
var DvtButton = function (context, upState, overState, downState, id) {
  this.Init(context, upState, overState, downState, id);
};

/*
 * make DvtButton a subclass of DvtContainer
 */
DvtObj.createSubclass(DvtButton, DvtContainer, "DvtButton");

DvtButton.STATE_ENABLED = 0;
DvtButton.STATE_OVER = 1;
DvtButton.STATE_DOWN = 2;

DvtButton.NO_EVENT_LISTENERS = true; //dont register any event listeners


/*--------------------------------------------------------------------*/
/*  Init()                                                            */
/*--------------------------------------------------------------------*/
DvtButton.prototype.Init = function (context, upState, overState, downState, id) {
  DvtButton.superclass.Init.call(this, context, id);

  this.setUpState(upState);
  this.setOverState(overState);
  this.setDownState(downState);

  // enable mouse events for upState
  this.setEnabled(true);
  this._drawUpState();

};



DvtButton.prototype.isEnabled = function () {
  return this._enabled;
};

DvtButton.prototype.setEnabled = function (enabled) {
  this._enabled = enabled;

  if (enabled) {
    this.addEventListener("mouseover", this._mouseOverHandler, false, this);
    this.addEventListener("mouseout", this._mouseOutHandler, false, this);
    this.addEventListener("mousedown", this._mouseDownHandler, false, this);
    this.addEventListener("mouseup", this._mouseUpHandler, false, this);
  }

  //TODO: show disable style
  else {
    this.removeEventListener("mouseover", this._mouseOverHandler, false, this);
    this.removeEventListener("mouseout", this._mouseOutHandler, false, this);
    this.removeEventListener("mousedown", this._mouseDownHandler, false, this);
    this.removeEventListener("mouseup", this._mouseUpHandler, false, this);
  }
};

// Mouse event handling
DvtButton.prototype._mouseOverHandler = function (event) {
  this._logEvent(event);
  this._drawOverState();
};

DvtButton.prototype._mouseOutHandler = function (event) {
  this._logEvent(event);
  this._drawUpState();
};

DvtButton.prototype._mouseDownHandler = function (event) {
  this._logEvent(event);
  this._drawDownState();
};

DvtButton.prototype._mouseUpHandler = function (event) {
  this._logEvent(event);
  this._drawOverState();
};

DvtButton.prototype._drawUpState = function () {
  this._enableButton(this.upState, true);
  this._enableButton(this.downState, false);
  this._enableButton(this.overState, false);
};

DvtButton.prototype._drawOverState = function () {
  this._enableButton(this.upState, false);
  this._enableButton(this.downState, false);
  this._enableButton(this.overState, true);
};

DvtButton.prototype._drawDownState = function () {
  this._enableButton(this.upState, false);
  this._enableButton(this.downState, true);
  this._enableButton(this.overState, false);
};

DvtButton.prototype._enableButton = function (button, enabled) {
  //   this._enableMouseEvents(button, enabled);
  button.setAlpha(enabled ? 1 : 0);

  //image button does not work when swapping different image states
  //   button.setVisible(enabled);
};

DvtButton.prototype._enableMouseEvents = function (container, enabled) {
  if (container.setMouseEnabled) {
    container.setMouseEnabled(enabled);
  }
  var child = container.firstChild;

  //loop over all childs
  while (child != null) {
    this._enableMouseEvents(child, enabled);
    child = child.nextSibling;
  }
};

DvtButton.prototype.setUpState = function (upState) {
  if (this.upState && this.upstate === upState) {
    return;
  }

  if (this.upState) {
    this.removeChild(this.upState);
  }

  if (upState) {
    this.addChild(upState);
  }
  this.upState = upState;
};

DvtButton.prototype.setDownState = function (downState) {
  if (this.downState && this.downstate === downState) {
    return;
  }

  if (this.downState) {
    this.removeChild(this.downState);
  }

  if (downState) {
    this.addChild(downState);
  }
  this.downState = downState;
};

DvtButton.prototype.setOverState = function (overState) {
  if (this.overState && this.overstate === overState) {
    return;
  }

  if (this.overState) {
    this.removeChild(this.overState);
  }

  if (overState) {
    this.addChild(overState);
  }
  this.overState = overState;
};

DvtButton.prototype._logEvent = function (event) {
  // logEvent(event, "Button");
};





/**
 * A logical object for a set of displayables.
 * @interface
 */
var DvtLogicalObject = function() {};

/**
 * Returns the array of DvtDisplayables corresponding to this object.
 * @return {array}
 */
DvtLogicalObject.prototype.getDisplayables = function() {};
/**
 * An object that displays tooltips.
 * @interface
 */
var DvtTooltipSource = function() {};

/**
 * Returns the tooltip text for this object.
 * @param {DvtDisplayable} target The displayable that was the target of the event.
 * @return {string} The tooltip text for this object.
 */
DvtTooltipSource.prototype.getTooltip = function(target, x, y) {};

/**
 * Returns the datatip text for this object.
 * @param {DvtDisplayable} target The displayable that was the target of the event.
 * @return {string} The datatip text for this object.
 */
DvtTooltipSource.prototype.getDatatip = function(target, x, y) {};

/**
 * Returns the border color of the datatip for this object.
 * @return {string} The datatip border color.
 */
DvtTooltipSource.prototype.getDatatipColor = function() {};
/**
 * An object that can be selected.
 * @interface
 */
var DvtSelectable = function() {};

/**
 * Returns true if this object is selectable.
 * @return {boolean} true if this object is selectable.
 */
DvtSelectable.prototype.isSelectable = function() {};

/**
 * Returns true if this object is selected.
 * @return {boolean} true if this object is selected.
 */
DvtSelectable.prototype.isSelected = function() {};

/**
 * Specifies whether this object is selected.
 * @param {boolean} selected true if this object is selected.
 * @protected
 */
DvtSelectable.prototype.setSelected = function(selected) {};

/**
 * Displays the hover effect.
 */
DvtSelectable.prototype.showHoverEffect = function() {};

/**
 * Hides the hover effect.
 */
DvtSelectable.prototype.hideHoverEffect = function() {};
/**
 * An object that can receive keyboard focus, and thus can be navigated to via the keyboard
 * @interface
 */
var DvtKeyboardNavigable = function() {};


/**
 * Returns the next item to receive keyboard focus
 * @param {DvtBaseEvent} event
 * @return {Object} The next item to get keyboard focus
 */
DvtKeyboardNavigable.prototype.getNextNavigable = function(event) {};

/**
 * Returns the bounding box for this navigable item
 * @return {DvtRectangle}
 */
DvtKeyboardNavigable.prototype.getKeyboardBoundingBox = function() {};

/**
 * Show a visual effect to indicate if this DvtKeyboardNavigable has keyboard focus
 */
DvtKeyboardNavigable.prototype.showKeyboardFocusEffect = function() {};

/**
 * Hide the visual effect to indicate if this DvtKeyboardNavigable has keyboard focus
 */
DvtKeyboardNavigable.prototype.hideKeyboardFocusEffect = function() {};
/**
 * An object that can belongs to a category.  
 * @interface
 */
var DvtCategoricalObject = function() {};

/**
 * Returns an array containing all categories to which this object belongs.
 * @return {array} The array of categories.
 */
DvtCategoricalObject.prototype.getCategories = function() {};
/**
 * An object that displays context menus.
 * @interface
 */
var DvtContextMenuSource = function() {};

/**
 * Returns the id of the specific context menu to display for the object.
 * @return {object} The menu id to pass into the context menu handler.
 */
DvtContextMenuSource.prototype.getContextMenuId = function() {};

/**
 * Returns the x,y coordinate of the upper left hand corner for the context menu, when the context menu
 * is triggered by a keyboard shortcut
 * Optional method to implement.
 * @return {DvtPoint} 
 */
DvtContextMenuSource.prototype.getContextMenuLocation = function() {};
/**
 * An object that displays popups.
 * @interface
 */
var DvtPopupSource = function() {};

/**
 * Returns the server side id for this object, which is used to set context on
 * the server.
 * @return {string} The server side id for this object.
 */
DvtPopupSource.prototype.getId = function() {};

/**
 * Returns the array of showPopupBehaviors for the object.
 * @return {array} The array of applicable DvtShowPopupBehaviors
 */
DvtPopupSource.prototype.getShowPopupBehaviors = function() {};
/**
 * For changing z-order of an object
 * @interface
 */
var DvtZOrderManager = function() {};

/**
 * Bring the object to the front of the z-order.
 *
 * @param {DvtDisplayable}  displayable  object to push back in the z-order
 */
DvtZOrderManager.prototype.bringToFrontOfSelection = function(displayable) {};

/**
 * Push the object to the back of the selected objects in the z-order.
 *
 * @param {DvtDisplayable}  displayable  object to push back in the z-order
 */
DvtZOrderManager.prototype.pushToBackOfSelection = function(displayable) {};

/**
 * Set the number of objects that must be kept in front of any selected
 * objects in the z-order.  
 * 
 * @param {number} num  number of objects to keep in front of selected objects
 */
DvtZOrderManager.prototype.setNumFrontObjs = function(num) {};
/**
 * An object that contains children that can be accessed by test automation 
 * @interface
 */
var DvtAutomationContainer = function() {};


/**
 * Dispatches an event triggered by test automation on the given subId
 * @param {Number} subId
 * @param {String} eventType
 * @param {String} params Parameters to initialize the event 
 */
DvtAutomationContainer.prototype.dispatchTestEvent = function(subId, eventType, params) {}; 


/**
 * Simple logical object for tooltip support.
 * @param {string} tooltip The tooltip to display.
 * @param {string} datatip The datatip to display.
 * @param {string} datatipColor The border color of the datatip.
 * @class
 * @constructor
 * @implements {DvtTooltipSource}
 */
var DvtSimpleObjPeer = function(tooltip, datatip, datatipColor) {
  this.Init(tooltip, datatip, datatipColor);
}

/**
 * @param {string} tooltip The tooltip to display.
 * @param {string} datatip The datatip to display.
 * @param {string} datatipColor The border color of the datatip.
 */
DvtSimpleObjPeer.prototype.Init = function(tooltip, datatip, datatipColor) {
  this._tooltip = tooltip;
  this._datatip = datatip;
  this._datatipColor = datatipColor;
}

/**
 * Specifies the tooltip for this object.
 * @param {string} tooltip
 */
DvtSimpleObjPeer.prototype.setTooltip = function(tooltip) {
  this._tooltip = tooltip;
}

/**
 * Specifies the datatip for this object.
 * @param {string} datatip
 */
DvtSimpleObjPeer.prototype.setDatatip = function(datatip) {
  this._datatip = datatip;
}

/**
 * Specifies the datatip color for this object.
 * @param {string} datatipColor
 */
DvtSimpleObjPeer.prototype.setDatatipColor = function(datatipColor) {
  this._datatipColor = datatipColor;
}

//---------------------------------------------------------------------//
// Tooltip Support: DvtTooltipSource impl                              //
//---------------------------------------------------------------------//

/**
 * @override
 */
DvtSimpleObjPeer.prototype.getTooltip = function(target) {
  return this._tooltip;
};

/**
 * @override
 */
DvtSimpleObjPeer.prototype.getDatatip = function(target) {
  return this._datatip;
};

/**
 * @override
 */
DvtSimpleObjPeer.prototype.getDatatipColor = function(target) {
  return this._datatipColor;
};
/**
 * Resource bundle base class.
 * @class
 * @constructor
 * @extends {DvtObj}
 */
var DvtBundle = function() {}

DvtObj.createSubclass(DvtBundle, DvtObj, "DvtBundle");

/**
 * Substitutes the replacement objects into the specified pattern.
 * @param {string} pattern The pattern string with placeholders.
 * @param {array} replacements The array of replacement strings.
 * @return {string} The resulting string.
 */
DvtBundle.format = function(pattern, replacements) {
  return pattern.replace(/\{(\d+)\}/g, function() {return replacements[arguments[1]];});
}

/**
 * Returns the translation for the specified string.  If an array of replacement
 * strings is provided, these strings will be substituted into the translated string.
 * @param {string} str The untranslated string.
 * @param {replacements} replacements The array of replacement strings.
 * @return {string} The translated string.
 */
DvtBundle.prototype.getTranslatedString = function(str, replacements) {
  // Translate the string
  var ret = str; // TODO Implement Resource Bundles
  
  // Substitute the replacements if provided
  if(replacements !== null && replacements !== undefined) {
    if(replacements instanceof Array)
      ret = DvtBundle.format(ret, replacements);
    else // Wrap a single object for convenience
      ret = DvtBundle.format(ret, [replacements]);
  }
    
  return ret; 
}

/**
 * Returns the string with replacements 
 * This will not first translate the string if key is found in bundle
 * @param {string} str The untranslated string.
 * @param {replacements} replacements The array of replacement strings.
 * @param {key} the key in the bundle
 * @return {string} The translated string.
 */
DvtBundle.prototype.getRBString = function(str, replacements, key) {
  var ret;
  if (typeof DvtChartBundle_RB !== "undefined" && key in DvtChartBundle_RB) {
    ret = DvtChartBundle_RB[key]; 
    // Substitute the replacements if provided
    if(replacements !== null && replacements !== undefined) {
        if(replacements instanceof Array)
        ret = DvtBundle.format(ret, replacements);
        else // Wrap a single object for convenience
        ret = DvtBundle.format(ret, [replacements]);
    }
    
    return ret; 
  } else {
    // If no bundle found, we fall back to default
    ret = this.getTranslatedString(str, replacements);
    return ret;
  }
  
}

/**
 * Interactivity manager for context menu support.
 * @param {DvtContext} context The platform specific context object.
 * @class DvtContextMenuHandler
 * @constructor
 */
var DvtContextMenuHandler = function(context) {
  this._context = context;
  this._xmlNodes = new Array();
  // Create the impl object
  this._impl = context.getImplFactory().newContextMenuHandler();
  this._impl.setObj(this);
};

DvtObj.createSubclass(DvtContextMenuHandler, DvtObj, "DvtContextMenuHandler");

DvtContextMenuHandler.TYPE_BODY_CONTEXT_MENU = "bodyContextMenu";
DvtContextMenuHandler.TYPE_CONTEXT_MENU = "contextMenu";
DvtContextMenuHandler.TYPE_MULTI_SELECT_CONTEXT_MENU = "multiSelectContextMenu";

DvtContextMenuHandler._ATTR_MENU_CONTAINER_TYPE = "t";
DvtContextMenuHandler._ATTR_MENU_CONTAINER_POPUP_ID = "id";
DvtContextMenuHandler._ATTR_MENU_ITEMS = "i";
// Menu Item Attrs
DvtContextMenuHandler._ATTR_ITEM_TEXT = "t";
DvtContextMenuHandler._ATTR_ITEM_DISABLED = "di";
DvtContextMenuHandler._ATTR_ITEM_SEP_BEFORE = "sb";
// CommandMenuItem Attrs
DvtContextMenuHandler._ATTR_ITEM_CLIENT_ID = "id";
// GoMenuItem Attrs
DvtContextMenuHandler._ATTR_ITEM_DESTINATION = "d";
DvtContextMenuHandler._ATTR_ITEM_TARGET_FRAME = "tf";

/**
 * Adds the specified context menu definition to this handler.
 * @param {DvtXmlNode} xmlNode The xml node defining the context menu.
 */
DvtContextMenuHandler.prototype.add = function(xmlNode) {
  this._xmlNodes.push(xmlNode);  
}

/**
 * Displays the context menu with the specified type and id.  Depending on the rendering context,
 * a context menu will either be shown immediately, or a contextMenuEvent will be returned.  If
 * a contextMenuEvent is returned, it should be dispatched through the event callback mechanism.
 * @param {object} event The event that is triggering the context menu.
 * @param {string} menuType The type of context menu being requested, such as bodyContextMenu.
 * @param {string} menuId The id of the specific menu being requested.
 * @return {DvtContextMenuEvent} A context menu event to dispatch or null, depending on the rendering context.
 */
DvtContextMenuHandler.prototype.show = function(event, menuType, menuId) {
  return this._impl.getMenuEvent(this._xmlNodes, event, menuType, menuId);
}

DvtContextMenuHandler.prototype.prepareMenuItems = function(event, menuType, menuId) {
  this._impl.prepareMenuItems(event, menuType, menuId);
}

/**
 * Returns the array of menu items for the specified menu type and menu id.
 * @param {string} menuType The type of context menu being requested, such as bodyContextMenu.
 * @param {string} menuId The id of the specific menu being requested.
 * @return {array} The array of DvtContextMenuItems.
 */
DvtContextMenuHandler.prototype.getMenuItems = function(menuType, menuId) {
  if (!menuId)
    menuId = 0;
  if (menuType != DvtContextMenuHandler.TYPE_CONTEXT_MENU) {
    menuId = 0;
  }
  // Look through all context menu definitions for the right context menu to show
  for(var i=0; i<this._xmlNodes.length; i++) {
    var xmlNode = this._xmlNodes[i];
    if(menuType == xmlNode.getAttribute(DvtContextMenuHandler._ATTR_MENU_CONTAINER_TYPE)) {
      if(menuId != null && menuId >= 0) {
        // menuNode is the menu definition that we are looking for
        var childNodes = xmlNode.getChildNodes();
        if(childNodes && childNodes.length > menuId) {
          var menuNode = childNodes[menuId];
          // Parse the list of items and return them
          var itemsStr = menuNode.getAttribute(DvtContextMenuHandler._ATTR_MENU_ITEMS);
          if(itemsStr) {
            // itemsContainer is the xml node containing all menu item definitions
            var itemsContainer = childNodes[childNodes.length-1];
            
            // menuItemNodes is the array of all menu items
            var menuItemNodes = itemsContainer.getChildNodes();
            
            // targetIds is the array of menu items to be added into this menu
            var targetIds = itemsStr.split(",");
            
            // Gather all target menu items and return them
            var targetMenuItems = new Array();
            for(var j=0; j<targetIds.length; j++) {
              var menuItemXmlNode = menuItemNodes[targetIds[j]];
              
              // Parse the display attributes
              var text = menuItemXmlNode.getAttribute(DvtContextMenuHandler._ATTR_ITEM_TEXT);
              var disabled = menuItemXmlNode.getAttribute(DvtContextMenuHandler._ATTR_ITEM_DISABLED);
              var sepBefore = menuItemXmlNode.getAttribute(DvtContextMenuHandler._ATTR_ITEM_SEP_BEFORE);
              
              // Create the event that would be fired on select
              var clientId = menuItemXmlNode.getAttribute(DvtContextMenuHandler._ATTR_ITEM_CLIENT_ID);
              var destination = menuItemXmlNode.getAttribute(DvtContextMenuHandler._ATTR_ITEM_DESTINATION);
              var targetFrame = menuItemXmlNode.getAttribute(DvtContextMenuHandler._ATTR_ITEM_TARGET_FRAME);
              var event = new DvtContextMenuSelectEvent(menuType, clientId, destination, targetFrame);
              
              // Add the menu item
              targetMenuItems.push(new DvtContextMenuItem(event, text, disabled, sepBefore));
            }
            
            return targetMenuItems;
          }
        }
      }
    }
  }
  return null;
}

DvtContextMenuHandler.prototype.getContext = function() {
  return this._context;
}
/**
 * Interactivity manager for popup support.
 * @param {DvtContext} context The platform specific context object.
 * @param {function} callback A function that responds to delayed popup events
 * @param {object} callbackObj The optional object instance that the callback function is defined on.
 * @class DvtPopupBehaviorHandler
 * @constructor
 */
var  DvtPopupBehaviorHandler = function(context, callback, callbackObj) {
  this._context = context;
  this._callback = callback;
  this._callbackObj = callbackObj;
  
  // Initialize the hover params
  this._popupPosition = null;   // The most recent position, useful for placing the popup
  this._hoverTarget = null;      // The current hover target
  this._hoverBehavior = null;    // The current showPopupBehavior for the hover
  this._hoverPopupShown = false; // true if a hover popup is being shown
  this._hoverTimer = new DvtTimer(context, 500, this._onHoverDelay, this, 1);
};

DvtObj.createSubclass(DvtPopupBehaviorHandler, DvtObj, "DvtPopupBehaviorHandler");

// TODO define an interface for the targets of the popup handler functions
// 1. getPopupBounds()
// 2. getId()

/**
 * Processes a click event and fires a DvtShowPopupEvent if a popup should be shown.
 * @param {object} target The target of the mouse event.
 * @param {array} behaviors The array of applicable show popup behaviors.
 * @param {DvtPoint} position The position for placing the popup.
 */
DvtPopupBehaviorHandler.prototype.processClick = function(target, behaviors, position) {
  var consumed = false;
  if(target && behaviors && behaviors.length>0) 
  {
    for(var i=0; i<behaviors.length; i++) {
      var behavior = behaviors[i];
      if(behavior && (behavior.getTriggerType() == DvtShowPopupBehavior.TRIGGER_TYPE_ACTION ||
                      behavior.getTriggerType() == DvtShowPopupBehavior.TRIGGER_TYPE_CLICK)) {
        // Create and fire the popup event
        var popupEvent = this._createShowPopupEvent(target, behavior, position);
  		this._context.getJsExt().dispatchEvent(this._callback, this._callbackObj, null, popupEvent);
        consumed = true;
      }
    }
  }

  return consumed;
};

/**
 * Processes a mouseOver event.
 * @param {object} target The target of the mouse event.
 * @param {array} behaviors The array of applicable show popup behaviors.
 * @param {DvtPoint} position The position for the popup.
 */
DvtPopupBehaviorHandler.prototype.processMouseOver = function(target, behaviors, position) {
  // Same target, no action needed
  if(target === this._hoverTarget)
    return;
  
  // Different target, look for applicable showPopupBehavior
  if(target && behaviors && behaviors.length>0) 
  {
    for(var i=0; i<behaviors.length; i++) {
      var behavior = behaviors[i];
      if(behavior && behavior.getTriggerType() == DvtShowPopupBehavior.TRIGGER_TYPE_MOUSE_HOVER) {
        // Found hover behavior, store the info for use in callback and rollout
        this._hoverTarget = target;
        this._hoverBehavior = behavior;
        
        this._popupPosition = position;
        // Start the hover timer
        this._hoverTimer.start();
        break;
      }
    }
  }
};

/**
 * Processes a mouseOver event and fires a DvtHidePopupEvent if a popup is to be hidden.
 * @param {object} target The target of the mouse event.
 */
DvtPopupBehaviorHandler.prototype.processMouseOut = function(target) {
  // Continue only is a hover popup was processed for this target
  if(!this._hoverTarget || !this._hoverBehavior || target !== this._hoverTarget)
    return;
    
  if(this._hoverPopupShown) {
    // Popup already shown, hide it
    var popupEvent = new DvtHidePopupEvent(this._hoverBehavior.getPopupId());
  	this._context.getJsExt().dispatchEvent(this._callback, this._callbackObj, null, popupEvent);
  }
  else {
    // Popup not shown yet, just stop the timer
    this._hoverTimer.stop();
  }
  
  // Clear out the fields
  this._hoverTarget = null;
  this._hoverBehavior = null;
  this._hoverPopupShown = false;
};

/**
 * Processes a mouseMove event.  The most recent position is stored to help position
 * hover popups relative to the mouse.
 * @param {DvtPoint} position The position for the popup.
 */
DvtPopupBehaviorHandler.prototype.processMouseMove = function(position) {
  this._popupPosition = position;
}

/**
 * Helper function used to create the DvtShowPopupEvent.
 * @param {object} target The target of the mouse event.
 * @param {DvtShowPopupBehavior} behavior The show popup behavior that is being fired.
 * @param {DvtPoint} position The position for placing the popup.
 * @return {DvtShowPopupEvent} The showPopupEvent, if a popup should be shown.
 * @private
 */
DvtPopupBehaviorHandler.prototype._createShowPopupEvent = function(target, behavior, position) {
  // If align and alignId are not defined, position the popup with alignId="endAfter".  The original
  // showPopupBehavior is not modified.
  var spb = behavior;
  if(!spb.getAlign() && !spb.getAlignId())
    spb = new DvtShowPopupBehavior(spb.getPopupId(), spb.getTriggerType(), null, DvtShowPopupBehavior.ALIGN_END_AFTER);
  
  // Find the bounds that the popup should align to
  var launcherBounds = target.getPopupBounds ? target.getPopupBounds(behavior) : null;
  if(!launcherBounds) {
    // If the object doesn't specify a bounds, then align to the mouse
    var pos = this._context.getDocumentUtils().getStageRelativePosition(this._context.getStage(), position.x, position.y);
    launcherBounds = new DvtRectangle(pos.x, pos.y-5, 1, 5);
  }

  var event = new DvtShowPopupEvent(spb, launcherBounds, null);
  // add the component specific context
  DvtEventManager._addContextInfo(target, event);

  return event;
}

/**
 * Callback function that is called by the timer when a hover popup should be shown.
 * @private
 */
DvtPopupBehaviorHandler.prototype._onHoverDelay = function() {
  if(!this._hoverTarget || !this._hoverBehavior)
    return;
  // Show the popup: Create the event and pass to the hover callback
  this._hoverPopupShown = true;
  var event = this._createShowPopupEvent(this._hoverTarget, this._hoverBehavior, this._popupPosition);
  this._context.getJsExt().dispatchEvent(this._callback, this._callbackObj, null, event);
}


/**
  * Interactivity manager for selection.
  * @class DvtSelectionHandler
  * @constructor
  */
var  DvtSelectionHandler = function(type) {
  this.Init(type);
};

DvtObj.createSubclass(DvtSelectionHandler, DvtObj, "DvtSelectionHandler");

DvtSelectionHandler.TYPE_SINGLE   = "s";
DvtSelectionHandler.TYPE_MULTIPLE = "m";

DvtSelectionHandler.prototype.Init = function(type) {
  this._selection = [];
  this._type      = type ? type : DvtSelectionHandler.TYPE_SINGLE ;
} ;

DvtSelectionHandler.prototype.getType = function() {
  return this._type;
};

/**
 * Returns the number of currently selected objects.
 * @return {number}
 */
DvtSelectionHandler.prototype.getSelectedCount = function() {
  return this._selection.length;
};

/**
 * Returns the current selection.
 * @return {array} The current selection.
 */
DvtSelectionHandler.prototype.getSelection = function() {
  return this._selection.slice(0);
}

/**
 * Processes the initially selected objects, updating the state of this handler.
 * @param {array} selectedIds The array of ids for the selected objects.
 * @param {array} targets The array of selectable objects.
 */
DvtSelectionHandler.prototype.processInitialSelections = function(selectedIds, targets) {
  if(!selectedIds || !targets)
    return;
    
  // Loop through all the selected ids, matching them to the targets  
  for(var i=0; i<selectedIds.length; i++) {
    for(var j=0; j<targets.length; j++) {
      var targetId = targets[j].getId();
      if(targetId != null && DvtSelectionHandler._isEquals(selectedIds[i], targetId)) {
        // Found a match, continue to next selected id
        this._addToSelection(targets[j], true);
        break;
      }
    }
  }
}

/**
 * Processes a click event.
 * @param {DvtSelectable} target
 * @param {boolean} isMultiSelect true if a key indicating multi-select should be performed was pressed during the click.
 * @return {boolean} true if the selection has changed.
 */
DvtSelectionHandler.prototype.processClick = function(target, isMultiSelect) {
  //BUG FIX 13381888: if this click is unrelated to selection, then
  //don't change selection at all
  if (target && target.isUnrelatedToSelection && target.isUnrelatedToSelection()) {
    return false;
  }
  
  // Check whether we are in multi-select mode
  var bMulti = (isMultiSelect && this._type == DvtSelectionHandler.TYPE_MULTIPLE);
  
  //*************************************************
  // Possible cases:
  // 1. Multi-select of selectable target
  // 2. Multi-select of non-selectable target (noop)
  // 3. Single select of selectable target
  // 4. Single select of non-selectable target
  //*************************************************
  
  var bChanged = false; // Keep track of whether the selection is changed
  if(bMulti) 
  {
    if(target && target.isSelectable && target.isSelectable()) {
      // 1. Multi-select of selectable target
      if(target.isSelected()) {
        bChanged = this._removeFromSelection(target);
      }
      else {
        bChanged = this._addToSelection(target, true);
      }
    }
    // Otherwise 2. Multi-select of non-selectable target (noop)
  }
  else // Single Select
  {
    if(target && target.isSelectable && target.isSelectable()) {
      // 3. Single select of selectable target
      bChanged = this._addToSelection(target, false);
    }
    else {
      // 4. Single select of non-selectable target
      bChanged = this._clearSelection();
    }
  }
  
  // Return whether the selection has changed.
  return bChanged;
};

/**
 * Processes a mouseOver event.
 * @param {DvtSelectable} target
 */
DvtSelectionHandler.prototype.processMouseOver = function(target) {
  if(target && target.isSelectable && target.isSelectable() && target.showHoverEffect) {
    target.showHoverEffect();
  }
};

/**
 * Processes a mouseOut event.
 * @param {DvtSelectable} target
 */
DvtSelectionHandler.prototype.processMouseOut = function(target) {
  if(target && target.isSelectable && target.isSelectable() && target.hideHoverEffect) {
    target.hideHoverEffect();
  }
};

/**
 * Selects a single object.
 * @param {DvtSelectable} target the object to select
 * @param {boolean} bAddToExisting true if the object should be added to the current selection.
 * @return {boolean} true if the selection has changed.
 */
DvtSelectionHandler.prototype._addToSelection = function(target, bAddToExisting) {
  // If already selected, return.  This intentionally ignores bAddToExisting.
  if(target.isSelected()) {
    return false;
  }
  
  // If not adding to the current selection, deselect all
  if(!bAddToExisting) {
    this._clearSelection();
  }
    
  // Finally, select the object
  target.setSelected(true);
  this._selection.push(target);
  return true;
};

/**
 * Deselects a single object in the selection.
 * @param {DvtSelectable} target the object to deselect
 * @return {boolean} true if the selection has changed.
 */
DvtSelectionHandler.prototype._removeFromSelection = function(target) {
  if(!target.isSelected())
    return false;

  // First deselect the object, then remove it from the selected array
  target.setSelected(false);
  for(var i = 0; i < this._selection.length; i++) {
    if(this._selection[i] == target) {
      this._selection.splice(i, 1);
      break; 
    }
  }
  return true;
};

/**
 * Clears the current selection.
 * @return {boolean} true if the selection has changed.
 */
DvtSelectionHandler.prototype._clearSelection = function() {
  if(this._selection.length <= 0)
    return false;

  while(this._selection.length > 0) {
    var obj = this._selection.pop();
    obj.setSelected(false);
  }
  return true;
};

/**
 * Utility function used to determine if two id objects are equal.
 * @param {object} a
 * @param {object} b
 * @private
 * @return {boolean}
 */
DvtSelectionHandler._isEquals = function(a, b) {
  if(a == b)
    return true;
  else
    return false;
}

/**
  * Interactivity manager for keyboard events.
  * @param {DvtEventManager} manager The owning DvtEventManager
  * @class DvtKeyboardHandler
  * @constructor
  */
var  DvtKeyboardHandler = function(manager) 
{ 
  this.Init(manager);
};

DvtObj.createSubclass(DvtKeyboardHandler, DvtObj, "DvtKeyboardHandler");

// Constants used for calculating penalties when calculating distances between two DvtKeyboardNavigables
// in DvtKeyboardHandler._calcDistanceAngleWeighted
DvtKeyboardHandler._OPTIMAL_ANGLE1 = 15/180*Math.PI;
DvtKeyboardHandler._OPTIMAL_ANGLE2 = 40/180*Math.PI;
DvtKeyboardHandler._SUBOPTIMAL_ANGLE_PENALTY1 = 2; // multiplier to the distance
DvtKeyboardHandler._SUBOPTIMAL_ANGLE_PENALTY2 = 6; // multiplier to the distance

DvtKeyboardHandler.prototype.Init = function(manager)
{
  this._eventManager = manager;
}

/**
 * Processes key down events.
 * @param {DvtKeyboardEvent} event
 * @return {DvtKeyboardNavigable} The object that has keyboard focus as a result of the keyboard event. Null if the event
 *                                does not affect which DvtKeyboardNavigable has focus.
 */
DvtKeyboardHandler.prototype.processKeyDown = function(event) 
{ 
  var currentNavigable = this._eventManager.getFocus();
  
  if(this.isNavigationEvent(event) || this.isMultiSelectEvent(event))
  {
    event.preventDefault();
    var next = currentNavigable.getNextNavigable(event);
    this._eventManager.setFocus(next);
    return next;
  }

  return null;
} ;


/**
 * Simple implementation to return a navigable item based on direction and bounding box of current focused item
 * @param {DvtKeyboardNavigable} currentNavigable The DvtKeyboardNavigable item with current focus
 * @param {DvtKeyboardEvent} event
 * @param {Array} navigableItems An array of items that could receive focus next
 */
DvtKeyboardHandler.getNextNavigable = function(currentNavigable, event, navigableItems) 
{
  var nextNavigable = null;
  var nextNavigableDelta = 0;
  var delta = 0;
  
  var direction = event.keyCode;

  if(!currentNavigable)
  {
    if(!navigableItems || navigableItems.length < 1)
      return null;
    else
      return navigableItems[0];
  }
    
  // get the bounds of the current navigable
  var currentBounds = currentNavigable.getKeyboardBoundingBox();
  var candidateBounds;

  for(var i=0; i < navigableItems.length; i++)
  {
    var navigable = navigableItems[i];
    
    if(currentNavigable === navigable)  
      continue;

    candidateBounds = navigable.getKeyboardBoundingBox();  

    if(DvtKeyboardHandler._isInBounds(currentBounds, candidateBounds, direction))
    {
      delta = DvtKeyboardHandler._computeDelta(currentBounds, candidateBounds, direction);

      if( (((direction == DvtKeyboardEvent.UP_ARROW) || (direction == DvtKeyboardEvent.LEFT_ARROW)) && (delta < 0) && (!nextNavigable || (delta > nextNavigableDelta))) ||
          (((direction == DvtKeyboardEvent.DOWN_ARROW) || (direction == DvtKeyboardEvent.RIGHT_ARROW)) && (delta > 0) && (!nextNavigable || (delta < nextNavigableDelta)))
        )
      {
        nextNavigable = navigable;
        nextNavigableDelta = delta;
      }
    }  
  }
  
  return nextNavigable ? nextNavigable : currentNavigable;
}

 
/**
 * Returns a default keyboard navigable by selecting the upper left or lower right-most item in the navigableItems
 * array.  Utility method that can be called by classes that implement DvtKeyboardNavigable
 * @param {Array} An array of DvtKeyboardNavigables from which to choose the default one to receive focus
 */
DvtKeyboardHandler.prototype.getDefaultNavigable = function(navigableItems)
{ 
  if(!navigableItems || navigableItems.length <= 0)
    return null;
 
  var defaultNavigable = navigableItems[0];
  var defaultLocation = defaultNavigable.getKeyboardBoundingBox();
  var navigable;
  var navigableLocation;
  
  for(var i=1; i<navigableItems.length; i++)
  {
    navigable = navigableItems[i];
    navigableLocation = navigable.getKeyboardBoundingBox();
      
    if( ((navigableLocation.x == defaultLocation.x) && (navigableLocation.y < defaultLocation.y)) ||
        (navigableLocation.x < defaultLocation.x))  
    {
      defaultNavigable = navigable;
      defaultLocation = defaultNavigable.getKeyboardBoundingBox();
    }
  }
  
  return defaultNavigable;
} 


/**
 * Returns true if the event requires us to update the DvtKeyboardNavigable with keyboard focus.  In the base 
 * implementation, we return true if the given event is an arrow keystroke. 
 * @param {DvtKeybaordEvent} event
 * @return {Boolean}
 */
DvtKeyboardHandler.prototype.isNavigationEvent = function(event)
{
  var keyCode = event.keyCode;

  switch(keyCode)
  {
    case DvtKeyboardEvent.UP_ARROW:
    case DvtKeyboardEvent.DOWN_ARROW:
    case DvtKeyboardEvent.LEFT_ARROW:
    case DvtKeyboardEvent.RIGHT_ARROW:
      return true;
    default:
      break;
  }
  return false;
}


/**
 * Returns true if the event requires us to perform a single select
 * @param {DvtKeyboardEvent} event
 * @return {Boolean}
 */
DvtKeyboardHandler.prototype.isSelectionEvent = function(event)
{
  return false; // subclasses should override
}

/**
 * Returns true if the event requires us to perform a multi select
 * @param {DvtKeybaordEvent} event
 * @return {Boolean}
 */ 
DvtKeyboardHandler.prototype.isMultiSelectEvent = function(event)
{
  return false; // subclasses should override
}

/**
 * Returns true if the keyboard event is the standard keystroke for opening context menus
 * (Ctrl + Alt + M)
 * @param {DvtKeyboardEvent} event
 * @return {Boolean} true if the event is Ctrl+Alt+M, false otherwise
 */
DvtKeyboardHandler.prototype.isContextMenuEvent = function(event)
{
  return  event.keyCode == DvtKeyboardEvent.M &&
          event.altKey && event.ctrlKey;
};


/**
 * Determines if the candidate bounds line up with the current bounds in the given direction
 * For example, if the direction is up, then the candidate's x-bounds should overlap with the 
 * current's x-bounds
 * 
 * @param {DvtRectangle} currentBounds
 * @param {DvtRectangle} candidateBounds
 * @param {Number} direction  One of DvtKeyboardEvent.UP_ARROW, DvtKeyboardEvent.DOWN_ARROW, 
 *                            DvtKeyboardEvent.LEFT_ARROW, or DvtKeyboardEvent.RIGHT_ARROW
 * @return {Boolean} True if the candidate bounds line up with the current bounds, in the given direction
 * @private
 */
DvtKeyboardHandler._isInBounds = function(currentBounds, candidateBounds, direction) 
{
  if(direction == DvtKeyboardEvent.UP_ARROW || direction == DvtKeyboardEvent.DOWN_ARROW)
  {
    // if up/down, check that the current x-bounds overlap with the candidate's x-bounds.
    // by making sure that the left edge of the current is not to the right of the candidate
    // and that the right edge of the current is not to the left of the candidate
    
    var currentX1 = currentBounds.x;
    var currentX2 = currentX1 + currentBounds.w;
    var candidateX1 = candidateBounds.x;
    var candidateX2 = candidateX1 + candidateBounds.w;
    
    return !((currentX1 >= candidateX2) || (currentX2 <= candidateX1));
  }
  else if(direction == DvtKeyboardEvent.LEFT_ARROW || direction == DvtKeyboardEvent.RIGHT_ARROW)
  {
    // if left/right, check that the current y-bounds overlap with the candidate's y-bounds.
    // by making sure that the top edge of the current is not below the candidate
    // and that the bottom edge of the current is not above the candidate
    
    var currentY1 = currentBounds.y;
    var currentY2 = currentY1 + currentBounds.h;
    var candidateY1 = candidateBounds.y;
    var candidateY2 = candidateY1 + candidateBounds.h;
    
    return !((currentY1 >= candidateY2) || (currentY2 <= candidateY1));    
  }
}


/**
 * Determines the diffeerence between the centers of the currentBounds and the candidatBounds,
 * in the given direction.  The difference is negative if the candidate is above or to the left
 * of the current, positive if the candidate is below or to the right
 * 
 * @param {DvtRectangle} currentBounds
 * @param {DvtRectangle} candidateBounds
 * @param {Number} direction  One of DvtKeyboardEvent.UP_ARROW, DvtKeyboardEvent.DOWN_ARROW, 
 *                            DvtKeyboardEvent.LEFT_ARROW, or DvtKeyboardEvent.RIGHT_ARROW
 * @return {Number} The difference between the centers of the currentBounds and candidateBounds, in
 *                  the given direction
 * @private                          
 */

DvtKeyboardHandler._computeDelta = function(currentBounds, candidateBounds, direction)
{
  var delta = 0;
  var currentX = currentBounds.getCenter().x;
  var currentY = currentBounds.getCenter().y;
  var candidateX = candidateBounds.getCenter().x;
  var candidateY = candidateBounds.getCenter().y;
  
  if((direction == DvtKeyboardEvent.UP_ARROW) || (direction == DvtKeyboardEvent.DOWN_ARROW))
    delta = candidateY - currentY;
  else if((direction == DvtKeyboardEvent.LEFT_ARROW) || (direction == DvtKeyboardEvent.RIGHT_ARROW))
    delta = candidateX - currentX;
    
  return delta;
}



/**
 * Returns the next navigable based on the arrow key that was pressed. This method will return the next navigable that
 * is adjacent to the current navigable, in the direction of the arrow key. If there are no adjacent navigables, the
 * closest navigable in the direction of the arrow key is returned.  Distance to the nearest navigable is based on
 * straight line distance between the midpoints of the navigables' keyboard bounding box, multiplied by a penalty
 * factor if the midpoints are too far off the vertical (in the case of up and down) or horizontal (for left and right)
 * 
 * @param {DvtKeyboardNavigable} current
 * @param {DvtKeyboardEvent} event
 * @param {Array} listOfObjects Array of DvtKeyboardNavigable objects
 * @return {DvtKeyboardNavigable}
 */
DvtKeyboardHandler.getNextAdjacentNavigable = function(current, event, listOfObjects)
{
  var keycode = event.keyCode;
  
  if (!listOfObjects)
    return null;			
			
  if (!current)
    return listOfObjects[0];
			
  var nextObject = current; //init to current object
  var nextDistance = Number.MAX_VALUE;
			
  // If an object is in contact it overrules all other attributes
  // Only another in contact object with better attributes will have higher precedence
  var nextInContact = false; 

  for(var i=0; i<listOfObjects.length; i++)
  {
    var object = listOfObjects[i];
    			
    if (object === current)
      continue;
            				
    if (!DvtKeyboardHandler._isValidDestination(object, current, keycode))
      continue;

    var inContact = DvtKeyboardHandler._calcInContact(object, current, keycode);
    
    if (nextInContact && !inContact)
      continue;

    var distance = DvtKeyboardHandler._calcDistanceAngleWeighted(object, current, keycode);
    // Make sure incontact flag have highest precedence
    if( (!nextInContact && inContact) ||
        (distance < nextDistance && ((nextInContact && inContact) || !nextInContact)) ) 
    {
      nextDistance = distance;
      nextObject = object;
      nextInContact = inContact;
    }
  }
  return nextObject;
}	



/**
 * Determine if two objects are in contact in the specified direction 
 * 
 * @param {DvtKeyboardNavigable} object
 * @param {DvtKeyboardNavigable} current
 * @param {Number} keycode
 * @return {Boolean}
 * @private
 */
DvtKeyboardHandler._calcInContact = function(object, current, keycode)
{
  var objRect = object.getKeyboardBoundingBox();
  var curRect = current.getKeyboardBoundingBox();

  switch (keycode) 
  {
    case DvtKeyboardEvent.UP_ARROW: 
      return  DvtKeyboardHandler._isVerticallyAligned(objRect, curRect) && 
              (curRect.y <= (objRect.y+objRect.h) || DvtKeyboardHandler._areEqualWithinTolerance(curRect.y, objRect.y+objRect.h));  
    case DvtKeyboardEvent.DOWN_ARROW: 
      return  DvtKeyboardHandler._isVerticallyAligned(objRect, curRect) && 
              (objRect.y <= (curRect.y+curRect.h) || DvtKeyboardHandler._areEqualWithinTolerance(objRect.y, curRect.y+curRect.h));
    case DvtKeyboardEvent.RIGHT_ARROW: 
      return  DvtKeyboardHandler._isHorizontallyAligned(objRect, curRect) && 
              (objRect.x <= (curRect.x+curRect.w) || DvtKeyboardHandler._areEqualWithinTolerance(objRect.x, curRect.x+curRect.w));
    case DvtKeyboardEvent.LEFT_ARROW: 
      return  DvtKeyboardHandler._isHorizontallyAligned(objRect, curRect) && 
              (curRect.x <= (objRect.x+objRect.w) || DvtKeyboardHandler._areEqualWithinTolerance(curRect.x, objRect.x+objRect.w));
    default:
      break;
  }
            
  return false;
}

/**
 * Returns true if the two input rectangles are lined up vertically
 * 
 * @param {DvtRectangle} rect1
 * @param {DvtRectangle} rect2
 * @return {Boolean}
 * @private
 */
DvtKeyboardHandler._isVerticallyAligned = function(rect1, rect2)
{
  return ((rect1.x >= rect2.x && rect1.x <= (rect2.x+rect2.w)) ||
          (rect2.x >= rect1.x && rect2.x <= (rect1.x+rect1.w)));
}

/**
 * Returns true if the two input rectangles are lined up horizontally
 * 
 * @param {DvtRectangle} rect1
 * @param {DvtRectangle} rect2
 * @return {Boolean}
 * @private
 */
DvtKeyboardHandler._isHorizontallyAligned = function(rect1, rect2)
{
  return ((rect1.y >= rect2.y && rect1.y <= (rect2.y+rect2.h)) ||
          (rect2.y >= rect1.y && rect2.y <= (rect1.y+rect1.h)));
}



/**
 * Returns the distance between the centers of the keyboard bounding boxes of the input DvtKeyboardNavigables.
 * Distance is multiplied by a penalty factor if the centers are too far off the vertical (in the case of up and down) 
 * or horizontal (for left and right)
 * 
 * @param {DvtKeyboardNavigable} object
 * @param {DvtKeyboardNavigable} current
 * @param {Number} keycode
 * @return {Number} 
 * @private
 */
DvtKeyboardHandler._calcDistanceAngleWeighted = function(object, current, keycode)
{
  var objectBB = object.getKeyboardBoundingBox();
  var objCenterX = objectBB.x + objectBB.w/2;
  var objCenterY = objectBB.y + objectBB.h/2;

  var currentBB = current.getKeyboardBoundingBox();
  var curCenterX = currentBB.x + currentBB.w/2;
  var curCenterY = currentBB.y + currentBB.h/2;

  var x_dist = Math.abs(objCenterX - curCenterX);
  var y_dist = Math.abs(objCenterY - curCenterY);
            
  var angle = Math.atan2(y_dist, x_dist);
            
  var distance = Math.sqrt(x_dist * x_dist + y_dist * y_dist);

  // Angle penalty based on direction   
  if( (angle > DvtKeyboardHandler._OPTIMAL_ANGLE1 && (keycode == DvtKeyboardEvent.RIGHT_ARROW || keycode == DvtKeyboardEvent.LEFT_ARROW)) ||
      (angle < DvtMath.HALF_PI - DvtKeyboardHandler._OPTIMAL_ANGLE1 && (keycode == DvtKeyboardEvent.UP_ARROW || keycode == DvtKeyboardEvent.DOWN_ARROW)) ) 
  {
    if( (angle > DvtKeyboardHandler._OPTIMAL_ANGLE2 && (keycode == DvtKeyboardEvent.RIGHT_ARROW || keycode == DvtKeyboardEvent.LEFT_ARROW)) ||
        (angle < DvtMath.HALF_PI - DvtKeyboardHandler._OPTIMAL_ANGLE2 && (keycode == DvtKeyboardEvent.UP_ARROW || keycode == DvtKeyboardEvent.DOWN_ARROW)) ) 
    {
      distance *= DvtKeyboardHandler._SUBOPTIMAL_ANGLE_PENALTY2;
    }
    else 
    {
      distance *= DvtKeyboardHandler._SUBOPTIMAL_ANGLE_PENALTY1;
    }
  }
                
  return distance;
}


/**
  * Determine if a point is valid based on the direction
  * @param {DvtKeyboardNavigable} object
  * @param {DvtKeyboardNavigable} current
  * @param {Number} keycode
  * @return {Boolean}
  * @private
  */
DvtKeyboardHandler._isValidDestination = function(object, current, keycode)
{
  var objBB = object.getKeyboardBoundingBox();
  var curBB = current.getKeyboardBoundingBox();
  
  switch (keycode) 
  {
    case DvtKeyboardEvent.UP_ARROW: 
      return (objBB.y<curBB.y) || DvtKeyboardHandler._areEqualWithinTolerance(objBB.y, curBB.y);
    case DvtKeyboardEvent.DOWN_ARROW: 
      return objBB.y>curBB.y || DvtKeyboardHandler._areEqualWithinTolerance(objBB.y, curBB.y);
    case DvtKeyboardEvent.RIGHT_ARROW: 
      return objBB.x>curBB.x || DvtKeyboardHandler._areEqualWithinTolerance(objBB.x, curBB.x);
    case DvtKeyboardEvent.LEFT_ARROW: 
      return objBB.x<curBB.x || DvtKeyboardHandler._areEqualWithinTolerance(objBB.x, curBB.x);
    default:
      break;
  }
  return true;
}

/**
 * Utility method to check if two numbers are equal, within a small tolerance. Used to account for small rounding
 * errors
 * 
 * @param {Number} a
 * @param {Number} b
 * @return {Boolean} true if the numbers are within 0.0000001 of each other
 * @private
 */
DvtKeyboardHandler._areEqualWithinTolerance = function(a,b)
{
  return Math.abs(a-b) <= 0.0000001;
}


// Handler used for marquee operations
var   DvtMarqueeHandler = function(context, rootDisplayable, bounds, panelBehavior)
{
    this.Init(context, rootDisplayable, bounds, panelBehavior);
}  

DvtMarqueeHandler.PANEL_BEHAVIOR_BOTH  = 0;
DvtMarqueeHandler.PANEL_BEHAVIOR_HORIZ   = 1;
DvtMarqueeHandler.PANEL_BEHAVIOR_VERT   = 1;

DvtObj.createSubclass(DvtMarqueeHandler, DvtObj, "DvtMarqueeHandler");

DvtMarqueeHandler.prototype.Init = function(context, rootDisplayable, bounds, panelBehavior) {
    this._context = context;
    this._rootDisplayable = rootDisplayable;
    
    this._panelBehavior = DvtMarqueeHandler.PANEL_BEHAVIOR_BOTH;
    if (panelBehavior)
        this._panelBehavior = panelBehavior;
    
    this.m_iBandWidth = 1;          // rubber band line width
    this.m_iBandColor = "#c0c0c0";  // rubber band color

    // Store and update the position
    this.x   = bounds.x ;
    this.y   = bounds.y ;

    // Height and width of the plotArea
    this.m_w = bounds.w ;
    this.m_h = bounds.h ;
    
    // Enabled by default
    this._isMarqueeEnabled = true;

    this.InitMarqueePanel();    
}

DvtMarqueeHandler.prototype.isMarqueeEnabled = function()
{
  return this._isMarqueeEnabled;
}

DvtMarqueeHandler.prototype.enableMarquee = function(marqueeEnabled)
{
  this._isMarqueeEnabled = marqueeEnabled;
}

DvtMarqueeHandler.prototype.InitMarqueePanel = function() {
    var panel = new DvtMarqueePanel(this._context);
    panel.setVisible(false);
    this._panel = panel;
    this._rootDisplayable.addChild(panel);
}
  
/**
* Returns true if the cursor is positioned within the plotArea.  
* When panning, also checks to make sure that a marker is not beneath the cursor.
*/ 
DvtMarqueeHandler.prototype.isInBounds = function(eventTarget) {
  if(this.m_mouseX >= 0 && this.m_mouseX <= this.m_w && this.m_mouseY >= 0 && this.m_mouseY <= this.m_h)
    return true;
  else
  {     
    return false;
  }
}

// TODO: Brandon - fill in
DvtMarqueeHandler.prototype.cancelMarqueeZoom = function()
{
  this.removeCursor();
  this.m_bMouseDown = false;
  var panel = this._panel;
  if (panel)
     panel.setVisible(false);
}

DvtMarqueeHandler.prototype.processDragStart = function(relPos, startObj) {
   // for interactive testing - redundant as MouseMove would 
   // have set these, but under testing, a mouse move prior to this
   // may not have been called!
   this.m_mouseX = relPos.x - this.x;
   this.m_mouseY = relPos.y - this.y;
   // If not zoom mode, pan mode, or within plotArea, return
   if(!(this._isMarqueeEnabled) || !this.isInBounds(startObj))
     return false;
     
   this.m_bMouseDown = true ;
   this.m_iStartPosX = this.m_mouseX ;  // else mouseX
   this.m_iStartPosY = this.m_mouseY ;  // else mouseY
   this.m_prevPosX = this.m_mouseX;  // else mouseX
   this.m_prevPosY = this.m_mouseY;  // else mouseY
   return true;
   
}

DvtMarqueeHandler.prototype.processDragMove = function(relPos) {
    this.m_mouseX = relPos.x - this.x;
    this.m_mouseY = relPos.y - this.y;
    
   // handle zoom or pan Modes
   if(this._isMarqueeEnabled)
     return this.handleMarqueeMove();  
   return false;
}

/**
 * Handles mouse moves while in zoom mode. 
 */ 
DvtMarqueeHandler.prototype.handleMarqueeMove = function() {
   // move our cursor to track the mouse
   this.updateCursor();
   //  If mouse is down, update the rubber band rect.
   if (this.m_bMouseDown)
   {
      var panel = this._panel;
      this.calcMarqueeCoords();  // Calculate the rectangle positions
      panel.setPanelSize(this._panelWidth, this._panelHeight);
      panel.Render();
      panel.setTranslateX(this.x + this._panelX);
      panel.setTranslateY(this.y + this._panelY);
      panel.setBandAttributes(this.m_iBandWidth, this.m_iBandColor);
      panel.setVisible(true);
      return true;
   }
   return false;
}

DvtMarqueeHandler.prototype.processDragEnd = function(relPos) {

   // for interactive testing - redundant as MouseMove would 
   // have set these, but under testing, a mouse move prior to this
   // may not have been called!
   this.m_mouseX = relPos.x - this.x;
   this.m_mouseY = relPos.y - this.y;
   
   if (! this.m_bMouseDown)
     return ;
   this.m_bMouseDown = false ;
   
   if(this._isMarqueeEnabled)
     this.handleMarqueeEnd();
}

/**
 * Handles mouse up while in zoom mode.
 */ 
DvtMarqueeHandler.prototype.handleMarqueeEnd = function() {
   // Hide the custom cursor
   this.removeCursor();
   // Calculate the rectangle position based on current mouse coords
   this.calcMarqueeCoords();

   this.HandleMarqueeDone();

}

DvtMarqueeHandler.prototype.HandleMarqueeDone = function() {
}

/**
* Using the current mouse position and a set of starting coordinates, calculates
* the location of the zoom rectangle.
*/ 
DvtMarqueeHandler.prototype.calcMarqueeCoords = function() {
  var mX = this.m_mouseX; // mouseX ;           
  var mY = this.m_mouseY; // mouseY ;           

  if (this.m_mouseX > this.m_w)
    mX = this.m_w;
  if (this.m_mouseX < 0)
    mX = 0;
  if (this.m_mouseY > this.m_h)
    mY = this.m_h;
  if (this.m_mouseY < 0)
    mY = 0;

  if (this._panelBehavior == (DvtMarqueeHandler.PANEL_BEHAVIOR_BOTH))
  {
     //  No contraints on rubber band rect (within Frame)
     this._panelX  =  Math.min(this.m_iStartPosX, mX - 1);
     this._panelY  =  Math.min(this.m_iStartPosY, mY - 1);
     this._panelWidth  =  Math.abs(mX - this.m_iStartPosX);
     this._panelHeight  =  Math.abs(mY - this.m_iStartPosY);
  }
  else if (this._panelBehavior == DvtMarqueeHandler.PANEL_BEHAVIOR_HORIZ)
  {
     //  Vertical sides extend to Frame height
     this._panelX  =  Math.min(this.m_iStartPosX, mX - 1);
     this._panelY  =  0;
     this._panelWidth  =  Math.abs(mX - this.m_iStartPosX);
     this._panelHeight  =  this.m_h;
  }
  else if (this._panelBehavior == DvtMarqueeHandler.PANEL_BEHAVIOR_VERT)
  {
     //  Horizontal sides extend to Frame width
     this._panelX  =  0;
     this._panelY  =  Math.min(this.m_iStartPosY, mY - 1);
     this._panelWidth  =  this.m_w;
     this._panelHeight  =  Math.abs(mY - this.m_iStartPosY);
  }
}


/**
 * Initializes and creates the zoom or pan cursors.
 */ 
DvtMarqueeHandler.prototype.updateCursor = function() {
    // Impl overrides
}

/*----------------------------------------------------------------------*/
/*    removeCursor()                                               */
/*----------------------------------------------------------------------*/
DvtMarqueeHandler.prototype.removeCursor = function() {
    // Impl overrides
}

/**
 * Returns a boolean indicating whether or not we are currently in the process of drawing a marquee rubber band
 * @return {boolean}
 */
DvtMarqueeHandler.prototype.isMarqueeHappening = function()
{
  return this.m_bMouseDown;
}
// Handler used for marquee zoom operations
var   DvtMarqueeZoomHandler = function(context, rootDisplayable, bounds, zoomMode, panelBehavior)
{
    this.InitZoom(context, rootDisplayable, bounds, zoomMode, panelBehavior);
}  

DvtMarqueeZoomHandler.ZOOM_OFF  = 0;
DvtMarqueeZoomHandler.ZOOM_ON   = 1;
DvtMarqueeZoomHandler.ZOOM_AUTO = 2;  // on if the CTRL key is pressed

DvtObj.createSubclass(DvtMarqueeZoomHandler, DvtMarqueeHandler, "DvtMarqueeZoomHandler");

DvtMarqueeZoomHandler.prototype.InitZoom = function(context, rootDisplayable, bounds, zoomMode, panelBehavior) {
    DvtMarqueeZoomHandler.superclass.Init.call(this, context, rootDisplayable, bounds, panelBehavior);

    this.m_bZoomIn    = true ;   // true == zoom in cursor, false == zoom out cursor
    
    this.m_zoomMode = DvtMarqueeZoomHandler.ZOOM_ON;
    if (zoomMode != null)
        this.m_zoomMode = zoomMode;

    this._isMarqueeEnabled = false;   // false == default mode, true == zoom mode
    if(this.m_zoomMode == DvtMarqueeZoomHandler.ZOOM_ON) {
       this._isMarqueeEnabled = true;  // for auto, isZooming is turned on by keyboard
       this.updateCursor();
    }   
}

/**
 * Process shift-zoom key events
 * @param {boolean} bKeyDown
 */
DvtMarqueeZoomHandler.prototype.processShiftZoom = function(bKeyDown)
{
  // Toggle between ZoomIn vs ZoomOut on SHIFT
     
  //  var bZoomState:Boolean = (! event.shiftKey)  ; // false if SHIFT, else true
  // 
  //  The above test doesn't seem to work in FireFox (ok for IE7).  The boolean
  //  is always false.  The following seems to be ok though.
      
  var bZoomIn = !bKeyDown;        // true if zoom in, false if zoom out
  if (this.m_bZoomIn != bZoomIn)  // if zoom state change
  {                                     
    this.m_bZoomIn = bZoomIn ;
    this.updateCursor();
  }
}
/**
 * Animation handler for black box animations.
 * @class DvtBlackBoxAnimationHandler
 */
var DvtBlackBoxAnimationHandler = function() {};

DvtObj.createSubclass(DvtBlackBoxAnimationHandler, DvtObj, "DvtBlackBoxAnimationHandler");

// Black Box Animation Types
DvtBlackBoxAnimationHandler.ALPHA_FADE            = "alphaFade";   
DvtBlackBoxAnimationHandler.CONVEYOR_FROM_RIGHT   = "conveyorFromRight";   
DvtBlackBoxAnimationHandler.CONVEYOR_FROM_LEFT    = "conveyorFromLeft";
DvtBlackBoxAnimationHandler.CUBE_TO_RIGHT         = "cubeToRight";
DvtBlackBoxAnimationHandler.CUBE_TO_LEFT          = "cubeToLeft";
DvtBlackBoxAnimationHandler.FLIP_RIGHT            = "flipRight";
DvtBlackBoxAnimationHandler.FLIP_LEFT             = "flipLeft";   
DvtBlackBoxAnimationHandler.TRANSITION_TO_RIGHT   = "transitionToRight";
DvtBlackBoxAnimationHandler.TRANSITION_TO_LEFT    = "transitionToLeft"; 
DvtBlackBoxAnimationHandler.SLIDE_TO_RIGHT        = "slideToRight";
DvtBlackBoxAnimationHandler.SLIDE_TO_LEFT         = "slideToLeft"; 
DvtBlackBoxAnimationHandler.ZOOM                  = "zoom";

/**
 * Returns true if the specified animation type should be handled by a black box animation.
 * @param {string} type The animation type.
 * @return {boolean}
 */
DvtBlackBoxAnimationHandler.isSupported = function(type) {
  return (type == DvtBlackBoxAnimationHandler.ALPHA_FADE || 
          type == DvtBlackBoxAnimationHandler.CONVEYOR_FROM_RIGHT || 
          type == DvtBlackBoxAnimationHandler.CONVEYOR_FROM_LEFT || 
          type == DvtBlackBoxAnimationHandler.CUBE_TO_RIGHT || 
          type == DvtBlackBoxAnimationHandler.CUBE_TO_LEFT || 
          type == DvtBlackBoxAnimationHandler.FLIP_RIGHT || 
          type == DvtBlackBoxAnimationHandler.FLIP_LEFT || 
          type == DvtBlackBoxAnimationHandler.TRANSITION_TO_RIGHT || 
          type == DvtBlackBoxAnimationHandler.TRANSITION_TO_LEFT || 
          type == DvtBlackBoxAnimationHandler.SLIDE_TO_RIGHT || 
          type == DvtBlackBoxAnimationHandler.SLIDE_TO_LEFT || 
          type == DvtBlackBoxAnimationHandler.ZOOM);
}

/**
 * Creates and returns the specified black box animation for the displayables.
 * @param {DvtContext} context The platform specific context object.
 * @param {string} type The animation type.
 * @param {object} objs The displayable or array of displayables.
 * @param {DvtRectangle} bounds The bounds of the objects to animate.
 * @param {number} duration The duration of the animation
 * @return {DvtPlayable} The animation from the old object to the new object.
 */
DvtBlackBoxAnimationHandler.getInAnimation = function(context, type, objs, bounds, duration) {
  if(type == DvtBlackBoxAnimationHandler.ALPHA_FADE) 
    return new DvtAnimFadeIn(context, objs, duration);
  else if(type == DvtBlackBoxAnimationHandler.CONVEYOR_FROM_RIGHT)
    return new DvtAnimConveyorIn(context, objs, DvtBaseAnimation.DIR_E, duration); 
  else if(type == DvtBlackBoxAnimationHandler.CONVEYOR_FROM_LEFT)
    return new DvtAnimConveyorIn(context, objs, DvtBaseAnimation.DIR_W, duration); 
  else if(type == DvtBlackBoxAnimationHandler.CUBE_TO_RIGHT)
    return new DvtAnimCubeIn(context, objs, DvtBaseAnimation.AXIS_Y, DvtBaseAnimation.ROT_DIR_CLOCKWISE, duration);  
  else if(type == DvtBlackBoxAnimationHandler.CUBE_TO_LEFT)
    return new DvtAnimCubeIn(context, objs, DvtBaseAnimation.AXIS_Y, DvtBaseAnimation.ROT_DIR_COUNTERCLOCKWISE, duration); 
  else if(type == DvtBlackBoxAnimationHandler.FLIP_RIGHT)
    return new DvtAnimFlipIn(context, objs, DvtBaseAnimation.AXIS_Y, DvtBaseAnimation.ROT_DIR_CLOCKWISE, duration);  
  else if(type == DvtBlackBoxAnimationHandler.FLIP_LEFT)
    return new DvtAnimFlipIn(context, objs, DvtBaseAnimation.AXIS_Y, DvtBaseAnimation.ROT_DIR_COUNTERCLOCKWISE, duration); 
  else if(type == DvtBlackBoxAnimationHandler.TRANSITION_TO_RIGHT)
    return new DvtAnimScaleFadeIn(context, objs, bounds, DvtBaseAnimation.DIR_NW, 0.5, duration); 
  else if(type == DvtBlackBoxAnimationHandler.TRANSITION_TO_LEFT) 
    return new DvtAnimScaleFadeIn(context, objs, bounds, DvtBaseAnimation.DIR_NE, 0.5, duration); 
  else if(type == DvtBlackBoxAnimationHandler.SLIDE_TO_RIGHT) {
    DvtBlackBoxAnimationHandler._offsetObjects(objs, -bounds.w, 0);
    return new DvtAnimMoveBy(context, objs, new DvtPoint(bounds.w, 0), duration); 
  }
  else if(type == DvtBlackBoxAnimationHandler.SLIDE_TO_LEFT) {
    DvtBlackBoxAnimationHandler._offsetObjects(objs, bounds.w, 0);
    return new DvtAnimMoveBy(context, objs, new DvtPoint(-bounds.w, 0), duration); 
  }
  else if(type == DvtBlackBoxAnimationHandler.ZOOM)
    return new DvtAnimScaleFadeIn(context, objs, bounds, DvtBaseAnimation.DIR_C, 0.5, duration); 
  else 
    return null; 
}

/**
 * Creates and returns the specified black box animation between the old displayable and
 * the new displayable.
 * @param {DvtContext} context The platform specific context object.
 * @param {string} type The animation type.
 * @param {object} outObjs The displayable or array of displayables to animate out.
 * @param {object} inObjs The displayable or array of displayables to animate in.
 * @param {DvtRectangle} bounds The bounds of the objects to animate.
 * @param {number} duration The duration of the animation (in seconds).
 * @return {DvtPlayable} The animation from the old object to the new object.
 */
DvtBlackBoxAnimationHandler.getCombinedAnimation = function(context, type, outObjs, inObjs, bounds, duration) {
  if(type == DvtBlackBoxAnimationHandler.ALPHA_FADE)
    return new DvtCombinedAnimFade(context, outObjs, inObjs, duration); 
  else if(type == DvtBlackBoxAnimationHandler.CONVEYOR_FROM_RIGHT)
    return new DvtCombinedAnimConveyor(context, outObjs, inObjs, DvtBaseAnimation.DIR_W, DvtBaseAnimation.DIR_E, duration); 
  else if(type == DvtBlackBoxAnimationHandler.CONVEYOR_FROM_LEFT)
    return new DvtCombinedAnimConveyor(context, outObjs, inObjs, DvtBaseAnimation.DIR_E, DvtBaseAnimation.DIR_W, duration); 
  else if(type == DvtBlackBoxAnimationHandler.CUBE_TO_RIGHT)
    return new DvtCombinedAnimCube(context, outObjs, inObjs, DvtBaseAnimation.AXIS_Y, DvtBaseAnimation.ROT_DIR_CLOCKWISE, duration); 
  else if(type == DvtBlackBoxAnimationHandler.CUBE_TO_LEFT)
    return new DvtCombinedAnimCube(context, outObjs, inObjs, DvtBaseAnimation.AXIS_Y, DvtBaseAnimation.ROT_DIR_COUNTERCLOCKWISE, duration); 
  else if(type == DvtBlackBoxAnimationHandler.FLIP_RIGHT)
    return new DvtCombinedAnimFlip(context, outObjs, inObjs, DvtBaseAnimation.AXIS_Y, DvtBaseAnimation.ROT_DIR_CLOCKWISE, duration); 
  else if(type == DvtBlackBoxAnimationHandler.FLIP_LEFT)
    return new DvtCombinedAnimFlip(context, outObjs, inObjs, DvtBaseAnimation.AXIS_Y, DvtBaseAnimation.ROT_DIR_COUNTERCLOCKWISE, duration); 
  else if(type == DvtBlackBoxAnimationHandler.TRANSITION_TO_RIGHT) 
    return new DvtCombinedAnimScaleFade(context, outObjs, inObjs, bounds, DvtBaseAnimation.DIR_SE, DvtBaseAnimation.DIR_NW, 0.5, duration); 
  else if(type == DvtBlackBoxAnimationHandler.TRANSITION_TO_LEFT)
    return new DvtCombinedAnimScaleFade(context, outObjs, inObjs, bounds, DvtBaseAnimation.DIR_SW, DvtBaseAnimation.DIR_NE, 0.5, duration); 
  else if(type == DvtBlackBoxAnimationHandler.SLIDE_TO_RIGHT) {
    DvtBlackBoxAnimationHandler._offsetObjects(inObjs, -bounds.w, 0);
    return new DvtCombinedAnimMoveBy(context, outObjs, inObjs, new DvtPoint(bounds.w, 0), new DvtPoint(bounds.w, 0), duration); 
  }
  else if(type == DvtBlackBoxAnimationHandler.SLIDE_TO_LEFT) {
    DvtBlackBoxAnimationHandler._offsetObjects(inObjs, bounds.w, 0);
    return new DvtCombinedAnimMoveBy(context, outObjs, inObjs, new DvtPoint(-bounds.w, 0), new DvtPoint(-bounds.w, 0), duration); 
  }
  else if(type == DvtBlackBoxAnimationHandler.ZOOM) 
    return new DvtCombinedAnimScaleFade(context, outObjs, inObjs, bounds, DvtBaseAnimation.DIR_C, DvtBaseAnimation.DIR_C, 0.5, duration); 
  else 
    return null; 
}

/**
 * Adjusts the objects by the specified offset.
 * @param {object} objs The displayable or array of displayables.
 * @param {number} offsetX The x offset to add.
 * @param {number} offsetY The y offset to add.
 @private
 */
DvtBlackBoxAnimationHandler._offsetObjects = function(objs, offsetX, offsetY) {
  if(objs.length) {
    for(var i=0; i<objs.length; i++)
      DvtBlackBoxAnimationHandler._offsetObjects(objs[i], offsetX, offsetY);
  }
  else if(objs) {
    // Adjust the displayable
    objs.setTranslateX(objs.getTranslateX() + offsetX);
    objs.setTranslateY(objs.getTranslateY() + offsetY);
  }
}
/**
 * Animation handler for data objects.
 * @param {DvtContext} context The platform specific context object.
 * @param {DvtContainer} deleteContainer The container where deletes should be moved for animation.
 * @class DvtDataAnimationHandler
 * @constructor
 */
var DvtDataAnimationHandler = function(context, deleteContainer) {
  this.Init(context, deleteContainer);
};

DvtObj.createSubclass(DvtDataAnimationHandler, DvtObj, "DvtDataAnimationHandler");

// TODO Document the expected interface for animatable objects:
// getId()
// animateUpdate(oldObj)
// animateDelete()
// animateInsert()

/**
 * Initializes the handler.
 * @param {DvtContext} context The platform specific context object.
 * @param {DvtContainer} deleteContainer The container where deletes should be moved for animation.
 * @protected
 */
DvtDataAnimationHandler.prototype.Init = function(context, deleteContainer) {
  this._context         = context;
  this._deleteContainer = deleteContainer;
  this._playables       = new Array();
  this._newChart        = null; // TODO this should be removed, doesn't belong in a generic animation handler
}

/**
 * Constructs an animation between two lists of logical objects.  This function 
 * delegates the specific animation behavior to the logical objects.  The animation
 * can be retrieved using getAnimation().
 * @param {array} oldList The list to animate from.
 * @param {array} newList The list to animate to.
 */
DvtDataAnimationHandler.prototype.constructAnimation = function(oldList, newList) {

  // Copy the new objects list, since we will modify it
  newList = newList.slice(0);

  // Loop through the two lists and diff the changes.
  // Note: This implementation considers changes in order to be updates.
  if (oldList) {
    for(var oldIndex=0; oldIndex<oldList.length; oldIndex++) {
      var oldItem = oldList[oldIndex];
      if(!oldItem) // oldItem must exist for update or delete
        continue;
      
      // Loop through the new list looking for a match
      var bMatchFound = false;
      for(var newIndex=0; newIndex<newList.length; newIndex++) {
        var newItem = newList[newIndex];
        if(!newItem) // newItem must exist for update
          continue;
        
        if(oldItem.getId() === newItem.getId()) {
          // Match found, remove the item from the new list since it's handled
          newItem.animateUpdate(this, oldItem);
          newList.splice(newIndex, 1);
          bMatchFound = true;
          break;
        }
      }
      
      // If no match found, it was a delete.  Pass in the delete container so that
      // the object can choose whether to move to the new container.
      if(!bMatchFound) {

        if (newList[0]) {
          if (newList[0].getChart)
	          oldItem._newChart = newList[0].getChart() ;        // new chart needed for
        }                                                    // some delete animation
        oldItem.animateDelete(this, this._deleteContainer);
      }
    }
  }

  // All remaining objects in newList are inserts
  for(var i=0; i<newList.length; i++) {
    if(newList[i]) // must be valid object for insert
      newList[i].animateInsert(this);
  }
}

/**
 * Adds the specified playable to this handler's animation.
 * @param {DvtPlayable} The playable to add to this animation.
 * @param {number} index The relative ordering of the animation, beginning at 0.
 */
DvtDataAnimationHandler.prototype.add = function(playable, index) {
  if(!playable)
    return;
    
  if(!index)
    index = 0;

  // Make sure the playables array is large enough
  while(this._playables.length <= index)
    this._playables.push(new Array());
  
  // Add the playable to the array
  this._playables[index].push(playable);
}

/**
 * Returns the animation constructed by this handler.
 * @return {DvtPlayable} The animation constructed by this handler.
 */
DvtDataAnimationHandler.prototype.getAnimation = function() {
  // Construct the sequential playable
  var masterPlayable = new Array();
  for(var i=0; i<this._playables.length; i++) {
    // Construct and add the playable for this index in the sequence
    if(this._playables[i].length > 0) {
      var detailPlayable = new DvtParallelPlayable(this._context, this._playables[i]);
      masterPlayable.push(detailPlayable);
    }
  }
  
  return new DvtSequentialPlayable(this._context, masterPlayable);
}


/**
 * Returns the number of playables in this animation.
 * @returns {Number} the number of playables in this animation.
 */
DvtDataAnimationHandler.prototype.getNumPlayables = function()
{
    return this._playables.length ;
};

/**
 * Base class object for tooltip services.
 * @class DvtTooltipManager
 * @extends DvtObj
 * @constructor
 */
var DvtTooltipManager = function() {};

DvtObj.createSubclass(DvtTooltipManager, DvtObj, "DvtTooltipManager");

/**
 * Displays a tooltip with the given parameters.
 * @param {int} x the x position as relative to coordinate space of implementation
 * @param {int} y the y position as relative to coordinate space of implementation
 * @param {string} text the text to show within the tooltip
 * @param {string} borderColor the border color of the tooltip
 */
DvtTooltipManager.prototype.showDatatip = function(x, y, text, borderColor)
{
  // TODO subclasses should override
};


/**
 * Displays a tooltip.
 * @param {int} x the x position as relative to coordinate space of implementation
 * @param {int} y the y position as relative to coordinate space of implementation
 * @param (string) text The text to display in the tooltip. 
 * @param (DvtDisplayable) component The display object to use for tracking mouse movements.
 * @param (boolean) bTrackMouse Optional boolean to specify whether mouse movement should
 *                  also reposition the tooltip.  Default is true.
 * @param {string} borderColor Optional the border color of the tooltip
 *
 * @see hideTooltip()
 * @see showDatatip()
 */
DvtTooltipManager.prototype.showTooltip = function(x, y, text, component, bTrackMouse, borderColor)
{
  // TODO subclasses should override
};


/**
 * Hides the tooltip.
 */
DvtTooltipManager.prototype.hideTooltip = function()
{
  // TODO subclasses should override
};



/**
 * Interactivity handle for category rollover effects support.  
 * Objects must implement DvtLogicalObject and DvtCategoricalObject to be supported by this handler.
 * @class DvtCategoryRolloverHandler
 * @extends DvtObj
 * @constructor
 */
var DvtCategoryRolloverHandler = function() {};

DvtObj.createSubclass(DvtCategoryRolloverHandler, DvtObj, "DvtCategoryRolloverHandler");

/**
 * Processes the specified DvtCategoryRolloverEvent for the array of objects.
 * @param {DvtCategoryRolloverEvent} event The event that was triggered.
 * @param {array} objs The array of objects containing hide and show targets.
 */
DvtCategoryRolloverHandler.processEvent = function(event, objs, customAlpha)
{
  if(!event || !objs)
    return;
  
  var dimmedAlpha = !customAlpha ? 0.35 : customAlpha;
  var category = event.getCategory();
  var alpha = (event.getType() === DvtCategoryRolloverEvent.TYPE_OVER) ? dimmedAlpha : 1;
  
  // Loop through the objects and update objects not belonging to the specified
  // category.
  for(var i=0; i<objs.length; i++) {
    var obj = objs[i];
    if(obj && obj.getCategories && obj.getCategories().indexOf(category) < 0) {
      // Found a match, update the displayables
      var displayables = obj.getDisplayables(displayables);
      DvtCategoryRolloverHandler._updateAlpha(displayables, alpha);
    }
  }
};

/**
 * Updates the alpha of the displayables to the specified value.
 * @param {array} displayables The array of displayables.
 * @param {number} alpha The new alpha value.
 * @param {DvtAnimator} anim Optional animator.
 */
DvtCategoryRolloverHandler._updateAlpha = function(displayables, alpha, anim) {
  if(!displayables)
    return;

  var disp;
  for(var i=0; i<displayables.length; i++) {
    disp = displayables[i];
    if (anim) {
      anim.addProp(DvtAnimator.TYPE_NUMBER, disp, 
                   disp.getAlpha, disp.setAlpha, alpha);
    }
    else {
      disp.setAlpha(alpha);
    }
  }
}
/**
 * Interactivity handle for category hide and show support.  
 * Objects must implement DvtLogicalObject and DvtCategoricalObject to be supported by this handler.
 * @class DvtHideShowCategoryHandler
 * @extends DvtObj
 * @constructor
 */
var DvtHideShowCategoryHandler = function() {};

DvtObj.createSubclass(DvtHideShowCategoryHandler, DvtObj, "DvtHideShowCategoryHandler");

/**
 * Processes the specified DvtHideShowCategoryEvent for the array of objects.
 * @param {DvtHideShowCategoryEvent} event The event that was triggered.
 * @param {array} objs The array of objects containing hide and show targets.
 */
DvtHideShowCategoryHandler.processEvent = function(event, objs)
{
  if(!event || !objs)
    return;
    
  var category = event.getCategory();
  var bHide = (event.getType() === DvtHideShowCategoryEvent.TYPE_HIDE);
  
  // Loop through the objects and find the categorical matches
  for(var i=0; i<objs.length; i++) {
    var obj = objs[i];
    if(obj && obj.getCategories && obj.getCategories().indexOf(category) >= 0) {
      // Found a match, update the displayables
      var displayables = obj.getDisplayables(displayables);
      DvtHideShowCategoryHandler._updateVisible(displayables, !bHide);
    }
  }
};

/**
 * Updates the visibility of the displayables to the specified value.
 * @param {array} displayables The array of displayables.
 * @param {boolean} bVisible
 */
DvtHideShowCategoryHandler._updateVisible = function(displayables, bVisible) {
  if(!displayables)
    return;

  for(var i=0; i<displayables.length; i++) {
    displayables[i].setVisible(bVisible);
  }
}
/**
 * Event manager that processes low level events and sends them to the appropriate handlers.
 * @param {DvtContext} context The platform specific context object.
 * @param {function} callback A function that responds to component events.
 * @param {object} callbackObj The optional object instance that the callback function is defined on.
 * @class
 * @constructor
 */
var DvtEventManager = function(context, callback, callbackObj) {
  this.Init(context, callback, callbackObj);
}

DvtObj.createSubclass(DvtEventManager, DvtObj, "DvtEventManager");

DvtEventManager.CLEAR_SELECTION_ACTION_TYPE = "clearSelectionActionType";

/**
 * @protected
 */
DvtEventManager.prototype.Init = function(context, callback, callbackObj) {
  this._context = context;
  this._callback = callback;
  this._callbackObj = callbackObj;
  
  // Initialize the higher level event handlers.  These handlers are exposed as protected fields 
  // so that subclasses can fully customize the behavior of this event manager.     
  this.SelectionHandler = null; 
  this.ContextMenuHandler = null;
  this.MarqueeHandler = null;
  this.PopupHandler = new DvtPopupBehaviorHandler(context, callback, callbackObj);
  this.KeyboardHandler = null;
  
  // Tooltips enabled by default
  this.TooltipsEnabled = true;
  
  var id = context.getStage().getId();
  if (!id)
    id = "undefinedId";
  this.CustomTooltipManager = this._context.getCustomTooltipManager();
  this.CustomTooltipManager.addTooltipEventListener(DvtActionTooltipEvent.TOOLTIP_CLOSED_TYPE, this.OnActionTooltipClosed, this);
  this.CustomTooltipManager.addTooltipEventListener(DvtActionTooltipEvent.TOOLTIP_STARTED_TYPE, this.OnActionTooltipStarted, this);
      
  this.TouchManager = null;
  this._isMagnifyShown = false;
  
  // The DvtKeyboardNavigable item that currently has keyboard focus
  this._focusedObj = null;
  
  //BUG FIX #13376229: support for ignoring the next click after a mouse drag, 
  //so that panning Diagram doesn't change selection, for example
  this._bIgnoreClickAfterDrag = false;
  this._bMouseDown = false;
  this._bMouseDrag = false;
  this._bIgnoreNextClick = false;
  this._ignoreNextClickOffTimer = null;
}

/**
 * Returns the DvtContext associated with this event manager.
 * @return {DvtContext}
 */
DvtEventManager.prototype.getContext = function() {
  return this._context;
}

/**
 * Associates the specified displayable with the specified object for this event manager.  This is used by the default
 * implementation of GetLogicalObject.
 * @param {DvtDisplayable} displayable The displayable to associate.
 * @param {object} obj The object to associate with.
 */
DvtEventManager.prototype.associate = function(displayable, obj) {
  if(displayable) {
    // Create the logical objects array if not already present
    if(!displayable._logicalObjects)
      displayable._logicalObjects = [];
    
    // Add this logical object and event manager mapping
    displayable._logicalObjects.push({logicalObject:obj, eventManager: this});
    
    // Tooltip support for XML renderer
    if ((displayable.getContext() instanceof DvtXmlContext) && displayable.getImpl().setLogicalObj)
      displayable.getImpl().setLogicalObj(obj);
  }
}

/**
 * Adds event listeners to the specified displayable.
 * @param {DvtDisplayable} displayable The object on which to add the listeners.
 */
DvtEventManager.prototype.addListeners = function(displayable) {
  if(!displayable)
    return;

  if (DvtAgent.getAgent().isTouchDevice()) {
       // Remove any previous listeners by instantiating new touch manager
       this._context.initializeTouchManager();
       // Hide any tooltips previously shown
       this._processHideTooltip();       
       
       // Hide any magnify lens previously shown
       this._hideMagnify(); 

       this.TouchManager = this._context.getTouchManager();

       displayable.addEventListener('touchstart', this.OnTouchStartBubble, false, this);
       displayable.addEventListener('touchmove', this.OnTouchMoveBubble, false, this);
       displayable.addEventListener('touchend', this.OnTouchEndBubble, false, this);
       
       displayable.addEventListener('touchstart', this.OnTouchStartCapture, true, this);
       displayable.addEventListener('touchmove', this.OnTouchMoveCapture, true, this);
       displayable.addEventListener('touchend', this.OnTouchEndCapture, true, this);

       this.TouchManager.addTouchEventListener(DvtComponentTouchEvent.TOUCH_HOVER_START_TYPE, this.OnTouchHoverStart, this);
       this.TouchManager.addTouchEventListener(DvtComponentTouchEvent.TOUCH_HOVER_MOVE_TYPE, this.OnTouchHoverMove, this);
       this.TouchManager.addTouchEventListener(DvtComponentTouchEvent.TOUCH_HOVER_END_TYPE, this.OnTouchHoverEnd, this);
       this.TouchManager.addTouchEventListener(DvtComponentTouchEvent.TOUCH_HOVER_OUT_TYPE, this.OnTouchHoverOut, this);
       this.TouchManager.addTouchEventListener(DvtComponentTouchEvent.TOUCH_HOVER_OVER_TYPE, this.OnTouchHoverOver, this);

       this.TouchManager.addTouchEventListener(DvtComponentTouchEvent.TOUCH_CLICK_TYPE, this.OnTouchClick, this);
       this.TouchManager.addTouchEventListener(DvtComponentTouchEvent.TOUCH_DOUBLE_CLICK_TYPE, this.OnTouchDblClick, this);
  } else {
      displayable.addEventListener('click', this.PreOnClick, false, this);
      displayable.addEventListener('dblclick', this.OnDblClick, false, this);
      displayable.addEventListener('contextmenu', this.OnContextMenu, false, this);
      displayable.addEventListener('mousemove',   this.OnMouseMove, false, this);
      displayable.addEventListener('mouseover',   this.OnMouseOver, false, this);
      displayable.addEventListener('mouseout',    this.OnMouseOut, false, this);
      displayable.addEventListener('mousedown',   this.OnMouseDown, false, this);
      displayable.addEventListener('mouseup',     this.OnMouseUp, false, this);
      displayable.addEventListener('keydown',     this.OnKeyDown, false, this);
      displayable.addEventListener('keyup',       this.OnKeyUp, false, this);
  }
}


/**
 * Removes event listeners from the specified displayable.
 * @param {DvtDisplayable} displayable The object on which to remove the listeners.
 */
DvtEventManager.prototype.removeListeners = function(displayable)
{
  if(!displayable)
    return;

  if (DvtAgent.getAgent().isTouchDevice()) {
       // Remove any previous listeners by instantiating new touch manager
       this._context.initializeTouchManager();
       // Hide any tooltips previously shown
       this._processHideTooltip();       
       
       // Hide any magnify lens previously shown
       this._hideMagnify(); 

       displayable.removeEventListener('touchstart', this.OnTouchStartBubble, false, this);
       displayable.removeEventListener('touchmove', this.OnTouchMoveBubble, false, this);
       displayable.removeEventListener('touchend', this.OnTouchEndBubble, false, this);
       
       displayable.removeEventListener('touchstart', this.OnTouchStartCapture, true, this);
       displayable.removeEventListener('touchmove', this.OnTouchMoveCapture, true, this);
       displayable.removeEventListener('touchend', this.OnTouchEndCapture, true, this);  
  } else {
      displayable.removeEventListener('click', this.PreOnClick, false, this);
      displayable.removeEventListener('dblclick', this.OnDblClick, false, this);
      displayable.removeEventListener('contextmenu', this.OnContextMenu, false, this);
      displayable.removeEventListener('mousemove',   this.OnMouseMove, false, this);
      displayable.removeEventListener('mouseover',   this.OnMouseOver, false, this);
      displayable.removeEventListener('mouseout',    this.OnMouseOut, false, this);
      displayable.removeEventListener('mousedown',   this.OnMouseDown, false, this);
      displayable.removeEventListener('mouseup',     this.OnMouseUp, false, this);
      displayable.removeEventListener('keydown',     this.OnKeyDown, false, this);
      displayable.removeEventListener('keyup',       this.OnKeyUp, false, this);
  }
  
}

/*---------------------------------------------------------------------*/
/*    destroy()                                                        */
/*---------------------------------------------------------------------*/
/*
 *    Releases all resources owned to prevent memory leaks.
 */
DvtEventManager.prototype.destroy = function()
{   
  if(this.CustomTooltipManager) 
  {
    this.CustomTooltipManager.removeTooltipEventListener(DvtActionTooltipEvent.TOOLTIP_CLOSED_TYPE, this.OnActionTooltipClosed, this);
    this.CustomTooltipManager.removeTooltipEventListener(DvtActionTooltipEvent.TOOLTIP_STARTED_TYPE, this.OnActionTooltipStarted, this);  
  }  
}


DvtEventManager.prototype.OnTouchStartCapture = function(event) {
    this.TouchManager.preEventBubble(event);
}

DvtEventManager.prototype.OnTouchMoveCapture = function(event) {
    this.TouchManager.preEventBubble(event);
}

DvtEventManager.prototype.OnTouchEndCapture = function(event) {
    this.TouchManager.preEventBubble(event);
}

/**
 * Sets the selection handler to use with this event manager.
 * @param {DvtSelectionHandler} handler The selection handler to use.
 */
DvtEventManager.prototype.setSelectionHandler = function(handler) {
  this.SelectionHandler = handler;
}

/**
 * Sets the marquee handler to use with this event manager.
 * @param {DvtMarqueeHandler} handler The marquee handler to use.
 */
DvtEventManager.prototype.setMarqueeHandler = function(handler) {
  this.MarqueeHandler = handler;
}

/**
 * Sets the drag source to use with this event manager.
 * @param {DvtDragSource} dragSource The drag source to use
 */
DvtEventManager.prototype.setDragSource = function(dragSource) {
  this.DragSource = dragSource;
}

/**
 * Sets the context menu handler to use with this event manager.
 * @param {DvtContextMenuHandler} handler The context menu handler to use.
 */
DvtEventManager.prototype.setContextMenuHandler = function(handler) {
  this.ContextMenuHandler = handler;
}

/**
 * Sets the keyboard handler to use with this event manager.
 * @param {DvtKeyboardHandler} handler The keyboard handler to use.
 */
DvtEventManager.prototype.setKeyboardHandler = function(handler) 
{
  this.KeyboardHandler = handler;
}

/**
 * Returns the keyboard handler used by this event manager
 * @return {DvtKeyboardHandler}
 */
DvtEventManager.prototype.getKeyboardHandler = function()
{
  return this.KeyboardHandler;  
}


/**
 * Sets the event manager's keyboard focus on the given DvtKeyboardNavigable
 * @param {DvtKeyboardNavigable} navigable The DvtKeyboardNavigable to receive keyboard focus
 */
DvtEventManager.prototype.setFocus = function(navigable)
{
  this._focusedObj = navigable;
}

/**
 * Returns the DvtKeyboardNavigable item with the current keyboard focus
 * @return {DvtKeyboardNavigable} The DvtKeyboardNavigable with the current keyboard focus
 */
DvtEventManager.prototype.getFocus = function()
{
  return this._focusedObj;
}


/**
 * Updates the view when the owning component receives keyboard focus 
 */
DvtEventManager.prototype.setFocused = function(isFocused)
{  
  var navigable = this.getFocus();
  if(navigable)
  {
    if(isFocused)
      navigable.showKeyboardFocusEffect();
    else
      navigable.hideKeyboardFocusEffect();
  }
    
}

DvtEventManager.prototype.setTooltipsEnabled = function(tooltipsEnabled) {
  this.TooltipsEnabled = tooltipsEnabled;
}

DvtEventManager.prototype.setCustomTooltipStyle = function(tooltipFill, tooltipFont) {
  if (this.CustomTooltipManager) {
      var actionTooltip = this.CustomTooltipManager.getActionTooltip();
      if (actionTooltip) {
        if (tooltipFill)
            actionTooltip.setTooltipFill(tooltipFill);
        if (tooltipFont) {
            actionTooltip.setFont(tooltipFont);
            actionTooltip.setMenuFontSize(tooltipFont.size);    
        }
      }
  }
}

/**
 * Returns the logical object corresponding to the specified DvtDisplayable.  All high level event handlers,
 * such as the selection and popup handlers, are designed to react to the logical objects.
 * @param {DvtDisplayable} target The displayable.
 * @return {object} The logical object corresponding to the target.
 * @protected
 */
DvtEventManager.prototype.GetLogicalObject = function(target) {
  var displayable = target;
  while (displayable) {
    if(displayable._logicalObjects) {
      for(var i=0; i<displayable._logicalObjects.length; i++) {
        var mapping = displayable._logicalObjects[i];
        if(mapping.eventManager == this)
          return mapping.logicalObject;
      }
    }
    
    displayable = displayable.getParent();
  }
}

/**
 * Returns the array of showPopupBehaviors for a specified logical object.
 * @param {object} obj The logical target object.
 * @return {array} The array of applicable DvtShowPopupBehaviors
 * @private
 */
DvtEventManager.prototype._getShowPopupBehaviors = function(obj) {
  if(obj && obj.getShowPopupBehaviors)
    return obj.getShowPopupBehaviors();
}

/**
 * Returns the menu type to display.
 * @return {object} The menu type to pass into the context menu handler.
 * @protected
 */
DvtEventManager.prototype.GetContextMenuType = function() {
  // Figure out the selection size, which determines which menu to display
  var selectionSize = this.SelectionHandler ? this.SelectionHandler.getSelection().length : 0;
  if(selectionSize <= 0)
    return DvtContextMenuHandler.TYPE_BODY_CONTEXT_MENU;
  else if(selectionSize == 1)
    return DvtContextMenuHandler.TYPE_CONTEXT_MENU;
  else
    return DvtContextMenuHandler.TYPE_MULTI_SELECT_CONTEXT_MENU;
}

/**
 * Returns the id of the specific context menu to display for the specified logical object.
 * @param {object} obj The logical object
 * @return {object} The menu id to pass into the context menu handler.
 * @private
 */
DvtEventManager.prototype._getContextMenuId = function(obj) {
  if(obj && obj.getContextMenuId)
    return obj.getContextMenuId();
}

/**
 * Returns the tooltip color for the specified object.
 * @param {object} obj The logical object.
 * @param {number} x The relative x coordinate of the event
 * @param {number} y The relative y coordinate of the event
 */
DvtEventManager.prototype.GetTooltipColor = function(obj, x, y) {
  if(obj && obj.getDatatipColor)
    return obj.getDatatipColor();
}

/**
 * Fires the specified event through the callback.
 * @param {object} event
 * @param {object} source The component that is the source of the event, if available.
 */
DvtEventManager.prototype.FireEvent = function(event, source) {
  if(this._callback)
    this._callback.call(this._callbackObj, event, source);
}

/**
 * Fires a selection event with the current selection state.
 * @private
 */
DvtEventManager.prototype._fireSelectionEvent = function() {
  if(!this.SelectionHandler)
    return;
    
  // Convert the array of selected objects into an array of selected ids
  var selectedObjs = this.SelectionHandler.getSelection();
  var selectedIds = new Array();
  for(var i=0; i<selectedObjs.length; i++)
    selectedIds.push(selectedObjs[i].getId());

  // Create and fire the event
  var selectionEvent = new DvtSelectionEvent(selectedIds);
  this._callback.call(this._callbackObj, selectionEvent);
}

//*******************************************************************************//
//*********************** Begin Event Listeners *********************************//
//*******************************************************************************//

/**
 * Click event handler that accounts for double clicks
 * @protected
 */
DvtEventManager.prototype.PreOnClick = function(event) {
  //BUG FIX #13376229: if ignoring the next click, toggle the flag and return
  if (this._bIgnoreClickAfterDrag && this.IsIgnoreNextClick()) {
    //turn off the flag
    this.SetIgnoreNextClick(false);
    return;
  }
  
  var obj = this.GetLogicalObject(event.target);
  if (!obj) {
    this.OnClick(event);
  }
  else {
    if (obj.isDoubleClickable && obj.isDoubleClickable()) {

      if (this._clickTimer && this._clickTimer.isRunning()) {
        var clickEvent = this._savedClickEvent;
        if (event.pageX == clickEvent.pageX && event.pageY == clickEvent.pageY) {
          // Same coords, this is a double click, so ignore second click event
          return;
        }
        else {
          // Different coords, so need to process first event
          this._clickTimer.stop();
          this._onClickTimerEnd();
        }
      }
      this._savedClickEvent = event;
      if (!this._clickTimer) {
        this._clickTimer = new DvtTimer(this._context, 250, this._onClickTimerEnd, this, 1);
      }
      this._clickTimer.reset();
      this._clickTimer.start()
    }
    else {
      this.OnClick(event);
    }
  }
}

DvtEventManager.prototype._onClickTimerEnd = function() {
  var clickEvent = this._savedClickEvent;
  this._savedClickEvent = null;
  if (clickEvent) {
    this.OnClick(clickEvent);
  }  
}


/**
 * Click event handler.
 * @protected
 */
DvtEventManager.prototype.OnClick = function(event) {
  var obj = this.GetLogicalObject(event.target);
  
  this.OnClickInternal(event);
  
  this._processSelectionEventHelper(obj, event.ctrlKey);
  
  var curFocus = this.getFocus();

  // Done if there is no object
  if(! obj)
  {
    // show the keyboard focus effect on the item with current keyboard focus, 
    // if we clicked on empty space in the component
    if(curFocus)
      curFocus.showKeyboardFocusEffect();
    
    return;
  }
  
  // BUGFIX 13263165 and 13377513 - update the keyboard focus on mouse click
  if(obj.getNextNavigable)  
  {
    var nextFocus = obj.getNextNavigable(event);
    this.setFocus(nextFocus);
    
    curFocus.hideKeyboardFocusEffect();
    nextFocus.showKeyboardFocusEffect();
  }

  // Popup Support for triggerType="click"
  var consumed = false;
  var behaviors = this._getShowPopupBehaviors(obj);
  if(behaviors) {
    var position = new DvtPoint(event.pageX, event.pageY);
    consumed = this.PopupHandler.processClick(obj, behaviors, position);
  }

  // fire an Action event if logical obj is a command component
  if (! consumed && obj.isCommandComponent && obj.isCommandComponent()) {
    // Create the action event
    var event = new DvtActionEvent(DvtActionEvent.SUBTYPE_ACTION, obj.getId());

    // add the component specific context
    DvtEventManager._addContextInfo(obj, event);

    // fire the action event
    this._callback.call(this._callbackObj, event);
  }
}

/**
 * Helper function to process selection events
 * @param {DvtLogicalObject} logicalObj The logical object to process selection on
 * @param {Boolean} isMultiSelect True if we are performing multi-select
 * @private 
 */
DvtEventManager.prototype._processSelectionEventHelper = function(logicalObj, isMultiSelect)
{
  // Selection Support
  if(this.SelectionHandler) {
    var bSelectionChanged = this.SelectionHandler.processClick(logicalObj, isMultiSelect);
    // If the selection has changed, fire an event
    if(bSelectionChanged) 
      this._fireSelectionEvent();
  }  
}

/**
 * Double click event handler.
 * @protected
 */
DvtEventManager.prototype.OnDblClick = function(event) {
  if (this._clickTimer && this._clickTimer.isRunning()) {
    this._clickTimer.stop();
    this._savedClickEvent = null;
  }
  else {
    if (DvtAgent.getAgent().getPlatform() == DvtAgent.IE_PLATFORM) {
      var obj = this.GetLogicalObject(event.target);
      if (!obj.isDoubleClickable || !obj.isDoubleClickable()) {
        // Need to turn this into a single click for IE which only sends out click,dblclick upon a double-click rather
        // than the click,click,dblclick sent out by other browsers
        this.OnClick(event);
        return;
      }
    }
  }
}

/**
 * Context Menu event handler.
 * @protected
 */
DvtEventManager.prototype.OnContextMenu = function(event) {
  var obj = this.GetLogicalObject(event.target);
  this._onContextMenuHelper(event, obj);
}

/**
 * Helper method that does the bulk of the context menu handling
 * 
 * @param {DvtMouseEvent} event
 * @param {Object} obj  The logical object on which the mouse event was fired
 */
DvtEventManager.prototype._onContextMenuHelper = function(event, obj)
{
  this.OnContextMenuInternal(event);
  var popupLaunched = this._processActionPopup(event.target,  new DvtPoint(event.pageX, event.pageY));
  if (popupLaunched)
    event.preventDefault();
    
  this._processSelectionEventHelper(obj, event.ctrlKey);
  
  // Context Menu Support
  if(this.ContextMenuHandler) {
    var menuType = this.GetContextMenuType();
    var menuId = this._getContextMenuId(obj);
    this.ContextMenuHandler.prepareMenuItems(event, menuType, menuId);
    var contextMenuEvent = this.ContextMenuHandler.show(event, menuType, menuId); 
    if(contextMenuEvent) {
      // Hide the tooltip before displaying the menu
      this._context.getTooltipManager().hideTooltip();
    
      // Request the context menu be displayed
      this._callback.call(this._callbackObj, contextMenuEvent);
    }
  }  
}

/**
 * Keypress down event handler.  Delegates to keyboard handler, if set
 * @param {DvtKeyboardEvent} event
 * @protected
 */
DvtEventManager.prototype.OnKeyDown = function(event) 
{  
  if(!this.KeyboardHandler)
    return;
  
  // clear tooltip if one is shown; tooltip can be shown if mouse is used to make a selection
  // and then we use the keyboard to navigate from the mouse-selected item
  this._processHideTooltip();
  
  var currentNavigable = this.getFocus();
  var nextNavigable = null;
  
  if(currentNavigable && this.KeyboardHandler.isContextMenuEvent(event))
  {
    var contextMenuLocation;
    
    if(currentNavigable.getContextMenuLocation)
    {
      contextMenuLocation = currentNavigable.getContextMenuLocation();      
    }
    else
    {
      var bounds = currentNavigable.getKeyboardBoundingBox();
      // adjust location for bidi; use top left corner for bidi, top right corner for non-bidi, 
      if(DvtStyleUtils.isLocaleR2L())
        contextMenuLocation = new DvtPoint(bounds.x, bounds.y);        
      else
        contextMenuLocation = new DvtPoint(bounds.x+bounds.w, bounds.y);
    }
  
    var mouseEvent = this.GenerateMouseEventFromKeyboardEvent(event, this._context.getStage(), contextMenuLocation.x, contextMenuLocation.y);
    // OnContextMenu checks for ctrlKey to perform multi-select before showing context menu
    // However, the keystroke combination for showing the context menu is Ctrl+Alt+M
    // CLEAR the ctrlKey field so that multi-select isn't performed, and send OnContextMenu
    // a mouse event that is equivalent to right-clicking on the navigable with keyboard focus
    // With the mouse, a user could Ctrl+right click a navigbale to multi-select it and then bring up the
    // context menu.  In the keyboard case, the user would first have to multi-select and then bring up the 
    // context menu, in two separate keystrokes
    mouseEvent.ctrlKey = false; 
    this._onContextMenuHelper(mouseEvent, currentNavigable);
    return;
  }

  nextNavigable = this.KeyboardHandler.processKeyDown(event);

  if(nextNavigable)
  {
    currentNavigable.hideKeyboardFocusEffect();
    if(this.KeyboardHandler.isSelectionEvent(event))
      this._processSelectionEventHelper(nextNavigable, event.shiftKey);
    else if(this.KeyboardHandler.isMultiSelectEvent(event))
      this._processSelectionEventHelper(nextNavigable, event.ctrlKey);
    nextNavigable.showKeyboardFocusEffect();    
  }
}


/**
 * Returns a DvtMouseEvent that wraps the given keyboard event.  The given stageX and stageY coordinates are used to
 * compute the DvtMouseEvent's pageX and pageY fields
 * 
 * @param {DvtKeyboardEvent} event
 * @param {DvtStage} stage
 * @param {Number} stageX
 * @param {Number} stageY
 * @return {DvtMouseEvent}
 * @protected
 */
DvtEventManager.prototype.GenerateMouseEventFromKeyboardEvent = function(event, stage, stageX, stageY)
{
  var dvtMouseEvent = null;
  
  if(this._context.isPlatformSvg())
  {    
    dvtMouseEvent = DvtSvgEventFactory.generateMouseEventFromKeyboardEvent(event, this._context, "click", stage, stageX, stageY);
  }
  
  // TODO: support other platforms
  return dvtMouseEvent;
}


/**
 * Keypress up event handler.  Empty implementation; subclasses will need to add their own implementation
 * @param {Object} event
 * @protected
 */
DvtEventManager.prototype.OnKeyUp = function(event) {  }

/**
 * Mouse Move event handler
 * @protected
 */
DvtEventManager.prototype.OnMouseMove = function(event) {
  //BUG FIX #13376229: maintain flag indicating if the mouse is dragged
  if (this._bIgnoreClickAfterDrag && this._bMouseDown) {
    this._bMouseDrag = true;
  }
  
  var target = event.target;
  var obj = this.GetLogicalObject(target);
  
  // Return if no object is found
  if(!obj)
    return;
    
  var pageX = event.pageX;
  var pageY = event.pageY;
  var relPos = this._context.getRelativePosition(pageX, pageY);

  if (this.IsTooltipShowable(obj, relPos)) {
      // Show and move the tooltip
      this._processShowTooltip(target, obj, pageX, pageY);
  } else {
      this._processHideTooltip();
  }

  var position = new DvtPoint(event.pageX, event.pageY);
  // Notify the popup handler of the mouse move
  this.PopupHandler.processMouseMove(position);

  if (this.MarqueeHandler) {
      var handled = this.MarqueeHandler.processDragMove(relPos);
      if (handled)
        event.preventDefault();
  }

}
    
/**
 * Mouse Over event handler
 * @protected
 */
DvtEventManager.prototype.OnMouseOver = function(event) {
  var obj = this.GetLogicalObject(event.target);
  var position = new DvtPoint(event.pageX, event.pageY);
  
  // Return if no object is found
  if(!obj)
    return;
    
  // Selection Support
  if(this.SelectionHandler)
    this.SelectionHandler.processMouseOver(obj);

  // Popup Support for triggerType="hover"
  var behaviors = this._getShowPopupBehaviors(obj);
  if(behaviors)
    this.PopupHandler.processMouseOver(obj, behaviors, position);
}

/**
 * Mouse Out event handler
 * @protected
 */
DvtEventManager.prototype.OnMouseOut = function(event) {
  var obj = this.GetLogicalObject(event.target);
    
  // Return if no object is found
  if(!obj)
    return;
  
  var relatedObj = this.GetLogicalObject(event.relatedTarget);
  if(obj == relatedObj)
    return; // not a mouse out if they correspond to the same object
  
  // Selection Support
  if(this.SelectionHandler) 
  {
    this.SelectionHandler.processMouseOut(obj);
        
    // some components may use the hover effect to indicate keyboard focus as well.
    // in these cases, do not remove the visual effect when we mouse out of the target
    // with keyboard focus
    if(obj === this.getFocus())
    {
      obj.showKeyboardFocusEffect();
    }
  }
  
  // Bug #12957574: If the mouse has moved off the component, hide the tooltip  
  this._processHideTooltip();
  
  // Popup Support for triggerType="hover"
  this.PopupHandler.processMouseOut(obj);
}

/**
 * Mouse Down event handler
 * @protected
 */
DvtEventManager.prototype.OnMouseDown = function(event) {
  //BUG FIX #13376229: maintain flag indicating if the mouse down
  if (this._bIgnoreClickAfterDrag) {
    this._bMouseDown = true;
  }
  
  var obj = this.GetLogicalObject(event.target);
  var relPos = this._context.getRelativePosition(event.pageX, event.pageY);

  var isPopup = this.isInActionPopup();
  if (isPopup) {
    this.CustomTooltipManager.closeActionTooltip();
  }
  
  if (this.MarqueeHandler) {
    var handled = this.MarqueeHandler.processDragStart(relPos, obj);
    if (handled)
      event.preventDefault();
  }
  
   // Drag and Drop Support
  if(this.DragSource)
    this.DragSource.setDragCandidate(obj);
}

/**
 * Mouse Up event handler
 * @protected
 */
DvtEventManager.prototype.OnMouseUp = function(event) {
  //BUG FIX #13376229: maintain flag indicating if we should ignore the
  //next click event because the mouse was dragged
  if (this._bIgnoreClickAfterDrag && this._bMouseDown && this._bMouseDrag) {
    //turn on the flag
    this.SetIgnoreNextClick(true);
  }
  this._bMouseDown = false;
  this._bMouseDrag = false;
  
  var relPos = this._context.getRelativePosition(event.pageX, event.pageY);
  if (this.MarqueeHandler)
    this.MarqueeHandler.processDragEnd(relPos);

  // no default behavior, subclasses can override
}

// Shows multi-touch tooltips.
DvtEventManager.prototype._processMultiTouchTooltip = function() {
    var tooltipInfoObj = this.TouchManager.getTooltipInfo();
    var touchIds = tooltipInfoObj.touchIds;
    var tooltipTarget = tooltipInfoObj.tooltipTarget;

    // If no hints are there, hide the tooltip
    if (touchIds.length == 0 || !tooltipTarget) {
        this._processHideTooltip();
        return;
    }
    
    var avgPos = this.TouchManager.calcAveragePosition(touchIds);
    var obj = this.GetLogicalObject(tooltipTarget);
    this._processObjectTooltip(avgPos.x, avgPos.y, obj, null);
}

/**
 * Get the timer to turn off the flag to ignore the next mouse click.
 * @protected
 */
DvtEventManager.prototype.GetIgnoreNextClickOffTimer = function () {
  if (!this._ignoreNextClickOffTimer) {
    this._ignoreNextClickOffTimer = new DvtTimer(this._context, 500, this.HandleIgnoreNextClickOffTimer, this, 1);
  }
  
  return this._ignoreNextClickOffTimer;
};

/**
 * Handle an event from the timer to turn off the flag to ignore the
 * next mouse click.  
 * @protected
 */
DvtEventManager.prototype.HandleIgnoreNextClickOffTimer = function (event) {
  //turn off the flag
  this.SetIgnoreNextClick(false);
};

/**
 * Set the flag to ignore the next mouse click.
 * @protected
 */
DvtEventManager.prototype.SetIgnoreNextClick = function(bIgnoreNextClick) {
  this._bIgnoreNextClick = bIgnoreNextClick;
  
  //if turning on the flag, start the timer to shut it off
  //automatically in case a mouse click is not registered
  //immediately
  if (bIgnoreNextClick)
  {
    this.GetIgnoreNextClickOffTimer().reset();
    this.GetIgnoreNextClickOffTimer().start();
  }
  //if turning off the flag, stop the auto-off timer
  else
  {
    if (this.GetIgnoreNextClickOffTimer().isRunning())
      this.GetIgnoreNextClickOffTimer().stop();
  }
};

/**
 * Determine if the flag to ignore the next mouse click is set.
 * @protected
 */
DvtEventManager.prototype.IsIgnoreNextClick = function() {
  return this._bIgnoreNextClick;
};

/**
 * Touch Start event handler
 * @protected
 */
DvtEventManager.prototype.OnTouchStartBubble = function(event) {

    if (event.isInitialTouch()) {
      this._popupJustClosed = false;
    }

    // Drag and Drop Support
    if(this.DragSource) {
        var obj = this.GetLogicalObject(event.target);
        this.DragSource.setDragCandidate(obj);
    }

    var isPopup = this.isInActionPopup();
    // Action popups block other types of interactions
    if (isPopup) {
       this.CustomTooltipManager.closeActionTooltip();
       this.TouchManager.resetTouchHold();
    }
    this.HandleImmediateTouchStartInternal(event);
    this.TouchManager.fireLogicalEvents(event);
    this.TouchManager.postEventBubble(event);
    
    this._processMultiTouchTooltip();
}
/**
 * Touch Move event handler
 * @protected
 */
DvtEventManager.prototype.OnTouchMoveBubble = function(event) {
  if (this.TouchManager) {
        this._prevActionClear = false;
    
        this.HandleImmediateTouchMoveInternal(event);
        this.TouchManager.fireLogicalEvents(event);
        this.TouchManager.postEventBubble(event);

        this._processMultiTouchTooltip();
    }
}

/*
 * Timeout needed to put touch end after an attempt to touch & hold
 */
DvtEventManager.prototype._handleTouchEndTimer = function() {    
    for (var i=0;i<this._touchEndTimer.length;i++) {
        var timerObj = this._touchEndTimer[i];
        timerObj["timer"].stop();
        var event = timerObj["event"];
        if (this.TouchManager) {
            this.HandleImmediateTouchEndInternal(event);
            this.TouchManager.fireLogicalEvents(event);
            this.TouchManager.postEventBubble(event);
        }
    }
    this._touchEndTimer = new Array();
}
/**
 * Touch End event handler
 * @protected
 */
DvtEventManager.prototype.OnTouchEndBubble = function(event) {    
   var timer = new DvtTimer(this._context, 0, this._handleTouchEndTimer, this, 1);
   if (!this._touchEndTimer)
    this._touchEndTimer = new Array();
   this._touchEndTimer.push({"event": event, "timer": timer});
   timer.start();
}

DvtEventManager.prototype.HandleImmediateTouchStartInternal = function(event) {
}

DvtEventManager.prototype.HandleImmediateTouchMoveInternal = function(event) {
}

DvtEventManager.prototype.HandleImmediateTouchEndInternal = function(event) {
}

DvtEventManager.prototype.OnTouchHoverStart = function(event) {
    var targetObj = event.targetObj;
    var obj = this.GetLogicalObject(targetObj);
    var touch = event.touch;
    var touchX = touch.pageX;
    var touchY = touch.pageY;
    var relPos = this._context.getRelativePosition(touchX, touchY);
      
    this.UpdateTouchHoverFeedback(targetObj);

    var magnifyShown = this.ProcessMagnifyStart(new DvtPoint(touchX, touchY), obj);

    this.HandleTouchHoverStartInternal(event);
        
    this._processMultiTouchTooltip();
  
    this._prevActionClear = false;
}

DvtEventManager.prototype.OnTouchHoverMove = function(event) {
    var targetObj = event.targetObj;
    var touch = event.touch;
    var touchX = touch.pageX;
    var touchY = touch.pageY;
    var relPos = this._context.getRelativePosition(touchX, touchY);
    var obj = this.GetLogicalObject(targetObj);
    
    this.UpdateTouchHoverFeedback(targetObj);

    var magnifyShown = this.ProcessMagnify(new DvtPoint(touchX, touchY), obj);
 
    this.HandleTouchHoverMoveInternal(event);
    
    var position = new DvtPoint(touch.pageX, touch.pageY);
    // Notify the popup handler of the mouse move
    this.PopupHandler.processMouseMove(position);

}

DvtEventManager.prototype.OnTouchHoverEnd = function(event) {
    var targetObj = event.targetObj;
    var obj = this.GetLogicalObject(targetObj);
    var touch = event.touch;

    this._hideMagnify();

    this.HandleTouchHoverEndInternal(event);

    if (obj && obj.isSelected && obj.isSelected()) {
        // Don't de-select on touch hover 
    } else {
        this._processTouchSelection(obj, event._isCancelEvent, false);
    }

    this._processTouchContextMenu(event, obj);

    this._processActionPopup(targetObj, new DvtPoint(touch.pageX, touch.pageY));

}

DvtEventManager.prototype.OnTouchHoverOut = function(event) {
  var targetObj = event.targetObj;
  var obj = this.GetLogicalObject(targetObj);

  this.HandleTouchHoverOutInternal(event);

  if(this.SelectionHandler)
    this.SelectionHandler.processMouseOut(obj);

  // Popup Support for triggerType="hover"
  this.PopupHandler.processMouseOut(obj);
}

DvtEventManager.prototype.OnTouchHoverOver = function(event) {
  var targetObj = event.targetObj;
  var obj = this.GetLogicalObject(targetObj);
 
  var touch = event.touch;
  var position = new DvtPoint(touch.pageX, touch.pageY);
  
  this.HandleTouchHoverOverInternal(event);

  if(this.SelectionHandler)
    this.SelectionHandler.processMouseOver(obj);
  // Popup Support for triggerType="hover"
  var behaviors = this._getShowPopupBehaviors(obj);
  if(behaviors)
    this.PopupHandler.processMouseOver(obj, behaviors, position);
}

DvtEventManager.prototype.OnTouchDblClick = function(event) {
}

DvtEventManager.prototype.OnTouchClick = function(event) {
    var targetObj = event.targetObj;        
    var touch = event.touch;
    var dlo = this.GetLogicalObject(targetObj);
    var position = new DvtPoint(touch.pageX, touch.pageY);
    // Popup Support for triggerType="click"
    var behaviors = this._getShowPopupBehaviors(dlo);
    if(behaviors)
        this.PopupHandler.processClick(dlo, behaviors, position);
    var done = this.HandleTouchClickInternal(event);
    if (done)
        return;
        
    this._processTouchSelection(dlo, this._popupJustClosed, true);

    if (this.CustomTooltipManager.displayActionPopup()) {
        this.UpdateActionTooltipLaunchedFeedback(targetObj, new DvtPoint(touch.pageX, touch.pageY));
        this.CustomTooltipManager.startActionPopupAtPosition(touch.pageX, touch.pageY, targetObj);   
    }
        
}

DvtEventManager.prototype._processTouchSelection = function(dlo, preventClear, isTap) {
    var bSelectionChanged = false;
    if (this.SelectionHandler) {
        if (!dlo || !dlo.isSelectable || !dlo.isSelectable()) {
            if (!preventClear && !this._prevActionClear) {
                // Don't ask for clear selection if popup just closed  
                var showClearDialog = false;
                var allowClear = false;
                // There are two different policies for the clear selection dialog
                // 1) If a tap, show clear selection only for multiple selection when more than 1 is selected
                // 2) If a touch and hold + release, don't attempt a clear or perform a  clear
                if (isTap) {
                    allowClear = true;
                    if (this.isClearMenuAllowed()) {
                        var selType = this.SelectionHandler.getType();
                        if (selType == DvtSelectionHandler.TYPE_MULTIPLE) {
                            if (this.SelectionHandler.getSelectedCount() > 1) {
                                showClearDialog = true;
                            }
                        }
                    }
                }
                if (allowClear) {
                  if (showClearDialog) {
                    this.addClearAllActionItem();
                  } else {
                    bSelectionChanged = this.SelectionHandler.processClick(null, false);
                    // If the selection has changed, fire an event
                    if(bSelectionChanged) 
                      this._fireSelectionEvent();
                }
              }
            }
        } else {
            // Process click immediately
            bSelectionChanged = this.SelectionHandler.processClick(dlo, true);
            // If the selection has changed, fire an event
            if(bSelectionChanged) 
              this._fireSelectionEvent();
        }
    }
    this._prevActionClear = false;
}

DvtEventManager.prototype.OnActionTooltipClosed = function(event) {
    var targetObj = event.targetObj;
    var dlo = this.GetLogicalObject(targetObj);
    
    this._popupJustClosed = true;
    this._isInActionPopup = false;     
    var actionPopup =  this.CustomTooltipManager.getActionTooltip();

    if (actionPopup.containsMenuId(DvtEventManager.CLEAR_SELECTION_ACTION_TYPE)) {
        this._prevActionClear = true;
    }
    this.CustomTooltipManager.clearActionTooltip();

    // end start
    this.UpdateActionTooltipClosedFeedback(targetObj);
}

DvtEventManager.prototype.OnActionTooltipStarted = function(event) {
    this._isInActionPopup = true;
}

//*******************************************************************************//
//************************* End Event Listeners *********************************//
//*******************************************************************************//
/*
 * Touch-related actions
 */

DvtEventManager.prototype._processObjectTooltip = function(touchX, touchY, obj, targetObj) {
    this._processShowTooltip(targetObj, obj, touchX, touchY);
}

DvtEventManager.prototype._getTooltipInfo = function(target, obj, x, y) {
    var text = null;
    var isDatatip = false;
    if (obj && obj.getDatatip) {
        text = obj.getDatatip(target, x, y);
        if (text)
            isDatatip = true;
    }

    if(!text && obj && obj.getTooltip) {
       text = obj.getTooltip(target, x, y);

    }
    return {"text" : text, "isDatatip": isDatatip};
}

DvtEventManager.prototype._processShowTooltip = function(target, obj, pageX, pageY) {
  if (this.TooltipsEnabled) {
      var relPos = this._context.getRelativePosition(pageX, pageY);
      var x = relPos.x;
      var y = relPos.y;
      
      var tooltipInfo = this._getTooltipInfo(target, obj, x, y);
      var isDatatip = tooltipInfo["isDatatip"];
      var text = tooltipInfo["text"];
      if(text) {
        this.CustomTooltipManager.clearActionTooltip();
        var borderColor = this.GetTooltipColor(obj, x, y);
        if (this._isMagnifyShown) {
            this.CustomTooltipManager.showMagnifyDatatip(pageX, pageY, text, borderColor);
        } else {
            var ttm = this._context.getTooltipManager();
            if (isDatatip) {
                ttm.showDatatip(pageX, pageY, text, borderColor);
            } else {
                ttm.showTooltip(pageX, pageY, text, null, true, borderColor);
            }
        }
        this.TooltipLaunched(text, borderColor);
    
      } else {
        this._processHideTooltip();
      }
  } else {
      this._processHideTooltip();
  }

}

DvtEventManager.prototype._processHideTooltip = function() {
    var tooltipManager = this._context.getTooltipManager();
    tooltipManager.hideTooltip();
    
    if (this._isMagnifyShown)
        this.CustomTooltipManager.hideTooltip(); 
    
    this.TooltipHidden();
}


DvtEventManager.prototype._processTouchContextMenu = function(event, dlo) {

    if (!this.ContextMenuHandler)
        return;
    var targetObj = event.targetObj;
    var touch = event.touch;

    var menuType = this.GetContextMenuType();
    var menuId = this._getContextMenuId(dlo);

    var allowContextMenu = false;
    if (dlo && dlo.isSelected && dlo.isSelected()) {
        allowContextMenu = true;
    } else {
        if (!dlo || !dlo.isSelectable || !dlo.isSelectable()) {
            menuType = DvtContextMenuHandler.TYPE_BODY_CONTEXT_MENU;
        }
        if (menuType == DvtContextMenuHandler.TYPE_BODY_CONTEXT_MENU) {
                allowContextMenu = true;
            }
        }
    if (allowContextMenu) {
        // Call the context menu handler to show the specified menu
        var menuItems = this.ContextMenuHandler.getMenuItems(menuType, menuId);
        if (menuItems) {
          for (var i=0; i<menuItems.length; i++) {
            var menuItem = menuItems[i];
            var actionTooltip = this.CustomTooltipManager.getActionTooltip();
            // Set to default border when there are context menu items launched for multple/body cases and there is no tooltip
            actionTooltip.setTooltipBorderColor(DvtCustomTooltip.DEFAULT_BORDER_COLOR);
            var listener = this._contextMenuItemListener;
            var ttipItem = new DvtContextMenuTooltipItem(this._context, "item"+i, listener, this, menuItem);
            actionTooltip.addMenuItem(ttipItem);
          }
          return menuItems.length > 0;
        }
    }

    return false;
}

DvtEventManager.prototype._processActionPopup = function(targetObj, position) {
    // Only if action tooltip shown
    if (this.CustomTooltipManager.displayActionPopup()) {    
        this.SetupTouchTooltip(targetObj);     
        this.UpdateActionPopupShownFeedback(targetObj);
        this.CustomTooltipManager.startActionPopupAtPosition(position.x, position.y, targetObj);  
        return true;
    } else {
        this.UpdateActionPopupHiddenFeedback(targetObj);
        return false;
    }
}
/*
 * General  hooks
 */

DvtEventManager.prototype.TooltipLaunched = function(tooltip, borderColor) {
}

DvtEventManager.prototype.TooltipHidden = function() {
}

DvtEventManager.prototype.SetupTouchTooltip = function(targetObj)
{
    var obj = this.GetLogicalObject(targetObj);
    var actionTooltip = this.CustomTooltipManager.getActionTooltip();
    var tooltipBorderColor = actionTooltip.getTooltipBorderColor(); 
    // If border color wasn't overridden, get it here
    if (tooltipBorderColor == null) {
        var borderColor = this.GetTooltipColor(obj);
        actionTooltip.setTooltipBorderColor(borderColor);  
    }
}

/*
 * Mouse-related hooks
 */
DvtEventManager.prototype.OnContextMenuInternal = function(event) {
}

DvtEventManager.prototype.OnClickInternal = function(event) {
}

/*
 * Touch-related hooks
 */
DvtEventManager.prototype.HandleTouchHoverStartInternal = function(event) {
}

DvtEventManager.prototype.HandleTouchHoverMoveInternal = function(event) {
}

DvtEventManager.prototype.HandleTouchHoverEndInternal = function(event) {
} 

DvtEventManager.prototype.HandleTouchHoverOverInternal = function(event) {
}

DvtEventManager.prototype.HandleTouchHoverOutInternal = function(event) {
}

DvtEventManager.prototype.HandleTouchClickInternal = function(event) {
    return false;
}

// Action popup shown for the given target object
DvtEventManager.prototype.UpdateActionPopupShownFeedback = function(targetObj) {
}

// Action popup hidden for the given target object
DvtEventManager.prototype.UpdateActionPopupHiddenFeedback = function(targetObj) {
}

DvtEventManager.prototype.UpdateTouchHoverFeedback = function(targetObj) {
}

DvtEventManager.prototype.UpdateActionTooltipClosedFeedback = function(targetObj) {
}

DvtEventManager.prototype.UpdateActionTooltipLaunchedFeedback = function(targetObj, position) {
}

DvtEventManager.prototype.isInActionPopup = function()
{
    return this._isInActionPopup;
}

DvtEventManager.prototype.GetMagnifyContent = function(pos) {
    return null;
}


DvtEventManager.prototype.ProcessMagnifyStart = function(pos, logicalObj) {
    if (this.IsMagnifyLensEnabled()) {
        var magLens = this.GetMagnifyLens();
        magLens.setDirty(true);
        
        this.ProcessMagnify(pos, logicalObj);
    }
}    

/** @protected */
DvtEventManager.prototype.ProcessMagnify = function(pos, logicalObj) {
    if (this.IsMagnifyLensEnabled()) {
        var magLens = this.GetMagnifyLens();
        var relPos = this._context.getRelativePosition(pos.x, pos.y);
        var region = this.GetMagnifyLensRegion(relPos, logicalObj);
        if (region) {
           if (magLens.isDirty()) {
               var content = this.GetMagnifyContent(pos);
               if (content)
                 magLens.updateMagnifyContent(content);
               magLens.setDirty(false);
           }
            
           magLens.UpdatePosition(relPos.x, relPos.y);        
           this.CustomTooltipManager.showMagnifyLens(pos.x, pos.y, magLens);
           this._isMagnifyShown = true;
        } else {
           this._hideMagnify();
           this._isMagnifyShown = false;
        }
    }
    return false;
}

DvtEventManager.prototype._hideMagnify = function()
{
    this.CustomTooltipManager.hideMagnifyLens(); 
    this.CustomTooltipManager.hideTooltip(); 
    this._isMagnifyShown = false;
}

DvtEventManager.prototype.IsMagnifyLensEnabled = function()
{
    return false;
}

DvtEventManager.prototype.GetMagnifyLensRegion = function(pos, logicalObj)
{
    return null;
}

DvtEventManager.prototype.GetMagnifyLens = function()
{
    return this.CustomTooltipManager.getMagnifyLens();
}

DvtEventManager.prototype.IsTooltipShowable = function(obj, pos) {
    if (!obj)
        return true;
    var tooltipRegion = this.GetTooltipsAllowedRegion(obj);
    var allowTooltips = true;
    if (tooltipRegion && !tooltipRegion.containsPoint(pos.x, pos.y)) {
        allowTooltips = false;
    }
    return allowTooltips && this.IsTooltipShowableInternal && 
        this.IsTooltipShowableInternal(obj, pos);
}

DvtEventManager.prototype.IsTooltipShowableInternal = function(obj, pos) {
    return true;
}

DvtEventManager.prototype.GetTooltipsAllowedRegion = function(obj) {
    return null;
}

/*
 * Useful functions
 */

DvtEventManager.prototype.GetClearSelectionText = function() {
    return "Clear Selection";
}

// Add a clear selection popup menu item
DvtEventManager.prototype.addClearAllActionItem = function() {
    this.addActionTooltipMenuItem(DvtEventManager.CLEAR_SELECTION_ACTION_TYPE, this.GetClearSelectionText(), this._actionTooltipClearListener, this);
    var actionTooltip = this.CustomTooltipManager.getActionTooltip();
    // Override color to always be gray
    if (actionTooltip)
        actionTooltip.setTooltipBorderColor(DvtCustomTooltip.DEFAULT_BORDER_COLOR);
}

DvtEventManager.prototype.isClearMenuAllowed = function()
{
    return true;
}

// Add a menu item to the action tooltip
DvtEventManager.prototype.addActionTooltipMenuItem = function(id, text, listener, obj)
{
    var actionTooltip = this.CustomTooltipManager.getActionTooltip();
    actionTooltip.addMenuItem(new DvtCustomTooltipItem(this._context, id, text, listener, obj));
}

/*
 * Touch-related listeners
 */
// Performed after tapping a context menu item
DvtEventManager.prototype._contextMenuItemListener = function(evt) {
    var targetObj = evt.targetObj; 
    var menuItem = evt.menuItem;
    var contextMenuEvent = menuItem.getEvent();
    this._callback.call(this._callbackObj, contextMenuEvent);
}

// Performed after tapping the clear selection option in an action popup
DvtEventManager.prototype._actionTooltipClearListener = function(evt) {
    var bSelectionChanged = this.SelectionHandler.processClick(null, false);
    // If the selection has changed, fire an event
    if(bSelectionChanged) 
      this._fireSelectionEvent();
}

// Performed after tapping the select option in an action popup
DvtEventManager.prototype._actionTooltipSelectListener = function(evt) {
    var targetObj = evt.targetObj; 
    var dlo = this.GetLogicalObject(targetObj);
    // Always control click for touch
    var bSelectionChanged = this.SelectionHandler.processClick(dlo, true);
    
    // If the selection has changed, fire an event
    if(bSelectionChanged) 
      this._fireSelectionEvent();
}

DvtEventManager.prototype.setTouchRegionBounds = function(bounds) {
    this.TouchManager.setTouchRegionBounds(bounds);
}

/**
 * Stop event propagation
 */
DvtEventManager.consumeEvent = function(event) {
  if (event){
    event.preventDefault();
    //BUG FIX 13381888: stop event propagation when the event is consumed
    event.stopPropagation();
  }
};


// add the component specific context to this event, such as the clientRowKey.
DvtEventManager._addContextInfo = function(target, event) {
  // diagram
  if (target.getContextCallback && target.getContextCallbackObj) {
    var ccb = target.getContextCallback();
    var ccbo = target.getContextCallbackObj();
    if (ccb && ccbo) {
      ccb.call(ccbo, event);
    }
  }
  // graph
  else {
    // store clientRowKey
    event.addParam(DvtBaseComponentEvent.CLIENT_ROW_KEY, target.getId());
  }
}



/**
 * Interactivity manager for custom tooltips and menus.  The two can be visually combined.
 * @class DvtCustomTooltipManager
 * @constructor
 */
var  DvtCustomTooltipManager = function(context, id) {
  this.Init(context, id);
};

DvtObj.createSubclass(DvtCustomTooltipManager, DvtObj, "DvtCustomTooltipManager");

DvtCustomTooltipManager.ACTION_POPUP_CLASS = "OraDVTContextMenuPopup";

DvtCustomTooltipManager.prototype.Init = function(context, id) {
    this._context = context;
    this._id = id;
    this._actionTooltip = new DvtCustomTooltip(this._context, this._id+"ActionPopup");
}

/*
 * For rendering a rich tooltip
 */
DvtCustomTooltipManager.prototype.GetRichTooltipManager = function() {
    if (!this._RichTooltipManager) {
      var tooltipId = this._id+"Tooltip";
      // TODO: may want to change tooltip managers to have their own impl
      this._RichTooltipManager = this._context.getImplFactory().newRichTooltipManager(tooltipId);
      this.initActionTooltip();
    }
    return this._RichTooltipManager;
}

/*
 * For rendering a magnify lens
 */
DvtCustomTooltipManager.prototype.GetMagnifyLensManager = function() {
    if (!this._ManifyLensManager) {
        // TODO: may want to change tooltip managers to have their own impl
        this._ManifyLensManager = this._context.getImplFactory().newRichTooltipManager(this._id+"MagLens");
    }
    return this._ManifyLensManager;
}

DvtCustomTooltipManager.prototype.getMagnifyLens = function() {
    if (!this._magnifyLens) {
        this._magnifyLens = new DvtMagnifyLens(this._context);
    }
    return this._magnifyLens;
}

// Clear settings on old action tooltip
DvtCustomTooltipManager.prototype.clearActionTooltip = function() {
    if (this._actionTooltip)
        this._actionTooltip.clearContent();
}

// Retrieve current action tooltip
DvtCustomTooltipManager.prototype.getActionTooltip = function() {
    return this._actionTooltip;
}

// Ensure the action tooltip is created
DvtCustomTooltipManager.prototype.initActionTooltip = function() {
    if (!this._actionTooltipInitialized) {
        // Attach listeners to action tooltip displayable
        var tooltipContext = this.GetRichTooltipManager().GetStoredContext();
        if (tooltipContext) {
            var eh = new DvtCustomTooltipEventHandler(tooltipContext, this, null, null);
            eh.addListeners(this._actionTooltip);
        }
        this._actionTooltipInitialized = true;
    }
}

// Hide a tooltip that is currently showing
DvtCustomTooltipManager.prototype.hideTooltip = function() {
    this.clearActionTooltip();
    this.GetRichTooltipManager().hideTooltip();
}

// Closes an action tooltip that was left on screen
DvtCustomTooltipManager.prototype.closeActionTooltip = function() {
    var closedEvent = new DvtActionTooltipEvent(DvtActionTooltipEvent.TOOLTIP_CLOSED_TYPE, this._actionPopupObj);
    this.FireListener(closedEvent);
    this._actionPopupObj = null;
    this.hideTooltip();
}

DvtCustomTooltipManager.prototype.showMagnifyLens = function(x, y, magLens) {
    // optimized for a fixed mag lens size
    var length = magLens.getSize();
    var size = new DvtRectangle(0,0,length,length);
    this.GetMagnifyLensManager().showRichElementAtPosition(x - size.w/2, y - size.h, magLens, false, true);
}

// Hide a tooltip that is currently showing
DvtCustomTooltipManager.prototype.hideMagnifyLens = function() {
    this.GetMagnifyLensManager().hideTooltip();
}

DvtCustomTooltipManager.prototype.showMagnifyDatatip = function(x, y, text, borderColor) {

    var box = this.GetMagnifyLensManager().getTooltipBox();

    var datatipLeftOffset = 12;
    var datatipTopOffset = 30;
    
    var radius = box.w/2;
    var angle = Math.PI/8;
    var segmentX = radius*Math.cos(angle);
    var segmentY = radius*Math.sin(angle);

    var adjustX = radius - segmentX;
    var adjustY = radius - segmentY;
    
    var actionTooltip = this.getActionTooltip();

    actionTooltip.setIncludePointer(true);
    actionTooltip._pointerLocation = new DvtPoint(-datatipLeftOffset - adjustX, datatipTopOffset + adjustY);
        
    this.showTextAtPosition(box.x + box.w - adjustX, box.y - datatipTopOffset, text, borderColor, false);
    
    if (this.GetRichTooltipManager()._isRightAdjusted) {
        actionTooltip.setIncludePointer(true);
        var textBox = this.GetRichTooltipManager().getTooltipBox();
        actionTooltip._pointerLocation = new DvtPoint(textBox.w, datatipTopOffset + adjustY);
        this.showTextAtPosition(box.x - textBox.w + adjustX, box.y - datatipTopOffset, text, borderColor, false);
    }
    
    actionTooltip.setIncludePointer(false);
    
}

DvtCustomTooltipManager.prototype.showDatatip = function(x, y, text, borderColor) {
    var actionTooltip = this.getActionTooltip();
    text = DvtTextUtils.formatTextString(text);
    actionTooltip.setTooltipText(text);
    if (borderColor != null)
        actionTooltip.setTooltipBorderColor(borderColor);
    this.GetRichTooltipManager().showRichElement(x, y, actionTooltip, true);
}

DvtCustomTooltipManager.prototype.showTextAtPosition = function(x, y, text, borderColor, useOffset, popupClass) {
    var actionTooltip = this.getActionTooltip();
    text = DvtTextUtils.formatTextString(text);
    actionTooltip.setTooltipText(text);
    if (borderColor != null)
        actionTooltip.setTooltipBorderColor(borderColor);
    this.GetRichTooltipManager().showRichElement(x, y, actionTooltip, useOffset);
}

DvtCustomTooltipManager.prototype.displayActionPopup = function() {
    var actionTooltip = this.getActionTooltip();
    // If no action tooltip initialized with actions (not just tooltips), don't show one
    if (!actionTooltip || !actionTooltip.hasMenuItems())
        return false;
    return true;
}

DvtCustomTooltipManager.prototype.startActionPopupAtPosition = function(pageX, pageY, targetObj, alignment) {
    var actionTooltip = this.getActionTooltip();
    if (!actionTooltip)
        return;

    this.GetRichTooltipManager().showRichElementAtPosition(pageX, pageY, actionTooltip, true, false, DvtCustomTooltipManager.ACTION_POPUP_CLASS);
    
    // Clear the text
    var startEvent = new DvtActionTooltipEvent(DvtActionTooltipEvent.TOOLTIP_STARTED_TYPE, targetObj);
    this.FireListener(startEvent);

    this._actionPopupObj = targetObj;

}

/**
 * Adds an event listener.
 **/
DvtCustomTooltipManager.prototype.addTooltipEventListener = function (type, listener, obj) {
  // Store a reference to the listener
  var listenersArray = this._getListeners(type, true);
  listenersArray.push(listener);
  listenersArray.push(obj);
}

/**
 * Removes an event listener.
 **/
DvtCustomTooltipManager.prototype.removeTooltipEventListener = function (type, listener, obj) {
  // Remove the listener
  var listenersArray = this._getListeners(type, false);
  if (listenersArray !== null) {
    for (var i = 0;i < listenersArray.length;i+=2) {
      if (listenersArray[i] === listener && 
           listenersArray[i+1] === obj) {
        listenersArray.splice(i, 2);
        break;
      }
    }
  }
}

/**
 * Returns the listeners of the given event type
 **/
DvtCustomTooltipManager.prototype._getListeners = function (type, createNew) {
  // First find the object where the listener arrays are stored
  if (!this._listenerObj) {
    if (createNew) {
      this._listenerObj = {
      };
    }
    else {
      return null;
    }
  }

  // Then find the array for this event type, creating if necessary 
  var eventKey = type;
  var listenersArray = this._listenerObj[eventKey];
  if (!listenersArray && createNew) {
    listenersArray = [];
    this._listenerObj[eventKey] = listenersArray;
  }

  return listenersArray;
};

/**
 * Notifies all applicable event listeners of the given event.
 **/
DvtCustomTooltipManager.prototype.FireListener = function (event) {
  var listenersArray = this._getListeners(event.getType(), false);
  if (listenersArray) {
    for (var i = 0;i < listenersArray.length;i+=2) {
      var obj = listenersArray[i+1];
      listenersArray[i].call(obj, event);
    }
  }
};
// Custom tooltip event handler
var  DvtCustomTooltipEventHandler = function(context, customTooltipManager, callback, callbackObj)
{
   this._customTooltipManager = customTooltipManager;
   this.Init(context, callback, callbackObj);

}

DvtObj.createSubclass(DvtCustomTooltipEventHandler, DvtEventManager, "DvtCustomTooltipEventHandler");

DvtCustomTooltipEventHandler.prototype.OnClickInternal = function(event) {
    var target = event.target;
    this._handleMenuClick(target);
}

DvtCustomTooltipEventHandler.prototype.HandleImmediateTouchStartInternal = function(event, touch) {
    event.blockTouchHold();
}

DvtCustomTooltipEventHandler.prototype.HandleTouchClickInternal = function(evt) {
    var targetObj = evt.targetObj;
    this._handleMenuClick(targetObj);
}

DvtCustomTooltipEventHandler.prototype._handleMenuClick = function(targetObj) {
    var actionObj = this._customTooltipManager._actionPopupObj;
    var menuItem = targetObj._menu;
    if (menuItem) {
        var fireAction = true;
        if (menuItem instanceof DvtContextMenuTooltipItem && menuItem._menuItem.isDisabled()) {
            fireAction = false;
        }
        if (fireAction) {
            // Close before menu item event fired since listener may need restored component visual state
            this._customTooltipManager.closeActionTooltip();
            menuItem.FireActionTooltipItem(actionObj);
        }
    }
}
/*--------------------------------------------------------------------*/
/*   DvtCustomTooltip              Action tooltip Component           */
/*--------------------------------------------------------------------*/
/**
  *  Action tooltip component.
  *  @extends DvtObj
  *  @class DvtCustomTooltip  Creates an action tooltip component.
  *  @constructor  
  */
var   DvtCustomTooltip = function(context, id)
{
    this._Init(context, id);
}  

DvtObj.createSubclass(DvtCustomTooltip, DvtContainer, "DvtCustomTooltip");

DvtCustomTooltip.DEFAULT_BORDER_COLOR = "gray";
DvtCustomTooltip.DEFAULT_BACKGROUND_COLOR = "#ffffff";

DvtCustomTooltip.TOOLTIP_ONLY = "tooltipOnly";
DvtCustomTooltip.MENU_ONLY = "menuOnly";
DvtCustomTooltip.MENU_AND_TOOLTIP = "menuAndTooltip";
DvtCustomTooltip.EMPTY = "empty";

DvtCustomTooltip.MENU_PADDING_LEFT = 21;
DvtCustomTooltip.MENU_PADDING_RIGHT = 10;

DvtCustomTooltip.prototype._Init = function(context, id)
{

    this._context = context;
    if (! this.getImpl()) {
     this.setImpl(context.getImplFactory().newContainer("customTT")) ;
    }
    DvtCustomTooltip.superclass.Init.call(this, context) ;

    this._tooltipText = null;
    this._tooltipBorderColor = null;
    this._menuFontSize = 11;
    this._tooltipFill = new DvtSolidFill(DvtCustomTooltip.DEFAULT_BACKGROUND_COLOR);    
    this._font = new DvtFont();
    this._font.size = 11;
    this._includePointer = false;//true;
    this._pointerLocation = new DvtPoint(0,0);
}

DvtCustomTooltip.prototype.setIncludePointer = function(includePointer)
{
    this._includePointer = includePointer;
}

DvtCustomTooltip.prototype.getRootDisplayable = function()
{
    return this;
}

DvtCustomTooltip.prototype.UpdateTooltipSize = function(width, height)
{
    this._displayWidth = width;
    this._displayHeight = height;
}

DvtCustomTooltip.prototype.getDisplayWidth = function() {
   return this._displayWidth;
}

DvtCustomTooltip.prototype.getDisplayHeight = function() {
   return this._displayHeight;
}

DvtCustomTooltip.prototype.clearContent = function() {
    this.clearMenuItems();
    this.setTooltipBorderColor(null);  
    this.setTooltipText(null);
}

DvtCustomTooltip.prototype.setMenuFontSize = function(font) {
    this._menuFontSize = font;
}

DvtCustomTooltip.prototype.setTooltipBorderColor = function(color) {
    this._tooltipBorderColor = color;
}

DvtCustomTooltip.prototype.getTooltipBorderColor = function() {
    return this._tooltipBorderColor;
}

DvtCustomTooltip.prototype.setTooltipFill = function(tooltipFill) {
    this._tooltipFill = tooltipFill;
}

DvtCustomTooltip.prototype.setFont = function(font) {
    this._font = font;
}

DvtCustomTooltip.prototype.setTooltipText = function(text) {
    this._tooltipText = text;
}

DvtCustomTooltip.prototype.getTooltipText = function() {
    return this._tooltipText;
}

DvtCustomTooltip.prototype.addMenuItem = function(menuItem) {
    this.getMenuItems().push(menuItem);
}

DvtCustomTooltip.prototype.hasMenuItems = function() {
    var menuItems = this.getMenuItems();
    return menuItems && menuItems.length > 0;
}

DvtCustomTooltip.prototype.hasTooltip = function() {
    return this._tooltipText != null && this._tooltipText.length > 0;
}

DvtCustomTooltip.prototype.clearMenuItems = function() {
    if (this._menuItems) {
        this._menuItems = [];
    }
}

DvtCustomTooltip.prototype.getMenuItems = function() {
    if (!this._menuItems)
        this._menuItems = new Array();
    return this._menuItems;
}

DvtCustomTooltip.prototype.containsMenuId = function(id) {
    var menuItems = this.getMenuItems();
    for (var i=0; i<menuItems.length; i++) {
        var menuItem = menuItems[i];
        if (menuItem.getId() == id) {
            return true;
        }
    }
    return false;
}

DvtCustomTooltip.prototype.getTooltipType = function() {
    var hasMenuItems = this.hasMenuItems();
    var hasTooltip = this.hasTooltip();
    if (hasMenuItems && hasTooltip) {
        return DvtCustomTooltip.MENU_AND_TOOLTIP;
    }
    if (hasMenuItems) {
        return DvtCustomTooltip.MENU_ONLY;
    }
    if (hasTooltip) {
        return DvtCustomTooltip.TOOLTIP_ONLY;
    }
    return DvtCustomTooltip.EMPTY;
}

/**
 * Renders this action tooltip.
 */
DvtCustomTooltip.prototype.Render = function() {

    var parent = this.getRootDisplayable();
    //parent.setPixelHinting(true);
    // First clear old drawables    
    parent.removeChildren();

    var type = this.getTooltipType();
    if (type == DvtCustomTooltip.EMPTY) {
        return;
    }
    
    // Constants
    var padding = 4;
    var menuItemPadding = 5;
    var tooltipBorderWidth = 2;

    if (this._includePointer) {
        tooltipBorderWidth = 3;
        padding = 10;
    }
            
    // Temp variables
    var hasMenuItems = this.hasMenuItems();
    var hasTooltip = this.hasTooltip();
    var topTextY = padding + tooltipBorderWidth/2;
    var runningHeight = 0;
    var maxWidth = 0;
    
    if (type == DvtCustomTooltip.TOOLTIP_ONLY) {
        parent.setAlpha(0.9);
    } else {
        parent.setAlpha(1);
    }

    if (hasTooltip) {
        
        var cursorText = new DvtTextArea(this._context, 0, 0);
        parent.addChild(cursorText);
        DvtTextUtils.applyFont(cursorText, this._font);
        
        cursorText.setMaxWidth(100000000);
        cursorText.setMouseEnabled(true);

        // There is a bug in Firefox and IE9 with aligning to top in SVG.
        // Wait until a feasible fix is in the toolkit for alignTop API.  For now the baseline is used.
        //  cursorText.alignTop();
        cursorText.alignBaseline();
        cursorText.alignStart();
        
        cursorText.setTranslateY(this._font.getSize() + padding+tooltipBorderWidth/2);

        this._cursorText = cursorText;
    
        this._cursorText.removeChildren();
        this._cursorText.setText(this._tooltipText);
    
        var textDimensions = this._cursorText.getDimensions();
        var textHeight = textDimensions.h;
        var textWidth = textDimensions.w;
        maxWidth = Math.max(textWidth, maxWidth);
        runningHeight += textHeight;
    }

    var textItems = new Array();
    var textWidths = new Array();
    
    if (type == DvtCustomTooltip.MENU_AND_TOOLTIP) {
        runningHeight += menuItemPadding;
    } else if (type == DvtCustomTooltip.MENU_ONLY) {
        runningHeight += menuItemPadding/2;        
    }
    
    if (hasMenuItems) {


        var menuItems = this.getMenuItems();
        for (var i=0; i<menuItems.length; i++) {
            var menuItem = menuItems[i];

            var text = new DvtText(this._context, menuItem.getText(), 0, 0, null); 

            DvtTextUtils.applyFont(text, this._font);
            text.setFontSize(this._menuFontSize);
            
            if (menuItem instanceof DvtContextMenuTooltipItem) {
                if (menuItem._menuItem.isDisabled()) {
                    text.setAlpha(0.5);                
                }
            }

            text._menu = menuItem;
            
            parent.addChild(text);
            var dimensions = text.getDimensions();
            dimensions.y = topTextY+runningHeight;
            var textWidth = dimensions.w;
            textWidths.push(dimensions);
            maxWidth = Math.max(textWidth + DvtCustomTooltip.MENU_PADDING_LEFT + DvtCustomTooltip.MENU_PADDING_RIGHT, maxWidth);
            text.setY(dimensions.y);
            runningHeight += dimensions.h;
    
            if (i < menuItems.length - 1) {
                runningHeight += menuItemPadding;
            }
            
            parent.removeChild(text);
            textItems.push(text);        
            text.alignStart();
            text.alignTop();
        }

    }
    if (type == DvtCustomTooltip.MENU_ONLY || type == DvtCustomTooltip.MENU_AND_TOOLTIP) {
        runningHeight += menuItemPadding/2;        
    }
    
    var contentWidth = maxWidth + 2*padding;
    var tooltipWidth = contentWidth + tooltipBorderWidth;
    var tooltipHeight = topTextY + runningHeight + padding + tooltipBorderWidth/2; 
    
    if (this._cursorText)
        this._cursorText.setTranslateX(padding + tooltipBorderWidth/2);

    var pointerWidth = 12;
    var isRightPointer = (this._pointerLocation.x > tooltipWidth);
    var pointerOffsetX = -this._pointerLocation.x;
    var pointerOffsetY = this._pointerLocation.y;

    if (this._includePointer) {

        if (tooltipHeight/2 < pointerWidth)
            pointerWidth = tooltipHeight/3;

        var newTooltipHeight = tooltipHeight + tooltipBorderWidth;
        newTooltipHeight = Math.max(pointerOffsetY + tooltipBorderWidth, newTooltipHeight);
        if (isRightPointer) {
            this.UpdateTooltipSize(this._pointerLocation.x, newTooltipHeight);
            parent.setTranslateX(tooltipBorderWidth/2);
        } else {
            this.UpdateTooltipSize(tooltipWidth+pointerOffsetX+tooltipBorderWidth, newTooltipHeight);
            parent.setTranslateX(tooltipBorderWidth/2 + pointerOffsetX);
        }
     //   parent.setTranslateX(pointerOffsetX+tooltipBorderWidth);

        parent.setTranslateY(tooltipBorderWidth/2);
    } else {
        this.UpdateTooltipSize(tooltipWidth + tooltipBorderWidth, tooltipHeight + tooltipBorderWidth);
        parent.setTranslateX(tooltipBorderWidth/2);
        parent.setTranslateY(tooltipBorderWidth/2);
    }

        
    // Add background panels
    var backgroundPanel = new DvtRect(this._context, 0, 0, tooltipWidth, tooltipHeight);
    if (this._includePointer) {

        var radius = 5;
        var beginArrowY = tooltipHeight/2; 

        if (isRightPointer) {
            //this._pointerStartOffset;
            var p1 = new DvtPoint(0, 0);
            var p2 = new DvtPoint(tooltipWidth, 0);
            var p3 = new DvtPoint(tooltipWidth, beginArrowY);
            var p4 = new DvtPoint(this._pointerLocation.x, pointerOffsetY);
            var p5 = new DvtPoint(tooltipWidth, beginArrowY + pointerWidth);
            var p6 = new DvtPoint(tooltipWidth, tooltipHeight);
            var p7 = new DvtPoint(0, tooltipHeight);
    
            var cmd = DvtPathUtils.moveTo(p1.x + radius,p1.y) + 
                DvtPathUtils.lineTo(p2.x - radius,p2.y) + 
                DvtPathUtils.arcTo(radius,Math.PI/2, 1, p2.x, p2.y + radius) + 
                DvtPathUtils.lineTo(p3.x,p3.y) + 
                DvtPathUtils.lineTo(p4.x,p4.y) + 
                DvtPathUtils.lineTo(p5.x,p5.y) + 
                DvtPathUtils.lineTo(p6.x,p6.y - radius) + 
                DvtPathUtils.arcTo(radius,Math.PI/2, 1, p6.x - radius, p6.y) + 
                DvtPathUtils.lineTo(p7.x + radius,p7.y) + 
                DvtPathUtils.arcTo(radius,Math.PI/2, 1, p7.x, p7.y - radius) + 
                DvtPathUtils.lineTo(0,radius) + 
                DvtPathUtils.arcTo(radius,Math.PI/2, 1, radius, 0) + 
                DvtPathUtils.closePath();
             backgroundPanel = new DvtPath(this._context, cmd, null);
        } else {
            //this._pointerStartOffset;
            var p1 = new DvtPoint(0, 0);
            var p2 = new DvtPoint(tooltipWidth, 0);
            var p3 = new DvtPoint(tooltipWidth, tooltipHeight);
            var p4 = new DvtPoint(0, tooltipHeight);
            var p5 = new DvtPoint(0, beginArrowY + pointerWidth);
            var p6 = new DvtPoint(-pointerOffsetX, pointerOffsetY);
            var p7 = new DvtPoint(0, beginArrowY);
    
            var cmd = DvtPathUtils.moveTo(p1.x + radius,p1.y) + 
                DvtPathUtils.lineTo(p2.x - radius,p2.y) + 
                DvtPathUtils.arcTo(radius,Math.PI/2, 1, p2.x, p2.y + radius) + 
                DvtPathUtils.lineTo(p3.x,p3.y - radius) + 
                DvtPathUtils.arcTo(radius,Math.PI/2, 1, p3.x - radius, p3.y) + 
                DvtPathUtils.lineTo(p4.x + radius,p4.y) + 
                DvtPathUtils.arcTo(radius,Math.PI/2, 1, p4.x, p4.y - radius) + 
                DvtPathUtils.lineTo(p5.x,p5.y) + 
                DvtPathUtils.lineTo(p6.x,p6.y) + 
                DvtPathUtils.lineTo(p7.x,p7.y) + 
                DvtPathUtils.lineTo(0,radius) + 
                DvtPathUtils.arcTo(radius,Math.PI/2, 1, radius, 0) + 
                DvtPathUtils.closePath();
             backgroundPanel = new DvtPath(this._context, cmd, null);
        }
    }

    if (hasTooltip) {
        var borderColor = this._tooltipBorderColor;
        if (!borderColor) {
            borderColor = DvtCustomTooltip.DEFAULT_BACKGROUND_COLOR;
        }
        backgroundPanel.setStroke(new DvtSolidStroke(borderColor, 1, tooltipBorderWidth));
    } else {
        backgroundPanel.setStroke(new DvtSolidStroke("rgb(229,232,238)", 1, 1));
    }
    
    if (!this._tooltipFill)
        this._tooltipFill = new DvtSolidFill(DvtCustomTooltip.DEFAULT_BACKGROUND_COLOR);
    backgroundPanel.setFill(this._tooltipFill);
    parent.addChildAt(backgroundPanel, 0);

    var dividerWidth = contentWidth*0.95;
    var dividerX = (tooltipWidth - dividerWidth)/2;
    // Add text items
    for (var i=0; i<textItems.length; i++) {
        var textItem = textItems[i];
        parent.addChild(textItem);
        var textWidth = textWidths[i].w;
        if (textItem._menu) {
            // Menus have target areas
            var hitAreaRect = new DvtRectangle(0, textWidths[i].y - menuItemPadding/2, tooltipWidth, textWidths[i].h + menuItemPadding); 
            //hitAreaRect = DvtGeomUtils.getSpecificPaddedRectangle(hitAreaRect, 4, 4, 10, 10);
            var hitTarget = new DvtRect(this._context, hitAreaRect.x, hitAreaRect.y, hitAreaRect.w, hitAreaRect.h);
            hitTarget.setFill(new DvtSolidFill("white", 0));

            hitTarget._menu = textItem._menu;
            parent.addChild(hitTarget);

            if (i == 0 && hasTooltip) {
                var fill = new DvtSolidFill("gray", 1);
                // show division between menu and tooltip
                this.renderDivider(parent, dividerX, textWidths[i].y - menuItemPadding, dividerWidth, fill);
            } else if (i > 0) {
                var menuItemObj = textItem._menu._menuItem;
                
                var prevItem = textItems[i-1];

                if (prevItem._menu instanceof DvtContextMenuTooltipItem) {
                    //Separators between context menu items
                    if (menuItemObj.hasSeparatorBefore()) {
                        var fill = new DvtSolidFill("gray", 0.5);
                        this.renderDivider(parent, dividerX, textWidths[i].y - menuItemPadding/2, dividerWidth, fill);
                    }
                } else {
                    // First context menu item, show a division between this and built in actions
                    //var fill = new DvtSolidFill("gray", 1);
                    //this.renderDivider(parent, dividerX, textWidths[i].y - menuItemPadding/2, dividerWidth, fill);
                }
            }
        }
        textItem.setTranslateX(DvtCustomTooltip.MENU_PADDING_LEFT);
    }
}

DvtCustomTooltip.prototype.renderDivider = function(parent, x, y, width, fill) {
    var divider = new DvtRect(this._context, x, y, width, 1);
    divider.setFill(fill);
    parent.addChild(divider);
}

/*--------------------------------------------------------------------*/
/*   DvtCustomTooltipItem              Action tooltip item            */
/*--------------------------------------------------------------------*/
/**
  *  Logical action tooltip item.  No dependency on drawables
  *  @extends DvtObj
  *  @class DvtCustomTooltipItem  Creates an action tooltip item.
  *  @constructor  
  */
var   DvtCustomTooltipItem = function(context, id, text, listener, listenerObj)
{
    this.Init(context, id, text, listener, listenerObj);
}  

DvtObj.createSubclass(DvtCustomTooltipItem, DvtObj, "DvtCustomTooltipItem");

DvtCustomTooltipItem.prototype.Init = function(context, id, text, listener, listenerObj) {
    this._context = context;
    this._id = id;
    this._text = text;
    this._listener = listener;
    this._listenerObj = listenerObj;
}

DvtCustomTooltipItem.prototype.getId = function() {
    return this._id;
}

DvtCustomTooltipItem.prototype.getText = function() {
    return this._text;
}

DvtCustomTooltipItem.prototype.FireActionTooltipItem = function(targetObj) {
    if (this._listenerObj && this._listener) {
        var evt = new Object();
        evt.targetObj = targetObj;
        evt.menuItem = this._menuItem;
        this._menuItemTimer = new DvtTimer(this._context, 1, this._handleMenuTimer, this);
        // store event on timer temporarily
        this._menuItemTimer.evt = evt;
        this._menuItemTimer.start();
    }
}

// Timer handler for menu item listener
DvtCustomTooltipItem.prototype._handleMenuTimer = function() {
    if (this._menuItemTimer) {
        this._menuItemTimer.stop();
    }
    this._listener.call(this._listenerObj, this._menuItemTimer.evt);
}

var   DvtContextMenuTooltipItem = function(context, id, listener, listenerObj, menuItem)
{
    this.Init(context, id, listener, listenerObj, menuItem);
}  

DvtObj.createSubclass(DvtContextMenuTooltipItem, DvtCustomTooltipItem, "DvtContextMenuTooltipItem");

DvtContextMenuTooltipItem.prototype.Init = function(context, id, listener, listenerObj, menuItem) {
    DvtContextMenuTooltipItem.superclass.Init.call(this, context, id, menuItem.getText(), listener, listenerObj);
    this._menuItem = menuItem;
}
var DvtAgent = function() {
}

DvtObj.createSubclass(DvtAgent, DvtObj, "DvtAgent");

/**
 * DvtAgent Platform constants
 */
DvtAgent.IE_PLATFORM = "ie";
DvtAgent.GECKO_PLATFORM = "gecko";
DvtAgent.WEBKIT_PLATFORM = "webkit";
DvtAgent.OPERA_PLATFORM = "opera";
DvtAgent.UNKNOWN_PLATFORM = "unknown";

/**
 * DvtAgent OS constants
 */
DvtAgent.WINDOWS_OS = "Windows";
DvtAgent.SOLARIS_OS = "Solaris";
DvtAgent.MAC_OS = "Mac";
DvtAgent.UNKNOWN_OS = "Unknown";

// TODO: JSDoc
DvtAgent.getAgent = function() {
    if (!DvtAgent._agent) {
        if (window) {
            if (window.isFlashEnvironment) {
                DvtAgent._agent = new FlashAgentImpl();
            } else {
                if (window.AdfAgent && AdfAgent.AGENT) {
                    DvtAgent._agent = new AdfAgentImpl();
                } else {
                    DvtAgent._agent = DvtAgentImpl.getAgent();
                }
            }
        } else {
            DvtAgent._agent = new DvtAgent();
        }
    }
    return DvtAgent._agent;
}

// TODO: JSDoc
DvtAgent.prototype.isTouchDevice = function()
{
    return false;
}
// TODO: JSDoc
DvtAgent.prototype.isSafari = function()
{
    return false;
}

/**
 * Returns true if the agent is webkit based.
 * @return {boolean}
 */
DvtAgent.prototype.isWebkit = function() {
  return false;
}

/**
 * Returns true if the agent is gecko based.
 * @return {boolean}
 */
DvtAgent.prototype.isGecko = function() {
  return false;
};

DvtAgent.prototype.isChrome = function()
{
    return false;
}

// TODO: JSDoc
DvtAgent.prototype.getElementPosition = function(element)
{
    // noop
    return {x: 0, y: 0};
}

// TODO: JSDoc
DvtAgent.prototype.elementFromPagePoint = function(x, y)
{
    return null;
}

/**
 * Returns the agent platform.
 * @return {string} agent platform
 */
DvtAgent.prototype.getPlatform = function()
{
    return null;
}

/**
 * Returns the agent name.
 * @return {string} agent name
 */
DvtAgent.prototype.getName = function()
{
    return null;
}

DvtAgent.prototype.isRightToLeft = function()
{
  return false;
}
/**
 * Abstract class for Events. 
 * 
 * <p>The supported fields are:
 * <ul>
 * <li>target</li>
 * <li>type</li>
 * </ul>
 * <p>
 */
var DvtBaseEvent = function() {}

DvtObj.createSubclass(DvtBaseEvent, DvtObj, "DvtBaseEvent");

/**
 * Object initializer
 * 
 * @param {String} type
 * @param {String} target
 */
DvtBaseEvent.prototype.Init = function(type, target)
{
  this.type = type;
  this.target = target;
}

/**
 * Returns the native event that we are wrapping
 * @return {Object} The native event that we are wrapping
 */
DvtBaseEvent.prototype.getNativeEvent = function() {
  return null; // subclasses should override
}

/**
 * Prevents the default browser action that the native event would have triggered
 */
DvtBaseEvent.prototype.preventDefault = function() {
  // subclasses should override
} 

/**
 * Stops propagation of the native event in the browser's event bubbling phase.
 */
DvtBaseEvent.prototype.stopPropagation = function() {
  // subclasses should override
} 
/**
 * Base class for component level events.
 * @class The base class for component level events.
 * @constructor
 */
var DvtBaseComponentEvent = function() {}

DvtObj.createSubclass(DvtBaseComponentEvent, DvtObj, "DvtBaseComponentEvent");


DvtBaseComponentEvent.CLIENT_ROW_KEY = "clientRowKey";


/**
 * @param {string} type The event type for this event.
 * @protected
 */
DvtBaseComponentEvent.prototype.Init = function(type) {
  this._type = type;
}

/**
 * Returns the event type for this event.
 * @return {string} The event type for this event.
 */
DvtBaseComponentEvent.prototype.getType = function() {
  return this._type;
}

/**
 * Return a list of additional parameter keys
 * @return {array} paramKeys additional parameter keys
 */
DvtBaseComponentEvent.prototype._getParamKeys = function() {
  return this._paramKeys;
}

/**
 * Return a list of additional parameter values
 * @return {array} paramValues additional parameter values
 */
DvtBaseComponentEvent.prototype._getParamValues = function() {
  return this._paramValues;
}


/**
 * Add an additional parameter (key, value) to this event (ex clientRowKey)
 * @param {String} paramKey parameter key
 * @param {String} paramValue parameter value
 */
DvtBaseComponentEvent.prototype.addParam = function(paramKey, paramValue) {
  if (! this._paramKeys) {
    this._paramKeys = [];
    this._paramValues = [];
  }

  this._paramKeys.push(paramKey);
  this._paramValues.push(paramValue);
}


/**
 * Get parameter value in this event 
 * @param {String} paramKey parameter key
 * @return {String} paramValue parameter value
 */
DvtBaseComponentEvent.prototype.getParamValue = function(paramKey) {
  if (! paramKey || ! this._paramKeys || ! this._paramValues) {
    return null;
  }

  var index = -1;
  for (var i = 0; i < this._paramKeys.length; i++) {
    if (this._paramKeys[i] == paramKey) {
      index = i;
      break;
    }
  }

  if (index != -1) {
    return this._paramValues[index];
  }  

  return null;
};





/**
 * Platform independent class for Keyboard Events.  
 * 
 * <p>The supported fields are:
 * <ul>
 * <li>altKey</li>
 * <li>ctrlKey</li>
 * <li>shiftKey</li>
 * <li>charCode</li>
 * <li>keyCode</li>
 * </ul>
 * 
 * @constructor
 * @param {String} type
 * @param {boolean} bubbles
 * @param {boolean} cancelable
 * @param {Object} view
 * @param {Number} charCode
 * @param {Number} keyCode
 * @param {Number} keyLocation
 * @param {Boolean} ctrlKey
 * @param {Boolean} altKey
 * @param {Boolean} shiftKey
 * @param {Boolean} repeat
 * @param {String} locale
 */
var DvtKeyboardEvent = function(type, bubbles, cancelable, view, charCode, keyCode, keyLocation, ctrlKey, altKey, shiftKey, repeat, locale)
{
  this.Init(type, bubbles, cancelable, view, charCode, keyCode, keyLocation, ctrlKey, altKey, shiftKey, repeat, locale);
}

DvtObj.createSubclass(DvtKeyboardEvent, DvtBaseEvent, "DvtKeyboardEvent");

// These constants apply for both Flash and Javascript
DvtKeyboardEvent.ENTER = 13;
DvtKeyboardEvent.SHIFT = 16;
DvtKeyboardEvent.CONTROL = 17;
DvtKeyboardEvent.ESCAPE = 27;
DvtKeyboardEvent.SPACE = 32;
DvtKeyboardEvent.PAGE_UP = 33;
DvtKeyboardEvent.PAGE_DOWN = 34;
DvtKeyboardEvent.UP_ARROW = 38;
DvtKeyboardEvent.DOWN_ARROW = 40;
DvtKeyboardEvent.DELETE = 46;
DvtKeyboardEvent.LEFT_ARROW = 37;
DvtKeyboardEvent.RIGHT_ARROW = 39;
DvtKeyboardEvent.OPEN_BRACKET = 219;
DvtKeyboardEvent.CLOSE_BRACKET = 221;

DvtKeyboardEvent.WEBKIT_PLUS = 187;
DvtKeyboardEvent.WEBKIT_MINUS =189;
DvtKeyboardEvent.GECKO_PLUS = 107;
DvtKeyboardEvent.GECKO_MINUS = 109;

DvtKeyboardEvent.A = 65;
DvtKeyboardEvent.M = 77;


/**
 * Object initializer.  This essentially mirrors the DOM initKeyboardEvent() API
 * @param {String} type
 * @param {boolean} bubbles
 * @param {boolean} cancelable
 * @param {Object} view
 * @param {Number} charCode
 * @param {Number} keyCode
 * @param {Number} keyLocation
 * @param {Boolean} ctrlKey
 * @param {Boolean} altKey
 * @param {Boolean} shiftKey
 * @param {Boolean} repeat
 * @param {String} locale
 */
DvtKeyboardEvent.prototype.Init = function(type, bubbles, cancelable, view, charCode, keyCode, keyLocation, ctrlKey, altKey, shiftKey, repeat, locale)
{
  DvtKeyboardEvent.superclass.Init.call(this, type, null);
  this.bubbles = bubbles;
  this.cancelable = cancelable;
  this.view = view;
  this.charCode = charCode;
  this.keyCode = keyCode;
  this.keyLocation = keyLocation;
  this.ctrlKey = ctrlKey;
  this.altKey = altKey;
  this.shiftKey = shiftKey;
  this.repeat = repeat;
  this.locale = locale;
}

/**
 * Utility method that returns true if the keyboard event is a plus keystroke. Handy because keycodes differ
 * across different render kits
 * @param {DvtKeyboardEvent} event
 * @return {Boolean} true if the event is a "+" keystroke
 */
DvtKeyboardEvent.isPlus = function(event)
{
  var keyCode = event.keyCode;
  
  if(DvtAgent.getAgent().isGecko())
  {
    // special case for Gecko/Firefox
    if(keyCode == DvtKeyboardEvent.GECKO_PLUS && event.shiftKey)
      return true;
    else
      return false;
  }
  else
  {
    if(keyCode == DvtKeyboardEvent.WEBKIT_PLUS && event.shiftKey)
      return true;
    else
      return false;
  }
  return false;
}


/**
 * Utility method that returns true if the keyboard event is a minus keystroke. Handy because keycodes differ
 * across different render kits
 * @param {DvtKeyboardEvent} event
 * @return {Boolean} true if the event is a "-" keystroke
 */
DvtKeyboardEvent.isMinus = function(event)
{
  var keyCode = event.keyCode;
  
  if(DvtAgent.getAgent().isGecko())
  {
    // special case for Gecko/Firefox
    if(keyCode == DvtKeyboardEvent.GECKO_MINUS && !event.shiftKey)
      return true;
    else
      return false;
  }
  else
  {
    if(keyCode == DvtKeyboardEvent.WEBKIT_MINUS && !event.shiftKey)
      return true;
    else
      return false;
  }
  return false;
}

/**
 * Abstract class for Mouse Events.  This class roughly follows the DOM Level 2 API.  
 * 
 * <p>The supported fields are:
 * <ul>
 * <li>ctrlKey</li>
 * <li>relatedTarget</li>
 * <li>target</li>
 * <li>type</li>
 * </ul>
 * <p>
 */
var DvtMouseEvent = function(type, target, relatedTarget, button, ctrlKey, metaKey, shiftKey, pageX, pageY) 
{
  this.Init(type, target, relatedTarget, button, ctrlKey, metaKey, shiftKey, pageX, pageY);
}

DvtObj.createSubclass(DvtMouseEvent, DvtBaseEvent, "DvtMouseEvent");

// Constants for mouse event types
DvtMouseEvent.CLICK = "click";

/**
 * Object initializer. This essentially mirrors the DOM initMouseEvent() API
 * @param {String} type
 * @param {Boolean} bubbles
 * @param {Boolean} cancelable
 * @param {Object} view
 * @param {Number} detail
 * @param {Number} pageX
 * @param {Number} pageY
 * @param {Number} clientX
 * @param {Number} clientY
 * @param {Boolean} ctrlKey
 * @param {Boolean} altKey
 * @param {Boolean} shiftKey
 * @param {Boolean} metaKey
 * @param {Number} button
 * @param {Object} relatedTarget
 */
DvtMouseEvent.prototype.Init = function(type, bubbles, cancelable, view, detail, pageX, pageY, clientX, clientY, ctrlKey, altKey, shiftKey, metaKey, button, relatedTarget)
{
  DvtMouseEvent.superclass.Init.call(this, type, null);
  this.bubbles = bubbles;
  this.cancelable = cancelable;
  this.view = view;
  this.detail = detail;
  this.pageX = pageX;
  this.pageY = pageY;
  this.clientX = clientX;
  this.clientY = clientY;
  this.ctrlKey = ctrlKey || metaKey;
  this.altKey = altKey;
  this.shiftKey = shiftKey;
  this.metaKey = metaKey;
  this.button = button;
  this.relatedTarget = relatedTarget;
}


/**
 * Abstract class for Touch Events.
 * 
 * <p>The supported fields are:
 * <ul>
 * <li>touches</li>
 * <li>targetTouches</li>
 * <li>changedTouches</li>
 * <li>target</li>
 * <li>type</li>
 * </ul>
 * <p>
 */
var DvtTouchEvent = function() {}

DvtObj.createSubclass(DvtTouchEvent, DvtBaseEvent, "DvtTouchEvent");

DvtTouchEvent.prototype.Init = function()
{
}
/**
 * Wrapper class providing access to a Touch.
 * @extends DvtObj
 * @class DvtTouch
 * <p>The supported fields are:
 * <ul>
 * <li>clientX</li>
 * <li>clientY</li>
 * <li>screenX</li>
 * <li>screenY</li>
 * <li>pageX</li>
 * <li>pageY</li>
 * <li>target</li>
 * <li>identifier</li>
 * </ul>
 * <p>
 */
var DvtTouch = function(touch) {
  this.Init(touch);
}

DvtObj.createSubclass(DvtTouch, DvtObj, "DvtTouch");

/**
 * @protected
 * @param {Touch} the DOM Touch
 */
DvtTouch.prototype.Init = function(touch) {
  this.clientX = touch.clientX;
  this.clientY = touch.clientY;
  this.screenX = touch.screenX;
  this.screenY = touch.screenY;
  this.pageX = touch.pageX;
  this.pageY = touch.pageY;
  this.target = touch.target;
  this.identifier = touch.identifier;
  if (!this.identifier)
    this.identifier = 1;
}
/**
 * Keeps track of the current state of touches and fires higher-level logical events
 * @extends DvtObj
 * @class DvtTouchManager
 */
var DvtTouchManager = function(id, context) {
  this.Init(id, context);
}

DvtObj.createSubclass(DvtTouchManager, DvtObj, "DvtTouchManager");

DvtTouchManager.TOUCH_MODE = "mode";
DvtTouchManager.TOUCH_MODE_DEFAULT = "defaultMode";
DvtTouchManager.TOUCH_MODE_LONG_PRESS = "longPressMode";

DvtTouchManager.PREV_HOVER_OBJ = "prevHoverObj";

DvtTouchManager.HOVER_TOUCH_KEY = "hoverTouch";

/**
 * @protected
 */
DvtTouchManager.prototype.Init = function(id, context) {
  this._context = context;
  this._id = id;
  
  // Total number of touches on the screen
  this._touchCount = 0;

  // Single timer for touch hold 
  this._touchHoldTimer = new DvtTimer(this._context, 200, this._handleTouchHoldStartTimer, this);

  // Stored mapping for history information on touches
  this._touchMap = new Object();

  // Limit the region for which this touch manager applies.
  this._touchRegionBounds = null;  

  // Save information on touches which are already associated with listeners
  this._savedTouchInfo = new Array();

  this._blockPan = false;

  // internal listener to translate to hover
  this._addTouchHoldMoveEventListener(this._onTouchHoldHover, this);

  // Single timer for double tap
  this._doubleTapTimer = new DvtTimer(this._context, 300, this._handleDoubleTapTimer, this, 1);

}

DvtTouchManager.prototype._addTouchHoldMoveEventListener = function (listener, obj) {
    this.addTouchEventListener(DvtComponentTouchEvent.TOUCH_HOLD_START_TYPE, listener, obj);
    this.addTouchEventListener(DvtComponentTouchEvent.TOUCH_HOLD_MOVE_TYPE, listener, obj);
    this.addTouchEventListener(DvtComponentTouchEvent.TOUCH_HOLD_END_TYPE, listener, obj);
}

// Internal touch hold listener to translate to hover events
DvtTouchManager.prototype._onTouchHoldHover = function(evt) {
    var type = evt.getType();
    var touch = evt.touch;
    
    var info = this._touchMap[touch.identifier];
    
    var obj = evt.targetObj;
    if (type == DvtComponentTouchEvent.TOUCH_HOLD_END_TYPE) {
        var hoverEvt = new DvtComponentTouchEvent(DvtComponentTouchEvent.TOUCH_HOVER_END_TYPE, obj, touch);
        hoverEvt._isCancelEvent = this._isCancelEvent;
        // It's very important that the previous hover object is used as hover out as objects can be moving (example: scrollable legend)
        if (obj != null)
            this.FireListener(new DvtComponentTouchEvent(DvtComponentTouchEvent.TOUCH_HOVER_OUT_TYPE, info[DvtTouchManager.PREV_HOVER_OBJ], touch));
        info[DvtTouchManager.PREV_HOVER_OBJ] = null;
            
        this.FireListener(hoverEvt);
    } else if (type == DvtComponentTouchEvent.TOUCH_HOLD_START_TYPE) {
        info[DvtTouchManager.PREV_HOVER_OBJ] = null;

        if (obj != null)
            this.FireListener(new DvtComponentTouchEvent(DvtComponentTouchEvent.TOUCH_HOVER_OVER_TYPE, obj, touch));
        info[DvtTouchManager.PREV_HOVER_OBJ] = obj;

        this.FireListener(new DvtComponentTouchEvent(DvtComponentTouchEvent.TOUCH_HOVER_START_TYPE, obj, touch));
    } else if (type == DvtComponentTouchEvent.TOUCH_HOLD_MOVE_TYPE) {
        this._fireHoverOverOutEvents(obj, info[DvtTouchManager.PREV_HOVER_OBJ], touch);
        info[DvtTouchManager.PREV_HOVER_OBJ] = obj;
        this.FireListener(new DvtComponentTouchEvent(DvtComponentTouchEvent.TOUCH_HOVER_MOVE_TYPE, obj, touch));

    }
}

DvtTouchManager.prototype._getObjFromTouch = function(touch) {
    var obj = null;

    if (touch) {
        var relPos = this._context.getRelativePosition(touch.pageX, touch.pageY);
        if (!this._touchRegionBounds || this._touchRegionBounds.containsPoint(relPos.x, relPos.y)) {
        // If the rendering impl doesn't define document utils for finding the element at a point, don't continue
            var documentUtils = this._context.getDocumentUtils();
            if (documentUtils) {
                obj = documentUtils.elementFromPoint(touch.clientX, touch.clientY);
            }
        }    
    }
    return obj;
}

// Fire logical hover events
DvtTouchManager.prototype._fireHoverOverOutEvents = function(currentObj, prevHoverObj, touch) {
    if (prevHoverObj != currentObj) {
        if (prevHoverObj != null)
            this.FireListener(new DvtComponentTouchEvent(DvtComponentTouchEvent.TOUCH_HOVER_OUT_TYPE, prevHoverObj, touch));
        if (currentObj != null)
            this.FireListener(new DvtComponentTouchEvent(DvtComponentTouchEvent.TOUCH_HOVER_OVER_TYPE, currentObj, touch));
    }
}

/**
 * Adds an event listener.
 **/
DvtTouchManager.prototype.addTouchEventListener = function (type, listener, obj) {
  // Store a reference to the listener
  var listenersArray = this._getListeners(type, true);
  listenersArray.push(listener);
  listenersArray.push(obj);
}

/**
 * Removes an event listener.
 **/
DvtTouchManager.prototype.removeTouchEventListener = function (type, listener, obj) {
  // Remove the listener
  var listenersArray = this._getListeners(type, false);
  if (listenersArray !== null) {
    for (var i = 0;i < listenersArray.length;i+=2) {
      if (listenersArray[i] === listener && 
           listenersArray[i+1] === obj) {
        listenersArray.splice(i, 2);
        break;
      }
    }
  }
}

/**
 * Returns the listeners of the given event type and capture mode.
 **/
DvtTouchManager.prototype._getListeners = function (type, createNew) {
  // First find the object where the listener arrays are stored
  if (!this._listenerObj) {
    if (createNew) {
      this._listenerObj = {
      };
    }
    else {
      return null;
    }
  }

  // Then find the array for this event type, creating if necessary 
  var eventKey = type;
  var listenersArray = this._listenerObj[eventKey];
  if (!listenersArray && createNew) {
    listenersArray = [];
    this._listenerObj[eventKey] = listenersArray;
  }

  return listenersArray;
};

/**
 * Notifies all applicable event listeners of the given event.
 **/
DvtTouchManager.prototype.FireListener = function (event) {
  var listenersArray = this._getListeners(event.getType(), false);
  if (listenersArray) {
    for (var i = 0;i < listenersArray.length;i+=2) {
      var obj = listenersArray[i+1];
      listenersArray[i].call(obj, event);
    }
  }
};

DvtTouchManager.prototype.startTouchHold = function() {
    var touchid = this._startSingleFingerTouchId;
    if (touchid) {
        var info = this._touchMap[touchid];
        if (info) {

            var touchStartObj = info["startTarget"];
            var startTouch = info["startTouch"];

            // If there are any immediate touches for this id, end it since touch hold has started            
            var matches = this._findMatches("touchId", touchid);
            for (var i=0; i<matches.length;i++) {
                var savedInfo = matches[i];
                var touchObj = savedInfo["touchObj"];
                var touchId = savedInfo["touchId"];
                if (touchObj != DvtTouchManager.HOVER_TOUCH_KEY) {
                    var touchInfo = this.getTouchInfo(touchId);
                    var touch = touchInfo["startTouch"];
                    this.performAssociatedTouchEnd(touch, touchObj, null);
                }
            }

            // Save mode on touch
            info[DvtTouchManager.TOUCH_MODE] = DvtTouchManager.TOUCH_MODE_LONG_PRESS;
            this.saveProcessedTouch(touchid, DvtTouchManager.HOVER_TOUCH_KEY, null, DvtTouchManager.HOVER_TOUCH_KEY, DvtTouchManager.HOVER_TOUCH_KEY, this.HoverMoveInternal, this.HoverEndInternal, this);
            
            var touchHoldStartEvent = new DvtComponentTouchEvent(DvtComponentTouchEvent.TOUCH_HOLD_START_TYPE, touchStartObj, startTouch);
            this.FireListener(touchHoldStartEvent);
            
        }
    }
}

// Execute listeners for logical events.
// Note that there is no way to bubble logical events in the framework at the moment
DvtTouchManager.prototype.fireLogicalEvents = function(touchEvent) {
    var type = touchEvent.type;
    if (type == "touchstart") {
      if (!touchEvent.isTouchHoldBlocked()) {
        this.processAssociatedTouchAttempt(touchEvent, DvtTouchManager.HOVER_TOUCH_KEY, this.HoverStartInternal, this);
      }
      if (this._doubleTapAttemptStarted) {
          touchEvent.preventDefault();
      }
    } else if (type == "touchmove") {
        this.processAssociatedTouchMove(touchEvent, DvtTouchManager.HOVER_TOUCH_KEY);
    } else if (type == "touchend") {
        this.processAssociatedTouchEnd(touchEvent, DvtTouchManager.HOVER_TOUCH_KEY);
    }

    if (type == "touchend") {
        var changedTouches = this._getStoredTouches(touchEvent.changedTouches);
        for (var i=0; i<changedTouches.length; i++) {
            var touch = changedTouches[i];
            var identifier = touch.identifier;
            var info = this.getTouchInfo(identifier);
    
            var targetObj = info.currentObj;
            
            if (info[DvtTouchManager.TOUCH_MODE] != DvtTouchManager.TOUCH_MODE_LONG_PRESS) {
                if (info.fireClick) {
                    var touchClickEvt = new DvtComponentTouchEvent(DvtComponentTouchEvent.TOUCH_CLICK_TYPE, targetObj, touch);
                    touchClickEvt.touchEvent = touchEvent;
                    this.FireListener(touchClickEvt);

                    if (this._doubleTapAttemptStarted) {
                        var prevTapObj = this._doubleTapAttemptObj;
                        this.resetDoubleTap();
                        if (targetObj == prevTapObj) {
                            var touchDblClickEvt = new DvtComponentTouchEvent(DvtComponentTouchEvent.TOUCH_DOUBLE_CLICK_TYPE, targetObj, touch);
                            touchDblClickEvt.touchEvent = touchEvent;
                            this.FireListener(touchDblClickEvt);
                        }
                    } else {
                        this.resetDoubleTap();
                        this._doubleTapTimer.start();
                        this._doubleTapAttemptStarted = true;
                        this._doubleTapAttemptObj = targetObj;
                    }
                }
            }
        }
    }
}

DvtTouchManager.prototype.getTouchInfo = function(touchId) {
    return this._touchMap[touchId];
}

DvtTouchManager.prototype.HoverStartInternal = function(event, touch) {
    var identifier = touch.identifier;
    this._startSingleFingerTouchId = identifier;
    this._touchHoldTimer.stop();
    this._touchHoldTimer.start();
}

DvtTouchManager.prototype.HoverMoveInternal = function(event, touch) {
    var identifier = touch.identifier;
    var info = this.getTouchInfo(identifier);
    var targetObj = info.currentObj;
    var touchHoldMoveEvent = new DvtComponentTouchEvent(DvtComponentTouchEvent.TOUCH_HOLD_MOVE_TYPE, targetObj, touch);
    this.FireListener(touchHoldMoveEvent);
    event.preventDefault();
}

DvtTouchManager.prototype.HoverEndInternal = function(event, touch) {
    var identifier = touch.identifier;
    var info = this.getTouchInfo(identifier);
    var targetObj = info.currentObj;
    var touchHoldEndEvent = new DvtComponentTouchEvent(DvtComponentTouchEvent.TOUCH_HOLD_END_TYPE, targetObj, touch);
    this.FireListener(touchHoldEndEvent);
    if (event)
        event.preventDefault();
}

DvtTouchManager.prototype.resetTouchHold = function() {
  this._startSingleFingerTouchId = null;
  if (this._touchHoldTimer)
      this._touchHoldTimer.stop();
}

// Updates state information for current touches before logical event "bubbles"
DvtTouchManager.prototype.preEventBubble = function(touchEvent) {
     var type = touchEvent.type;
     if (type == "touchstart") {
         this.processTouchStart(touchEvent); 
     } else if (type == "touchmove") {
         this.processTouchMove(touchEvent); 
     } else if (type == "touchend") {
         this.processTouchEnd(touchEvent);    
     }
}

// Updates state information after logical event is done "bubbling"
DvtTouchManager.prototype.postEventBubble = function(touchEvent) {
     var type = touchEvent.type;

     if (type == "touchstart") {
     } else if (type == "touchmove") {
     } else if (type == "touchend") {
        var changedTouches = this._getStoredTouches(touchEvent.changedTouches);
        for (var i=0; i<changedTouches.length; i++)
        {
            var changedTouch = changedTouches[i];
            var identifier = changedTouch.identifier;

            delete this._touchMap[identifier];
            if (this._startSingleFingerTouchId == identifier) {
                this._startSingleFingerTouchId = null;
            }
            // Stop propagation may not allow touch manager to clear saved touch info.  Need to check for any remaining
            // info and remove
            var savedMatches = this._findMatches("touchId", identifier);
            for (var j=0;j<savedMatches.length;j++) {
                var match = savedMatches[j];
                this.removeTooltipInfo(match["touchId"], match["touchObj"]);
            }
        }
    }
}

DvtTouchManager.prototype._findMatch = function(matchProp, matchValue) {
    var idx = -1;
    for (var i=0; i<this._savedTouchInfo.length; i++) {
        var info = this._savedTouchInfo[i];
        if (info[matchProp] == matchValue) {
            idx = i;
        }
    }
    return idx;
}

DvtTouchManager.prototype.saveProcessedTouch = function(touchId, touchObj, tooltipObjOverride, grouping, type, moveListener, endListener, listenerObj) {
  if (touchId) {
    var info = DvtTouchManager.createSavedTouchInfo(touchId, touchObj, tooltipObjOverride, grouping, type, moveListener, endListener, listenerObj);
    this._savedTouchInfo.push(info);
    return true;
  }
  return false;
}

DvtTouchManager.prototype.saveProcessedTouchDefault = function(touchId, touchObj, tooltipObjOverride, grouping, type, listenerObj) {
    var movedListener = null;
    if (listenerObj.immediateTouchMoved)
       movedListener = listenerObj.immediateTouchMoved;
    var endListener = null;
    if (listenerObj.immediateTouchEnded)
       endListener = listenerObj.immediateTouchEnded;

    this.saveProcessedTouch(touchId, touchObj, tooltipObjOverride, grouping, type, movedListener, endListener, listenerObj);
}

DvtTouchManager.prototype.processAssociatedTouch = function(event, uniqueKey, startListener, listenerObj) {
    var type = event.type;
    if (type == "touchstart") {
        this.processAssociatedTouchAttempt(event, uniqueKey, startListener, listenerObj);
    } else if (type == "touchmove") {
        this.processAssociatedTouchMove(event, uniqueKey);
    } else if (type == "touchend") {
        this.processAssociatedTouchEnd(event, uniqueKey);
    }
}

// immediateTouchObj implements a defined interface for handling single touches on the object
DvtTouchManager.prototype.processAssociatedTouchDefault = function(event, immediateTouchObj) {
    this.processAssociatedTouch(event, immediateTouchObj, immediateTouchObj.immediateTouchAttempted, immediateTouchObj);
}

DvtTouchManager.prototype.cancelTouchHold = function() {
    var uniqueKey = DvtTouchManager.HOVER_TOUCH_KEY;
    var touchIds = this.getTouchIdsForObj(uniqueKey);
    for (var i=0; i<touchIds.length; i++) {
        var touchId = touchIds[i];
        var info = this.getTouchInfo(touchId);
        var touch = info["startTouch"];
        if (touch) {
            this._isCancelEvent = true;
            this.performAssociatedTouchEnd(touch, uniqueKey, null);
            this._isCancelEvent = false;
            delete this._touchMap[touchId];
        }
    }

}

DvtTouchManager.prototype.performAssociatedTouchEnd = function(touch, uniqueKey, event) {
    var identifier = touch.identifier;
    var savedInfo = this.getSavedTouchInfo(identifier, uniqueKey);
    if (savedInfo) {
        var listenerObj = savedInfo["listenerObj"];
        var endListener = savedInfo["endListener"]; 

        // Remove tooltip info first
        this.removeTooltipInfo(identifier, uniqueKey);
        if (endListener) {
            endListener.call(listenerObj, event, touch, savedInfo);
        }
    }
}

DvtTouchManager.prototype.processAssociatedTouchAttempt = function(event, uniqueKey, startListener, listenerObj) {
    var touches = event.changedTouches;
    for (var i=0; i<touches.length; i++) {
        var touch = touches[i];
        if (touch) {
            if (startListener)
                startListener.call(listenerObj, event, touch);
        }
    }
}

DvtTouchManager.prototype.processAssociatedTouchMove = function(event, uniqueKey) {
    var touchIds = this.getTouchIdsForObj(uniqueKey);
    for (var i=0; i<touchIds.length; i++) {
        var touchId = touchIds[i];
        if (touchId) {
            var touch = DvtTouchManager.getTouchById(touchId, this._getStoredTouches(event.changedTouches));
            if (touch) {
                var savedInfo = this.getSavedTouchInfo(touch.identifier, uniqueKey);
                if (savedInfo) {
                    var listenerObj = savedInfo["listenerObj"];
                    var moveListener = savedInfo["moveListener"];
    
                    if (moveListener)
                        moveListener.call(listenerObj, event, touch);
                        
                }
            }
        }
    }
}

DvtTouchManager.prototype.processAssociatedTouchEnd = function(event, uniqueKey) {
    var touchIds = this.getTouchIdsForObj(uniqueKey);
    for (var i=0; i<touchIds.length; i++) {
        var touchId = touchIds[i];
        var touch = DvtTouchManager.getTouchById(touchId, this._getStoredTouches(event.changedTouches));
        if (touch) {
            this.performAssociatedTouchEnd(touch, uniqueKey, event);
        }
    }
}

DvtTouchManager.prototype._findMatch = function(matchProp, matchValue) {
    var idx = -1;
    for (var i=0; i<this._savedTouchInfo.length; i++) {
        var info = this._savedTouchInfo[i];
        if (info[matchProp] == matchValue) {
            idx = i;
        }
    }
    return idx;
}
DvtTouchManager.prototype._findMatches = function(matchProp, matchValue) {
    var results = new Array();
    for (var i=0; i<this._savedTouchInfo.length; i++) {
        var info = this._savedTouchInfo[i];
        if (info[matchProp] == matchValue) {
            results.push(info);
        }
    }
    return results;
}



DvtTouchManager.prototype.getSavedTouchInfo = function(touchId, uniqueKey) {
    var matches = this._findMatches("touchId", touchId);
    for (var i=0; i<matches.length;i++) {
        var info = matches[i];
        if (info["touchObj"] == uniqueKey) {
            return info;
        }
    }
    return null;
}
DvtTouchManager.prototype.containsTouchId = function(touchId) {
    var matches = this._findMatches("touchId", touchId);
    return matches.length > 0;
}

DvtTouchManager.prototype.getTouchIdsForObj = function(touchObj) {
    var results = new Array();
    var matches = this._findMatches("touchObj", touchObj);
    for (var i=0; i<matches.length;i++) {
        var info = matches[i];
        var touchId = info["touchId"];
        results.push(touchId);
    }
    return results;
}

DvtTouchManager.prototype.removeTooltipInfo = function(touchId, uniqueKey) {
    var matches = this._findMatches("touchId", touchId);
    var removeObjects = new Array();
    for (var i=0; i<matches.length;i++) {
        var info = matches[i];
        if (info["touchObj"] == uniqueKey) {
            removeObjects.push(info);
        }
    }
    for (var i=0; i<removeObjects.length;i++) {
        var removeObj = removeObjects[i];
        var removeIdx = -1;
        for (var j=0; j<this._savedTouchInfo.length; j++) {
            var info = this._savedTouchInfo[j];
            if (info == removeObj) {
                removeIdx = j;
            }
        }
        if (removeIdx != -1 ){
            this._savedTouchInfo.splice(removeIdx, 1);
            if (this._savedTouchInfo.length == 0) {
                this._context.getTooltipManager().hideTooltip();
            }
        }
    }
}

DvtTouchManager.prototype.setTooltipEnabled = function(touchId, enabled) {
    var tooltipInfoArray = this._savedTouchInfo;
    for (var i=0; i<tooltipInfoArray.length; i++) {
        var tooltipInfo = tooltipInfoArray[i];
        var tooltipTouchId = tooltipInfo.touchId;
        if (tooltipTouchId == touchId) {
            tooltipInfo["allowTooltips"] = enabled;
        }
    }
}

DvtTouchManager.prototype.getTooltipInfo = function() {
  var tooltipInfoObj = new Object();
  var touchIds = new Array();
  var tooltipTarget = null;

  var firstGroup = null;
  var multipleGroups = false;

  var matches = this._findMatches("allowTooltips", true);
  for (var i=0;i<matches.length;i++) {
    var tooltipInfo = matches[i];
    var touchId = tooltipInfo["touchId"];

    if (!firstGroup) {
        firstGroup = tooltipInfo.grouping;
    } else {
        // Multiple groups are not supported for tooltips yet
        if (tooltipInfo.grouping != firstGroup) {
            multipleGroups = true;
        }
    }
    
    var touchInfo = this._touchMap[touchId];
    // By default, show tooltip for item under finger
    var tooltipObj = touchInfo["currentObj"];
    // If an override is present, use this instead
    if (tooltipInfo["tooltipObjOverride"]) {
        tooltipObj = tooltipInfo["tooltipObjOverride"];
    }
    
    touchIds.push(touchId);
    tooltipTarget = tooltipObj;
        
  }
  if (multipleGroups)
    touchIds = new Array();
  tooltipInfoObj.touchIds = touchIds;
  tooltipInfoObj.tooltipTarget = tooltipTarget;

  return tooltipInfoObj;
}

DvtTouchManager.prototype._onlyContainsValue = function(matchProp, matchValue) {
    for (var i=0; i<this._savedTouchInfo.length; i++) {
        var info = this._savedTouchInfo[i];
        if (info[matchProp] != matchValue) {
            return false;
        }
    }
    return true;
}
DvtTouchManager.prototype.containsGrouping = function(type) {
    var matches = this._findMatches("grouping", type);
    return matches.length > 0;
}
DvtTouchManager.prototype.onlyContainsType = function(type) {
    return this._onlyContainsValue("type", type);
}

DvtTouchManager.prototype.onlyContainsGroup = function(group) {
    return this._onlyContainsValue("grouping", group);
}

DvtTouchManager.prototype.processTouchStart = function(touchEvent) {
  var changedTouches = touchEvent.changedTouches;
  var touches = touchEvent.touches;

  this._touchCount = touches.length;
  for (var i=0; i<changedTouches.length; i++)
  {
    var changedTouch = changedTouches[i];
    var screenX = changedTouch.screenX;
    var screenY = changedTouch.screenY;
    var identifier = changedTouch.identifier;
    var targetObj = this._getObjFromTouch(changedTouch);
    var touchInfo = {
      "x":screenX,
      "y":screenY,
      "pageX":changedTouch.pageX,
      "pageY":changedTouch.pageY,
      "dx":0,
      "dy":0,
      "fireClick":true,
      "startTarget":targetObj,
      "currentObj":targetObj,
      "touchMoved":false,
      "touchtype":null,
      "startTouch":changedTouch
    };
    touchInfo[DvtTouchManager.TOUCH_MODE] = DvtTouchManager.TOUCH_MODE_DEFAULT;
    touchInfo["origx"] = screenX;
    touchInfo["origy"] = screenY;      
      
    this._touchMap[identifier] = touchInfo;

  }
  
  // For now, keep the restriction of only one finger being able to be in hover mode at a time
  if (this._isHovering() || !this._isTouchHoldAllowed()) {
      touchEvent.blockTouchHold();
  }
  return true;
}

DvtTouchManager.prototype._isTouchHoldAllowed = function() {
  var touchMoved = false;
  var count = 0;
  for (var id in this._touchMap) {
      var info = this.getTouchInfo(id);
      if (info.touchMoved)
        touchMoved = true;
      count++;
  }
  if (count > 1 && !touchMoved) {
    this.resetTouchHold();
    return false;
  }
  return true;
}

DvtTouchManager.prototype._isHovering = function() {
    for (var id in this._touchMap) {
        var info = this.getTouchInfo(id);
        if (info[DvtTouchManager.TOUCH_MODE] == DvtTouchManager.TOUCH_MODE_LONG_PRESS) {
            return true;
        }
    }
    return false;
}

DvtTouchManager.prototype._getStoredTouches = function(touches) {
  var storedTouches = new Array();
  for (var i=0; i<touches.length; i++) {
    var touch = touches[i];
    var touchid = touch.identifier;
    var info = this.getTouchInfo(touchid);
    if (info) {
        storedTouches.push(touch);
    }
  }
  return storedTouches;
}

DvtTouchManager.prototype.processTouchMove = function(touchEvent) {
  var changedTouches = this._getStoredTouches(touchEvent.changedTouches);
  var touches = this._getStoredTouches(touchEvent.touches);

  for (var i=0; i<changedTouches.length; i++) {
    var touch = changedTouches[i];
    var targetObj = this._getObjFromTouch(touch);
    var touchid = touch.identifier;
    var info = this.getTouchInfo(touchid);
    // If the single finger touch id moves, don't attempt a touch hold
    if (info[DvtTouchManager.TOUCH_MODE] != DvtTouchManager.TOUCH_MODE_LONG_PRESS &&
        this._startSingleFingerTouchId == touchid && 
        Math.abs(info["pageX"] - touch.pageX) > 0)  {
        this.resetTouchHold();
    }
    
    info.currentObj = targetObj;
    info.touchMoved = true;
    info["pageX"] = touch.pageX;
    info["pageY"] = touch.pageY;
   
    // If the move ever goes out of the initial object, don't fire a click
    if (info.fireClick) {
        if (info[DvtTouchManager.TOUCH_MODE] == DvtTouchManager.TOUCH_MODE_LONG_PRESS) {
        } else {
            if (info.currentObj != info.startTarget) {
                info.fireClick = false;
            }
        }
    }

  }

  for (var i=0; i<touches.length;i++) {
      var touch = touches[i];
      var identifier = touch.identifier;
      var info = this.getTouchInfo(identifier);
      var screenX = touch.screenX;
      var screenY = touch.screenY;
      var deltaX = screenX - info["x"];
      var deltaY = screenY - info["y"];

      info["dx"] = deltaX;
      info["dy"] = deltaY;
      info["x"] = screenX;
      info["y"] = screenY;
  }
  return true;
}

DvtTouchManager.prototype.processTouchEnd = function(touchEvent) {  
    var changedTouches = touchEvent.changedTouches;
    this._touchCount = touchEvent.touches.length;  

    for (var i=0; i<changedTouches.length; i++) {
        var touch = changedTouches[i];
        var targetObj = this._getObjFromTouch(touch); 
        var touchid = touch.identifier;
        var info = this.getTouchInfo(touchid);
        if (!info)
            continue;
        if (info.fireClick) {
            if (info[DvtTouchManager.TOUCH_MODE] == DvtTouchManager.TOUCH_MODE_LONG_PRESS) {
              this._startSingleFingerTouchId = null;
            } else {
                var sameTarget = targetObj == info.startTarget;
                var touchMoved = info.touchMoved;
                var fireClick = (sameTarget && !touchMoved);
                info.fireClick = fireClick;
            }
        }
    }
  return true;
}

DvtTouchManager.getTouchById = function(id, touches) {
    if (id) {
        for (var i=0; i<touches.length; i++) {
            var touch = touches[i];
            if (touch.identifier == id) {
                return touch;
            }
        }
    }
    return null;
}

DvtTouchManager.createSavedTouchInfo = function(touchId, touchObj, tooltipObjOverride, grouping, type, moveListener, endListener, listenerObj) {
    var obj = {"touchId" : touchId, "tooltipObjOverride" : tooltipObjOverride, "grouping" : grouping, "type" : type, "touchObj" : touchObj, "allowTooltips" : true};
    obj["moveListener"] = moveListener;
    obj["endListener"] = endListener;
    obj["listenerObj"] = listenerObj;
    return obj;
}

DvtTouchManager.prototype.setTouchRegionBounds = function(touchRegionBounds) {
    this._touchRegionBounds = touchRegionBounds;
}

// Timer used for touch hold event
DvtTouchManager.prototype._handleTouchHoldStartTimer = function() {

    this._touchHoldTimer.stop();
    this.startTouchHold();

}

DvtTouchManager.prototype._handleDoubleTapTimer = function() {
    this.resetDoubleTap();
}

DvtTouchManager.prototype.resetDoubleTap = function() {
    this._doubleTapAttemptStarted = false;
    this._doubleTapAttemptObj = null;
    this._doubleTapTimer.stop();
}

// pan code
DvtTouchManager.prototype.getMultiTouchDelta = function(touchIds)
{

  //Touches are a list of those currently being tracked
  // When a touch is moved, we will compare its screenX and screenY from its last known point.
  // We will then call the handlerCallback, passing in the deltaX and deltaY information.
  //var touches = touchEvent.touches;
  // Handle the case when the number of touches on the surfaces is equal to this._touchCount:
  if (touchIds)
  {
    var touchData;
    var touchType;
    // Have we determined the type of touch this is (only applicable for two finger touches)?
    if (touchIds.length == 2)
    {
      var touch1Data = this._touchMap[touchIds[0]];
      var touch2Data = this._touchMap[touchIds[1]];
      if (touch1Data == null || touch2Data == null)
      {
        // Missing touch data
        return;
      }

      if (touch1Data["touchtype"] == null)
      {
        // Determine if the touches are going away from each other, towards each other, or are
        // moving in unison.
        var touch1Direction = this._determineTouchDirection(touch1Data);
        if (touch1Direction != null)
        {
          var touch2Direction = this._determineTouchDirection(touch2Data);
          if (touch2Direction != null)
          {

            // We have enough data to determine which direction each touch is going.
            touchType = this._isSameDirection(touch1Direction, touch2Direction) ?
              "scroll" : "pinch";

            touch1Data["touchtype"] = touchType;
          }
        }
      }

      touchType = touch1Data["touchtype"];
      if (touchType == null)
      {
        return;
      }
      else if (touchType == "pinch")
      {
        // We currently do not handle pinch actions
        return;
      }
    }
    // If we have the right number of touches that were moved or less (the devices tend to pick up
    // one finger on occassion).
    //if (changedTouches.length <= this._touchCount)
   // {
      // Compute the average deltas:
      var averageXDelta = 0;
      var averageYDelta = 0;
      for (var j=0; j<touchIds.length; j++)
      {
        touchData = this._touchMap[touchIds[j]];
        averageXDelta += touchData["dx"];
        averageYDelta += touchData["dy"];
      }
      averageXDelta /= touchIds.length;
      averageYDelta /= touchIds.length;

      // Determine if each delta was within a small tolerance from the average:
      var changesWereMovement = true;
/*
      for (j=0; j<touchIds.length; j++)
      {
        touchId = touchIds[j];
        touchData = this._touchMap[touchId];
        var DISTANCE_TOLERANCE = 20; // pixels
        if (Math.abs(touchData["dx"] - averageXDelta) > DISTANCE_TOLERANCE ||
            Math.abs(touchData["dy"] - averageYDelta) > DISTANCE_TOLERANCE)
        {
          changesWereMovement = false;
          break;
        }
      }

*/
      if (changesWereMovement)
      {
        // Prevent the default event handling if we've determined that the touch event was in fact
        // for a movement.
        //touchEvent.preventDefault();

        // If there was non-zero movement:
  //      if (averageXDelta != 0 || averageYDelta != 0)
    //    {
          var scaleFactor = 1;//(window.outerWidth / window.innerWidth);
          return {deltaX: averageXDelta * scaleFactor, deltaY: averageYDelta * scaleFactor};
          // Notify the registered function of the deltas:
          //this._handlerCallback(averageXDelta * scaleFactor, averageYDelta * scaleFactor);
      //  }
      }
    }
  return null;
}

/**
 * Given two directions (see _determineTouchDirection) determine if they are moving roughly in
 * the same direction or opposite directions (pinch vs. scroll).
 */
DvtTouchManager.prototype._isSameDirection = function(
  direction1,
  direction2)
{
  if (direction1 == direction2)
  {
    return true;
  }

  // Code below determines that the directions are the same if they are adjacent to each other.
  // Example: treat "ul" as the same direction as "l" and "u".
  if (direction1.length == 2 && direction2.length == 1)
  {
    return direction1.charAt(0) == direction2 || direction1.charAt(1) == direction2;
  }
  else if (direction1.length == 1 && direction2.length == 2)
  {
    return direction1 == direction2.charAt(0) || direction2 == direction1.charAt(1);
  }
  else
  {
    return false;
  }
}

/**
 * Given a touch data object (see _handleTouchMove), determine which direction it is moving.
 * Values are "ul", "u", "ur", "l", "r", "dl", "d" or "dr",
 * where "u" is up, "l" is left, "r" is right and "d" is down.
 * "
 * @return {String} the direction or null if the distance is not significant enough.
 */
DvtTouchManager.prototype._determineTouchDirection = function(touchData)
{
  var origX = touchData["origx"];
  var origY = touchData["origy"];

  if (origX == null || origY == null)
  {
    return null;
  }

  var currentX = touchData["x"];
  var currentY = touchData["y"];

  var MINIMUM_DISTANCE_REQUIRED_RATIO = 0.01; // 1% of zoomed screen

  // Distance formula = sqrt( (x2 - x1)^2 + (y2 - y2)^2 )
  var distanceX = currentX - origX;
  var distanceY = currentY - origY;

  var distance = Math.sqrt( Math.pow(distanceX, 2) + Math.pow(distanceY, 2) );
  var minDistance = window.innerWidth * MINIMUM_DISTANCE_REQUIRED_RATIO;
  if (distance < minDistance)
  {
    // Touch has not moved far enough to determine
    return null;
  }

  // Given a change to both the x and the y coordinates, determine if one is insignificant.
  var INSIGNIFICANT_RATIO = 0.25;
  var directionX = null;
  if (Math.abs(distanceX / distanceY) >= INSIGNIFICANT_RATIO)
  {
    directionX = (distanceX < 0) ? "l" : "r"; // note that we are not considering LTR/RTL here.
      // This is okay as we are not currently concerned with left or right, only if the touches
      // are in the same or different directions.
  }

  var directionY = null;
  if (Math.abs(distanceY / distanceX) >= INSIGNIFICANT_RATIO)
  {
    directionY = (distanceY < 0) ? "u" : "d";
  }

  if (directionX != null && directionY != null)
  {
    return directionY + directionX;
  }
  else if (directionX == null)
  {
    return directionY;
  }
  else if (directionY == null)
  {
    return directionX;
  }

  // Should never reach here
  return null;
}

DvtTouchManager.prototype.calcAveragePosition = function(touchIds) {
    var pointX = 0;
    var pointY = 0;
    var touchCount = touchIds.length;
    for (var i=0;i<touchCount;i++) {
        var touchId = touchIds[i];
        var touchData = this.getTouchInfo(touchId);
        pointX += touchData.pageX;
        pointY += touchData.pageY;
    }
    pointX /= touchCount;
    pointY /= touchCount;
    return new DvtPoint(pointX, pointY);
}

/**
 * Abstract class for DvtRestoreCollapse Events.  
 * 
 * <p>The supported fields are:
 * <ul>
 * <li>state</li>
 * </ul>
 * <p>
 */
var DvtListItemEvent = function(listItemId, attributeGroupId, showHide, evt)
{   
   this.Init(listItemId, attributeGroupId, showHide, evt);
};

DvtListItemEvent.TYPE = 'listItemShowHide';
DvtListItemEvent.SHOW = 'show';
DvtListItemEvent.HIDE = 'hide';

DvtObj.createSubclass(DvtListItemEvent, DvtBaseComponentEvent, "DvtListItemEvent");

DvtListItemEvent.prototype.getNativeEvent = function() {
  return this._evt;
};

DvtListItemEvent.prototype.Init = function(listItemId, attributeGroupId, showHide, evt)
{
  this.type = DvtListItemEvent.TYPE;
  this._listItemId = listItemId;
  this._attrGroupId = attributeGroupId;
  this._showHide = showHide;
  this._evt = evt;
};

DvtListItemEvent.prototype.getListItemId = function () 
{
  return this._listItemId;    
}

DvtListItemEvent.prototype.getShowHide = function () 
{
  return this._showHide;    
}

DvtListItemEvent.prototype.getAttributeGroupId = function () 
{
  return this._attrGroupId;
}

/**
 * Abstract class for DvtRestoreCollapse Events.  
 * 
 * <p>The supported fields are:
 * <ul>
 * <li>state</li>
 * </ul>
 * <p>
 */
var DvtLegendItemRollOverEvent = function(listItemId, attributeGroupId, hideAttr, mouseState, evt)
{   
   this.Init(listItemId, attributeGroupId, hideAttr, mouseState, evt);
};

DvtLegendItemRollOverEvent.TYPE = 'legendItemRollOver';
DvtLegendItemRollOverEvent.MOUSEOVER = 'mouseover';
DvtLegendItemRollOverEvent.MOUSEOUT = 'mouseout';

DvtObj.createSubclass(DvtLegendItemRollOverEvent, DvtBaseComponentEvent, "DvtLegendItemRollOverEvent");

DvtLegendItemRollOverEvent.prototype.getNativeEvent = function() {
  return this._evt;
};

DvtLegendItemRollOverEvent.prototype.Init = function(listItemId, attributeGroupId, hideAttr, mouseState, evt)
{
  this.type = DvtLegendItemRollOverEvent.TYPE;
  this._listItemId = listItemId;
  this._attrGroupId = attributeGroupId;
  this._hideAttr = hideAttr;
  this._mouseState = mouseState;
  this._evt = evt;
};

DvtLegendItemRollOverEvent.prototype.getHideAttributes = function () 
{
  return this._hideAttr;    
}

DvtLegendItemRollOverEvent.prototype.getListItemId = function () 
{
  return this._listItemId;    
}

DvtLegendItemRollOverEvent.prototype.getMouseState = function () 
{
  return this._mouseState;
}

DvtLegendItemRollOverEvent.prototype.getAttributeGroupId = function () 
{
  return this._attrGroupId;
}
var ViewportChangeEvent = function(oldDim, newDim, evt)
{   
   this.Init(oldDim, newDim, evt);
};

ViewportChangeEvent.TYPE = 'viewportChange';

DvtObj.createSubclass(ViewportChangeEvent, DvtBaseComponentEvent, "ViewportChangeEvent");

ViewportChangeEvent.prototype.getNativeEvent = function() {
  return this._evt;
};

ViewportChangeEvent.prototype.Init = function(oldDim, newDim, evt)
{
  this.type = ViewportChangeEvent.TYPE;
  this._oldDim = oldDim;
  this._newDim = newDim;
  this._evt = evt;
};

ViewportChangeEvent.prototype.getOldDimensions = function () 
{
  return this._oldDim;    
}

ViewportChangeEvent.prototype.getNewDimensions = function () 
{
  return this._newDim;    
}


// Events when a custom tooltip action menu is interacted with
var DvtActionTooltipEvent = function(type, targetObj) {
    this.Init(type);
    this.targetObj = targetObj;
}

DvtActionTooltipEvent.TOOLTIP_CLOSED_TYPE = "actiontooltipclosed";
DvtActionTooltipEvent.TOOLTIP_STARTED_TYPE = "actiontooltipstarted";

DvtObj.createSubclass(DvtActionTooltipEvent, DvtBaseComponentEvent, "DvtActionTooltipEvent");

DvtActionTooltipEvent.prototype.Init = function(type) {
  DvtActionTooltipEvent.superclass.Init.call(this, type);
}
/**
 * A higher-level component touch event.
 * @extends DvtBaseComponentEvent
 * @class DvtComponentTouchEvent
 */
var DvtComponentTouchEvent = function(type, targetObj, touch) {
    this.Init(type, targetObj, touch);
}

DvtComponentTouchEvent.TOUCH_HOLD_START_TYPE = "touchholdstart";
DvtComponentTouchEvent.TOUCH_HOLD_MOVE_TYPE = "touchholdmove";
DvtComponentTouchEvent.TOUCH_HOLD_END_TYPE = "touchholdend";

DvtComponentTouchEvent.TOUCH_HOVER_START_TYPE = "touchhoverstart";
DvtComponentTouchEvent.TOUCH_HOVER_MOVE_TYPE = "touchhovermove";
DvtComponentTouchEvent.TOUCH_HOVER_END_TYPE = "touchhoverend";
DvtComponentTouchEvent.TOUCH_HOVER_OVER_TYPE = "touchhoverover";
DvtComponentTouchEvent.TOUCH_HOVER_OUT_TYPE = "touchhoverout";

DvtComponentTouchEvent.TOUCH_CLICK_TYPE = "touchclick";
DvtComponentTouchEvent.TOUCH_DOUBLE_CLICK_TYPE = "touchdblclick";

DvtObj.createSubclass(DvtComponentTouchEvent, DvtBaseComponentEvent, "DvtComponentTouchEvent");

DvtComponentTouchEvent.prototype.Init = function(type, targetObj, touch) {
  DvtComponentTouchEvent.superclass.Init.call(this, type);
  this.targetObj = targetObj;
  this.touch = touch;
}
var DvtComboBoxEvent = function (index, evt) {
    this.Init(index, evt);
}

DvtComboBoxEvent.TYPE = 'comboBoxchange';

DvtObj.createSubclass(DvtComboBoxEvent, DvtBaseEvent, "DvtComboBoxEvent");

/**
 * Constructor.
 *
 * @param index index of selected item
 */
DvtComboBoxEvent.prototype.Init = function (index, evt) {
  this.type = DvtComboBoxEvent.TYPE;

  if (index === undefined) {
    index = -1;
  }
  this._index = index;
  this._evt = evt;
};

/**
 * Get the index of the selected item.
 *
 * @return index of the selected item
 */
DvtComboBoxEvent.prototype.getIndex = function () {
  return this._index;
}
var DvtControlPanelEvent = function (type) {
  this.Init(type);
}

DvtControlPanelEvent.TYPE_SHOW = "dvtPZCPExpand";
DvtControlPanelEvent.TYPE_HIDE = "dvtPZCPCollapse";

DvtObj.createSubclass(DvtControlPanelEvent, DvtBaseEvent, "DvtControlPanelEvent");

/**
 * Constructor.
 *
 * @param type type of controlPanel (show or hide)
 */
DvtControlPanelEvent.prototype.Init = function (type) {
  this._type = type;
};



var DvtBaseScroller= function(context, w, h, id)
{

  this.Init(context, w, h, id);
}

DvtObj.createSubclass(DvtBaseScroller, DvtContainer, "DvtBaseScroller");

// The type of upState to display
DvtBaseScroller.TYPE_DISABLED = 0;
DvtBaseScroller.TYPE_ENABLED = 1;
DvtBaseScroller.TYPE_ACTIVE = 2;

// Width and Height of the scroller symbol
DvtBaseScroller.SYMBOL_WIDTH = 11;
DvtBaseScroller.SYMBOL_HEIGHT = 5;
DvtBaseScroller.BUTTON_CORNER_RADIUS = 0;

DvtBaseScroller.UP_BORDER_COLOR = "#858585";
DvtBaseScroller.UP_FILL_COLOR = "#FFFFFF";
DvtBaseScroller.OVER_BORDER_COLOR = "#7BA0D9";
DvtBaseScroller.OVER_FILL_COLORS = ["#BFD8FB", "#FFFFFF"];
DvtBaseScroller.OVER_FILL_ALPHAS = [100, 100];
DvtBaseScroller.OVER_FILL_RATIOS = [0, 255];
    
DvtBaseScroller.DOWN_BORDER_COLOR = "#69849E";
DvtBaseScroller.DOWN_FILL_COLORS= ["#ACB9CA", "#7488A5"];
DvtBaseScroller.DOWN_FILL_ALPHAS = [100, 100];
DvtBaseScroller.DOWN_FILL_RATIOS = [0, 255];
    
DvtBaseScroller.SYMBOL_BORDER_COLOR_UP = "#46566C"; 
DvtBaseScroller.SYMBOL_BORDER_COLOR_OVER = "#858585";     
DvtBaseScroller.SYMBOL_BORDER_COLOR_DOWN = "#858585";  
DvtBaseScroller.SYMBOL_BORDER_COLOR_DISABLED = "#999999"; 
DvtBaseScroller.SYMBOL_FILL_COLOR_UP = "#625D5D"; //0x333333
DvtBaseScroller.SYMBOL_FILL_COLOR_OVER = "#46566C";     
DvtBaseScroller.SYMBOL_FILL_COLOR_DOWN = "#FFFFFF"; 
DvtBaseScroller.SYMBOL_FILL_COLOR_UP_DISABLED = "#999999"; 

DvtBaseScroller.prototype.Init = function(context, w, h, id){
    this._context = context;
    
    var container = new DvtContainer(context, "legendScroller_" + id);
    var impl = container.getImpl();
    DvtBaseScroller.superclass.Init.call(this, context, impl.getId());
    
    this._width = w;
    this._height = h;

    
    if (DvtAgent.getAgent().isTouchDevice()) {
        var back = this._createTouchArea();
        this.addChild(back);      
    }

    this.drawUpState();
    
}


DvtBaseScroller.prototype.addMouseEventHandlers = function(){
    this.addEventListener("mouseout", this.mouseOutHandler, false, this);
    this.addEventListener("mouseover", this.mouseOverHandler, false, this);
}

DvtBaseScroller.prototype.mouseOverHandler = function(event){
    if(this._upStateType == DvtBaseScroller.TYPE_ENABLED)
        this.drawOverState();
}
DvtBaseScroller.prototype.mouseOutHandler = function(event){
    if(this._upStateType == DvtBaseScroller.TYPE_ENABLED)
        this.drawUpState();
}

DvtBaseScroller.prototype.drawUpState = function(){
    if(this._upStateType == DvtBaseScroller.TYPE_ENABLED){
        return this.drawEnabledState();
    }
    else if(this._upStateType == DvtBaseScroller.TYPE_ACTIVE){
        return this.drawActiveState();
    }
    else
        return this.drawDisabledState();
}

DvtBaseScroller.prototype.drawEnabledState = function(){
    if(this._upStateType !== DvtBaseScroller.TYPE_DISABLED){
        if(!this._button){
            this._button = this._drawButtonShape();
            this.addChild(this._button);
        }
        if(!this._upButton){
          this._upButton = this._drawUpButtonShape();
          this.addChild(this._upButton);
        }
        if(!this._pointer){
          this._pointer = this._drawSymbol();
          this.addChild(this._pointer);
        }
    }
      

    this._button.setAlpha(0.001);
    this._upButton.setAlpha(1);
    
    // Although the button is invisible when first loading
    // We still need to set the fill or stroke, so it can respond to mouse event
    var buttonFill = new DvtSolidFill(DvtBaseScroller.UP_FILL_COLOR, 0);
    this._button.setFill(buttonFill);
    
    var buttonStroke = new DvtSolidStroke(DvtBaseScroller.UP_BORDER_COLOR, 1);
    this._upButton.setStroke(buttonStroke);
    
    var pointerStroke = new DvtSolidStroke(DvtBaseScroller.SYMBOL_BORDER_COLOR_UP, 1);
    var pointerFill = new DvtSolidFill(DvtBaseScroller.SYMBOL_FILL_COLOR_UP, 1);
    this._pointer.setFill(pointerFill);
    this._pointer.setStroke(pointerStroke);
    
    return;
}

DvtBaseScroller.prototype.drawActiveState = function(){
    if(this._upStateType !== DvtBaseScroller.TYPE_DISABLED){
        if(!this._button){
            this._button = this._drawButtonShape();
            this.addChild(this._button);
        }
        if(!this._upButton){
          this._upButton = this._drawUpButtonShape();
          this.addChild(this._upButton);
        }
        if(!this._pointer){
          this._pointer = this._drawSymbol();
          this.addChild(this._pointer);
        }
        
        this._upButton.setAlpha(0.001);
        this._button.setAlpha(1);
        
        var buttonStroke = new DvtSolidStroke(DvtBaseScroller.UP_BORDER_COLOR, 1);
        var buttonFill = new DvtSolidFill(DvtBaseScroller.UP_FILL_COLOR, 1);
        this._button.setStroke(buttonStroke);
        this._button.setFill(buttonFill);
        
        var pointerStroke = new DvtSolidStroke(DvtBaseScroller.SYMBOL_BORDER_COLOR_UP, 1);
        var pointerFill = new DvtSolidFill(DvtBaseScroller.SYMBOL_FILL_COLOR_UP, 1);
        this._pointer.setFill(pointerFill);
        this._pointer.setStroke(pointerStroke);
    }
    
    return;
}

DvtBaseScroller.prototype.drawDisabledState = function(){
    if(!this._button){
        this._button = this._drawButtonShape();
        this.addChild(this._button);
    }
    if(!this._upButton){
      this._upButton = this._drawUpButtonShape();
      this.addChild(this._upButton);
    }
    if(!this._pointer){
      this._pointer = this._drawSymbol();
      this.addChild(this._pointer);
    }
    
    this._button.setAlpha(0.001);
    this._upButton.setAlpha(1);
    
    var buttonStroke = new DvtSolidStroke(DvtBaseScroller.SYMBOL_FILL_COLOR_UP_DISABLED, 1);
    this._upButton.setStroke(buttonStroke);
    
    var pointerStroke = new DvtSolidStroke(DvtBaseScroller.SYMBOL_BORDER_COLOR_DISABLED, 1);
    var pointerFill = new DvtSolidFill(DvtBaseScroller.SYMBOL_FILL_COLOR_UP_DISABLED, 1);
    this._pointer.setFill(pointerFill);
    this._pointer.setStroke(pointerStroke);
    
    return;
}

DvtBaseScroller.prototype.drawOverState = function(){
    if(this._upStateType !== DvtBaseScroller.TYPE_DISABLED){
        if(!this._button){
            this._button = this._drawButtonShape();
            this.addChild(this._button);
        }
        if(!this._upButton){
          this._upButton = this._drawUpButtonShape();
          this.addChild(this._upButton);
        }
        if(!this._pointer){
          this._pointer = this._drawSymbol();
          this.addChild(this._pointer);
        }
    
        this._upButton.setAlpha(0.001);
        this._button.setAlpha(1);
          
        var buttonFill = new DvtLinearGradientFill(90, DvtBaseScroller.OVER_FILL_COLORS);
        var buttonStroke = new DvtSolidStroke(DvtBaseScroller.OVER_BORDER_COLOR, 1);
        this._button.setFill(buttonFill);
        this._button.setStroke(buttonStroke);
        
        var pointerStroke = new DvtSolidStroke(DvtBaseScroller.SYMBOL_BORDER_COLOR_OVER, 1);
        var pointerFill = new DvtSolidFill(DvtBaseScroller.SYMBOL_FILL_COLOR_OVER, 1);
        this._pointer.setFill(pointerFill);
        this._pointer.setStroke(pointerStroke);
    }
    return;
}
/*--------------------------------------------------------------------*/
/*  init()                                                            */
/*--------------------------------------------------------------------*/
/**
 *    Implementation of DvtDetObj.init()
 */
DvtBaseScroller.prototype.init = function()
{

}

DvtBaseScroller.prototype._drawSymbol = function(){

}

DvtBaseScroller.prototype._drawUpButtonShape = function(){

}

DvtBaseScroller.prototype._drawButtonShape = function(){
    var buttonCmds = DvtPathUtils.moveTo(DvtBaseScroller.BUTTON_CORNER_RADIUS, 0)+
    DvtPathUtils.lineTo(this._width - DvtBaseScroller.BUTTON_CORNER_RADIUS, 0)+
    DvtPathUtils.quadTo(this._width, 0, this._width, DvtBaseScroller.BUTTON_CORNER_RADIUS)+
      DvtPathUtils.lineTo(this._width, DvtBaseScroller.BUTTON_CORNER_RADIUS)+
      DvtPathUtils.lineTo(this._width, this._height - DvtBaseScroller.BUTTON_CORNER_RADIUS)+
      DvtPathUtils.quadTo(this._width, this._height, this._width - DvtBaseScroller.BUTTON_CORNER_RADIUS, this._height)+
      DvtPathUtils.lineTo(this._width - DvtBaseScroller.BUTTON_CORNER_RADIUS, this._height)+
      DvtPathUtils.lineTo(DvtBaseScroller.BUTTON_CORNER_RADIUS, this._height)+
      DvtPathUtils.quadTo(0, this._height, 0, this._height - DvtBaseScroller.BUTTON_CORNER_RADIUS)+
      DvtPathUtils.lineTo(0, this._height - DvtBaseScroller.BUTTON_CORNER_RADIUS)+
      DvtPathUtils.lineTo(0, DvtBaseScroller.BUTTON_CORNER_RADIUS)+
      DvtPathUtils.quadTo(0, 0, DvtBaseScroller.BUTTON_CORNER_RADIUS, 0)+
      DvtPathUtils.lineTo(DvtBaseScroller.BUTTON_CORNER_RADIUS, 0);
    DvtPathUtils.closePath();
    var button = new DvtPath(this._context, buttonCmds);
    button.setCursor(DvtSelectionEffectUtils.getSelectingCursor());
    button.setPixelHinting(true);
    return button;
}

DvtBaseScroller.prototype.setUpStateType = function(type){
    this._upStateType = type;
    if(type == DvtBaseScroller.TYPE_DISABLED){
        this.drawDisabledState();
    } else {
        this.drawUpState();
    }
}
var DvtUpScroller = function(context, w, h, id) {
    DvtUpScroller.superclass.Init.call(this, context, w, h, id);
}

DvtObj.createSubclass(DvtUpScroller, DvtBaseScroller, "DvtUpScroller");

DvtUpScroller.prototype._drawSymbol = function(){
    // Position container
    var symbolX = (this._width/2) - (DvtBaseScroller.SYMBOL_WIDTH/2);
    var symbolY = (this._height/2) - (DvtBaseScroller.SYMBOL_HEIGHT/2);


    // Arrow
    var pointerCmds = DvtPathUtils.moveTo(symbolX + DvtBaseScroller.SYMBOL_WIDTH/2, symbolY) + 
              DvtPathUtils.lineTo(symbolX+DvtBaseScroller.SYMBOL_WIDTH, symbolY + DvtBaseScroller.SYMBOL_HEIGHT) + 
              DvtPathUtils.lineTo(symbolX, symbolY+DvtBaseScroller.SYMBOL_HEIGHT) + 
              DvtPathUtils.lineTo(symbolX+DvtBaseScroller.SYMBOL_WIDTH/2, symbolY);
              DvtPathUtils.closePath();
    var pointer = new DvtPath(this._context, pointerCmds);
    var dataCursorArrowFill = new DvtSolidFill("rgb(193, 194, 211)", 1);
    pointer.setFill(dataCursorArrowFill);
    this._pointer = pointer;
    pointer.setCursor(DvtSelectionEffectUtils.getSelectingCursor());
    return pointer;
}

DvtUpScroller.prototype._drawUpButtonShape = function(){
        var buttonCmds = DvtPathUtils.moveTo(0, this._height)+
        DvtPathUtils.lineTo(this._width, this._height)+
        DvtPathUtils.moveTo(0, 0);
    DvtPathUtils.closePath();
    var button = new DvtPath(this._context, buttonCmds);
    var buttonFill = new DvtSolidFill("rgb(19, 180, 200)", 1);
    button.setFill(buttonFill);
    var buttonStroke = new DvtSolidStroke("rgb(19, 180, 200)", 1);
    button.setStroke(buttonStroke);
    button.setPixelHinting(true);
    return button;
}

DvtUpScroller.prototype._createTouchArea = function(){
    var back = new DvtRect(this._context, 0, -15, this._width, this._height + 15);
    back.setFill(new DvtSolidFill("#FFFFFF", 0.001));
    return back;
}
var DvtDownScroller = function(context, w, h, id) {
    DvtDownScroller.superclass.Init.call(this, context, w, h, id);
}

DvtObj.createSubclass(DvtDownScroller, DvtBaseScroller, "DvtDownScroller");

DvtDownScroller.prototype._drawSymbol = function(){
    // Position container
    var symbolX = (this._width/2) - (DvtBaseScroller.SYMBOL_WIDTH/2);
    var symbolY = (this._height/2) - (DvtBaseScroller.SYMBOL_HEIGHT/2);


    // Arrow
    var pointerCmds = DvtPathUtils.moveTo(symbolX, symbolY) + 
              DvtPathUtils.lineTo(symbolX+DvtBaseScroller.SYMBOL_WIDTH, symbolY) + 
              DvtPathUtils.lineTo(symbolX+DvtBaseScroller.SYMBOL_WIDTH/2, symbolY+DvtBaseScroller.SYMBOL_HEIGHT) + 
              DvtPathUtils.lineTo(symbolX, symbolY);
              DvtPathUtils.closePath();
    var pointer = new DvtPath(this._context, pointerCmds);
    var dataCursorArrowFill = new DvtSolidFill("rgb(193, 194, 211)", 1);
    pointer.setFill(dataCursorArrowFill);
    this._pointer = pointer;
    pointer.setCursor(DvtSelectionEffectUtils.getSelectingCursor());
    return pointer;
}

DvtDownScroller.prototype._drawUpButtonShape = function(){
        var buttonCmds = DvtPathUtils.moveTo(0, 0)+
        DvtPathUtils.lineTo(this._width, 0)+
        DvtPathUtils.moveTo(0, 0);
    DvtPathUtils.closePath();
    var button = new DvtPath(this._context, buttonCmds);
    var buttonFill = new DvtSolidFill("rgb(19, 180, 200)", 1);
    button.setFill(buttonFill);
    var buttonStroke = new DvtSolidStroke("rgb(19, 180, 200)", 1);
    button.setStroke(buttonStroke);
    button.setPixelHinting(true);
    return button;
}

DvtDownScroller.prototype._createTouchArea = function(){
    var back = new DvtRect(this._context, 0, 0, this._width, this._height + 15);
    back.setFill(new DvtSolidFill("#FFFFFF", 0.001));
    return back;
}
/**
 * Class representing a scrollable legend.
 * @param {DvtContext} context
 * @param {Number} x
 * @param {Number} y
 * @param {Number} w
 * @param {Number} h
 * @param {Number} legendHeight
 * @param {Object} handle
 * @param {Number} numItems
 * @class 
 * @constructor
 * @extends {DvtRect}
 * @implements {DvtAutomationContainer}
 */

var DvtScrollableLegend = function (context, x, y, w, h, legendHeight, handle, numItems) {
  this.Init(context, x, y, w, h, legendHeight, handle, numItems);
}

DvtObj.createSubclass(DvtScrollableLegend, DvtRect, "DvtScrollableLegend");

DvtScrollableLegend.VERTICAL_GAP = 4;
DvtScrollableLegend.SCROLLER_HEIGHT = 10;
DvtScrollableLegend.HORIZONTAL_SCROLLER_PADDING = 2;
DvtScrollableLegend.VERTICAL_SCROLLER_PADDING = 2;
DvtScrollableLegend.SCROLL_ACCELERATION_PER_SECOND = 7;
DvtScrollableLegend.MAX_SCROLL_VELOCITY_PER_SECOND = 30;

// for automation purposes
DvtScrollableLegend._TEST_ID_THIS = 0;
DvtScrollableLegend._TEST_ID_SCROLL_BUTTON_TOP = 1;
DvtScrollableLegend._TEST_ID_SCROLL_BUTTON_BOTTOM = 2;

DvtScrollableLegend.prototype.Init = function (context, x, y, w, h, legendHeight, handle, numItems) {
  this._context = context;
  var container = new DvtRect(context, x, y, w, h, "scrollableLegend");
  var impl = container.getImpl();
  DvtScrollableLegend.superclass.Init.call(this, context, x, y, w, h, impl.getId());

  this._width = w;
  this._height = h;
  this._x = x;
  this._y = y;
  this._legendHeight = legendHeight;
  this._topScroller = null;
  this._bottomScroller = null;
  this._legendHandle = null;
  this._overlay = null;
  this._legendHandleMaxY = 0;
  this._legendHandleMinY = 0;
  this._legendItemSpace = 0;
  this._legendViewableHeight = 0;
  /** 
   * The array of logical objects for this legend.
   * @private 
   */
  this._peers = [];

  this._topScroller = new DvtUpScroller(context, (this._width - 2 * DvtScrollableLegend.HORIZONTAL_SCROLLER_PADDING), DvtScrollableLegend.SCROLLER_HEIGHT, "top");

  this._topScroller.setTranslateX(x + DvtScrollableLegend.HORIZONTAL_SCROLLER_PADDING);
  this._topScroller.setTranslateY(y + DvtScrollableLegend.VERTICAL_GAP);
  this.addChild(this._topScroller);

  this._bottomScroller = new DvtDownScroller(context, (this._width - 2 * DvtScrollableLegend.HORIZONTAL_SCROLLER_PADDING), DvtScrollableLegend.SCROLLER_HEIGHT, "bottom");

  this._bottomScroller.setTranslateX(x + DvtScrollableLegend.HORIZONTAL_SCROLLER_PADDING);
  this._bottomScroller.setTranslateY(y + h - DvtScrollableLegend.SCROLLER_HEIGHT - DvtScrollableLegend.VERTICAL_GAP);
  this.addChild(this._bottomScroller);

  this._maskTopY = y + DvtScrollableLegend.SCROLLER_HEIGHT + DvtScrollableLegend.VERTICAL_SCROLLER_PADDING + DvtScrollableLegend.VERTICAL_GAP;
  this._maskBottomY = y + h - DvtScrollableLegend.SCROLLER_HEIGHT - DvtScrollableLegend.VERTICAL_SCROLLER_PADDING - DvtScrollableLegend.VERTICAL_GAP;
  this._legendViewableHeight = this._maskBottomY - this._maskTopY;

  this._bottomScrollTimer = new DvtTimer(context, 50, this.scrollDown, this);
  this._topScrollTimer = new DvtTimer(context, 50, this.scrollUp, this);

  this._handle = handle;

  if (!DvtAgent.getAgent().isTouchDevice()) {
    // Touch is handled in MEH
    this._topScroller.addMouseEventHandlers();
    this._bottomScroller.addMouseEventHandlers();
    this._topScroller.addEventListener("mousedown", this.onStartTopScroller, false, this);
    this._topScroller.addEventListener("mouseup", this.onStopTopScroller, false, this);
    this._topScroller.addEventListener("click", this.onClickTopScroller, false, this);
    this._bottomScroller.addEventListener("mousedown", this.onStartBottomScroller, false, this);
    this._bottomScroller.addEventListener("mouseup", this.onStopBottomScroller, false, this);
    this._bottomScroller.addEventListener("click", this.onClickBottomScroller, false, this);
  }
  else {
    if (this._handle) {
      this._handle.addEventListener("touchstart", this._touchHandler, false, this);
      this._handle.addEventListener("touchmove", this._touchHandler, false, this);
      this._handle.addEventListener("touchend", this._touchHandler, false, this);
      this._topScroller.addEventListener("touchstart", this._touchTopHandler, false, this);
      this._topScroller.addEventListener("touchmove", this._touchTopHandler, false, this);
      this._topScroller.addEventListener("touchend", this._touchTopHandler, false, this);
      this._bottomScroller.addEventListener("touchstart", this._touchBottomHandler, false, this);
      this._bottomScroller.addEventListener("touchmove", this._touchBottomHandler, false, this);
      this._bottomScroller.addEventListener("touchend", this._touchBottomHandler, false, this);
    }
  }

  if (this._handle) {
    this._handle.moveY(this._maskTopY - this._y);
    this._topScroller.setUpStateType(DvtBaseScroller.TYPE_DISABLED);
    this._bottomScroller.setUpStateType(DvtBaseScroller.TYPE_ENABLED);
    this._legendHandleMaxY = this._handle._y;
    this._legendHandleMinY = (this._legendHandleMaxY - this._legendHeight) + (this._maskBottomY - this._maskTopY);
    this._handle.setClipRect(new DvtRectangle(this._x, this._maskTopY, this._width, this._maskBottomY - this._maskTopY));
  }

  this._legendItemSpace = (this._legendHeight) / (numItems == 0 ? 1 : numItems);
}

/**
 * Registers the object peer with the legend.  The peer must be registered to participate
 * in interactivity.
 * @param {DvtLegendObjPeer} peer
 */
DvtScrollableLegend.prototype.__registerObject = function(peer) {
  this._peers.push(peer);
}

/**
 * Processes a category rollover event. If the event is for a logical object associated with this scrollable legend, 
 * the legend will scroll it into view.
 * @param {object} event
 */
DvtScrollableLegend.prototype.processCategoryRollover = function(event) {
  var category = event.getCategory();
  for (var i = 0; i < this._peers.length; i++) {
    var obj = this._peers[i];
    if (obj && obj.getCategories && obj.getCategories().indexOf(category) > -1) {
      this.scrollIntoView(i);
      break;
    }
  }
}

DvtScrollableLegend.prototype.scrollLegend = function (diff) {
  if (diff != 0) {
    this._handle.moveY(diff);

    // Set enabled/disabled for the scroller buttons
    if (this.isTopScrollerDisabled())
      this._topScroller.setUpStateType(DvtBaseScroller.TYPE_DISABLED);
    else 
      this._topScroller.setUpStateType(DvtBaseScroller.TYPE_ENABLED);

    if (this.isBottomScrollerDisabled())
      this._bottomScroller.setUpStateType(DvtBaseScroller.TYPE_DISABLED);
    else 
      this._bottomScroller.setUpStateType(DvtBaseScroller.TYPE_ENABLED);
  }
}

DvtScrollableLegend.prototype.onStartTopScroller = function (event) {
  this.processStartTopScroller();
  if (event)
    event.preventDefault();
}

DvtScrollableLegend.prototype.processStartTopScroller = function () {
  // Shade the background of the scrollable legend
  if (!DvtAgent.getAgent().isTouchDevice()) {
    this._topScroller.drawActiveState();
  }

  this._prevTime = new Date().getTime();
  this._currTime = this._prevTime;
  this._velocity = 0;
  this._topScrollTimer.start();
}

DvtScrollableLegend.prototype.onStopTopScroller = function (event) {
  this.processStopTopScroller();
  if (event)
    event.preventDefault();
}

DvtScrollableLegend.prototype.processStopTopScroller = function () {
  // Remove the shading of the background of the scrollable legend
  if (DvtAgent.getAgent().isTouchDevice()) {
    this._topScroller.drawUpState();
  }
  else {
    this._topScroller.drawOverState();
  }
  this._topScrollTimer.stop();
}

DvtScrollableLegend.prototype.onClickTopScroller = function (event) {
  this.processClickTopScroller();
  if (event)
    event.preventDefault();
}

DvtScrollableLegend.prototype.processClickTopScroller = function () {
  var diff = this._legendHandleMaxY - this._handle._y;
  if (diff > this._legendItemSpace) {
    this.scrollLegend(this._legendItemSpace);
  }
  else {
    this.scrollLegend(diff);
  }
  this.onStopTopScroller(null);
}

DvtScrollableLegend.prototype.onStartBottomScroller = function (event) {
  this.processStartBottomScroller();
  if (event)
    event.preventDefault();
}

DvtScrollableLegend.prototype.processStartBottomScroller = function () {
  if (!DvtAgent.getAgent().isTouchDevice()) {
    this._bottomScroller.drawActiveState();
  }
  this._prevTime = new Date().getTime();
  this._currTime = this._prevTime;
  this._velocity = 0;

  this._bottomScrollTimer.start();
}

DvtScrollableLegend.prototype.onStopBottomScroller = function (event) {
  this.processStopBottomScroller();
  if (event)
    event.preventDefault();
}

DvtScrollableLegend.prototype.processStopBottomScroller = function () {
  if (DvtAgent.getAgent().isTouchDevice()) {
    this._bottomScroller.drawUpState();
  }
  else {
    this._bottomScroller.drawOverState();
  }
  this._bottomScrollTimer.stop();
}

DvtScrollableLegend.prototype.onClickBottomScroller = function (event) {
  this.processClickBottomScroller();
  if (event)
    event.preventDefault();
}

DvtScrollableLegend.prototype.processClickBottomScroller = function () {
  var diff = this._legendHandleMinY - this._handle._y;
  if (Math.abs(diff) > this._legendItemSpace) {
    this.scrollLegend( - this._legendItemSpace);
  }
  else {
    this.scrollLegend(diff);
  }

  this.onStopBottomScroller(null);
}

DvtScrollableLegend.prototype.processScrollerStart = function (targetObj) {
  if (targetObj) {
    var searchArray = new Array();
    searchArray.push(targetObj);
    var parentObj = targetObj.getParent();
    if (parentObj)
      searchArray.push(parentObj);
    for (var i = 0;i < searchArray.length;i++) {
      var searchObj = searchArray[i];
      if (searchObj instanceof DvtDownScroller) {
        this.processStartBottomScroller();
        return true;
      }
      else if (searchObj instanceof DvtUpScroller) {
        this.processStartTopScroller();
        return true;
      }
    }
  }
  return false;
}

DvtScrollableLegend.prototype.processScrollerEnd = function (targetObj) {
  if (targetObj) {
    var searchArray = new Array();
    searchArray.push(targetObj);
    var parentObj = targetObj.getParent();
    if (parentObj)
      searchArray.push(parentObj);
    for (var i = 0;i < searchArray.length;i++) {
      var searchObj = searchArray[i];
      if (searchObj instanceof DvtDownScroller) {
        this.processStopBottomScroller();
        return true;
      }
      else if (searchObj instanceof DvtUpScroller) {
        this.processStopTopScroller();
        return true;
      }
    }
  }
  return false;
}

DvtScrollableLegend.prototype.isTopScrollerDisabled = function () {
  if (this._handle._y >= this._legendHandleMaxY)
    return true;
  else 
    return false;
}

DvtScrollableLegend.prototype.isBottomScrollerDisabled = function () {
  if (this._handle._y <= this._legendHandleMinY)
    return true;
  else 
    return false;
}

DvtScrollableLegend.prototype.scrollDown = function () {
  if (this._handle._y > this._legendHandleMinY) {
    this._prevTime = this._currTime;
    this._currTime = new Date().getTime();
    var elapsed = this._currTime - this._prevTime;
    var acceleration = DvtScrollableLegend.SCROLL_ACCELERATION_PER_SECOND * (elapsed / 1000);
    this._velocity = Math.min(DvtScrollableLegend.MAX_SCROLL_VELOCITY_PER_SECOND, this._velocity + acceleration);
    var diff = Math.max(this._legendHandleMinY - this._handle._y,  - this._velocity);
    this.scrollLegend(diff);
  }
  else {
    this.onStopBottomScroller(null);
  }
}

DvtScrollableLegend.prototype.scrollUp = function () {
  if (this._handle._y < this._legendHandleMaxY) {
    this._prevTime = this._currTime;
    this._currTime = new Date().getTime();
    var elapsed = this._currTime - this._prevTime;
    var acceleration = DvtScrollableLegend.SCROLL_ACCELERATION_PER_SECOND * (elapsed / 1000);
    this._velocity = Math.min(DvtScrollableLegend.MAX_SCROLL_VELOCITY_PER_SECOND, this._velocity + acceleration);
    var diff = Math.min(this._legendHandleMaxY - this._handle._y, this._velocity);
    this.scrollLegend(diff);
  }
  else {
    this.onStopTopScroller(null);
  }
}

DvtScrollableLegend.prototype.scrollIntoView = function (idx) {
  if (idx < 0) {
    return;
  }

  var diff = 0;
  var targetY = this._legendHandleMaxY - (idx * this._legendItemSpace);

  if (targetY <= this._handle._y - this._legendViewableHeight + 1) {
    diff = (targetY + this._legendViewableHeight) - this._handle._y - this._legendItemSpace;
    this.scrollLegend(diff);
  }
  else if (targetY > this._handle._y) {
    diff = targetY - this._handle._y - this._legendItemSpace;
    this.scrollLegend(diff);

    //scroll up one more notch if necessary
    diff = this._legendHandleMaxY - this._handle._y;
    if (diff > this._legendItemSpace) {
      this.scrollLegend(this._legendItemSpace);
    }
    else {
      this.scrollLegend(diff);
    }
  }
}

DvtScrollableLegend.prototype._touchHandler = function (event) {
  this.getContext().getTouchManager().processAssociatedTouchDefault(event, this);
}

DvtScrollableLegend.prototype._touchTopHandler = function (event) {
  this.getContext().getTouchManager().processAssociatedTouch(event, this._topScroller, this.OnTouchStartTopScroller, this);
}

DvtScrollableLegend.prototype._touchBottomHandler = function (event) {
  this.getContext().getTouchManager().processAssociatedTouch(event, this._bottomScroller, this.OnTouchStartBottomScroller, this);
}

DvtScrollableLegend.prototype.OnTouchStartTopScroller = function (event, touch) {
  this.processStartTopScroller();
  this.getContext().getTouchManager().saveProcessedTouch(touch.identifier, this._topScroller, this._topScroller, "scrollablelegendtop", "scrollablelegendtop", null, this.OnTouchEndTopScroller, this);
  event.blockTouchHold();
}

DvtScrollableLegend.prototype.OnTouchEndTopScroller = function (event, touch) {
  this.processStopTopScroller();
}

DvtScrollableLegend.prototype.OnTouchStartBottomScroller = function (event, touch) {
  this.processStartBottomScroller();
  this.getContext().getTouchManager().saveProcessedTouch(touch.identifier, this._bottomScroller, this._bottomScroller, "scrollablelegendbottom", "scrollablelegendbottom", null, this.OnTouchEndBottomScroller, this);
  event.blockTouchHold();
}

DvtScrollableLegend.prototype.OnTouchEndBottomScroller = function (event, touch) {
  this.processStopBottomScroller();
}

DvtScrollableLegend.prototype.immediateTouchAttempted = function (event, touch) {
  var tm = this.getContext().getTouchManager();

  var touchX = touch.pageX;
  var touchY = touch.pageY;
  var relPos = this.getContext().getRelativePosition(touchX, touchY);
  var legendRect = new DvtRectangle(this._x, this._y, this._width, this._height);
  var stagePoint = this.localToStage(new DvtPoint(legendRect.x, legendRect.y));
  legendRect.x = stagePoint.x;
  legendRect.y = stagePoint.y;
  if (legendRect.containsPoint(relPos.x, relPos.y)) {
      this._prevTouchY = relPos.y;
      tm.saveProcessedTouchDefault(touch.identifier, this, this, "scrollablelegend", "scrollablelegend", this);
      // BUG #12883879: Still allow touch and hold to be performed on legend
      //event.blockTouchHold();
  }
}

DvtScrollableLegend.prototype.immediateTouchMoved = function (event, touch) {
  var touchX = touch.pageX;
  var touchY = touch.pageY;
  var relPos = this.getContext().getRelativePosition(touchX, touchY);
  var relX = relPos.x;
  var relY = relPos.y;
  var diffY = (relY - this._prevTouchY);
  if (this._handle._y + diffY < this._legendHandleMinY)
    diffY = 0;
  if (this._handle._y + diffY > this._legendHandleMaxY)
    diffY = 0;
  this.scrollLegend(diffY);
  this._prevTouchY = relY;
  event.preventDefault();

}

DvtScrollableLegend.prototype.immediateTouchEnded = function (event, touch) {

  //var handled = legend.processScrollerEnd(targetObj);
}

/**
 * @override
 */
DvtScrollableLegend.prototype.dispatchTestEvent = function(subId, eventType, params) 
{
  // implementation of interface DvtAutomationContainer
  var subComponent;

  if(subId <= DvtScrollableLegend._TEST_ID_THIS)
    subComponent = this;
  else if(subId == DvtScrollableLegend._TEST_ID_SCROLL_BUTTON_TOP)
    subComponent = this._topScroller;
  else if(subId == DvtScrollableLegend._TEST_ID_SCROLL_BUTTON_BOTTOM)
    subComponent = this._bottomScroller;

  if(subComponent && subComponent instanceof DvtDisplayable)
    subComponent.dispatchDisplayableEvent(eventType, params);
              
};
/**
  *  Handle.
  *  @extends DvtContainer
  *  @class DvtHandle  handle. 
  *  @constructor  
  */
var   DvtHandle = function(context, sId, boundRect, clipRect, clipId) {
    this.Init(context, sId, boundRect, clipRect, clipId);
}

DvtObj.createSubclass(DvtHandle, DvtContainer, "DvtHandle");



/**
 *    @protected
 */
DvtHandle.prototype.Init = function(context, sId, boundRect, clipRect, clipId) {

    DvtHandle.superclass.Init.call(this, context, sId);
    this.Id = sId;
    this._x = 0;
    this._y = 0;
    this._boundRect = boundRect;
    this._clipRect = this._normalizeRect(clipRect);
    this._clipId = clipId;
}

/**
 * getId - returns this handle ID
 */
DvtHandle.prototype.getId = function() {
    return this.Id;
}

/**
 * getBoundingPoints - returns the bounding points for this handle
 *
 */
DvtHandle.prototype.getBoundingPoints = function() {
    return this._boundRect;
}

/**
 * getClipRect - returns the clipping rect for this handle
 *
 */
DvtHandle.prototype.getClipRect = function() {
    return this._clipRect;
}

/**
 * setClipRect - sets the clipRect on this handle
 *
 */
DvtHandle.prototype.setClipRect = function(clipRect) {
    this._clipRect = this._normalizeRect(clipRect);
}

DvtHandle.prototype.getX = function() {
    return this._x;
}

DvtHandle.prototype.getY = function() {
    return this._y;
}

DvtHandle.prototype.moveX = function(nx) {

    this._x += nx;

    if (this._boundRect != null) {
        this._boundRect[0] += nx;
        this._boundRect[2] += nx;
    }
    
    // Bug #12826435: Translate the container instead of all the children indiv
    var oldX = this.getTranslateX();
    this.setTranslateX(oldX + nx);

    // TODO: preClippingSanityCheck();
    // TODO: updateBackgroundEraser();
}


DvtHandle.prototype.moveY = function(ny) {

    this._y += ny;

    if (this._boundRect != null) {
        this._boundRect[1] += ny;
        this._boundRect[3] += ny;
    }
    
    // Bug #12826435: Translate the container instead of all the children indiv
    
    var oldY = this.getTranslateY();
    this.setTranslateY(oldY + ny);

    // TODO: preClippingSanityCheck();
    // TODO: updateBackgroundEraser();
}


DvtHandle.prototype.render = function() {
    if (this._clipRect) {
        var cp = new DvtClipPath(this._clipId);
        cp.addRect(this._clipRect.x, this._clipRect.y, this._clipRect.w, this._clipRect.h);
        this.setClipPath(cp);
    }
}


DvtHandle.prototype._normalizeRect = function(rect) {

    // for some reason the clipRect may be defined "backward" with height
    // (and width ?) < 0, if so, normalize it
    if (rect && rect.w < 0) {
        rect.w = -rect.w;
        rect.x -= rect.w;
    }
    if (rect && rect.h < 0) {
        rect.h = -rect.h;
        rect.y -= rect.h;
    }
    return rect;
}

/**
 *  A static class for DnD support.
 *  @class DvtDnDUtils
 */
var DvtDnDUtils = function () {
};

/**
 * Returns a {DvtRectangle} representing the drag feedback bounds.
 * @param {object} displayables The DvtDisplayable or array of DvtDisplayables to display for drag feedback.
 * @param {DvtDisplayable} targetCoordinateSpace The displayable defining the coordinate space of the resulting bounds.  The
 *                                               parent coordinate space is used if none is provided.
 */
DvtDnDUtils.getDragFeedbackBounds = function (displayables, targetCoordinateSpace) {
  if (!displayables)
    return null;

  var bounds = null;
  if (!(displayables instanceof Array)) {
    // for simple objects, just return the object bounds
    // TODO: eventually should ensure that bounds are in container coordinates
    bounds = displayables.getDimensions(targetCoordinateSpace ? targetCoordinateSpace : displayables.getParent());
  }
  else if (displayables.length > 0) {
    // TODO: eventually should ensure that bounds are in container coordinates
    // for arrays, initialize bounds based on the first object
    bounds = displayables[0].getDimensions(targetCoordinateSpace ? targetCoordinateSpace : displayables[0].getParent());

    // ... and adjust it to acommodate other objects in the collection
    for (var i = 1;i < displayables.length;i++) {
      var obj = displayables[i];
      var objBounds = obj.getDimensions(targetCoordinateSpace ? targetCoordinateSpace : obj.getParent());

      if (objBounds.x < bounds.x) {
        bounds.w += (bounds.x - objBounds.x);
        bounds.x = objBounds.x;
      }
      if (objBounds.y < bounds.y) {
        bounds.h += (bounds.y - objBounds.y);
        bounds.y = objBounds.y;
      }
      if ((objBounds.x + objBounds.w) > (bounds.x + bounds.w)) {
        bounds.w = objBounds.x + objBounds.w - bounds.x;
      }
      if ((objBounds.y + objBounds.h) > (bounds.y + bounds.h)) {
        bounds.h = objBounds.y + objBounds.h - bounds.y;
      }
    }
  }
  return bounds;
}
/**
 * Abstract class for XML parser.  
 * @extends DvtObj
 * @class DvtXmlParser
 * @constructor
 * 
 * @param {DvtContext}  context  platform specific context object
 */
var DvtXmlParser = function(context) {
  if (!this._impl) {
    this._impl = context.getImplFactory().newParser();
  }
};

DvtObj.createSubclass(DvtXmlParser, DvtObj, "DvtXmlParser");

/**
 * Parses the XML string and returns the root node.
 * @params {string} xmlString the XML string to parse
 * @return {DvtXmlNode} the root node of the XML document
 */
DvtXmlParser.prototype.parse = function(xmlString) {
  if (this._impl && this._impl.parse) {
    return this._impl.parse(xmlString);
  }
  
  return null;
}
/**
 * Abstract class for XML node.  Subclasses should override to provide support
 * for different platforms.
 * @extends DvtObj
 * @class DvtXmlNode
 * @constructor
 */
var DvtXmlNode = function() {}

DvtObj.createSubclass(DvtXmlNode, DvtObj, "DvtXmlNode");

/**
 * Returns the value for the given attribute in this XML node.
 * @param {string} attr the attribute to look for
 * @return {string} the value of the attribute, if available
 */
DvtXmlNode.prototype.getAttribute = function(attr) {
  return null; // subclasses should override
}

/**
 * Returns an Array containing the child elements of this node.  Only nodes that
 * are XML elements are returned.  Text nodes are ignored.
 * @return {array} an Array containing all child elements of this node.
 */
DvtXmlNode.prototype.getChildNodes = function() {
  return new Array(); // subclasses shoudl override
}

/**
 * Returns the child element of this node. Only nodes that
 * are XML elements are returned.  Text nodes are ignored.
 * @return {DvtXmlNode} the first child element
 */
DvtXmlNode.prototype.getChild = function(i) {
  var children = this.getChildNodes();
  if(children != null && children.length > i)
    return children[i];
  else
    return null;
}

/**
 * Returns the first child element of this node. Only nodes that
 * are XML elements are returned.  Text nodes are ignored.
 * @return {DvtXmlNode} the first child element
 */
DvtXmlNode.prototype.getFirstChild = function() {
  return this.getChild(0);
}

/**
 * Returns the name of this node.
 * @return {string} the name of the node
 */
DvtXmlNode.prototype.getName = function() {
  return null; //subclasses should override
};

/**
 * Returns the attributes of this node as an array of 
 * {name:, value:} pairs.
 * @return {array} the attributes of the node
 */
DvtXmlNode.prototype.getAttributes = function() {
  return null; //subclasses should override
};


/**
 * Returns an Array containing the children of this node. 
 * @return {array} an Array containing all child elements and text nodes of this node.
 */
DvtXmlNode.prototype.getAllChildNodes = function() {
  return new Array(); // subclasses shoudl override
}


/**
 * Returns the value of this node.
 * @return {string} the value of the node
 */
DvtXmlNode.prototype.getNodeValue = function() {
  return null; //subclasses should override
};

/**
 * Returns the textContent of this node.
 * @return {string} the textContent of the node
 */
DvtXmlNode.prototype.getTextContent = function() {
  return null; //subclasses should override
};

/**
 * Returns a node list of all child element nodes whose tagName match the speccified name.
 * @return {string} the name of the node
 */
DvtXmlNode.prototype.getElementsByTagName = function(name) {
  return null; //subclasses should override
};


// Copyright (c) 2008, 2012, Oracle and/or its affiliates. 
// All rights reserved. 

/**
  * A factory class for HTML to create object implementations.
  * @extends  DvtImplFactory
  * @class DvtHtmlImplFactory  A factory class to create HTML implementation objects.
  * @constructor  Creates HTML inplementation objects.
  */
var DvtHtmlImplFactory = function(context) {
  this.Init(context) ;
};

DvtObj.createSubclass(DvtHtmlImplFactory, DvtImplFactory, "DvtHtmlImplFactory");

/**
  *  Object initializer.
  *  @protected
  */
DvtHtmlImplFactory.prototype.Init = function(context)
{
   DvtHtmlImplFactory.superclass.Init.call(this, context) ;
};

/*-------------------------------------------------------------------------*/
/*     Other Constructors                                                  */
/*-------------------------------------------------------------------------*/

/**
 * @override
 */
DvtHtmlImplFactory.prototype.newParser = function() {
  return new DvtDomXmlParser();
};


/**
  * Create a new timer.
  * 
  * @returns {DvtHtmlTimer}
  * @override
  */
DvtHtmlImplFactory.prototype.newTimer = function () {
  return new DvtHtmlTimer();
};

/**
 * @override
 */
DvtHtmlImplFactory.prototype.newContextMenuHandler = function () {
  return new DvtHtmlContextMenuHandler();
};

/**
 * @override
 */
DvtHtmlImplFactory.prototype.newTooltipManager = function (id) {
  return new DvtHtmlTooltipManager(id);
};

/**
 * @override
 */
DvtHtmlImplFactory.prototype.newRichTooltipManager = function (id) {
  return new DvtHtmlRichTooltipManager(id);
};

/**
 * @override
 */
DvtHtmlImplFactory.prototype.newJsExt = function () {
  return new DvtSvgJsExt();
};
// Copyright (c) 2011, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/**
  * Class representing a timer in HTML.
  * @class DvtHtmlTimer
  * @constructor
  */
var DvtHtmlTimer = function()
{
  this.Init();
};

DvtObj.createSubclass(DvtHtmlTimer, DvtObj, "DvtHtmlTimer");

/**
  * @protected
  */
DvtHtmlTimer.prototype.Init = function()
{
  this._timerId = null;
};

/**
  * Start the internal timer implementation.
  * 
  * @param {number}  interval  interval between timer ticks, in milliseconds
  * @param {function}  callback  function to call for each timer tick
  * @param {object}  callbackObj  optional object instance that callback 
  *        function is defined on
  */
DvtHtmlTimer.prototype.startTimer = function(interval, callback, callbackObj)
{
  this._timerId = window.setInterval(function() {callback.call(callbackObj)}, interval);
};

/**
  * Stop the internal timer implementation.
  */
DvtHtmlTimer.prototype.stopTimer = function()
{
  if (this._timerId)
  {
    window.clearInterval(this._timerId);
    this._timerId = null;
  }
};

/**
 * Context Menu Handler implementation for HTML context menus.
 * @class DvtHtmlContextMenuHandler
 * @constructor
 */
var DvtHtmlContextMenuHandler = function() {
	this.Init();
};

DvtObj.createSubclass(DvtHtmlContextMenuHandler, DvtObj, "DvtHtmlContextMenuHandler");

DvtHtmlContextMenuHandler.prototype.Init = function()
{
}

DvtHtmlContextMenuHandler.prototype.setObj = function(obj)
{
	this._obj = obj;
}

DvtHtmlContextMenuHandler.prototype.prepareMenuItems = function(event, menuType, menuId) {
    //Nothing
}

DvtHtmlContextMenuHandler.prototype.getMenuEvent = function(xmlNodes, event, menuType, menuId) {
  var nativeEvent = event.getNativeEvent();
  // Look through all context menu definitions for the right context menu to show
  for(var i=0; i<xmlNodes.length; i++) {
    var xmlNode = xmlNodes[i];
    
    if(menuType == xmlNode.getAttribute(DvtContextMenuHandler._ATTR_MENU_CONTAINER_TYPE)) {
      // Match found.  This implementation will fire a showPopupEvent.
      var popupId = xmlNode.getAttribute(DvtContextMenuHandler._ATTR_MENU_CONTAINER_POPUP_ID);
      return new DvtContextMenuEvent(nativeEvent, popupId);
    }
  }
  return null;
}
/**
 * @extends DvtTooltipManager
 * @class DvtHtmlTooltipManager
 */
var DvtHtmlTooltipManager = function(domElementId) {
    this.Init(domElementId);
};

DvtObj.createSubclass(DvtHtmlTooltipManager, DvtTooltipManager, "DvtHtmlTooltipManager");

/** @private */
DvtHtmlTooltipManager._TOOLTIP_DIV_ID = "_dvtTooltip";

DvtHtmlTooltipManager.SHOW_DELAY = 500;  // in ms
DvtHtmlTooltipManager.HIDE_DELAY = 5000; // in ms
DvtHtmlTooltipManager.TRANSITION_DURATION = 250;  // in ms

DvtHtmlTooltipManager.BG_COLOR = "#c1ccd7";
DvtHtmlTooltipManager.BORDER_COLOR = "#9ba2b0";
DvtHtmlTooltipManager.FONT_COLOR = "#383a47";

DvtHtmlTooltipManager.UNSTYLED_POPUP_CLASS = "OraDVTUnstyledPopup";
DvtHtmlTooltipManager.DATATIP_POPUP_CLASS = "OraDVTDatatipPopup";
DvtHtmlTooltipManager.TOOLTIP_POPUP_CLASS = "OraDVTTooltipPopup";


DvtHtmlTooltipManager.BORDER_BUFFER = 2;            // Buffer for border, only used for y for now
DvtHtmlTooltipManager.TOOLTIP_ABOVE_OFFSET = 10;    // Adjustment for tooltip position when above mouse


DvtHtmlTooltipManager.prototype.Init = function(domElementId) 
{
    // if a dom element is specified, it will override the default tooltip div
    this._domElementId = (domElementId ? domElementId : DvtHtmlTooltipManager._TOOLTIP_DIV_ID);
    this._initializeTooltipElement();
    this._isTooltip = true;
}

/** @inheritDoc */
// x and y are pageX and pageY in this html-based implementation
DvtHtmlTooltipManager.prototype.showDatatip = function(x, y, text, borderColor)
{
    this._isTooltip = false;
    this.showTextAtPosition(x, y, text, borderColor, true, DvtHtmlTooltipManager.DATATIP_POPUP_CLASS);
};

DvtHtmlTooltipManager.prototype.showTextAtPosition = function(x, y, text, borderColor, useOffset, popupClass)
{
  var tooltipElem = document.createElement("span");
  if (text)
      text = text.replace(/\n/g, '<br>'); // replace logical newlines sequences
  tooltipElem.style.visibility = "inherit";
  tooltipElem.innerHTML = text;
  var outerElem = this.getTooltipElem();
  outerElem.style.borderColor = borderColor;
  this.showElementAtPosition(x, y, tooltipElem, useOffset, true, popupClass);
}

DvtHtmlTooltipManager.PrepElement = function(tooltip, popupClass) {
  if (!popupClass)
    popupClass = DvtHtmlTooltipManager.UNSTYLED_POPUP_CLASS;
  tooltip.className = popupClass;
}

DvtHtmlTooltipManager.prototype.PostElement = function(tooltip, x, y, noEvents, useOffset) {
  if (noEvents) {
      tooltip.style["pointer-events"] = "none";
  } else {
      tooltip.style["pointer-events"] = "auto";
  }
  if (useOffset) {
      var offsets = this.getOffsets(tooltip);
      this.positionTip(tooltip, x+offsets.x, y+offsets.y, x, y);
  } else
      this.positionTip(tooltip, x, y, x, y);

  tooltip.style.visibility = "visible";    
}

DvtHtmlTooltipManager.prototype.showElementAtPosition = function(x, y, element, useOffset, noEvents, popupClass) {
  var tooltip = this.getTooltipElem();
  
  DvtHtmlTooltipManager.PrepElement(tooltip, popupClass);

  tooltip.innerHTML = "";
  tooltip.appendChild(element);

  this.PostElement(tooltip, x, y, noEvents, useOffset);

}

/** @inheritDoc */
DvtHtmlTooltipManager.prototype.hideTooltip = function()
{
  this.clearTooltip();

  var tooltip = document.getElementById(DvtHtmlTooltipManager._TOOLTIP_DIV_ID); 
  if (this._domElementId) {
      tooltip = document.getElementById(this._domElementId);
  }
  this._tooltipDisplayed = false;
  this._timerIsRunning = false;

  if(tooltip) {
    tooltip.style.visibility='hidden';
    tooltip.style.width = null;
    tooltip.style.left = '0px';
    tooltip.style.top = '0px';
  }
};

DvtHtmlTooltipManager.prototype.getTooltipElem = function() {
  this._initializeTooltipElement();
  return document.getElementById(this._domElementId);
};

DvtHtmlTooltipManager.prototype._initializeTooltipElement = function() {
  var tooltip = document.getElementById(this._domElementId);
  // If the tooltip div doesn't exist, create it
  if (!tooltip) {
    tooltip = document.createElement("div");
    tooltip.id = this._domElementId;
    tooltip.style.visibility = "hidden";
    document.body.appendChild(tooltip);
    this.InitContent(tooltip);
  }
}

DvtHtmlTooltipManager.prototype.InitContent = function(tooltip) {
}

/** @inheritDoc */
DvtHtmlTooltipManager.prototype.showTooltip = function(x, y, text, shape, bTrackMouse, borderColor)
{

  if (! text || text.length == 0)
    return;

  this._shape = shape;
  this._x = x;
  this._y = y;
  this._text = text;

  //TODO: trackMouse is not working!
  this._trackMouse = bTrackMouse;

  if (this._timerIsRunning)
    return;
  
  var tooltipElem = document.createElement("span");
  tooltipElem.className = "OraDVTTooltipText";
  tooltipElem.innerHTML = text;
  tooltipElem.style.color = DvtHtmlTooltipManager.FONT_COLOR;
  //TODO: display gradient background color
  // Set backgroundColor and borderColor
//   var gfill = new DvtLinearGradient(270, ["#c1ccd7", "#ffffff"],
//                                     [1, 1], [0, 255]);
//   DvtSvgGradientUtils.createElem(gfill, "_tpid");
//   tooltip.setStroke(new DvtSolidStroke("#9ba2b0", undefined, 1));
  if (! borderColor) {
    borderColor = DvtHtmlTooltipManager.BORDER_COLOR;
  }
  var outerElem = this.getTooltipElem();
  outerElem.style.borderColor = borderColor;
//  this.showElementAtPosition(x, y, tooltipElem, true);
  if (DvtAgent.getAgent().isTouchDevice() || (this._tooltipDisplayed && this._trackMouse)) {
      this._displayTooltip(this._x, this._y, this._text, this._borderColor);
  } else {
      // Tooltips fade-in and remove themselves after a delay.
      this._timerIsRunning = true;
      this._showTimerId = window.setTimeout(DvtObj.createCallback(this, this.handleShowTimer), 
                                            DvtHtmlTooltipManager.SHOW_DELAY);
  }
};


DvtHtmlTooltipManager.prototype.clearTooltip = function()
{
  if (this._showTimerId) {
    window.clearTimeout(this._showTimerId);

    this._showTimerId = undefined;
    this._x = undefined;
    this._y = undefined;
    this._text = undefined;

    this._trackMouse = undefined;
    this._shape = undefined;
  }
  if (this._hideTimerId) {
    window.clearTimeout(this._hideTimerId);
    this._hideTimerId = undefined;
  }
};


DvtHtmlTooltipManager.prototype.handleHideTimer = function(event)
{
  this.hideTooltip();
};

DvtHtmlTooltipManager.prototype.handleShowTimer = function(event)
{
  this._timerIsRunning = false;
  this._displayTooltip(this._x, this._y, this._text, this._borderColor);
  // TODO: support auto hide behavior as an option
  //this._hideTimerId = window.setTimeout(DvtObj.createCallback(this, this.handleHideTimer),
  //                                      DvtHtmlTooltipManager.HIDE_DELAY);
  this._tooltipDisplayed = true;
};

DvtHtmlTooltipManager.prototype._displayTooltip = function(x, y, text, borderColor) 
{
  this._isTooltip = true;
  this.showTextAtPosition(x, y, text, borderColor, true, DvtHtmlTooltipManager.TOOLTIP_POPUP_CLASS);
}

DvtHtmlTooltipManager.prototype.getOffsets = function(tooltip)
{
    var size = DvtHtmlTooltipManager.getContentBox(tooltip);
    if (DvtAgent.getAgent().isTouchDevice()) {
        return new DvtPoint(0 - size.w/2, -30 - size.h);
    } else {
      var yOffset = -12 - size.h;
      var xOffset = 12;
      if (this._isTooltip) {
        yOffset = 22;
        xOffset = 0;
      }
      var bBidi = DvtStyleUtils.isLocaleR2L();
      if (bBidi) {
        xOffset = -xOffset - size.w;          
      }

      return new DvtPoint(xOffset, yOffset);
    }
}

/*----------------------------------------------------------------------*/
/*  positionTip()   Position the tip based on the mouse position in     */
/*                  relation to the tooltip size and the mouse position */
/*----------------------------------------------------------------------*/
DvtHtmlTooltipManager.prototype.positionTip = function(tooltip, xx, yy, mouseX, mouseY)
{
  var tooltipX;
  var tooltipY;

  if (DvtAgent.getAgent().isTouchDevice()) {
      var buffer = 2;
      if (xx-window.pageXOffset < buffer) {
          tooltipX = window.pageXOffset + buffer;
          this._isRightAdjusted = false;
      } else if (xx-window.pageXOffset+tooltip.offsetWidth > window.innerWidth - buffer) {
          tooltipX = window.pageXOffset+window.innerWidth - tooltip.offsetWidth - buffer;
          this._isRightAdjusted = true;
      } else {
          tooltipX = xx;
          this._isRightAdjusted = false;
      }
      if (yy-window.pageYOffset < buffer){
          tooltipY = window.pageYOffset + buffer;
      } else if (yy-window.pageYOffset+tooltip.offsetHeight > window.innerHeight - buffer) {
          tooltipY = window.pageYOffset+window.innerHeight - tooltip.offsetHeight - buffer;
      }
      else{
          tooltipY = yy;
      }
      var widthAdjustment = 4;
      if (tooltip.className == DvtHtmlTooltipManager.UNSTYLED_POPUP_CLASS) {
          widthAdjustment = 0;
      }
      if (tooltipX + tooltip.offsetWidth>document.body.clientWidth) tooltip.style.width = (tooltip.clientWidth-widthAdjustment) + 'px';
  } else {
      var viewport = new DvtRectangle(window.pageXOffset, window.pageYOffset, document.body.clientWidth, document.body.clientHeight);
      //position x
      if (xx+tooltip.offsetWidth > viewport.x + viewport.w) {
          tooltipX = mouseX - (xx - mouseX) - tooltip.offsetWidth;
      } else if (xx < viewport.x) {
          tooltipX = mouseX - (xx - mouseX) - tooltip.offsetWidth;
      } else {
          tooltipX = xx;
      }
      //position y
      if (yy < viewport.y){
          tooltipY = mouseY + (mouseY - (yy + tooltip.offsetHeight));
      } else if (yy + tooltip.offsetHeight > viewport.y+viewport.h) {
          tooltipY = mouseY + (mouseY - (yy + tooltip.offsetHeight));
      } else {
          tooltipY = yy;
      }
      if (tooltipX>document.body.clientWidth) tooltip.style.width = (tooltip.clientWidth-4) + 'px';
  }
  tooltip.style.left = tooltipX + 'px';
  tooltip.style.top = tooltipY + 'px';
  
};

DvtHtmlTooltipManager.prototype.getTooltipBox = function()
{
    var tooltip = this.getTooltipElem();
    return DvtHtmlTooltipManager.getContentBox(tooltip);
}

DvtHtmlTooltipManager.getContentBox = function(tooltip)
{
    return new DvtRectangle(parseInt(tooltip.style.left), parseInt(tooltip.style.top), tooltip.offsetWidth, tooltip.offsetHeight);
}

/**
 * Utility class for providing keyboard listeners to add to HTML divs
 * @class DvtHtmlKeyboardListenerUtils
 */
var DvtHtmlKeyboardListenerUtils = function() {};

/**
 * @param {Boolean} useCapture True if the listener is to be used in the event capture phase, 
 *                             false if the listener is to be used in the event bubble phase
 * @return {function} A function that can be used as an event listener during the bubble or capture phase
 */
DvtHtmlKeyboardListenerUtils.getListener = function(useCapture)
{
  if(useCapture)
    return DvtHtmlKeyboardListenerUtils._captureListener;
  else
    return DvtHtmlKeyboardListenerUtils._bubbleListener;  
}


/**
 * The event listener that is called by the implementation object's bubble phase listeners.
 * This function will wrap the event and delegate to the real event listeners.  
 * @param {object} event the DOM event object
 * @this {object} the platform object actively processing the event object with an event listener
 * @private
 */
DvtHtmlKeyboardListenerUtils._bubbleListener = function(event)
{
  if(this._obj && this._obj instanceof Array)
  {
    var i;
    var svgObj;
    var dvtEvent;
    var length = this._obj.length;
    for(i=0; i<length; i++)
    {
      svgObj = this._obj[i];
      dvtEvent = DvtSvgEventFactory.newEvent(event, svgObj.getObj().getContext());
      svgObj.getObj().FireListener(dvtEvent, false);
    }
  }  
}


/**
 * The event listener that is called by the implementation object's capture phase listeners.
 * This function will wrap the event and delegate to the real event listeners.  
 * @param {object} event the DOM event object
 * @this {object} the platform object actively processing the event object with an event listener
 * @private
 */
DvtHtmlKeyboardListenerUtils._captureListener = function()
{
  if(this._obj && this._obj instanceof Array)
  {
    var i;
    var svgObj;
    var dvtEvent;
    var length = this._obj.length;
    for(i=0; i<length; i++)
    {
      svgObj = this._obj[i];
      dvtEvent = DvtSvgEventFactory.newEvent(event, svgObj.getObj().getContext());
      svgObj.getObj().FireListener(dvtEvent, true);
    }
  }  
}
/*
** Copyright (c) 2004, 2012, Oracle and/or its affiliates. 
** All rights reserved. 
*/

/**
 * Abstraction for services with user-agent-specific implementations.
 * To get an instance, use <code>AdfAgent.AGENT</code>.
 * @constructor {private} Use <code>AdfAgent.AGENT</code> to get an instance.
 * @abstract
 * @author Blake Sullivan
 */
function DvtAgentImpl(domWindow)
{
  this.Init(DvtAgent.UNKNOWN_PLATFORM, DvtAgentImpl.guessOS(), DvtAgentImpl.guessVersion(), domWindow);
}

DvtObj.createSubclass(DvtAgentImpl, DvtAgent, "DvtAgentImpl");

/**
 * @param {Window} domWindow DOM Window object to use to determine the Agent to use
 * @return {AdfAgent} AdfAgent instance to use for this User Agent
 * @see #AGENT
 */
DvtAgentImpl.getAgent = function()
{
  var domWindow = window;
  
  /*
  if (domWindow != null)
  {
    // If domWindow is non-null, assume we want to re-create the
    // agent instance.
    DvtAgentImpl._agent = null;
  }
  */
  
  if (!DvtAgentImpl._agent)
  {
    // domWindow should never be null when initializing the
    // agent instance
    //AdfAssert.assert(domWindow != null);

    var agentName = navigator.userAgent.toLowerCase();

    var agent;
    var version;
    
    //checkAgentSupport doesn't seem to be defined when running local
    //html pages, which results in error being thrown and default agent
    //impl being used.  Wrap that check inside a try to avoid that problem.
    var bCheckAgentSupport = false;
    try
    {
      bCheckAgentSupport = checkAgentSupport;
    }
    catch (e2)
    {
      //do nothing
    }

    // check opera first, since it likes to claim its mozilla and msie
    try
    {
      if(agentName.indexOf("opera")!=-1)
      {
        agent = new DvtOperaAgent(domWindow);
        // we only check for unsupported agents once per session.
        if (bCheckAgentSupport)
          alert(DvtAgentImpl._UNSUPPORTED_BROWSER_ALERT);
      }
      else if (agentName.indexOf("msie")!=-1)
      {
        // parse the version number out of the Agent String
        version = DvtAgentImpl._parseFloatVersion(agentName, /msie (\d+[.]\d+)/);

        // The XMLHttpRequest Object is new for IE7, so check for that in case
        // the version number is screwed up for some reason (see bug 6663872)
        if (window.XMLHttpRequest || (version >= 7))
        {
          if (version >= 9)
            agent = new DvtIE9Agent(domWindow);
          else if (version >= 8)
            agent = new DvtIE8Agent(domWindow);
          else
            agent = new DvtIEAgent(domWindow);
        }
        else
        {
          // Our minimum IE requirement is IE7. One reason is that we use composite
          // selectors and IE6 does not support these.
          // we only check for unsupported agents once per session.
          if (bCheckAgentSupport)
            alert(DvtAgentImpl._UNSUPPORTED_BROWSER_ALERT);
          agent = new DvtIE6Agent(domWindow);
        }
      }
      else if ((agentName.indexOf("applewebkit")!=-1)||
               (agentName.indexOf("safari")!=-1))
      {
        // Mac Desktop:
        // Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_3; en-us) AppleWebKit/525.18 (KHTML, like Gecko) Version/3.1.1 Safari/525.20
        // Windows Desktop:
        // Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.18 (KHTML, like Gecko) Version/3.1.1 Safari/525.17
        // iPod Touch:
        // Mozilla/5.0 (iPod; U; CPU like Mac OS X; en) AppleWebKit/420.1 (KHTML, like Gecko) Version/3.0 Mobile/3A110a Safari/419.3
        // iPhone:
        // Mozilla/5.0 (iPhone; U; CPU like Mac OS X; en) AppleWebKit/420.1 (KHTML, like Gecko) Version/3.0 Mobile/4A102 Safari/419.3

        // According to the spec:
        // If you need to detect the version of the browser accessing your site, use the
        // AppleWebKit/XX portion of the user-agent string.
        // A given build version of WebKit, the rendering and JavaScript engine embedded in Safari,
        // provides consistent site compatibility in Safari or any third party application embedding
        // WebKit to display page content.
        // WebKit version numbers may contain a minor version and possibly a sub-version number as
        // well:
        // For example: AppleWebKit/125.5.5 or AppleWebKit/125.3 or AppleWebKit/125
        version = DvtAgentImpl._parseFloatVersion(agentName, /applewebkit\/(\d+([.]\d+)*)/);
        if (agentName.indexOf("mobile") == -1)
        {
          agent = new DvtSafariAgent(version, domWindow);
        }
        else
        {
          agent = new DvtSafariMobileAgent(version, domWindow);
        }

        // We only check for unsupported agents once per session.
        if (bCheckAgentSupport && (version < 525.18))
        {
          // Google Chrome's first beta is using a slightly older version of WebKit.
          // As a temporary workaround, we will abstain from the version being unsupported only if
          // we can tell it is chrome and we should get rid of this special case once it comes out
          // of bet or at least uses a more supportable version of WebKit:
          if (version < 525.18 && agentName.indexOf("chrome/")!=-1)
          {
            // Using Google Chrome
          }
          else
          {
            alert(DvtAgentImpl._UNSUPPORTED_BROWSER_ALERT);
          }
        }
      }
      else if(agentName.indexOf("gecko/")!=-1)
      {
        version = DvtAgentImpl._parseFloatVersion(agentName, /rv:(\d+[.]\d+)/);
        if (version >= 1.9)
        {
          // Firefox 3.0 with Gecko 1.9
          agent = new DvtGecko19Agent(version, domWindow);
        }
        else if (version >= 1.8)
        {
          // Firefox 1.1 with Gecko 1.8
          agent = new DvtGeckoAgent(version, domWindow);
        }
        else
        {
          // Firefox 1.0 with Gecko 1.7 and all lower versions
          agent = new DvtGecko17Agent(version, domWindow);
        }

        // we only check for unsupported agents once per session
        if (bCheckAgentSupport)
        {
          var geckoAgentSupported = DvtAgentImpl._isGeckoAgentSupported(agentName, version);
          if (!geckoAgentSupported)
            alert(DvtAgentImpl._UNSUPPORTED_BROWSER_ALERT);
        }
      }
      else if (!agent)
      {
        if (bCheckAgentSupport)
        {
            alert(DvtAgentImpl._UNSUPPORTED_BROWSER_ALERT);
        }
        agent = new DvtAgentImpl(domWindow);
      }

      DvtAgentImpl._agent = agent;
    }
    catch (e)
    {
      DvtAgentImpl._agent = new DvtAgentImpl(domWindow);
      //AdfLogger.LOGGER.logError(e, AdfLogger.SEVERE, "Unable to initialize AdfAgent");
    }
  }

  return DvtAgentImpl._agent;
}

/**
 * Guess the OS of the agent
 * @return {String} One of
 * <ul>
 *   <li><code>AdfAgent.WINDOWS_OS</code></li>
 *   <li><code>AdfAgent.SOLARIS_OS</code></li>
 *   <li><code>AdfAgent.MAC_OS</code></li>
 *   <li><code>AdfAgent.UNKNOWN_OS</code></li>
 * </ul>
 */
DvtAgentImpl.guessOS = function()
{
  var agentName = navigator.userAgent.toLowerCase();

  if (agentName.indexOf('win')!= -1)
  {
    return DvtAgent.WINDOWS_OS;
  }
  else if (agentName.indexOf('mac') != -1)
  {
    return DvtAgent.MAC_OS;
  }
  else if (agentName.indexOf('sunos') != -1)
  {
    return DvtAgent.SOLARIS_OS;
  }
}

/**
 * Guess the version of the AdfAgent
 * @return {Number} Floating point version of the user agent's version
 */
DvtAgentImpl.guessVersion = function()
{
  return parseFloat(navigator.appVersion);
}


// Parses the float version out of of the specified agent string using
// a regular expression to identify the version portion of the string
DvtAgentImpl._parseFloatVersion = function (agentName, versionNumberPattern)
{
  var matches = agentName.match(versionNumberPattern);

  if (matches)
  {
    var versionString = matches[1];

    if (versionString)
      return parseFloat(versionString);
  }

  return undefined;
}

// We support Firefox 2.0.0.2 and higher. Any other Gecko agent we do not support.
// Notes:
// Firefox 1.5* is on Gecko 1.8
// Firefox 2.0* is on Gecko 1.8.1
// Firefox 3.0* is on Gecko 1.9
DvtAgentImpl._isGeckoAgentSupported = function (agentName, geckoVersion)
{
  // check for the easiest things first
  if (geckoVersion < 1.8 || (agentName.indexOf("firefox/") == -1))
    return false;

  // from here on, we know this is firefox
  if (geckoVersion > 1.8)
    return true;

  // now check the firefox versions
  var firefoxVersionFloat = DvtAgentImpl._parseFloatVersion(agentName, /firefox\/(\d+[.]\d+)/);

  if (firefoxVersionFloat < 2.0 || firefoxVersionFloat == undefined)
    return false;

  if (firefoxVersionFloat >= 2.1)
    return true;

  // Check the Firefox 2.0 versions. The supported browsers are version 2.0.0.2 and higher.
  //  This does not include versions 2.0b1, 2.0b2, 2.0, or 2.0.0.1.
  // It will include 2.0.0.2, 2.0.0.3, 2.0.0.4 and if they make any other version like 2.0.1
  //
  // The easiest check is to check for two decimals because there have been no 2.0 releases
  // that have two or more decimals other than 2.0.0.*. If it has 2 decimals, and it isn't 2.0.0.1
  // then it is supported.
  var matches = agentName.match(/firefox\/(2([.]\d+){1,3})/);

  if (matches)
  {
    var versionString = matches[1];

    // now make sure the version isn't 2.0.0.1. Everything else at this point is ok.
    return versionString != "2.0.0.1";
  }

  return false;
}

DvtAgentImpl.InitClass = function()
{
  DvtAgentImpl._agent = null;
}

/**
 * Create an instance of an AdfAgent
 */
DvtAgentImpl.prototype.Init = function(
  platform,
  os,
  version,
  domWindow)
{

  if (!platform)
    platform = DvtAgent.UNKNOWN_PLATFORM;

  if (!os)
    os = DvtAgent.UNKNOWN_OS;

  this._platform = platform;
  this._os = os;
  this._version = version;

  // Stash away the window and the document
  this._window = domWindow;
  this._document = domWindow.document;
}

/**
 * @override
 */
DvtAgentImpl.prototype.isWebkit = function() {
  return this._platform == DvtAgent.WEBKIT_PLATFORM;
}

/**
 * @override
 */
DvtAgentImpl.prototype.isSafari = function() {
  var safari = (DvtAgentImpl._agent instanceof DvtSafariAgent) || (DvtAgentImpl._agent instanceof DvtSafariMobileAgent);
  var agentName = navigator.userAgent.toLowerCase();
  var chrome = agentName.indexOf("chrome/")!=-1;
  return (safari && !chrome);
}

/**
 * Returns HTML element's coordinates relative to the document's body
 * @param element HTML element
 * @return an object with two properties (x for the left coordinate and y for
 * the top coordinate)
 */
DvtAgentImpl.prototype.getElementPosition = function(element)
{
  // =-= VG Default implementation for Safari/Opera
  var bodyElement = element.ownerDocument.body;

  var currParent = element.offsetParent;
  var currLeft   = element.offsetLeft;
  var currTop   = element.offsetTop;
  //In safari/opera position absolute incorrectly account for body offsetTop
  //if (this.getComputedStyle(element).position == "absolute")
  //{
  //  currTop -= bodyElement.offsetTop;
  //}

  // store cssLengthAsInt function in local
  //var cssLengthAsInt = AdfAgent.getCSSLengthAsInt;

  while (currParent)
  {
    element = currParent;
    currLeft += element.offsetLeft;
    currTop += element.offsetTop;
    if (element != bodyElement)
    {
      //adjust for border
      //var style = this.getComputedStyle(element);
      //currLeft += cssLengthAsInt(style.borderLeftWidth);
      //currTop += cssLengthAsInt(style.borderTopWidth);

      currLeft -= element.scrollLeft;
      currTop -= element.scrollTop;
    }

    currParent = currParent.offsetParent;
  }

  return {x:currLeft, y:currTop};
}

/**
 * @override
 */
DvtAgentImpl.prototype.elementFromPagePoint = function(x, y)
{
    return document.elementFromPoint(x, y);
}

/**
 * @override
 */
DvtAgentImpl.prototype.getPlatform = function()
{
    return this._platform;
}

/**
 * @override
 */
DvtAgentImpl.prototype.getName = function()
{
    return navigator.userAgent.toLowerCase();
}

DvtAgentImpl.prototype.isChrome = function()
{
    var agentName = navigator.userAgent.toLowerCase();
    var chrome = agentName.indexOf("chrome/")!=-1;
    return chrome;
}

DvtAgentImpl.prototype.isTouchDevice = function()
{
    return (window && window.DvtSafariMobileAgent && DvtAgent.getAgent() instanceof DvtSafariMobileAgent);
}

DvtAgentImpl.prototype.isRightToLeft = function()
{
  return document.documentElement.dir === "rtl";
}

/*
** Copyright (c) 2008, 2012, Oracle and/or its affiliates. 
** All rights reserved. 
**
**34567890123456789012345678901234567890123456789012345678901234567890123456789
*/

/**
 * SafariAdfAgent AdfAgent capabilities.
 * @author Blake Sullivan
 */
function DvtSafariAgent(version, domWindow)
{
  this.Init(version, domWindow);
}

DvtObj.createSubclass(DvtSafariAgent, DvtAgentImpl, "DvtSafariAgent");

DvtSafariAgent.prototype.Init = function(version, domWindow)
{
  DvtSafariAgent.superclass.Init.call(this,
                                   DvtAgent.WEBKIT_PLATFORM,
                                   DvtAgentImpl.guessOS(),
                                   version,
                                   domWindow);
}
/*
** Copyright (c) 2008, 2012, Oracle and/or its affiliates. 
** All rights reserved. 
*/

/**
 * AdfSafariMobileAgent capabilities.
 */
function DvtSafariMobileAgent(version, domWindow)
{
  this.Init(version, domWindow);
}

DvtObj.createSubclass(DvtSafariMobileAgent, DvtSafariAgent, "DvtSafariMobileAgent");

DvtSafariMobileAgent.prototype.Init = function(version, domWindow)
{
  // =-= Should this agent's platform be expanded out to match the Trinidad Agent's e.g. "iphone"
  //     and other flavors of mobile webkit?
  DvtSafariMobileAgent.superclass.Init.call(this, version, domWindow);
}
/**
 * Wrapper class providing XML parsing functionality using the DOM.
 * @class DvtDomXmlParser
 * @extends DvtXmlParser
 * @constructor
 */
var DvtDomXmlParser = function() {
  this._parser = new DOMParser();
}

DvtObj.createSubclass(DvtDomXmlParser, DvtObj, "DvtDomXmlParser");

/**
 * Parses the XML string and returns the root node.
 * @params {string} xmlString the XML string to parse
 * @return {DvtDomXmlNode} the root node of the XML document
 */
DvtDomXmlParser.prototype.parse = function(xmlString) {
  var xmlDoc = this._parser.parseFromString(xmlString, "text/xml");
  var root = xmlDoc.documentElement;
  return new DvtDomXmlNode(root);
}
/**
 * Wrapper class providing access to DOM XML Nodes.
 * @extends DvtXmlNode
 * @class DvtDomXmlNode
 * @constructor
 * @param {Node} node the DOM Node object
 */
var DvtDomXmlNode = function(node) {
  this._node = node;
}

// Make DvtDomXmlNode a subclass of DvtXmlNode
DvtObj.createSubclass(DvtDomXmlNode, DvtXmlNode, "DvtDomXmlNode");

/**
 * @override
 */
DvtDomXmlNode.prototype.getAttribute = function(attr) {
  return this._node.getAttribute(attr);
}

/**
 * @override
 */
DvtDomXmlNode.prototype.getChildNodes = function() {
  var ret = new Array();
  
  // Loop through the children of this node.  
  // Note: Using nextSibling because w3schools.com says it's faster than 
  //       childNodes for looping through the children.
  var child = this._node.firstChild;
  while(child != null) {
    if(child.nodeType == 1) // Element
      ret.push(new DvtDomXmlNode(child));
      
    child = child.nextSibling;  
  }
  
  return ret;
}

/**
  * @override
  */
DvtDomXmlNode.prototype.getName = function() {
  return this._node.nodeName;
};

/**
  * @override
  */
DvtDomXmlNode.prototype.getAttributes = function() {
  var array = [];
  var numAttrs = this._node.attributes.length;
  for (var i = 0; i < numAttrs; i++)
  {
    var attr = this._node.attributes[i];
    if (attr.name && attr.value)
    {
      array.push({name:attr.name, value:attr.value});
    }
  }
  return array;
};


/**
 * @override
 * @return {array} an Array containing all child elements and text nodes of this node.
 */
DvtDomXmlNode.prototype.getAllChildNodes = function() {
  var ret = new Array();
  
  // Loop through the children of this node.  
  // Note: Using nextSibling because w3schools.com says it's faster than 
  //       childNodes for looping through the children.
  var child = this._node.firstChild;
  while(child != null) {
    ret.push(new DvtDomXmlNode(child));
    child = child.nextSibling;  
  }
  
  return ret;
}


/**
  * @override
  */
DvtDomXmlNode.prototype.getNodeValue = function() {
  return this._node.nodeValue;
};

/**
  * @override
  */
DvtDomXmlNode.prototype.getTextContent = function() {
  return this._node.textContent;
};

//TODO: find a better place this method
DvtDomXmlNode._removeTextNodes = function(elem) {
  var child = elem.firstChild;
  while(child != null) {
    var delNode = child;
    child = child.nextSibling;  
    elem.removeChild(delNode);
  }
}

/**
  * @override
  */
DvtDomXmlNode.prototype.getElementsByTagName = function(name) {
  var ret = [];
  var nodes = this._node.getElementsByTagName(name);
  if (nodes) {
    for (var i = 0; i < nodes.length; i++) {
        ret.push(new DvtDomXmlNode(nodes[i]));
    }
  }
  return ret;
};


/*---------------------------------------------------------------------*/
/*   DvtObjDimUtils  Impl Level Object Dimension Utility Functions     */
/*---------------------------------------------------------------------*/

/**
 *   Static implementation level object utility functions
 *   @class DvtObjDimUtils
 */
var DvtObjDimUtils = function () {
};

/**
 *   Returns the rectangular dimensions for the specified displayable.  This function
 *   is currently only available for Canvas and Xml contexts.
 *   @param {DvtDisplayable} obj the implementation displayable object such as
 *                           {@link DvtCanvasPolygon} whose dimensions are to be returned.
 *   @returns {DvtRectangle} returns the rectangular dimensions for the specified displayable implementation.
 */
DvtObjDimUtils.getDimensions = function (implObj) {
  var isContainer = false;
  var selfDims = DvtObjDimUtils.getDimensionsSelf(implObj);
  if (!selfDims) {
    selfDims = new DvtRectangle(Number.MAX_VALUE,Number.MAX_VALUE,0,0);
    isContainer = true;
  }

  //  If children, find min/max x/y of the children
  var minX, minY, maxX, maxY;
  var obj = implObj.getObj();
  var children = obj.getNumChildren();
  var bChild = false;

  for (var i = 0;i < children;i++) {
    var child = obj.getChildAt(i);
    var dims = child.getDimensions();

    if ((!dims) || dims.w === 0 && dims.h === 0) {
      continue;
    }
    if ((!bChild) || (dims.x < minX)) {
      minX = dims.x;
    }
    if ((!bChild) || (dims.y < minY)) {
      minY = dims.y;
    }
    if ((!bChild) || ((dims.x + dims.w) > maxX)) {
      maxX = dims.x + dims.w;
    }
    if ((!bChild) || ((dims.y + dims.h) > maxY)) {
      maxY = dims.y + dims.h;
    }
    bChild = true;// a child had been measured
  }

  if (bChild) {
    if (!isContainer) { // Create union if not a container. Containers have no initial dimension.
      minX = Math.min(minX, selfDims.x);
      minY = Math.min(minY, selfDims.y);
      maxX = Math.max(maxX, selfDims.x + selfDims.w);
      maxY = Math.max(maxY, selfDims.y + selfDims.h);
    }
  
    selfDims.x = minX;
    selfDims.y = minY;
    selfDims.w = maxX - minX;
    selfDims.h = maxY - minY;
  }
  
  //Apply any transforms to object
  var mat = obj.getMatrix();
  if (mat) {
    var scaleX = mat.getA();
    var scaleY = mat.getD();
    var transX = mat.getTx();
    var transY = mat.getTy();
    if (scaleX !== 1 || scaleY !== 1 || transX !==0 || transY !== 0) { //Do nothing for identity matrix
      if (obj instanceof DvtMarker) { //Marker dimensions are already scaled but not translated
        selfDims.x = selfDims.x + transX;
        selfDims.y = selfDims.y + transY;
      } else {
        selfDims.x = (selfDims.x * scaleX) + transX;
        selfDims.y = (selfDims.y * scaleY) + transY;
        selfDims.w = (selfDims.w * scaleX);
        selfDims.h = (selfDims.h * scaleY);
      }
    }
  }
  
  return selfDims;
};

/**
 *  Returns the rectangular dimensions of this object.
 *  @returns {DvtRectangle}
 */
DvtObjDimUtils.getDimensionsSelf = function (implObj) {
  var selfDims;
  var r;
  var obj = implObj.getObj();

  if (obj instanceof DvtLine) {
    var minX = Math.min(implObj.getX1(), implObj.getX2());
    var minY = Math.min(implObj.getY1(), implObj.getY2());
    var w = Math.abs(implObj.getX1() - implObj.getX2());
    var h = Math.abs(implObj.getY1() - implObj.getY2());

    selfDims = new DvtRectangle(minX, minY, w, h);
  }
  else if ((obj instanceof DvtRect) || (obj instanceof DvtImage)) {
    selfDims = new DvtRectangle(implObj.getX(), implObj.getY(), implObj.getWidth(), implObj.getHeight());
  }
  else if (obj instanceof DvtCircle) {
    r = implObj.getRadius();
    var rx = implObj.getRx() || r;
    var ry = implObj.getRy() || r;

    selfDims = new DvtRectangle(implObj.getCx() - rx, implObj.getCy() - ry, 2 * rx, 2 * ry);
  }
  else if (obj instanceof DvtMarker) {
    selfDims = implObj.getBounds();
  }
  else if (obj instanceof DvtText) {
    if (!obj.getContext() instanceof DvtCanvasContext)
      return new DvtRectangle();
    var style = implObj.getCSSStyle();
    var fontSize = style["font-size"];
    var fontStyle = style["font-style"];
    var fontFamily = style["font-family"];
    var fontWeight = style["font-weight"];

    var pt = implObj.getRotatePoint();
    var cx, cy;
    if (pt) {
      cx = pt.x;
      cy = pt.y;
    }

    var utils = DvtCanvasTextUtils;

    if (!utils) {
      return new DvtRectangle();// no svg support currently.
    }
    selfDims = utils.measureText(implObj.getTextString(), implObj.getAngle(), cx, cy, fontFamily, fontSize, fontStyle, fontWeight);

    //  Get the x, y of the bounding box.  This is probably too course and will need
    // to be revisited.
    var x = obj.getX();
    var y = obj.getY();

    if (x !== undefined && y !== undefined) {
      var xPos = x;
      var yPos = y;
      var anchor = implObj.getAnchor() || 'start';
      var baseline = implObj.getBaseline() || 'top';

      if (anchor === 'start' || anchor === 'left') {
        // revisit for BiDi
      }
      else if (anchor === 'end' || anchor === 'right') {
        // revisit for BiDi
        xPos -= selfDims.w;
      }
      else if (anchor === 'center') {
        xPos -= selfDims.w / 2;
      }
      if (baseline === 'alphabetic') {
        yPos -= selfDims.h;
      }
      else if (baseline === 'top') {
      }
      else if (baseline === 'middle') {
        yPos -= selfDims.h / 2;
      }

      selfDims.x = xPos;
      selfDims.y = yPos;
    }
    else {
      selfDims.x = undefined;
      selfDims.y = undefined;
    }

    if (obj.getMatrix()) {
      r = Math.abs(Math.round(obj.getRotation() * DvtMath.DEGREES_PER_RAD));

      if (r === 90 || r === 270) {
        // jrm temp - todo
        var temp = selfDims.w;
        selfDims.w = selfDims.h;// switch width/height
        selfDims.h = temp;
      }
    }
  }
  else if (obj instanceof DvtPath) {
    selfDims = DvtPathUtils.getDimensions(obj.getCommands());
  }
  else if ((obj instanceof DvtPolyline) || (obj instanceof DvtPolygon)) {
    selfDims = DvtPolygonUtils.getDimensions(obj.getPoints());
  }
  else if (obj instanceof DvtArc) {
    r = implObj.getRadius();
    selfDims = new DvtRectangle(implObj.getCx() - r, implObj.getCy() - r, 2 * r, 2 * r);
  }

  return selfDims;
};
/*
** Copyright (c) 2004, 2012, Oracle and/or its affiliates. 
** All rights reserved. 
*/

/**
 * Adf agent impl
 */
function AdfAgentImpl()
{
}

DvtObj.createSubclass(AdfAgentImpl, DvtAgent, "AdfAgentImpl");

AdfAgentImpl.prototype.isTouchDevice = function()
{
    return (window && window.AdfSafariMobileAgent && AdfAgent.getAgent() instanceof AdfSafariMobileAgent);
}

AdfAgentImpl.prototype.isSafari = function()
{
    // TODO: figure out what check to make for safari because framework initializes safari agent for chrome
    var safari = (window && window.AdfSafariAgent && AdfAgent.getAgent() instanceof AdfSafariAgent);
    var chrome = this.isChrome();
    return (safari && !chrome);
}

AdfAgentImpl.prototype.isChrome = function()
{
    var agentName = navigator.userAgent.toLowerCase();
    var chrome = agentName.indexOf("chrome/")!=-1;
    return chrome;
}

/**
 * @override
 */
AdfAgentImpl.prototype.isWebkit = function() {
  return AdfAgent.AGENT.getPlatform() == AdfAgent.WEBKIT_PLATFORM;
}

/**
 * @override
 */
AdfAgentImpl.prototype.isGecko = function() {
  return AdfAgent.AGENT.getPlatform() == AdfAgent.GECKO_PLATFORM;
}

/**
 * @override
 */
AdfAgentImpl.prototype.getElementPosition = function(element)
{
    return AdfAgent.AGENT.getElementPosition(element);
}

/**
 * @override
 */
AdfAgentImpl.prototype.elementFromPagePoint = function(x, y)
{
    return document.elementFromPoint(x, y);
}

/**
 * @override
 */
AdfAgentImpl.prototype.getPlatform = function()
{
    return AdfAgent.AGENT.getPlatform();
}

/**
 * @override
 */
AdfAgentImpl.prototype.isRightToLeft = function()
{
  // Call ADF if available
  try {
    return AdfPage.PAGE.getLocaleContext().isRightToLeft();
  }
  catch (e) {
  }
  
  // Otherwise use the document direction
  return document.documentElement.dir === "rtl";
}

/**
 * @override
 */
DvtAgent.prototype.getName = function()
{
    return navigator.userAgent.toLowerCase();
}

/**
 * A component level selection event.
 * @param {array} selection The array of currently selected ids for the component.
 * @class
 * @constructor
 */
var DvtSelectionEvent = function(selection) {
  this.Init(DvtSelectionEvent.TYPE);
  this._selection = selection;
}

DvtObj.createSubclass(DvtSelectionEvent, DvtBaseComponentEvent, "DvtSelectionEvent");

DvtSelectionEvent.TYPE = "selection";

/**
 * Returns the array of currently selected ids for the component.
 * @return {array} The array of currently selected ids for the component.
 */
DvtSelectionEvent.prototype.getSelection = function() {
  return this._selection;
}
/**
 * A component level selection event.
 * @param {object} context Component specific context about this event, such as the clientRowKey.
 * @param {DvtShowPopupBehavior} showPopupBehavior The showPopupBehavior that was triggered.
 * @param {DvtRectangle} launcherBounds The bounding box of the object that triggered the popup, 
 *                                      relative to the component's top left coordinates.
 * @param {string} launcherId The component that launched the popup.  This may be different
 *                            than the component that owns the showPopupBehavior.
 *                                      
 * @class
 * @constructor
 */
var DvtShowPopupEvent = function(showPopupBehavior, launcherBounds, launcherId) {
  this.Init(DvtShowPopupEvent.TYPE);
  this._showPopupBehavior = showPopupBehavior;
  this._launcherBounds = launcherBounds;
  this._launcherId = launcherId;
}

DvtObj.createSubclass(DvtShowPopupEvent, DvtBaseComponentEvent, "DvtShowPopupEvent");

DvtShowPopupEvent.TYPE = "showPopup";

/**
 * Returns the component specific context about this event, such as the clientRowKey.
 * @return {object} Component specific context about this event, such as the clientRowKey.
 */
// DvtShowPopupEvent.prototype.getContext = function() {
//   return this._context;
// }

/**
 * Returns the showPopupBehavior that was triggered.
 * @return {DvtShowPopupBehavior} The showPopupBehavior that was triggered.
 */
DvtShowPopupEvent.prototype.getShowPopupBehavior = function() {
  return this._showPopupBehavior;
}

/**
 * Returns the bounding box of the object that triggered the popup, relative to the component's
 * top left coordinates.
 * @return {DvtRectangle} The bounding box of the object that triggered the popup, relative 
 *                        to the component's top left coordinates.
 */
DvtShowPopupEvent.prototype.getLauncherBounds = function() {
  return this._launcherBounds;
}

/**
 * Returns the component that launched the popup.  This may be different than the component 
 * that owns the showPopupBehavior.
 * @return {string} The component that launched the popup.
 */
DvtShowPopupEvent.prototype.getLauncherId = function() {
  return this._launcherId;
}

/**
 * Set the component that launched the popup.  This may be different than the component 
 * that owns the showPopupBehavior.
 * @param {string} The component that launched the popup.
 */
DvtShowPopupEvent.prototype.setLauncherId = function(launcherId) {
  this._launcherId = launcherId;
}




/**
 * A component level hide popup event.
 * @param {string} popupId The id of the popup to be hidden.
 * @param {string} clientId The id of the naming container owning the showPopupBehavior.
 * @class
 * @constructor
 */
var DvtHidePopupEvent = function(popupId) {
  this.Init(DvtHidePopupEvent.TYPE);
  this._popupId = popupId;
}

DvtObj.createSubclass(DvtHidePopupEvent, DvtBaseComponentEvent, "DvtHidePopupEvent");

DvtHidePopupEvent.TYPE = "hidePopup";

/**
 * Returns the id of the popup to be hidden.
 * @return {string} popupId The id of the popup to be hidden.
 */
DvtHidePopupEvent.prototype.getPopupId = function() {
  return this._popupId;
}
/**
 * A component level context menu event.
 * @param {object} nativeEvent The native event that triggered the context menu.
 * @param {string} menuId The client id of the context menu that is being requested.
 * @class
 * @constructor
 */
var DvtContextMenuEvent = function(nativeEvent, menuId) {
  this.Init(DvtContextMenuEvent.TYPE);
  this._nativeEvent = nativeEvent;
  this._menuId = menuId;
}

DvtObj.createSubclass(DvtContextMenuEvent, DvtBaseComponentEvent, "DvtContextMenuEvent");

DvtContextMenuEvent.TYPE = "contextMenu";

/**
 * Returns the native event that triggered the context menu.
 * @return {object} The native event that triggered the context menu.
 */
DvtContextMenuEvent.prototype.getNativeEvent = function() {
  return this._nativeEvent;
}

/**
 * Returns the client id of the context menu that is being requested.
 * @return {string} The client id of the context menu that is being requested.
 */
DvtContextMenuEvent.prototype.getMenuId = function() {
  return this._menuId;
}
/**
 * A component level event for selection of a context menu item.
 * @param {string} menuType The type of context menu being requested, such as bodyContextMenu.
 * @param {string} clientId The id for a commandMenuItem.
 * @param {string} destination The destination for a goMenuItem.
 * @param {string} targetFrame The targetFrame for a goMenuItem.
 * @class
 * @constructor
 */
var DvtContextMenuSelectEvent = function(menuType, clientId, destination, targetFrame) {
  this.Init(DvtContextMenuSelectEvent.TYPE);
  this._menuType = menuType;
  this._clientId = clientId;
  this._destination = destination;
  this._targetFrame = targetFrame;
}

DvtObj.createSubclass(DvtContextMenuSelectEvent, DvtBaseComponentEvent, "DvtContextMenuSelectEvent");

DvtContextMenuSelectEvent.TYPE = "contextMenuSelect";

/**
 * Returns the type of context menu being requested, such as bodyContextMenu.
 * @return {string} The type of context menu being requested, such as bodyContextMenu.
 */
DvtContextMenuSelectEvent.prototype.getMenuType = function() {
  return this._menuType;
}

/**
 * Returns the id for a commandMenuItem.
 * @return {string} The id for a commandMenuItem.
 */
DvtContextMenuSelectEvent.prototype.getClientId = function() {
  return this._clientId;
}

/**
 * Returns the destination for a goMenuItem.
 * @return {string} The destination for a goMenuItem.
 */
DvtContextMenuSelectEvent.prototype.getDestination = function() {
  return this._destination;
}

/**
 * Returns the targetFrame for a goMenuItem.
 * @return {string} The targetFrame for a goMenuItem.
 */
DvtContextMenuSelectEvent.prototype.getTargetFrame = function() {
  return this._targetFrame;
}
/**
 * A component level drill replace event.
 * @param {string} id The id of the data item that was drilled.
 * @class
 * @constructor
 */
var DvtDrillReplaceEvent = function(id) {
  this.Init(DvtDrillReplaceEvent.TYPE);
  this._id = id;
}

DvtObj.createSubclass(DvtDrillReplaceEvent, DvtBaseComponentEvent, "DvtDrillReplaceEvent");

DvtDrillReplaceEvent.TYPE = "drillReplace";

/**
 * Returns the id of the data item that was drilled.
 * @return {string} The id of the data item that was drilled.
 */
DvtDrillReplaceEvent.prototype.getId = function() {
  return this._id;
}
/**
 * A component level rollover behavior event.
 * @type {string} type The type of event, either roll over or roll out.
 * @type {string} category The category that is the target of the event.
 * @class
 * @constructor
 * @extends DvtBaseComponentEvent
 */
var DvtCategoryRolloverEvent = function(type, category) {
  this.Init(type);
  this._category = category;
}

DvtObj.createSubclass(DvtCategoryRolloverEvent, DvtBaseComponentEvent, "DvtCategoryRolloverEvent");

// Event Types
DvtCategoryRolloverEvent.TYPE_OVER = "categoryRollOver";
DvtCategoryRolloverEvent.TYPE_OUT = "categoryRollOut";

/**
 * Returns the category that is target of the event.
 * @return {string}
 */
DvtCategoryRolloverEvent.prototype.getCategory = function() {
  return this._category;
}
/**
 * A component level hide and show behavior event.
 * @type {string} type The type of event, either hide or show.
 * @type {string} category The category that is the target of the event.
 * @class
 * @constructor
 * @extends DvtBaseComponentEvent
 */
var DvtHideShowCategoryEvent = function(type, category) {
  this.Init(type);
  this._category = category;
}

DvtObj.createSubclass(DvtHideShowCategoryEvent, DvtBaseComponentEvent, "DvtHideShowCategoryEvent");

// Event Types
DvtHideShowCategoryEvent.TYPE_HIDE = "hideCategory";
DvtHideShowCategoryEvent.TYPE_SHOW = "showCategory";

/**
 * Returns the category that is target of the event.
 * @return {string}
 */
DvtHideShowCategoryEvent.prototype.getCategory = function() {
  return this._category;
}
/**
 * A pan event.
 * @param {string}  subType  subtype of the event; one of the constants 
 *        defined in this class
 * @param {number}  newX  new x-coord
 * @param {number}  newY  new y-coord
 * @param {number}  oldX  old x-coord
 * @param {number}  oldY  old y-coord
 * @param {DvtAnimator}  animator  optional animator used to animate the zoom
 * @class
 * @constructor
 */
var DvtPanEvent = function(subType, newX, newY, oldX, oldY, animator) {
  this.Init(DvtPanEvent.TYPE);
  this.type = this.getType();
  this._subtype = subType;
  this._newX = newX;
  this._newY = newY;
  this._oldX = oldX;
  this._oldY = oldY;
  this._animator = animator;
};

DvtObj.createSubclass(DvtPanEvent, DvtBaseComponentEvent, "DvtPanEvent");

DvtPanEvent.TYPE = "dvtPan";

DvtPanEvent.SUBTYPE_DRAG_PAN_BEGIN = "dragPanBegin";
DvtPanEvent.SUBTYPE_DRAG_PAN_END = "dragPanEnd";
DvtPanEvent.SUBTYPE_PANNED = "panned";
DvtPanEvent.SUBTYPE_PANNING = "panning";

/**
 * 
 */
DvtPanEvent.prototype.getSubType = function() {
  return this._subtype;
};

/**
 * 
 */
DvtPanEvent.prototype.getNewX = function() {
  return this._newX;
};

/**
 * 
 */
DvtPanEvent.prototype.getNewY = function() {
  return this._newY;
};

/**
 * 
 */
DvtPanEvent.prototype.getOldX = function() {
  return this._oldX;
};

/**
 * 
 */
DvtPanEvent.prototype.getOldY = function() {
  return this._oldY;
};

/**
 * 
 */
DvtPanEvent.prototype.getAnimator = function() {
  return this._animator;
};
/**
 * A zoom event.
 * @param {string}  subType  subtype of the event; one of the constants 
 *        defined in this class
 * @param {number}  newZoom  new zoom factor
 * @param {number}  oldZoom  old zoom factor
 * @param {DvtAnimator}  animator  optional animator used to animate the zoom
 * @param {DvtRectangle}  zoomToFitBounds  bounds to use for zoom-to-fit
 * @param {DvtPoint}  centerPoint  center of zoom
 * @class
 * @constructor
 */
var DvtZoomEvent = function(subType, newZoom, oldZoom, animator, zoomToFitBounds, centerPoint) {
  this.Init(DvtZoomEvent.TYPE);
  this.type = this.getType();
  this._subtype = subType;
  this._newZoom = newZoom;
  this._oldZoom = oldZoom;
  this._animator = animator;
  this._zoomToFitBounds = zoomToFitBounds;
  this._centerPoint = centerPoint;
};

DvtObj.createSubclass(DvtZoomEvent, DvtBaseComponentEvent, "DvtZoomEvent");

DvtZoomEvent.TYPE = "dvtZoom";

DvtZoomEvent.SUBTYPE_DRAG_ZOOM_BEGIN = "dragZoomBegin";
DvtZoomEvent.SUBTYPE_DRAG_ZOOM_END = "dragZoomEnd";
DvtZoomEvent.SUBTYPE_ZOOMED = "zoomed";
DvtZoomEvent.SUBTYPE_ZOOMING = "zooming";
//DvtZoomEvent.SUBTYPE_ZOOM_AND_CENTER = "zoomAndCenter";
DvtZoomEvent.SUBTYPE_ZOOM_TO_FIT = "zoomToFit";

/**
 * 
 */
DvtZoomEvent.prototype.getSubType = function() {
  return this._subtype;
};

/**
 * 
 */
DvtZoomEvent.prototype.getNewZoom = function() {
  return this._newZoom;
};

/**
 * 
 */
DvtZoomEvent.prototype.getOldZoom = function() {
  return this._oldZoom;
};

/**
 * 
 */
DvtZoomEvent.prototype.getAnimator = function() {
  return this._animator;
};

/**
 * 
 */
DvtZoomEvent.prototype.setZoomToFitBounds = function(bounds) {
  this._zoomToFitBounds = bounds;
};

/**
 * 
 */
DvtZoomEvent.prototype.getZoomToFitBounds = function() {
  return this._zoomToFitBounds;
};

/**
 * 
 */
DvtZoomEvent.prototype.getCenterPoint = function() {
  return this._centerPoint;
};

/**
 * An action event.
 * ActionEvent is generated by a AfCommandButton, AfCommandLink,  AfCommandImageLink or
 * AfCommandMenuItem when it is clicked
 * @param {string}  commandId
 * @param {string}  clientId
 * @class
 * @constructor
 */
var DvtActionEvent = function(actionEventType, commandId, clientId) {
  this.Init(DvtActionEvent.TYPE);
  this.type = this.getType();
  this._subtype = actionEventType;
  this._commandId = commandId;
  this._clientId = clientId;
};

DvtObj.createSubclass(DvtActionEvent, DvtBaseComponentEvent, "DvtActionEvent");

DvtActionEvent.TYPE = "dvtAct";

DvtActionEvent.SUBTYPE_ACTION = "action";
//DvtActionEvent.SUBTYPE_NAVIGATE_UP = "navigateUp";
DvtActionEvent.SUBTYPE_SET_ANCHOR = "setAnchor";


DvtActionEvent.prototype.getSubType = function() {
  return this._subtype;
};

DvtActionEvent.prototype.getCommandId = function() {
  return this._commandId;
};

DvtActionEvent.prototype.getClientId = function() {
  return this._clientId;
};

DvtActionEvent.prototype.setClientId = function(clientId) {
  this._clientId = clientId;
};


/**
 * A component level breadcrumb drill event.
 * @param {string} id The id of the data item that was drilled.
 * @class
 * @constructor
 */
var DvtBreadcrumbsDrillEvent = function(id) {
  this.Init(DvtBreadcrumbsDrillEvent.TYPE);
  this._id = id;
}

DvtObj.createSubclass(DvtBreadcrumbsDrillEvent, DvtBaseComponentEvent, "DvtBreadcrumbsDrillEvent");

DvtBreadcrumbsDrillEvent.TYPE = "breadcrumbsDrill";

/**
 * Returns the id of the item that was drilled.
 * @return {string} The id of the item that was drilled.
 */
DvtBreadcrumbsDrillEvent.prototype.getId = function() {
  return this._id;
}
// Copyright (c) 2011, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
var DvtEventDispatcher = {};

/**
 * Dispatches the event to the callback function.
 * @param {object} callback The function that should be called to dispatch component events.
 * @param {object} callbackObj The object context for the callback function
 * @param {object} component The component firing the event
 * @param {object} event The event to be dispatched.
 * @protected
 */
DvtEventDispatcher.dispatchEvent = function(callback, callbackObj, component, event) {
  if (!callback)
    return;
  else if (callbackObj) 
    callback.call(callbackObj, event, component);
  else {
    // THIS CODE PATH WILL NOT WORK AFTER JS OBFUSCATION!!!

    // Create the string to be called
    var result = callback + "(event, component)";
    
    // Evaluate the javascript string.  The callback is defined by the peer,
    // and never is the result of user input, so there is no security hole
    // in using eval here.
    eval(result);
  }
};

// Copyright (c) 2008, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/*-------------------------------------------------------------------------*/
/*   DvtFlashContext         Flash implementation of DvtContext                */
/*-------------------------------------------------------------------------*/
/**
  *  @extends DvtContext
  *  @class DvtFlashContext
  *  @constructor
  *  @param {root}  
  *  @param {id}  
  */
var  DvtFlashContext = function(implFactory, root, id)
{
  this.Init(implFactory, root, id);
};

DvtObj.createSubclass(DvtFlashContext, DvtContext, "DvtFlashContext");

/**
 * Queues a rendering of the stage to occur.
 */
DvtFlashContext.prototype.queueRender = function() {
}
/*
** Copyright (c) 2004, 2012, Oracle and/or its affiliates. 
** All rights reserved. 
*/

/**
 */
function FlashAgentImpl()
{
}

DvtObj.createSubclass(FlashAgentImpl, DvtAgent, "FlashAgentImpl");

// TODO: JSDoc
FlashAgentImpl.prototype.isTouchDevice = function()
{
    return false;
}
// TODO: JSDoc
FlashAgentImpl.prototype.isSafari = function()
{
    return false;
}

/**
 * Returns true if the agent is webkit based.
 * @return {boolean}
 */
FlashAgentImpl.prototype.isWebkit = function() {
  return false;
}

/**
 * Returns true if the agent is gecko based.
 * @return {boolean}
 */
FlashAgentImpl.prototype.isGecko = function() {
  return false;
};

FlashAgentImpl.prototype.isChrome = function()
{
    return false;
}

// TODO: JSDoc
FlashAgentImpl.prototype.getElementPosition = function(element)
{
    // noop
    return {x: 0, y: 0};
}

// TODO: JSDoc
FlashAgentImpl.prototype.elementFromPagePoint = function(x, y)
{
    return null;
}

/**
 * Returns the agent platform.
 * @return {string} agent platform
 */
FlashAgentImpl.prototype.getPlatform = function()
{
    return null;
}

/**
 * Returns the agent name.
 * @return {string} agent name
 */
FlashAgentImpl.prototype.getName = function()
{
    return null;
}
// Copyright (c) 2008, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/**
 * Document APIs.
 * @class DvtFlashDocumentUtils
 */
var DvtFlashDocumentUtils = function(){};

// TODO JSDoc
// Return displayable
DvtFlashDocumentUtils.elementFromPoint = function(posX, posY) {
  if (DvtFlashDocumentUtils.stage) {
      var objects = DvtFlashDocumentUtils.stage.getObjectsUnderPoint(DvtFlashDocumentUtils.context.getImplFactory().newPoint(posX, posY));
      if (objects && objects.length > 0) {
          var domObj = objects[objects.length - 1];
          while (domObj) {
            if (domObj.hasOwnProperty("_obj")) {
                if (domObj._obj && domObj.getObj && domObj.getObj())
                    return domObj.getObj();
            }
            domObj = domObj.parent;
          }
      }
  }
  return null;
};

// TODO JSDoc
// Return coordinates relative to stage
DvtFlashDocumentUtils.getStageRelativePosition = function(stage, x, y) {
  var pos = DvtFlashDocumentUtils.getStageAbsolutePosition(stage);
  var xPos = x - pos.x;
  var yPos = y - pos.y;
  return new DvtPoint(xPos, yPos);
}

// TODO JSDoc
// Return absolute coordinates of stage
DvtFlashDocumentUtils.getStageAbsolutePosition = function(stage) {
  return new DvtPoint(0, 0);
}

// TODO JSDoc
// Return whether or not filters are supported
DvtFlashDocumentUtils.isFilterSupported = function(stage) {
    return false;
}

DvtFlashDocumentUtils.isStrokeTimeoutRequired = function() {
    return false;
}

/*
 * Whether or not events in SVG are received on regions that are visually clipped such that they are not visible
 */
DvtFlashDocumentUtils.isEventAvailableOutsideClip = function() {
    return false;
}

/*
 * Bug #12805402: In Firefox 4, horizontal/vertical polylines must be bent by 0.01 pixes to show up when fitlers are used
 */
DvtFlashDocumentUtils.isFilterStraightLineAdjustmentNeeded = function() {
    return false;
}

/**
 * Works around bug 12622757, where updating objects whose ancestors have filters
 * does not work in the recent Webkit versions.
 * @param svgDomElement The SVG DOM element ancestor that contains the offending filter.
 */
DvtFlashDocumentUtils.fixWebkitFilters = function(svgDomElement) {
}

/**
 * Works around bug 12622757, where updating objects whose ancestors have filters
 * does not work in the recent Webkit versions.
 * @param displayable The displayable that contains the offending filter.
 */
DvtFlashDocumentUtils.fixWebkitFiltersForDisplayable = function(displayable) {
}

DvtFlashDocumentUtils._fixFilter = function(svgDomElement) {
}

/**
 * Cancel a DOM event.
 * 
 * @param {object}  e  event object to cancel
 */
DvtFlashDocumentUtils.cancelDomEvent = function(e)
{

}

// Copyright (c) 2008, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/*-------------------------------------------------------------------------*/
/*   DvtSvgContext         SVG implementation of DvtContext                */
/*-------------------------------------------------------------------------*/
/**
  *  @extends DvtContext
  *  @class DvtSvgContext
  *  @constructor
  *  @param {root}  
  *  @param {id}  
  */
var  DvtSvgContext = function(root, id)
{
  // Create the impl factory, defs, and stage

  this._implFactory = new DvtSvgImplFactory(this) ;
  this._defs = this._implFactory.newDefs();
  this._root = root ;
  root.appendChild(this._defs);

  // Create the tooltip manager

  // Pass to the superclass

  this.Init(this._implFactory, root, id);

  root.appendChild(this._stage.getImpl().getElem());
  
  //BUG FIX 12613719: map of DvtClipPath objects stored by id
  this._clipPathMap = {};
};

DvtObj.createSubclass(DvtSvgContext, DvtContext, "DvtSvgContext");

/**
 * Append element(s) to the application global <defs> element.
 */
DvtSvgContext.prototype.appendDefs = function(elem)
{
  this._defs.appendChild(elem) ;
};


/**
  *   @returns {DOM_Element}  the global <defs> DOM element
  */
DvtSvgContext.prototype.getDefs = function()
{
  return this._defs ;
};

/**
  *   @returns {DvtSvgImplFactory}  the platform implementation factory.
  */
DvtSvgContext.prototype.getImplFactory = function()
{
  return this._implFactory ;
};


/**
  *   Removes the specified element from the global <defs> element.
  */
DvtSvgContext.prototype.removeDefs = function(elem)
{
  this._defs.removeChild(elem) ;
};


/**
  *   @returns {DvtSvgStage}  the platform stage implementation object.
  */
DvtSvgContext.prototype.getStage = function()
{
  return this._stage ;
};


/**
  * Determine if the platform is Canvas.
  *
  * @type boolean
  */
DvtSvgContext.prototype.isPlatformCanvas = function () {
  return false ;
};


/**
  * Determine if the platform is SVG.
  *
  * @type boolean
  */
DvtSvgContext.prototype.isPlatformSvg = function () {
  return true;
};

//BUG FIX 12613719: 
/**
  * Store the clipping path.
  *
  * @param {string}  id  id of the clipping path
  * @param {DvtClipPath}  clipPath  clipping path object
  */
DvtSvgContext.prototype.storeClipPath = function (id, clipPath) {
  //store the clipping path if it's non-null
  if (clipPath)
  {
    this._clipPathMap[id] = clipPath;
  }
  //delete any stored clipping path with the given id if the 
  //one passed in is null
  else
  {
    this._clipPathMap[id] = null;
    delete this._clipPathMap[id];
  }
};

//BUG FIX 12613719: 
/**
  * Determine if the clipping path already exists.
  * 
  * @param {string}  id  id of the clipping path
  * @param {DvtClipPath}  clipPath  clipping path object
  *
  * @type boolean
  */
DvtSvgContext.prototype.hasClipPath = function (id, clipPath) {
  var storedClipPath = this._clipPathMap[id];
  //return true if it's the same instance of the object
  if (storedClipPath)
  {
    return (storedClipPath === clipPath);
  }
  return false;
};


//BUG FIX 12566921.
/**  Chrome (as at version 12.0.742.91 6/12/11) honors the dir="rtl"
  *  on the top <html> for the page and causes text alignment rendering
  *  issues with the current MT generated XML (because the (x,y) are
  *  assumed to pertain to the right hand side) ;  IE9, Firefox and
  *  Safari currently do not. This fix overrides this locally for the
  *  svg element, and isolates the fix to the Dvt toolkit for BiDi only
  *  to avoid any undesirable external consequences in Adf.
  */

DvtSvgContext.prototype.fixBrowserTextRTL = function()
{
  if ((DvtAgent.getAgent().isWebkit() ||  DvtAgent.getAgent().getName().indexOf("opera")!=-1) && !DvtAgent.getAgent().isTouchDevice())
    this._root.setAttributeNS(null, "text-anchor", "end");
  else{
    this._root.setAttributeNS(null, "text-anchor", "start");
  }
};

// Copyright (c) 2008, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/*-------------------------------------------------------------------------*/
/*  DvtSvgUtils()                                                          */
/*-------------------------------------------------------------------------*/

// SVG Utilities for Drawing

/**
  *   @constructor
  */
var DvtSvgUtils = new Object();

DvtSvgUtils.SVG_NS   = "http://www.w3.org/2000/svg";
DvtSvgUtils.XLINK_NS = "http://www.w3.org/1999/xlink";

/**
 * Creates and returns a new SVG document with the specified id.
 * @param {string} id The id for the new SVG document.
 * @return A new SVG document.
 */
DvtSvgUtils.createSvgDocument = function(id) {
  var svg = document.createElementNS(DvtSvgUtils.SVG_NS, "svg");
  svg.setAttributeNS(null, "id", id);
  svg.setAttributeNS(null, "width", "100%");
  svg.setAttributeNS(null, "height", "100%");
  return svg;
}

/**
 * Returns the drag feedback for the specified objects.
 * @param {object} displayables The DvtDisplayable or array of DvtDisplayables to display for drag feedback.
 * @return {object} An object containing drag feedback information.
 */
DvtSvgUtils.getDragFeedback = function (displayables) { 
  var bounds = DvtDnDUtils.getDragFeedbackBounds(displayables);
  var svg = DvtSvgUtils._getDragFeedbackSVG(displayables, bounds);

  var feedback = new Object();
  feedback.width = bounds.w + DvtDragSource.DRAG_FEEDBACK_MARGIN * 2;
  feedback.height = bounds.h + DvtDragSource.DRAG_FEEDBACK_MARGIN * 2;
  if (svg)
    feedback.svg = svg;

  return feedback;
}

/**
 * Returns an svg string representing the drag over feedback.
 * @param {object} displayables The DvtDisplayable or array of DvtDisplayables to display for drag feedback.
 * @param {DvtRectangle} bounds The bounds for the drag feedback displayables, used to translate the feedback to 0.
 * @private
 */
DvtSvgUtils._getDragFeedbackSVG = function(displayables, bounds) {
  // Wrap in an array if not already wrapped.
  if (!(displayables instanceof Array)) {
    displayables = [displayables];
  }

  /// BUG #12805155: A new svg document must be created programmatically and appended to the wrapping div later on.
  //  This is necessary for Safari 5.0 and earlier, as well as iOS.  innerHTML should not be used.
  var svgElem = DvtSvgUtils.createSvgDocument("dnd");
  
  // Create a group element to apply the top level translate to show the drag feedback at (0, 0)
  var tx = DvtDragSource.DRAG_FEEDBACK_MARGIN - bounds.x;
  var ty = DvtDragSource.DRAG_FEEDBACK_MARGIN - bounds.y;
  var translate = "translate(" + tx + "," + ty + ")";
  var container = DvtSvgShapeUtils.createElement("g");
  container.setAttributeNS(null,'transform', translate) ;
  svgElem.appendChild(container);
  
  // Loop through and add the displayables
  for (var i = 0;i < displayables.length;i++) {
    // Clone the selected node and add
    var src = displayables[i];
    var elem = src.getImpl().getElem();
    var clone = elem.cloneNode(true);
    container.appendChild(clone);
  }
  
  return svgElem;
}
// Copyright (c) 2008, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/*-------------------------------------------------------------------------*/
/*  DvtCanvasUtils()                                                       */
/*-------------------------------------------------------------------------*/

/**
  *   @constructor
  */
var DvtCanvasUtils = new Object();

/**
 * Creates and returns a new Canvas document.
 * @param {Number} w  optional width for the canvas
 * @param {Number} h  optional height for the canvas.
 * @param {string} id optional id for the canvas.
 * @returns {Canvas} A new Canvas document.
 */
DvtCanvasUtils.createCanvasDocument = function(w, h, id) {

  var canvas  = document.createElement('Canvas') ;
  if (id) {
    canvas.id = id ;
  }
  if (w) {
    canvas.width  =  w ;
  }
  if (h) {
    canvas.height = h ;
  }

  return canvas;
}
// Copyright (c) 2008, 2012, Oracle and/or its affiliates. 
// All rights reserved. 
/*-------------------------------------------------------------------------*/
/*   DvtCanvasContext         Canvas implementation of DvtContext          */
/*-------------------------------------------------------------------------*/
/**
  *  @extends DvtContext
  *  @class DvtCanvasContext
  *  @constructor
  *  @param {root}  
  *  @param {id}  
  */
var  DvtCanvasContext = function(root, id)
{
  // Create the impl factory, defs, and stage

  this._implFactory = new DvtCanvasImplFactory(this) ;
  this._root        = root ;
  this._parent      = root.parentNode ;

  this.Init(this._implFactory, root, id);     // create the stage, tooltip manager.

  //BUG FIX 12613719: map of DvtClipPath objects stored by id
  this._clipPathMap = {};
  
};

DvtObj.createSubclass(DvtCanvasContext, DvtContext, "DvtCanvasContext");


/**
  *   @returns {DvtCanvasImplFactory}  the platform implementation factory.
  */
DvtCanvasContext.prototype.getImplFactory = function()
{
  return this._implFactory ;
};


/**
  *   @returns {DvtCanvasStage}  the platform stage implementation object.
  */
DvtCanvasContext.prototype.getStage = function()
{
  return this._stage ;
};

/**
  * Obtain document utils singleton.
  *
  * @type Object
  * @override
  */

DvtCanvasContext.prototype.getDocumentUtils = function () {
  return DvtCanvasDocumentUtils;
};

/**
  * Obtain document utils singleton.
  *
  * @type Object
  * @override
  */
DvtCanvasContext.prototype.getDocumentUtils = function () {
  return DvtCanvasDocumentUtils;
};


/**
  *   Obtains the external Js interface singleton.
  *   @returns {DvtCanvasJsExt}  the external interface singleton.
  */

DvtCanvasContext.prototype.getJsExt = function()
{
   if (! this._externalInterface) {
     this._externalInterface = new DvtCanvasJsExt() ;
   }

   return this._externalInterface ;

};


/**
  * Determine if the platform is Canvas.
  *
  * @type boolean
  */
DvtCanvasContext.prototype.isPlatformCanvas = function () {
  return true;
};

/**
  * Determine if the platform is SVG.
  * @type boolean
  */
DvtCanvasContext.prototype.isPlatformSvg = function () {
  return false ;
};


/**
  *  Queues-up a render of the stage and all its contained displayables at
  *  the end of this cycle.
  */
DvtCanvasContext.prototype.queueRender = function ()
{
  //console.log('DvtCanvasContext.queueRender()') ;

  if (! this._renderTimer) {
    this._renderTimer = new DvtTimer(this, 0, this._renderEvent, this, 1) ;
    this._renderTimer.start() ;
  }
} ;

/**
  *   Performs the actual queued render (see {@link DvtCanvasContext#queueRender()}).
  */
DvtCanvasContext.prototype._renderEvent = function ()
{
   //console.log('DvtCanvasContext timer event') ;
   this._renderTimer = null ;
   this._stage.getImpl().render() ;
} ;


//BUG FIX 12613719: 
/**
  * Store the clipping path.
  *
  * @param {string}  id  id of the clipping path
  * @param {DvtClipPath}  clipPath  clipping path object
  */
/*
DvtSvgContext.prototype.storeClipPath = function (id, clipPath) {
  //store the clipping path if it's non-null
  if (clipPath)
  {
    this._clipPathMap[id] = clipPath;
  }
  //delete any stored clipping path with the given id if the 
  //one passed in is null
  else
  {
    this._clipPathMap[id] = null;
    delete this._clipPathMap[id];
  }
};
*/
//BUG FIX 12613719: 
/**
  * Determine if the clipping path already exists.
  * 
  * @param {string}  id  id of the clipping path
  * @param {DvtClipPath}  clipPath  clipping path object
  *
  * @type boolean
  */
/*
DvtSvgContext.prototype.hasClipPath = function (id, clipPath) {
  var storedClipPath = this._clipPathMap[id];
  //return true if it's the same instance of the object
  if (storedClipPath)
  {
    return (storedClipPath === clipPath);
  }
  return false;
};
*/

//BUG FIX 12566921.
/**  Chrome (as at version 12.0.742.91 6/12/11) honors the dir="rtl"
  *  on the top <html> for the page and causes text alignment rendering
  *  issues with the current MT generated XML (because the (x,y) are
  *  assumed to pertain to the right hand side) ;  IE9, Firefox and
  *  Safari currently do not. This fix overrides this locally for the
  *  svg element, and isolates the fix to the Dvt toolkit for BiDi only
  *  to avoid any undesirable external consequences in Adf.
  */

DvtCanvasContext.prototype.fixBrowserTextRTL = function()
{
/*
  if ((DvtAgent.getAgent().isWebkit() ||  DvtAgent.getAgent().getName().indexOf("opera")!=-1) && !DvtAgent.getAgent().isTouchDevice())
    this._root.setAttributeNS(null, "text-anchor", "end");
  else{
    this._root.setAttributeNS(null, "text-anchor", "start");
  }
*/
};

if (!Array.prototype.indexOf) {
  Array.prototype.indexOf = function(obj) { 
     for (var i=0; i<this.length; i++) {
        if (this[i] == obj)
          return i;
     }
     return -1;
  }
}
/**
  *  @extends DvtContext
  *  @class DvtXmlContext
  *  @constructor
  *  @param {root}  
  *  @param {id}  
  */
var DvtXmlContext = function (id) {
  // Create the impl factory, defs, and stage
  this._implFactory = new DvtXmlImplFactory(this);
  this.Init(this._implFactory, null, id);

  this._root = new DvtXmlContainer(id + "_svg", 'svg');
  this._root.Svg["width"] = "100%";
  this._root.Svg["height"] = "100%";
  this._root.Svg["xmlns"] = "http://www.w3.org/2000/svg";
  this._root.Svg["xmlns:xlink"] = "http://www.w3.org/1999/xlink";

  this._defs = this._implFactory.newDefs();

  this._root.addChild(this._defs);
  this._root.addChild(this._stage.getImpl());
  // TODO clip map
}

DvtObj.createSubclass(DvtXmlContext, DvtContext, "DvtXmlContext");


/**
 * Append element(s) to the SVG <defs> element.
 */
DvtXmlContext.prototype.appendDefs = function (elem) {
  this._defs.addChild(elem);
}

/**
  * @returns {Object}  The object containing information about the SVG <defs> element
  */
DvtXmlContext.prototype.getDefs = function () {
  return this._defs;
}

/**
 * Returns the string xml representation of the SVG element associated with this context.
 * @return {string}
 */
DvtXmlContext.prototype.toSvg = function () {
  return this._root.toSvg();
}

DvtXmlContext.prototype.supportsAnimation = function () {
  return false;
}

