/**
 * @constructor
 * dvt.AfMarker
 */
dvt.AfMarker = function() {
  this.Init();
};


// Make dvt.AfMarker a subclass of dvt.AfComponent
dvt.Obj.createSubclass(dvt.AfMarker, dvt.AfComponent, 'dvt.AfMarker');


// Register the dvt.AfMarker tag with dvt.AfComponentFactory
/** @const */
dvt.AfMarker.TAG_NAME = 'mk';
dvt.AfComponentFactory.registerComponent(dvt.AfMarker.TAG_NAME, dvt.AfMarker);

// Space between marker and label
/** @const */
dvt.AfMarker.MARKER_LABEL_PADDING = 2;

// dvt.AfMarker Attributes
/** @const */
dvt.AfMarker.ATTR_LABEL_DISPLAY = 'labelDisplay';

/** @const */
dvt.AfMarker.ATTR_LABEL_POSITION = 'labelPosition';

/** @const */
dvt.AfMarker.ATTR_LABEL_STYLE = 'labelStyle';

/** @const */
dvt.AfMarker.ATTR_VALUE = 'value';

/** @const */
dvt.AfMarker.ATTR_SCALE_X = 'scaleX';

/** @const */
dvt.AfMarker.ATTR_SCALE_Y = 'scaleY';

/** @const */
dvt.AfMarker.ATTR_SHAPE = 'shape';

/** @const */
dvt.AfMarker.ATTR_SHAPE_PATH = 'shapePath';

/** @const */
dvt.AfMarker.ATTR_FILL_COLOR = 'fillColor';

/** @const */
dvt.AfMarker.ATTR_FILL_PATTERN = 'fillPattern';

/** @const */
dvt.AfMarker.ATTR_GRADIENT_EFFECT = 'gradientEffect';

/** @const */
dvt.AfMarker.ATTR_OPACITY = 'opacity';

/** @const */
dvt.AfMarker.ATTR_WIDTH = 'width';

/** @const */
dvt.AfMarker.ATTR_HEIGHT = 'height';

/** @const */
dvt.AfMarker.ATTR_X = 'x';

/** @const */
dvt.AfMarker.ATTR_Y = 'y';

/** @const */
dvt.AfMarker.ATTR_BORDER_STYLE = 'borderStyle';

/** @const */
dvt.AfMarker.ATTR_BORDER_WIDTH = 'borderWidth';

/** @const */
dvt.AfMarker.ATTR_BORDER_COLOR = 'borderColor';

/** @const */
dvt.AfMarker.ATTR_BORDER_RADIUS = 'borderRadius';

/** @const */
dvt.AfMarker.ATTR_SOURCE = 'source';

/** @const */
dvt.AfMarker.ATTR_SOURCE_HOVER = 'sourceHover';

/** @const */
dvt.AfMarker.ATTR_SOURCE_SELECTED = 'sourceSelected';

/** @const */
dvt.AfMarker.ATTR_SOURCE_HOVER_SELECTED = 'sourceHoverSelected';

/** @const */
dvt.AfMarker.ATTR_HAS_ACTION_LISTENER = 'hasActionListener';

/** @const @private */
dvt.AfMarker._BI_DEFAULT_MARKER_SIZE = 9;

// valid values for the Shape attribute. Default: circle
/** @const */
dvt.AfMarker.CIRCLE = 'c';

/** @const */
dvt.AfMarker.SQUARE = 's';

/** @const */
dvt.AfMarker.DIAMOND = 'd';

/** @const */
dvt.AfMarker.TRIANGLE_UP = 'tu';

/** @const */
dvt.AfMarker.TRIANGLE_DOWN = 'td';

/** @const */
dvt.AfMarker.PLUS = 'p';

/** @const */
dvt.AfMarker.HUMAN = 'h';

/** @const */
dvt.AfMarker.RECTANGLE = 'r';

/** @const */
dvt.AfMarker.ROUNDED_RECT = 'rr';


//  Note: these marker types are defined in the same order
//        as the definitions in the parser.  Don't change
//        one without changing the other!
dvt.AfMarker._markerTypeMap = {
  'c' : dvt.SimpleMarker.CIRCLE,
  's' : dvt.SimpleMarker.SQUARE,
  'd' : dvt.SimpleMarker.DIAMOND,
  'tu' : dvt.SimpleMarker.TRIANGLE_UP,
  'td' : dvt.SimpleMarker.TRIANGLE_DOWN,
  'p' : dvt.SimpleMarker.PLUS,
  'h' : dvt.SimpleMarker.HUMAN,
  'r' : dvt.SimpleMarker.RECTANGLE,
  'rr' : dvt.SimpleMarker.RECTANGLE // roundedRectangle deprecated, use rectangle instead
};

dvt.AfMarker._markerFillPatternMap = {
  'smallDiagonalLeft' : dvt.PatternFill.SM_DIAG_UP_LT,
  'largeDiagonalLeft' : dvt.PatternFill.LG_DIAG_UP_LT,
  'smallDiagonalRight' : dvt.PatternFill.SM_DIAG_UP_RT,
  'largeDiagonalRight' : dvt.PatternFill.LG_DIAG_UP_RT,
  'smallCrosshatch' : dvt.PatternFill.SM_CROSSHATCH,
  'largeCrosshatch' : dvt.PatternFill.LG_CROSSHATCH,
  'smallChecker' : dvt.PatternFill.SM_CHECK,
  'largeChecker' : dvt.PatternFill.LG_CHECK,
  'smallTriangle' : dvt.PatternFill.SM_TRIANGLE_CHECK,
  'largeTriangle' : dvt.PatternFill.LG_TRIANGLE_CHECK,
  'smallDiamond' : dvt.PatternFill.SM_DIAMOND_CHECK,
  'largeDiamond' : dvt.PatternFill.LG_DIAMOND_CHECK
};


/*-------------------------------------------------------------------------*/
/*   dvt.AfMarker attributes                                                */
/*-------------------------------------------------------------------------*/
/**
 * Gets the shape of the marker.
 * @return {string} the shape of the marker
 */
dvt.AfMarker.prototype.getShape = function() {
  return this.getProperty(dvt.AfMarker.ATTR_SHAPE);
};


/**
 * Specifies the shape of the marker.
 * @param {string} shape the shape of the marker
 */
dvt.AfMarker.prototype.setShape = function(shape) {
  this.setProperty(dvt.AfMarker.ATTR_SHAPE, shape);
};


/**
 * Gets the path to the svg file to use as a custom shape
 * @return {string} path to custom svg file
 */
dvt.AfMarker.prototype.getShapePath = function() {
  return this.getProperty(dvt.AfMarker.ATTR_SHAPE_PATH);
};


/**
 * Specifies the path to the svg file to use as a custom shape
 * @param {string} shapePath path to custom svg file
 */
dvt.AfMarker.prototype.setShapePath = function(shapePath) {
  this.setProperty(dvt.AfMarker.ATTR_SHAPE_PATH, shapePath);
};


/**
 * Gets the value of the component. When labelDisplay="on", this value will be used as the
 * text label for this marker
 * @return {string} value of the component
 */
dvt.AfMarker.prototype.getValue = function() {
  return this.getProperty(dvt.AfMarker.ATTR_VALUE);
};


/**
 * Sets the value of the component. When labelDisplay="on", this value will be used as the
 * text label for this marker
 * @param {string} value value of the component
 */
dvt.AfMarker.prototype.setValue = function(value) {
  this.setProperty(dvt.AfMarker.ATTR_VALUE, value);
};


/**
 * Gets the fill color of this marker. Valid values are RGB hexadecimal
 * @return {string} fill color of this marker
 */
dvt.AfMarker.prototype.getFillColor = function() {
  return this.getProperty(dvt.AfMarker.ATTR_FILL_COLOR);
};


/**
 * Sets the fill color of this marker. Valid values are RGB hexadecimal
 * @param {string} fillColor fill color of this marker
 */
dvt.AfMarker.prototype.setFillColor = function(fillColor) {
  this.setProperty(dvt.AfMarker.ATTR_FILL_COLOR, fillColor);
};


/**
 * Gets the built-in pattern used to fill this marker. Valid values are:
 * "smallDiagonalLeft"
 * "smallChecker"
 * "smallDiagonalRight"
 * "smallTriangle"
 * "smallCrosshatch"
 * "smallDiamond"
 * "largeDiagonalLeft"
 * "largeChecker"
 * "largeDiagonalRight"
 * "largeTriangle"
 * "largeCrosshatch"
 * "largeDiamond"
 *
 * The pattern is drawn with a white background, and the foreground color is taken from the fillColor attribute.
 * @return {string} pattern used to fill the marker
 */
dvt.AfMarker.prototype.getFillPattern = function() {
  return this.getProperty(dvt.AfMarker.ATTR_FILL_PATTERN);
};


/**
 * Sets the built-in pattern used to fill this marker. Valid values are:
 * "smallDiagonalLeft"
 * "smallChecker"
 * "smallDiagonalRight"
 * "smallTriangle"
 * "smallCrosshatch"
 * "smallDiamond"
 * "largeDiagonalLeft"
 * "largeChecker"
 * "largeDiagonalRight"
 * "largeTriangle"
 * "largeCrosshatch"
 * "largeDiamond"
 *
 * The pattern is drawn with a white background, and the foreground color is taken from the fillColor attribute.
 * @param {string} fillPattern pattern used to fill the marker
 */
dvt.AfMarker.prototype.setFillPattern = function(fillPattern) {
  this.setProperty(dvt.AfMarker.ATTR_FILL_PATTERN, fillPattern);
};


/**
 * Gets the horizontal scale factor for this marker. This determines how much to scale the marker from its default size.
 * @return {number} horizontal scale factor
 */
dvt.AfMarker.prototype.getScaleX = function() {
  return this.getProperty(dvt.AfMarker.ATTR_SCALE_X);
};


/**
 * Sets the horizontal scale factor for this marker. This determines how much to scale the marker from its default size.
 * @param {number} scaleX horizontal scale factor
 */
dvt.AfMarker.prototype.setScaleX = function(scaleX) {
  this.setProperty(dvt.AfMarker.ATTR_SCALE_X, scaleX);
};


/**
 * Gets the vertical scale factor for this marker. This determines how much to scale the marker from its default size.
 * @return {number} vertical scale factor
 */
dvt.AfMarker.prototype.getScaleY = function() {
  return this.getProperty(dvt.AfMarker.ATTR_SCALE_Y);
};


/**
 * Gets the vertical scale factor for this marker. This determines how much to scale the marker from its default size.
 * @param {number} scaleY vertical scale factor
 */
dvt.AfMarker.prototype.setScaleY = function(scaleY) {
  this.setProperty(dvt.AfMarker.ATTR_SCALE_Y, scaleY);
};


/**
 * Gets the font style for labels associated with this marker. Accepts font-related CSS attributes like font-name,
 * font-weight, font-size, color, etc.
 * @return {string} font style for labels associated with this marker
 */
dvt.AfMarker.prototype.getLabelStyle = function() {
  return this.getProperty(dvt.AfMarker.ATTR_LABEL_STYLE);
};


/**
 * Sets the font style for labels associated with this marker. Accepts font-related CSS attributes like font-name,
 * font-weight, font-size, color, etc.
 * @param {string} labelStyle font style for labels associated with this marker
 */
dvt.AfMarker.prototype.setLabelStyle = function(labelStyle) {
  this.setProperty(dvt.AfMarker.ATTR_LABEL_STYLE, labelStyle);
};


/**
 * Gets the position relative to the marker that the specified value label should be displayed at. Valid values are:
 * "top" - Display the label on top of the marker
 * "bottom" - Display the label below the marker
 * "center" - (default) Display the label on the center of the marker
 * @return {string} position of the marker's label
 */
dvt.AfMarker.prototype.getLabelPosition = function() {
  return this.getProperty(dvt.AfMarker.ATTR_LABEL_POSITION);
};


/**
 * Sets the position relative to the marker that the specified value label should be displayed at. Valid values are:
 * "top" - Display the label on top of the marker
 * "bottom" - Display the label below the marker
 * "center" - (default) Display the label on the center of the marker
 * @param {string} labelPosition position of the marker's label
 */
dvt.AfMarker.prototype.setLabelPosition = function(labelPosition) {
  this.setProperty(dvt.AfMarker.ATTR_LABEL_POSITION, labelPosition);
};


/**
 * Gets the label display behavior for this marker. Valid values are:
 * "on" - Display the label provided in the value attribute
 * "off" - (default) Do not display the label provided in the value attribute
 * @return {string} label display behavior for this marker
 */
dvt.AfMarker.prototype.getLabelDisplay = function() {
  return this.getProperty(dvt.AfMarker.ATTR_LABEL_DISPLAY);
};


/**
 * Sets the label display behavior for this marker. Valid values are:
 * "on" - Display the label provided in the value attribute
 * "off" - (default) Do not display the label provided in the value attribute
 * @param {string} labelDisplay label display behavior for this marker
 */
dvt.AfMarker.prototype.setLabelDisplay = function(labelDisplay) {
  this.setProperty(dvt.AfMarker.ATTR_LABEL_DISPLAY, labelDisplay);
};


/**
 * Gets the gradient effect that should be used for this marker. Valid values are:
 * "auto" - (default) Sets a gradient on the marker
 * "none" - Do not use gradients on the marker. This causes markers to appear flat.
 * @return {string} gradient effect for this marker
 */
dvt.AfMarker.prototype.getGradientEffect = function() {
  return this.getProperty(dvt.AfMarker.ATTR_GRADIENT_EFFECT);
};


/**
 * Specifies the gradient effect that should be used for this marker. Valid values are:
 * "auto" - (default) Sets a gradient on the marker
 * "none" - Do not use gradients on the marker. This causes markers to appear flat.
 * @param {string} gradientEffect gradient effect for this marker
 */
dvt.AfMarker.prototype.setGradientEffect = function(gradientEffect) {
  this.setProperty(dvt.AfMarker.ATTR_GRADIENT_EFFECT, gradientEffect);
};


/**
 * Gets the opacity of the fill color of the marker. Valid values are from 0.0 - 1.0, where 0.0 is transparent and 1.0 is opaque.
 * @return {number} opacity of the marker
 */
dvt.AfMarker.prototype.getOpacity = function() {
  return this.getProperty(dvt.AfMarker.ATTR_OPACITY);
};


/**
 * Specifies the opacity of the fill color of the marker. Valid values are from 0.0 - 1.0, where 0.0 is transparent and 1.0 is opaque.
 * @param {number} opacity opacity of the marker
 */
dvt.AfMarker.prototype.setOpacity = function(opacity) {
  this.setProperty(dvt.AfMarker.ATTR_OPACITY, opacity);
};


/**
 * Gets the border style of this marker. Valid values are:
 * "none" - (default) No border will be displayed
 * "solid" - A solid border will be displayed
 * @return {string} the border style
 */
dvt.AfMarker.prototype.getBorderStyle = function() {
  return this.getProperty(dvt.AfMarker.ATTR_BORDER_STYLE);
};


/**
 * Sets the border style of this marker. Valid values are:
 * "none" - (default) No border will be displayed
 * "solid" - A solid border will be displayed
 * @param {string} borderStyle the border style
 */
dvt.AfMarker.prototype.setBorderStyle = function(borderStyle) {
  this.setProperty(dvt.AfMarker.ATTR_BORDER_STYLE, borderStyle);
};


/**
 * Gets the border width of this marker.
 * @return {number} the border width
 */
dvt.AfMarker.prototype.getBorderWidth = function() {
  return this.getFloatProp(dvt.AfMarker.ATTR_BORDER_WIDTH);
};


/**
 * Sets the border width of this marker.
 * @param {number} borderWidth the border width
 */
dvt.AfMarker.prototype.setBorderWidth = function(borderWidth) {
  this.setProperty(dvt.AfMarker.ATTR_BORDER_WIDTH, borderWidth);
};


/**
 * Gets the border color of this marker. Valid values are RGB hexadecimal
 * @return {string} the border color
 */
dvt.AfMarker.prototype.getBorderColor = function() {
  return this.getProperty(dvt.AfMarker.ATTR_BORDER_COLOR);
};


/**
 * Sets the border color of this marker. Valid values are RGB hexadecimal
 * @param {string} borderColor the border color
 */
dvt.AfMarker.prototype.setBorderColor = function(borderColor) {
  this.setProperty(dvt.AfMarker.ATTR_BORDER_COLOR, borderColor);
};


/**
 * Gets the border radius of this marker.
 * @return {string} the border radius
 */
dvt.AfMarker.prototype.getBorderRadius = function() {
  return this.getProperty(dvt.AfMarker.ATTR_BORDER_RADIUS);
};


/**
 * Sets the border radius of this marker.
 * @param {string} borderRadius the border radius
 */
dvt.AfMarker.prototype.setBorderRadius = function(borderRadius) {
  this.setProperty(dvt.AfMarker.ATTR_BORDER_RADIUS, borderRadius);
};


/**
 * Gets the width for this marker.
 * @return {number} width
 */
dvt.AfMarker.prototype.getWidth = function() {
  return this.getFloatProp(dvt.AfMarker.ATTR_WIDTH);
};


/**
 * Sets the width for this marker.
 * @param {number} width
 */
dvt.AfMarker.prototype.setWidth = function(width) {
  this.setProperty(dvt.AfMarker.ATTR_WIDTH, width);
};


/**
 * Gets the height for this marker.
 * @return {number} height
 */
dvt.AfMarker.prototype.getHeight = function() {
  return this.getFloatProp(dvt.AfMarker.ATTR_HEIGHT);
};


/**
 * Gets the height for this marker.
 * @param {number} height
 */
dvt.AfMarker.prototype.setHeight = function(height) {
  this.setProperty(dvt.AfMarker.ATTR_HEIGHT, height);
};


/**
 * Gets the image source for this marker.
 * @return {string} source
 */
dvt.AfMarker.prototype.getSource = function() {
  return this.getProperty(dvt.AfMarker.ATTR_SOURCE);
};


/**
 * Sets the image source for this marker.
 * @param {string} source
 */
dvt.AfMarker.prototype.setSource = function(source) {
  this.setProperty(dvt.AfMarker.ATTR_SOURCE, source);
};


/**
 * Gets the hover image source for this marker.
 * @return {string} source
 */
dvt.AfMarker.prototype.getSourceHover = function() {
  return this.getProperty(dvt.AfMarker.ATTR_SOURCE_HOVER);
};


/**
 * Sets the hover image source for this marker.
 * @param {string} source
 */
dvt.AfMarker.prototype.setSourceHover = function(source) {
  this.setProperty(dvt.AfMarker.ATTR_SOURCE_HOVER, source);
};


/**
 * Gets the selected image source for this marker.
 * @return {string} source
 */
dvt.AfMarker.prototype.getSourceSelected = function() {
  return this.getProperty(dvt.AfMarker.ATTR_SOURCE_SELECTED);
};


/**
 * Sets the selected image source for this marker.
 * @param {string} source
 */
dvt.AfMarker.prototype.setSourceSelected = function(source) {
  this.setProperty(dvt.AfMarker.ATTR_SOURCE_SELECTED, source);
};


/**
 * Gets the hover selected image source for this marker.
 * @return {string} source
 */
dvt.AfMarker.prototype.getSourceHoverSelected = function() {
  return this.getProperty(dvt.AfMarker.ATTR_SOURCE_HOVER_SELECTED);
};


/**
 * Sets the hover selected image source for this marker.
 * @param {string} source
 */
dvt.AfMarker.prototype.setSourceHoverSelected = function(source) {
  this.setProperty(dvt.AfMarker.ATTR_SOURCE_HOVER_SELECTED, source);
};

/**
 * Get x coord for this marker.
 * @return {number} source
 */
dvt.AfMarker.prototype.getX = function() {
  return this.getFloatProp(dvt.AfMarker.ATTR_X, 0);
};

/**
 * Get y coord for this marker.
 * @return {number} source
 */
dvt.AfMarker.prototype.getY = function() {
  return this.getFloatProp(dvt.AfMarker.ATTR_Y, 0);
};



/*-------------------------------------------------------------------------*/
/*   CreateDisplayObject                                                   */
/*-------------------------------------------------------------------------*/


/**
 * @override
 */
dvt.AfMarker.prototype.createDisplayObj = function(afContext) {
  //Bug 13477511 - RENDERED FLAG ISN'T WORKING CORRECTLY FOR MARKERS
  if (! this.renderMe())
    return null;

  //BUG 13971862: save the parent node so we can call back to it for popups
  //BUG 14456277: Save the parent node for markers, because they do not call super.createDisplayObj
  this._parentNode = afContext.getParentNode();

  this.setAfContext(afContext);
  var dvtContext = this.getDvtContext();
  this.registerAsTabStop();

  //Bug 13491092 - action attribute on dvt:marker used within diagram overlay is ignored
  // save context callback
  this.SaveContextCallback();

  // if it has an Id, make it unique
  // otherwise, generate a unique Id
  var id = this._getUniqueId();

  var ww = this.getWidth();
  var hh = this.getHeight();
  var x = 0;
  var y = 0;
  if (ww && !hh) {
    hh = ww;
  }
  else if (!ww && hh) {
    ww = hh;
  }
  else if (!ww && !hh) {
    ww = dvt.AfMarker._BI_DEFAULT_MARKER_SIZE;
    hh = dvt.AfMarker._BI_DEFAULT_MARKER_SIZE;
  }

  //NOTE: get dimensions seems ignore scale
  //resolve scaleX and scaleY -
  //For builtin marker: width and height are scaled here
  var scaleX = this.getScaleX();
  var scaleY = this.getScaleY();
  ww = scaleX ? scaleX * ww : ww;
  hh = scaleY ? scaleY * hh : hh;

  var type;
  var br;
  // Marker type can be
  // 1) custom marker image
  // 2) custom marker shape
  // 3) built-in marker shape
  var imgSrc = this.getSource();
  var shapeSrc = this.getShapePath();
  if (imgSrc) { // Case 1
    type = [imgSrc, this.getSourceSelected(), this.getSourceHover(), this.getSourceHoverSelected()];
    br = this.getBorderRadius();
  }
  else if (shapeSrc) { // Case 2
    // if shapePath is specified, find the custom marker def and use it
    //Note: in graph mt="s,10" or mt="/resources/svg/cherry.svg,9"
    type = shapeSrc;
    x = this.getX();
    y = this.getY();
  }
  else { // Case 3
    var mshape = this.getShape();
    // no svgPath and no shape specified, default to circle
    if (!mshape)
      mshape = dvt.AfMarker.CIRCLE;

    br = this.getBorderRadius();
    if (!br && mshape == dvt.AfMarker.ROUNDED_RECT)
      br = dvt.SimpleMarker.DEFAULT_BORDER_RADIUS;
    type = dvt.AfMarker._markerTypeMap[mshape];
  }

  // create marker
  var marker;
  var cx = x + 1 / 2 * ww;
  var cy = y + 1 / 2 * hh;
  var bs = this.getBorderStyle();
  var hasBorder = !this.getShapePath() && bs && bs != 'none';
  var bw = this.getBorderWidth();
  if (hasBorder) {
    bw = bw ? bw : 1;
    ww -= bw;
    hh -= bw;
  }
  if (type instanceof Array) {
    marker = new dvt.ImageMarker(dvtContext, cx, cy, ww, hh, br, type[0], type[1], type[2], type[3]);
    // Bug 30527927 - COLOR NOT FILLED IN PHOTOREALISTIC VIEW COMPONENT
    marker.setPreserveAspectRatio('none');
  }
  else {
    marker = new dvt.SimpleMarker(dvtContext, type, afContext.getSkinName(), cx, cy, ww, hh, br, false);
  }
  // Bug 17291324 - EM: CLICKABLE MOUSE CURSOR IS NOT SHOWN UP WHEN MOUSE OVER MARKER TAG
  var bAction = this.getProperty(dvt.AfMarker.ATTR_HAS_ACTION_LISTENER);
  if (! bAction) {
    var spbs = this.getShowPopupBehaviors();
    if (dvt.ArrayUtils.isArray(spbs)) {
      for (var i = 0; i < spbs.length; i++) {
        if (spbs[i] && spbs[i].getTriggerType() == 'click') {
          bAction = true;
          break;
        }
      }
    }
    if (! bAction) {
      var cbs = this.getClientBehaviors();
      if (dvt.ArrayUtils.isArray(cbs)) {
        for (var i = 0; i < cbs.length; i++) {
          if (cbs[i] && cbs[i].getTriggerType() == 'click') {
            bAction = true;
            break;
          }
        }
      }
    }
  }
  marker.setCursor(bAction ? dvt.SelectionEffectUtils.getSelectingCursor() : null);

  marker._prop = this._prop;

  // solid, gradient, pattern fill?
  var fc = this.getFillColor();
  var fa = this.getOpacity();
  var ge = this.getGradientEffect();
  var fp = this.getFillPattern();

  if (fp) {
    fp = dvt.AfMarker._markerFillPatternMap[fp];
  }
  if (fp) {
    marker.setFill(new dvt.PatternFill(fp, fc));
  }
  else if (ge == 'auto') {
    marker.setFill(dvt.MarkerGradient.createMarkerGradient(fc ? fc : '#000000', marker, fa ? fa : 1.0));
  }
  else if (fc || fa) {
    marker.setSolidFill(fc, fa);
  }

  if (hasBorder) {
    var bc = this.getBorderColor();
    bc = bc ? bc : '#000000';

    var stroke = new dvt.SolidStroke(bc, 1, bw);
    stroke.setType(dvt.Stroke.convertTypeString(bs));

    marker.setStroke(stroke);

  }

  this._marker = marker;

  // create marker label
  var value = this.getValue();
  var bvis = (this.getLabelDisplay() && this.getLabelDisplay() === 'off') ? false : true;

  if (value && bvis) {
    var labelId = id + '_lb';
    var label = new dvt.OutputText(dvtContext, value, 0, 0, labelId);

    var cssStyle;
    var lstyle = this.getLabelStyle();
    if (dvt.AfComponentFactory.CACHE_STYLES) {
      cssStyle = afContext.GetCSSStyle(this.getTagName(), '', lstyle, true);
    }
    else {
      cssStyle = lstyle ? this.createTextStyles(new dvt.CSSStyle(lstyle), dvt.AfStyleUtils.getDefaultTextStyle()) : dvt.AfStyleUtils.getDefaultTextStyle();
    }

    if (cssStyle) {
      label.setCSSStyle(cssStyle);
    }
    this._label = label;

    // create a container for both marker and label
    var group = new dvt.Container(dvtContext, id);
    var position = this.getLabelPosition();
    if (position === 'top') {
      group.addChild(label);
      group.addChild(marker);
    }
    else {
      group.addChild(marker);
      group.addChild(label);
    }
    this._bgShape = group;
  }
  else {
    this._bgShape = marker;
  }

  //save a reference back to the af component
  this._bgShape._afComp = this;
  return this._bgShape;
};


//extends dvt.AfComponent
// dvt.AfMarker.prototype.getDisplayObj = function() {
//   return this._bgShape;
// }

dvt.AfMarker.prototype.getMarkerDisplayObj = function() {
  return this._marker;
};

//extends dvt.AfComponent TODO: comment out?
dvt.AfMarker.prototype.setTranslateX = function(relx) {
  this._bgShape.setTranslateX(relx);
};

//extends dvt.AfComponent TODO: comment out?
dvt.AfMarker.prototype.setTranslateY = function(rely) {
  this._bgShape.setTranslateY(rely);
};


dvt.AfMarker.prototype.render = function(afContext) {
  //Bug 13477511 - RENDERED FLAG ISN'T WORKING CORRECTLY FOR MARKERS
  if (! this.renderMe())
    return;

  //if shortDesc is specified, show it in a tooltip
  var shape = this.getDisplayObj();
  if (this.getShortDesc() || this.getProperty(dvt.AfMarker.ATTR_HAS_ACTION_LISTENER) || this.getShowPopupBehaviors() || this.getClientBehaviors()) {
    this.associate(shape, this);
  }

  var marker = this._marker;
  var label = this._label;
  var dims = marker.getDimensionsWithStroke();

  var markerDim = {
    x: this.getX(),
    y: this.getY(),
    w: dims.w,
    h: dims.h
  };

  // no visible label
  if (! label) {
    //extends dvt.AfComponent
    this._setBounds(afContext, markerDim.x, markerDim.y, markerDim.w, markerDim.h);
    return;
  }

  //Bug 13408941 - diagrammer js code stops executing when markersize is zero
  if (markerDim.w === 0 && markerDim.h === 0) {
    this._setBounds(afContext, markerDim.x, markerDim.y, 0, 0);
    return;
  }

  var labelDim = label.getDimensions();


  var afMarkerWidth;
  var afMarkerHeight;
  var position = this.getLabelPosition();

  switch (position) {
    case 'top':
      if (markerDim.w > labelDim.w) {
        label.setX(markerDim.w / 2);
        label.alignCenter();
      }
      else {
        marker.setCx(labelDim.w / 2);
      }
      marker.setCy(labelDim.h + dvt.AfMarker.MARKER_LABEL_PADDING + markerDim.h / 2);

      afMarkerWidth = Math.max(markerDim.w, labelDim.w);
      afMarkerHeight = labelDim.h + dvt.AfMarker.MARKER_LABEL_PADDING + markerDim.h;
      break;

    case 'bottom':
      if (markerDim.w > labelDim.w) {
        label.setX(markerDim.w / 2);
        label.alignCenter();
      }
      else {
        marker.setCx(labelDim.w / 2);
      }
      label.setY(markerDim.h + dvt.AfMarker.MARKER_LABEL_PADDING);

      afMarkerWidth = Math.max(markerDim.w, labelDim.w);
      afMarkerHeight = markerDim.h + dvt.AfMarker.MARKER_LABEL_PADDING + labelDim.h;
      break;

    case 'left':
      if (markerDim.h > labelDim.h) {
        label.setY(markerDim.h / 2);
        label.alignMiddle();
      }
      else {
        marker.setCy(labelDim.h / 2);
      }
      marker.setCx(labelDim.w + dvt.AfMarker.MARKER_LABEL_PADDING + markerDim.w / 2);

      afMarkerWidth = labelDim.w + dvt.AfMarker.MARKER_LABEL_PADDING + markerDim.w;
      afMarkerHeight = Math.max(markerDim.h, labelDim.h);
      break;

    case 'right':
      if (markerDim.h > labelDim.h) {
        label.setY(markerDim.h / 2);
        label.alignMiddle();
      }
      else {
        marker.setCy(labelDim.h / 2);
      }
      label.setX(markerDim.w + dvt.AfMarker.MARKER_LABEL_PADDING);

      afMarkerWidth = markerDim.w + dvt.AfMarker.MARKER_LABEL_PADDING + labelDim.w;
      afMarkerHeight = Math.max(markerDim.h, labelDim.h);
      break;

    case 'center':
    default:
      if (markerDim.w > labelDim.w) {
        label.setX(markerDim.w / 2);
        label.alignCenter();
      }
      else {
        marker.setCx(labelDim.w / 2);
      }
      if (markerDim.h > labelDim.h) {
        label.setY(markerDim.h / 2);
        label.alignMiddle();
      }
      else {
        marker.setCy(labelDim.h / 2);
      }
      afMarkerWidth = Math.max(markerDim.w, labelDim.w);
      afMarkerHeight = Math.max(markerDim.h, labelDim.h);
      break;
  }

  //extends dvt.AfComponent
  this._setBounds(afContext, markerDim.x, markerDim.y, afMarkerWidth, afMarkerHeight);
};


//extends dvt.AfComponent
// dvt.AfMarker.prototype.getDimensions = function() {
//   return this._groupDim;
// }



dvt.AfMarker.prototype.getTagName = function() {
  return dvt.AfMarker.TAG_NAME;
};


//extends dvt.AfComponent
/**
 * @private
 * Note: only need to create one instance of _afStyles per class
 */
dvt.AfMarker.prototype.GetDefaultStyles = function() {
  return dvt.AfMarker._afStyles;
};


//extends dvt.AfComponent
/**
 * @private
 * Note: only need to create one instance of _afStyles per class
 */
dvt.AfMarker.prototype.SetDefaultStyles = function(styleList) {
  dvt.AfMarker._afStyles = styleList;
};


//extends dvt.AfComponent
/**
 * @private
 */
dvt.AfMarker.prototype._render = function(availWidth, availHeight) {
  if (! this.renderMe())
    return;

  //if shortDesc is specified, show it in a tooltip
  var shape = this.getDisplayObj();
  if (this.getShortDesc() || this.getProperty(dvt.AfMarker.ATTR_HAS_ACTION_LISTENER) || this.getShowPopupBehaviors() || this.getClientBehaviors()) {
    this.associate(shape, this);
  }

  //Performance: using the same context during rendering
  //so we have a list of dimensions for all text objects
  dvt.AfComponent._renderComp(this.getAfContext(), this, availWidth, availHeight);
};

//extends dvt.AfComponent
dvt.AfMarker.prototype.renderSelfBeforeChildren = function() {
};


dvt.AfMarker.prototype._setBounds = function(afContext, xx, yy, ww, hh) {
  this._dim = new dvt.Rectangle(xx, yy, ww, hh);

  // clipped?
  this._addClipPathIfNeeded(afContext, 0, 0,
                            afContext.getAvailableWidth(), this._dim.w,
                            afContext.getAvailableHeight(), this._dim.h);
};


/*
dvt.AfMarker.prototype._getExplicitHeight = function(cssStyle) {
  return this.getProperty(dvt.AfMarker.ATTR_HEIGHT);
};

dvt.AfMarker.prototype._getExplicitWidth = function(cssStyle) {
  return this.getProperty(dvt.AfMarker.ATTR_WIDTH);
};
*/


//Bug 13491092 - action attribute on dvt:marker used within diagram overlay is ignored
dvt.AfMarker.prototype.isCommandComponent = function() {
  return true;
};

dvt.AfMarker.prototype.isClickEventPropagationStopped = function() {
  return this.getProperty(dvt.AfMarker.ATTR_HAS_ACTION_LISTENER);
};

dvt.AfMarker.prototype.registerAsTabStop = function() {
  this.getAfContext().registerTabStop(this);
};

/**
 * @override
 */
dvt.AfMarker.prototype.GetClipPathDimensions = function() {
  var afContext = this.getAfContext();
  return new dvt.Rectangle(0,
      0,
      Math.min(afContext.getAvailableWidth(), this._dim.w),
      Math.min(afContext.getAvailableHeight(), this._dim.h));
};

/**
 * Converts an abbreviated marker shape string to the full marker shape, i.e. 'circle', 'human', etc.
 * @param {string} shape The abbreviated marker shape string to convert
 * @return {string}
 */
dvt.AfMarker.convertShapeString = function(shape) {
  return dvt.AfMarker._markerTypeMap[shape];
};

