package demo.style
{
	import com.yworks.canvas.geom.IOrientedRectangle;
	import com.yworks.canvas.geom.OrientedRectangle;
	import com.yworks.canvas.geom.YRectangle;
	import com.yworks.graph.drawing.SimpleLabelStyle;
	import com.yworks.graph.model.ILabel;
	import com.yworks.graph.model.ILabelModel;
	import com.yworks.graph.model.ILabelModelParameter;
	import com.yworks.graph.model.INode;
	import com.yworks.support.FontManager;
    import com.yworks.support.ILookup;
    import com.yworks.support.Lookups;

	import mx.core.UITextField;
	import mx.core.UITextFormat;
	
	/**
	 * A label model for nodes which places a label at the center of the node
	 * and sets its size such that it doesn't exceed the node's bounds.
	 * If necessary, the label text will be word wrapped into more than one line.
	 */	
	public class VerticalCenterStretchLabelModel implements ILabelModel
	{
		/**
		 * Creates a dummy text field which will be used for text measurement.
		 */		
		public function VerticalCenterStretchLabelModel() {
			this._measureTextField = new UITextField();
			// allow word wrap and multi line text.
			this._measureTextField.wordWrap = true;
			this._measureTextField.multiline = true;
		}
		
		private var _measureTextField:UITextField;
		
		/**
		 * This method sets the given label's bounds according to the given parameter.
		 * If the parameter isn't a VerticalCenterStretchLabelModelParameter or the label
		 * is null or the label's owner is not a node, an empty rectangle will be returned.
		 * @param modelParameter The parameter.
		 * @param label The label to set the bounds for.
		 * @return The bounding box of the label.
		 */		
		public function getGeometry(modelParameter:ILabelModelParameter, label:ILabel):IOrientedRectangle
		{
			if (label != null && modelParameter is VerticalCenteredStretchLabelModelParameter) {
				var node:INode = label.owner as INode;
				if (node != null) {
					// can only be used for node labels
					var x:Number = node.layout.x;
					var y:Number = node.layout.y;
					var width:Number = node.layout.width;
					var height:Number = node.layout.height;
					
					// get the label's text format for the measurement
					var tf:UITextFormat = label.style is SimpleLabelStyle ? SimpleLabelStyle(label.style).textFormat : FontManager.INSTANCE.getDefaultTextFormat();
					if (tf == null) {
						tf = FontManager.INSTANCE.getDefaultTextFormat();
					}
					
					// prepare the maximum bounds of the label: it shouldn't be larger than the node
					_measureTextField.width = width;
					_measureTextField.height = height;
					// set the text and text format of the dummy text field
					_measureTextField.defaultTextFormat = tf;
					_measureTextField.embedFonts = FontManager.INSTANCE.isEmbedded( tf );
					_measureTextField.htmlText = label.text;
					
					// w is the measured width of the text + a "safety" margin.
					// if the label's width would be w, the text may be cropped
					// at certain zoom levels.
					// If there are still cropping problems it may help to experiment a little
					// with these values.
					var w:Number = _measureTextField.textWidth + 3;
					if (w > width) {
						w = width;
					}
					var h:Number = _measureTextField.textHeight + 3;
					if (h > height) {
						h = height;
					}
					return YRectangle.create(x + (width - w) / 2, y + (height - h) / 2, w, h);
				}
			}
			return OrientedRectangle.EMPTY;
		}
		
		public function createDefaultParameter():ILabelModelParameter
		{
			return new VerticalCenteredStretchLabelModelParameter(this);
		}
		
		public function lookup(type:Class):Object
		{
			return null;
		}

        public function getContext(label:ILabel, parameter:ILabelModelParameter):ILookup
        {
            return Lookups.EMPTY;
        }
	}
}

import com.yworks.graph.model.ILabel;
import com.yworks.graph.model.ILabelModel;
import com.yworks.graph.model.ILabelModelParameter;
import com.yworks.graph.model.INode;

class VerticalCenteredStretchLabelModelParameter implements ILabelModelParameter
{
	public function VerticalCenteredStretchLabelModelParameter(model:ILabelModel)
	{
		this._model = model;
	}
	
	private var _model:ILabelModel;
	
	public function get model():ILabelModel
	{
		return this._model;
	}
	
	public function supports(label:ILabel):Boolean
	{
		return label != null && label.owner is INode;
	}
	
	public function clone():Object
	{
		return new VerticalCenteredStretchLabelModelParameter(_model);
	}
}