/**
 * Make table cell content editable.
 * 
 * The `.uiRichtable()` method makes table cells editable, which are marked with the attribute data-ep-editable="true".
 * 
 * The cells content must be wrapped in a HTML-Element as `span` or `div`. The `data-ep-attribute`-value
 * represents the name of the objects attribute on which the saveAction should be executed. The innerHTML will be
 * saved.
 * 
 * If the edited values should be saved, the `Input` in the first cell in the following example must be
 * an `input`-element, containing the object id of the destinated object in the `value`-attribute.
 * First cell must have the class `Checkbox` and contain an `input` node of type `checkbox`. This `checkbox` will be
 * selected, once the surrounding table row is clicked.
 *  <td class="Checkbox"><input type="checkbox" value="12345" /></td>
 * 
 * ### Examples
 * Apply editable feature to a table.
 * 
 * JavaScript:
 * 
 *     ep('#contentTable').uiRichtable({
 *       'saveAction': 'Save',
 *       'region': jQuery.i18n.settings.region,
 *       'editIcon': true
 *     });
 * 
 * HTML:
 * 
 *     <table id="contentTable" class="ContentList">
 *       <tr>
 *         <td class="Checkbox">Input</td>
 *         <td class="OneQuarter" data-ep-editable="true"><span data-ep-attribute="Name">Text</span></td>
 *         <td class="OneQuarter AlignRight editable50" data-ep-editable="true"><div data-ep-attribute="Price" data-ep-additional="CurrencyID">199,95 &euro;</div></td>
 *         <td class="OneQuarter AlignRight editable40" data-ep-editable="true"><div data-ep-attribute="StockLevel">0</div></td>
 *       </tr>
 *     </table>
 * 
 * 
 * @class jQuery.ui.uiRichtable
 * @extends jQuery.widget
 * 
 * @uses ep
 * @uses jQuery.ui.widget
 * @uses jQuery.event.special.load
 * @uses ep.fn.contextOrientation
 * @uses ep.ui.textedit
 * @uses ep.ui.validate
 * @since 6.15.0
 */

/**
 * @cfg {String} saveAction Name of the SaveAction
 */

/**
 * @cfg {String} region region-string like de-DE
 */

/**
 * @cfg {String} currency currency-string representing the current currency
 */

/**
 * @cfg {Boolean} editIcon A boolean indication whether an edit icon should be shown.
 */

/**
 * @cfg {Boolean} alterIcon A boolean indicator whether the edit icon should always be shown on the right side (false) or depending by the horizontal alignment (true)
 */

/**
 * See `jQuery.ui.uiRichtable` for details.
 * 
 * @param {Object} [options] A map of additional options pass to the method.
 * @param {String} saveAction Name of the SaveAction
 * @param {String} region region-string like de-DE
 * @param {String} currency currency-string representing the current currency
 * @param {Boolean} editIcon A boolean indication whether an edit icon should be shown.
 * @param {Boolean} alterIcon A boolean indicator whether the edit icon should always be shown on the right side (false) or depending by the horizontal alignment (true)
 * 
 * @method uiRichtable
 * @member jQuery
 * 
 * @since 6.15.0
 */

/*
 * @copyright		© Copyright 2006-2012, epages GmbH, All Rights Reserved.
 *
 * @module			ep.ui.richtable
 */
define("ep/ui/richtable", [
	"jquery",
	"ep",

	"jquery/ui/widget",
	"jquery/event/special/load",
	"ep/ui/validate",
	"ep/ui/textedit",
	"ep/fn/contextorientation"
], function($, ep){

		// helper methods
	var getRow = function( elem ){
			return elem = elem.is(":checkbox") ? elem.closest("tr") : elem;
		},

		getCheckbox = function( elem ){
			return elem = elem.is(":checkbox") ? elem : elem.find("> td:first-child input[type=checkbox]");
		},

		toggleRow = function( elem, bool ){
			var checkbox = getCheckbox(elem),
				row = getRow(elem);

			row.toggleClass("RowSelected",  bool===undefined ? checkbox.is(":checked") : bool);
		},

		toggleCheckbox = function( elem, bool ){
			var checkbox = getCheckbox(elem);

			if (bool===undefined || bool !== checkbox.is(":checked")) {
				checkbox.trigger({
						type: "click",
						originalTarget: checkbox[0]
					});
			}
		};	// exclude from toggle row selections

	$.widget("ui.uiRichtable", {
		STR_EDIT_ICON: '<i class="Sprite ico_s_edit"></i>',

		options: {
		//	grossPrice:	"c2",						// format for net/gross prices
			editIcon: 	true,						// indicator if a edit icon should be shown
			alterIcon: 	false,						// flag if the edit icon should be shown always right (false) or depending by align (true)
			region:		$.i18n.settings.region,		// region string
			currency:	$.i18n.settings.currency,	// currency acronym
			saveAction: "Save",						// save method
			noselect: [								// Selectors to prevent row selection
				"a", 									// Links and child elements
				"a *",
				":input",								// Input elements
				".ep-uiInput-custom",					// Custom UI input elements
				".epEditWrapper", 						// Editable elements and editable elements
				".epEditWrapper *"
			]
		},

		_create: function(){
			var self = this,
				o = self.options;

			if(self.element[0]===undefined){
				return;
			}

			// get the currency format (default "c2": two decimal places)
			o.grossPrice = (o.grossPrice===undefined)? "c2" : o.grossPrice;

			self.element
				.addClass("RowSelection ep-uirichtable")
				// delegate checkbox for select all
				.on("change.uiRichtable", "thead > tr > *:first-child input[type=checkbox]", function(){
					var isChecked = $(this).is(":checked");

					self.element
						.find("> tbody > tr > td:first-child input[type=checkbox]")
						.each(function(){
							toggleCheckbox( $(this), isChecked );
						});
				})
				// delegate checkbox for row selection
				.on("change.uiRichtable", "tbody > tr > td:first-child input[type=checkbox]", function () {
					toggleRow($(this));
				})
				// delegate cell click
				.on("click.uiRichtable", "tbody > tr > td", function (event) {
					var target = $(event.originalTarget),
						cell = $(this),
						row = cell.parent();

					// prevent row selection if target is an image
					if(target[0].tagName.toLowerCase() === "img"){
						return;
					}

					// Inline editing
					if (cell.data("epEditable")) {
						self._handleEditable(row, cell, target);
					}
					// Check selectbox
					else if (target.length && !target.is(o.noselect.join(", "))) {
						toggleCheckbox(row.find("> td:first-child input[type=checkbox]"));
					}
				})
				// delegate mouseenter editable cell for initalize
				.on("mouseenter", "tbody > tr > td[data-ep-editable]:not(.RowSelectionInputCell)", function(){
					var o = self.options,
						cell = $(this).addClass("RowSelectionInputCell"),
						wrapper = cell.find("*[data-ep-attribute]");

					if( wrapper.length > 0 ){

						wrapper.addClass("epEditWrapper ClickIcon");

						// if an edit icon should be shown
						if( o.editIcon ){
							if( !o.alterIcon || cell.css("text-align") != "right" ){
								wrapper
									.append(self.STR_EDIT_ICON)
									.data("epTextAlign", "left");

								if( cell.css("text-align") == "right" ){
									cell.addClass("ep-Textedit-right");
								}
							}
							else{
								wrapper
									.prepend(self.STR_EDIT_ICON)
									.data("epTextAlign", "right");

								cell.addClass("ep-Textedit-right");
							}
						}

						switch( wrapper.data("epAttribute").toLowerCase() ){
							case "name":
								wrapper.css("display", "inline-block");
								break;
						}
					}
				});
		},

		_handleEditable: function( row, cell, target ){
			var self = this,
				o = self.options,
				wrapper = ep(".epEditWrapper", cell),	// element which should be editable
				oValidate,								// object/hash for the uiValidate widget
				oTextEditOptions;						// object/hash for the uiTextedit widget

			// if the element is not editable yet
			if( wrapper.data('epUiTextedit') === undefined ){

				// mark that the element is just created
				wrapper.prop("justCreated", true);

				switch( wrapper.data("epAttribute") ){
					case "Name":						// value of the data-ep-attribute correlate to the Save attribute
						oValidate = {
							maxlength: 100
						};
						break;
					case "Price":						// value of the data-ep-attribute correlate to the Save attribute
						oValidate = {
							type: "number",
							format: o.grossPrice,
							region: o.region,
							currency: o.currency,
							min: -2147483648,
							max: 2147483647,
							needFormat: true
						};
						break;
					case "StockLevel":					// value of the data-ep-attribute correlate to the Save attribute
						oValidate = {
							type: "number",
							format: "n2",
							region: o.region,
							min: -2147483648,
							max: 2147483647
						};
						break;
					default:
						oValidate = {};
						break;
				}

				oValidate.valid = false;

				// object/hash for the uiTextedit widget
				oTextEditOptions = {
					action		: self.options.saveAction, 						// SaveAction "Save"
					objectId	: getCheckbox(row).data('id') ? getCheckbox(row).data('id') : getCheckbox(row).val(),						// objectId
					name		: wrapper.data("epAttribute"),					// name/value pair (from data-ep-attribute)
					stripHTML	: true,
					validate	: oValidate,
					preventDefaultOnEnter : true,

					// callback called before element becomes editable
					onBeforeOpen: function(input){
						var icon = wrapper.find(".Sprite"),
							iconWidth;

						// remove edit icon if necessary
						if(self.options.editIcon){
							iconWidth = icon.outerWidth() +  parseInt(icon.css('margin-left'));
							ep(".Sprite", wrapper).remove();
						}
						// show element
						input.show();
						input.attr("disabled", false);

						if(self.options.editIcon && wrapper.parent().hasClass('ep-Textedit-right')){
							input.css('margin-right', iconWidth + 'px');
						}

						wrapper.css("width","98%");
						cell.find("*.hideOnEditable").hide();
					},

					onAfterOpen: function(input){
						// if element was just created
						if( wrapper.prop("justCreated") ){
							wrapper.prop("justCreated", false);
							// prevent an invalid message if input is empty
							if(input.val().length==0){
								input[0].formInvalid = false;
								input.blur();
								wrapper.trigger("click.uiTextedit");
								//input.focus();
							}
						}
					},

					// Called before data gets written to *wrapper*.
					formatOnWriteBack: function(input, evt) {
						// Format input value.
						var value = (oValidate.needFormat===true && oValidate.type=="number" && !isNaN( $.i18n.parseNumber(input.val()))) ?
								$.i18n.formatNumber($.i18n.parseNumber(input.val()), oValidate.format, {currency: self.options.currency, region: self.options.region}) :
								input.val();

						input.val(value);

						if ((typeof evt!="undefined") && evt.keyCode==27) {
						// On "ESC" *onAfterClose* will not be called.
							wrapper.hide();
							var invalid = input.is(":input:invalid");
							// short delay for webkit-engines to prevent default action
							setTimeout(function(){
						 		self._setContent(input, wrapper, true);
								if (!invalid) {
									wrapper.show();
									input.hide();
								}
								else {
									wrapper.hide();
									input.show();
								}
								wrapper.css("width","");
								cell.find("*.hideOnEditable").show();
							},10);
						}
					},

					// Called after element becomes uneditable and data has been saved to server.
					onAfterClose: function(input){
						self._setContent(input, wrapper, true);

						// If HasSubOwnPrices has just been set,
						// update the DOM and the corresponding server action.
						var ownpriceWasSet = wrapper.data("epOwnprice");
//#JSCOVERAGE_IF false
						if (ownpriceWasSet !== undefined) {
							// Update style and title of *wrapper* enclosing *cell*.
							cell.removeClass("InheritedValue");
							cell.attr("title", wrapper.data("epOwnpriceTitle"));

							// Update *additional* option of *uiTextedit*.
							var additional = wrapper.uiTextedit("option","additional");
							delete additional[ownpriceWasSet];
							wrapper.uiTextedit("option","additional",additional);

							// Update DOM of *wrapper*.
							wrapper
								.removeData(["epOwnprice","epOwnpriceTitle"])
								.removeAttr("data-ep-ownprice")
								.removeAttr("data-ep-ownprice-title");
						}
//#JSCOVERAGE_ENDIF
						wrapper.css("width","");
						cell.find("*.hideOnEditable").show();
					}
				};

				// if additional parameters are needed for the SaveAction
				if(wrapper.data("epAdditional")!==undefined){
					oTextEditOptions.additional = {};
					// e.g. oTextEditOptions.additional["CurrencyID"] = "EUR"
					oTextEditOptions.additional[wrapper.data("epAdditional")] = self.options.currency;
				}

				// if additional parameters are needed for the SaveAction
				if(wrapper.data("epOwnprice")!==undefined){
					oTextEditOptions.additional = (oTextEditOptions.additional===undefined)? {} : oTextEditOptions.additional;
					// e.g. oTextEditOptions.additional["HasSubOwnPrices"] = 1
					oTextEditOptions.additional[wrapper.data("epOwnprice")] = 1;
				}

				// build the uiTextedit widget
				wrapper.uiTextedit(oTextEditOptions);
			}

			// trigger click event to show the editable element
			wrapper.uiTextedit("open");
		},

		_setContent: function( input, wrapper, disabled ){
			var self = this,
				value = input.val();

			input
				.attr("disabled", disabled)
				.prop('defaultValue', value)
				.trigger("change");

			// if an edit icons should be shown
			if( self.options.editIcon ){
				if( !self.options.alterIcon || wrapper.data("epTextAlign") != "right" ){
					wrapper.append(self.STR_EDIT_ICON);
				}
				else{
					wrapper.prepend(self.STR_EDIT_ICON);
				}
			}
		}
	});

	return ep;

});