/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxStylesheet
 *
 * Defines the appearance of the cells in a graph. See <putCellStyle> for an
 * example of creating a new cell style. It is recommended to use objects, not
 * arrays for holding cell styles. Existing styles can be cloned using
 * <mxUtils.clone> and turned into a string for debugging using
 * <mxUtils.toString>.
 *
 * Default Styles:
 *
 * The stylesheet contains two built-in styles, which are used if no style is
 * defined for a cell:
 *
 *   defaultVertex - Default style for vertices
 *   defaultEdge - Default style for edges
 *
 * Example:
 *
 * (code)
 * var vertexStyle = stylesheet.getDefaultVertexStyle();
 * vertexStyle[mxConstants.STYLE_ROUNDED] = true;
 * var edgeStyle = stylesheet.getDefaultEdgeStyle();
 * edgeStyle[mxConstants.STYLE_EDGE] = mxEdgeStyle.EntityRelation;
 * (end)
 *
 * Modifies the built-in default styles.
 *
 * To avoid the default style for a cell, add a leading semicolon
 * to the style definition, eg.
 *
 * (code)
 * ;shadow=1
 * (end)
 *
 * Removing keys:
 *
 * For removing a key in a cell style of the form [stylename;|key=value;] the
 * special value none can be used, eg. highlight;fillColor=none
 *
 * See also the helper methods in mxUtils to modify strings of this format,
 * namely <mxUtils.setStyle>, <mxUtils.indexOfStylename>,
 * <mxUtils.addStylename>, <mxUtils.removeStylename>,
 * <mxUtils.removeAllStylenames> and <mxUtils.setStyleFlag>.
 *
 * Constructor: mxStylesheet
 *
 * Constructs a new stylesheet and assigns default styles.
 */
function mxStylesheet()
{
	this.styles = new Object();

	this.putDefaultVertexStyle(this.createDefaultVertexStyle());
	this.putDefaultEdgeStyle(this.createDefaultEdgeStyle());
};

/**
 * Function: styles
 *
 * Maps from names to cell styles. Each cell style is a map of key,
 * value pairs.
 */
mxStylesheet.prototype.styles;

/**
 * Function: createDefaultVertexStyle
 *
 * Creates and returns the default vertex style.
 */
mxStylesheet.prototype.createDefaultVertexStyle = function()
{
	var style = new Object();

	style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_RECTANGLE;
	style[mxConstants.STYLE_PERIMETER] = mxPerimeter.RectanglePerimeter;
	style[mxConstants.STYLE_VERTICAL_ALIGN] = mxConstants.ALIGN_MIDDLE;
	style[mxConstants.STYLE_ALIGN] = mxConstants.ALIGN_CENTER;
	style[mxConstants.STYLE_FILLCOLOR] = '#C3D9FF';
	style[mxConstants.STYLE_STROKECOLOR] = '#6482B9';
	style[mxConstants.STYLE_FONTCOLOR] = '#774400';

	return style;
};

/**
 * Function: createDefaultEdgeStyle
 *
 * Creates and returns the default edge style.
 */
mxStylesheet.prototype.createDefaultEdgeStyle = function()
{
	var style = new Object();

	style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_CONNECTOR;
	style[mxConstants.STYLE_ENDARROW] = mxConstants.ARROW_CLASSIC;
	style[mxConstants.STYLE_VERTICAL_ALIGN] = mxConstants.ALIGN_MIDDLE;
	style[mxConstants.STYLE_ALIGN] = mxConstants.ALIGN_CENTER;
	style[mxConstants.STYLE_STROKECOLOR] = '#6482B9';
	style[mxConstants.STYLE_FONTCOLOR] = '#446299';

	return style;
};

/**
 * Function: putDefaultVertexStyle
 *
 * Sets the default style for vertices using defaultVertex as the
 * stylename.
 *
 * Parameters:
 * style - Key, value pairs that define the style.
 */
mxStylesheet.prototype.putDefaultVertexStyle = function(style)
{
	this.putCellStyle('defaultVertex', style);
};

/**
 * Function: putDefaultEdgeStyle
 *
 * Sets the default style for edges using defaultEdge as the stylename.
 */
mxStylesheet.prototype.putDefaultEdgeStyle = function(style)
{
	this.putCellStyle('defaultEdge', style);
};

/**
 * Function: getDefaultVertexStyle
 *
 * Returns the default style for vertices.
 */
mxStylesheet.prototype.getDefaultVertexStyle = function()
{
	return this.styles['defaultVertex'];
};

/**
 * Function: getDefaultEdgeStyle
 *
 * Sets the default style for edges.
 */
mxStylesheet.prototype.getDefaultEdgeStyle = function()
{
	return this.styles['defaultEdge'];
};

/**
 * Function: putCellStyle
 *
 * Stores the given map of key, value pairs under the given name in
 * <styles>.
 *
 * Example:
 *
 * The following example adds a new style called 'rounded' into an
 * existing stylesheet:
 *
 * (code)
 * var style = new Object();
 * style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_RECTANGLE;
 * style[mxConstants.STYLE_PERIMETER] = mxPerimeter.RectanglePerimeter;
 * style[mxConstants.STYLE_ROUNDED] = true;
 * graph.getStylesheet().putCellStyle('rounded', style);
 * (end)
 *
 * In the above example, the new style is an object. The possible keys of
 * the object are all the constants in <mxConstants> that start with STYLE
 * and the values are either JavaScript objects, such as
 * <mxPerimeter.RightAngleRectanglePerimeter> (which is in fact a function)
 * or expressions, such as true. Note that not all keys will be
 * interpreted by all shapes (eg. the line shape ignores the fill color).
 * The final call to this method associates the style with a name in the
 * stylesheet. The style is used in a cell with the following code:
 *
 * (code)
 * model.setStyle(cell, 'rounded');
 * (end)
 *
 * Parameters:
 *
 * name - Name for the style to be stored.
 * style - Key, value pairs that define the style.
 */
mxStylesheet.prototype.putCellStyle = function(name, style)
{
	this.styles[name] = style;
};

/**
 * Function: getCellStyle
 *
 * Returns the cell style for the specified stylename or the given
 * defaultStyle if no style can be found for the given stylename.
 *
 * Parameters:
 *
 * name - String of the form [(stylename|key=value);] that represents the
 * style.
 * defaultStyle - Default style to be returned if no style can be found.
 */
mxStylesheet.prototype.getCellStyle = function(name, defaultStyle)
{
	var style = defaultStyle;

	if (name != null && name.length > 0)
	{
		var pairs = name.split(';');

		if (style != null &&
			name.charAt(0) != ';')
		{
			style = mxUtils.clone(style);
		}
		else
		{
			style = new Object();
		}

		// Parses each key, value pair into the existing style
	 	for (var i = 0; i < pairs.length; i++)
	 	{
	 		var tmp = pairs[i];
	 		var pos = tmp.indexOf('=');

	 		if (pos >= 0)
	 		{
		 		var key = tmp.substring(0, pos);
		 		var value = tmp.substring(pos + 1);

		 		if (value == mxConstants.NONE)
		 		{
		 			delete style[key];
		 		}
		 		else if (mxUtils.isNumeric(value))
		 		{
		 			style[key] = parseFloat(value);
		 		}
		 		else
		 		{
			 		style[key] = value;
		 		}
			}
	 		else
	 		{
	 			// Merges the entries from a named style
				var tmpStyle = this.styles[tmp];

				if (tmpStyle != null)
				{
					for (var key in tmpStyle)
					{
						style[key] = tmpStyle[key];
					}
				}
	 		}
		}
	}

	return style;
};
