Ext.ns('Zarafa.common.plugins');

/**
 * @class Zarafa.common.plugins.FieldLabeler
 * @extends Ext.util.Observable
 * @ptype zarafa.fieldlabeler
 *
 * <p>A plugin for Field Components which renders standard Ext form wrapping and labels
 * round the Field at render time regardless of the layout of the Container.</p>
 * <p>Usage:</p>
 * <pre><code>
    {
        xtype: 'combo',
        plugins: [{
            ptype : 'zarafa.fieldlabeler'
        }],
        triggerAction: 'all',
        fieldLabel: 'Select type',
        store: typeStore
    }
 * </code></pre>
 */
Zarafa.common.plugins.FieldLabeler = Ext.extend(Ext.util.Observable, {
	/**
	 * Initialize the plugin for the given {@link Ext.form.Field field}
	 * @param {Ext.form.Field} field The field on which the plugin is placed
	 */
	init : function(field)
	{
		field.onRender = field.onRender.createSequence(this.onRender);
		field.onResize = this.onResize;
		field.adjustPosition = this.adjustPosition;
		field.onDestroy = field.onDestroy.createSequence(this.onDestroy);
	},

	/**
	 * Renders the component
	 * @private
	 */
	onRender : function()
	{
		// Do nothing if being rendered by a form layout
		if (this.ownerCt) {
			if (this.ownerCt.layout instanceof Ext.layout.FormLayout) {
				return;
			}
		}

		//  Pulls a named property down from the first ancestor Container it's found in
		function getParentProperty(propName) {
			for (var p = this.ownerCt; p; p = p.ownerCt) {
				if (p[propName]) {
					return p[propName];
				}
			}
		}

		this.resizeEl = (this.wrap || this.el).wrap({
			cls: 'x-form-element'
		});
		this.positionEl = this.itemCt = this.resizeEl.wrap({
			cls: 'x-form-item '
		});
		if (this.nextSibling()) {
			this.margins = {
				top: 0,
				right: 0,
				bottom: this.positionEl.getMargins('b'),
				left: 0
			};
		}
		this.actionMode = 'itemCt';

		// If our Container is hiding labels, then we're done!
		if (!Ext.isDefined(this.hideLabels)) {
			this.hideLabels = getParentProperty.call(this, 'hideLabels');
		}
		if (this.hideLabels) {
			this.resizeEl.setStyle('padding-left', '0px');
			return;
		}

		// Collect the info we need to render the label from our Container.
		if (!Ext.isDefined(this.labelSeparator)) {
			this.labelSeparator = getParentProperty.call(this, 'labelSeparator');
		}
		if (!Ext.isDefined(this.labelPad)) {
			this.labelPad = getParentProperty.call(this, 'labelPad');
		}
		if (!Ext.isDefined(this.labelAlign)) {
			this.labelAlign = getParentProperty.call(this, 'labelAlign') || 'left';
		}
		this.itemCt.addClass('x-form-label-' + this.labelAlign);

		if(this.labelAlign == 'top'){
			if (!this.labelWidth) {
				this.labelWidth = 'auto';
			}
			this.resizeEl.setStyle('padding-left', '0px');
		} else {
			if (!Ext.isDefined(this.labelWidth)) {
				this.labelWidth = getParentProperty.call(this, 'labelWidth') || 100;
			}
			this.resizeEl.setStyle('padding-left', (this.labelWidth + (this.labelPad || 5)) + 'px');
			this.labelWidth += 'px';
		}

		this.label = this.itemCt.insertFirst({
			tag: 'label',
			cls: 'x-form-item-label',
			style: {
				width: this.labelWidth
			},
			html: this.fieldLabel + (this.labelSeparator || ':')
		});
	},

	/**
	 * Ensure the input field is sized to fit in the content area of the resizeEl (to the right of its padding-left)
	 * We perform all necessary sizing here. We do NOT call the current class's onResize because we need this control
	 * we skip that and go up the hierarchy to {@link Ext.form.Field Field}
	 *
	 * @param {Number} adjWidth The box-adjusted width that was set
	 * @param {Number} adjHeight The box-adjusted height that was set
	 * @param {Number} rawWidth The width that was originally specified
	 * @param {Number} rawHeight The height that was originally specified
	 * @private
	 */
	onResize : function(adjWidth, adjHeight, rawWidth, rawHeight)
	{
		var width = adjWidth;
		var height = adjHeight;
		var widthCt = adjWidth;
		var heightCt = adjHeight;

		// If this field is not placed on a FormLayout, and this
		// field has the 'flex' property set, then the padding
		// (better known as the labelWidth + padding) must be
		// removed from the width.
		if (!(this.layout instanceof Ext.layout.FormLayout)) {
			if (!Ext.isEmpty(this.flex) || !Ext.isEmpty(this.columnWidth)) {
				width -= this.resizeEl.getPadding('l');
			} else {
				widthCt += this.resizeEl.getPadding('l');
			}
		}

		// If there is an inner Container (in other words, was this a CompositeField)
		// then we must resize this accordingly. Note that the fieldLabel comes before
		// the innerContainer, so the width excluding the label must be used.
		if (this.innerCt) {
			this.innerCt.setSize(width, heightCt);
		}

		Ext.form.Field.prototype.onResize.apply(this, arguments);

		if (this.resizeEl) {
			this.resizeEl.setWidth(heightCt);
		}
		if (this.itemCt) {
			this.itemCt.setWidth(widthCt);
		}

		if (this.getTriggerWidth) {
			this.wrap.setWidth(width);
			this.el.setWidth(width - this.getTriggerWidth());
		} else {
			this.el.setWidth(width);
		}

		if (this.el.dom.tagName.toLowerCase() == 'textarea') {
			height = this.resizeEl.getHeight(true);
			if (!this.hideLabels && (this.labelAlign == 'top')) {
				height -= this.label.getHeight();
			}
			this.el.setHeight(height);
		}

		if (this instanceof Ext.form.ComboBox) {
			if (!isNaN(width) && this.isVisible() && this.list) {
				this.doResize(width);
			} else {
				this.bufferSize = width;
			}
		}
	},

	/**
	 * If the owner is a HBox, we must compensate for the
	 * resizing of the container element of the _previous_
	 * item. This if the current item is not the first item,
	 * we must change the offset to the left-offset + size of the
	 * previous item.
	 * @param {Number} x The suggested X offset for the component
	 * @param {Number} y The suggested Y offset for the component
	 * @private
	 */
	adjustPosition : function(x, y)
	{
		if (this.ownerCt.layout instanceof Ext.layout.HBoxLayout) {
			x = 0;
			this.ownerCt.items.each(function(item) {
				if (item === this) {
					return false;
				}

				x += item.getActionEl().getWidth();
			}, this);
		}

		return { x: x, y: y};
	},

	/**
	 * Remove elements created by this plugin
	 * @private
	 */
	onDestroy: function()
	{
		if(this.ownerCt) {
			Ext.destroy(this.ownerCt);
			this.ownerCt.remove();
		}
	}
});

Ext.preg('zarafa.fieldlabeler', Zarafa.common.plugins.FieldLabeler);
