/**
 * EGroupware  eTemplate2 widget browser
 * View & play with et2 widgets - javascript
 *
 * @link http://www.egroupware.org
 * @author Nathan Gray
 * @author Hadi Nategh
 * @copyright 2013 Nathan Gray
 * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
 * @package etemplate
 * @subpackage tools
 * @version $Id$
 */

/*egw:uses
	etemplate2;
*/

/**
 * widget_browser shows a list of widgets, and allows you to view them one at a time.
 * You can view and edit defined properties to see the effect.
 */
function widget_browser(list_div, widget_div)
{

	// Initialize etemplate2
	this.et2 = new etemplate2(widget_div, "etemplate::ajax_process_content");

	// Normally this would be passed from app
	var _data = {};

	// Create the basic widget container and attach it to the DOM
	// Not really needed, but let's be consitent with et2
        this.et2.widgetContainer = new et2_container(null);
        this.et2.widgetContainer.setApiInstance(egw('etemplate', egw.elemWindow(this.et2.DOMContainer)));
        this.et2.widgetContainer.setInstanceManager(this.et2);
        this.et2.widgetContainer.setParentDOMNode(this.et2.DOMContainer);
	this.et2.widgetContainer.setArrayMgrs(this.et2._createArrayManagers(_data));

	// Set up UI
	this.list_div = jQuery(list_div);
	this.widget_div = jQuery(widget_div);
	this.attribute_list = null;

	// Create and popuplate the widget list
	this._init_list();

	// Build DTD
	this._init_dtd();
}

/**
 * Read the widget registry and create a list.
 * The user can pick a widget, and we'll instanciate it.
 */
widget_browser.prototype._init_list = function()
{
	var self = this;

	// Create list
	var list = jQuery(document.createElement('ul'))
		.attr('id', 'widgets')
		.click(function(e) {self.select_widget(e);})
		.appendTo(this.list_div);

	// Sort the registry
	var types = [];
	for(var type in et2_registry)
	{
		types.push(type);
		}
	types.sort();
	for(var i = 0; i < types.length; i++)
	{
		list.append('<li>'+types[i]+'</li>');
		this.dump_attributes(types[i]);
	}

	// Build attribute table
	attribute_table = jQuery(document.createElement('table'));
	attribute_table.append('<thead class = "ui-widget-header"><td>'+egw().lang('Name')+"</td><td>"+egw().lang("Data type") +
		"</td><td>"+egw().lang("Value") + "</td></thead>");
	this.attribute_list = jQuery(document.createElement('tbody'))
		.appendTo(attribute_table);

	this.list_div.append(
		jQuery(document.createElement('div'))
			.attr('id', 'widget_attributes')
			.append(attribute_table)
	);
};

widget_browser.prototype.dump_attributes = function(_type)
{
	console.log(_type);

	try {
		var attrs = {};
		window.wb_widget = this.widget = et2_createWidget(_type, attrs, this.et2.widgetContainer);
		this.widget.loadingFinished();

		if(this.widget !== null && this.widget.attributes)
		{
			for(var attr in this.widget.attributes)
			{
				console.log(attr, this.widget.attributes[attr]);
			}
		}
	}
	catch(e) {
		console.log('*** '+_type+' error '+(typeof e.message != 'undefined' ? e.message : e));
	}
	try {
		if (this.widget)
		{
			this.widget.destroy();
			delete this.widget;
		}
	}
	catch(e) {

	}
};

/**
 * User selected a widget from the list
 *
 * Create an instance of the widget, get its attributes, and display it.
 */
widget_browser.prototype.select_widget = function(e,f)
{
	// UI prettyness - clear selected
	jQuery(e.target).parent().children().removeClass("ui-state-active");

	// Clear previous widget
	if(this.widget)
	{
		this.et2.widgetContainer.removeChild(this.widget);
		this.widget.free();
		this.widget = null;
	}

	// Get the type of widget
	var type = jQuery(e.target).text();
	if(!type || e.target.nodeName != 'LI')
	{
		return;
	}

	// UI prettyness - show item as selected
	jQuery(e.target).addClass('ui-state-active');

	// Widget attributes
	var attrs = {};


	window.wb_widget = this.widget = et2_createWidget(type, attrs, this.et2.widgetContainer);
	this.widget.loadingFinished();

	// Attribute list
	this.attribute_list.empty();
	if(this.widget !== null && this.widget.attributes)
	{
		for(var attr in this.widget.attributes)
		{
			if(this.widget.attributes[attr].ignore) continue;
			this.create_attribute(attr, this.widget.attributes[attr])
				.appendTo(this.attribute_list);
						}
						}
};


/**
 * Create the UI (DOM) elements for a single widget attribute
 *
 * @param name Name of the attribute
 * @param settings attribute attributes (Human name, description, etc)
 */
widget_browser.prototype.create_attribute = function(name, settings)
{
	var set_function_name = "set_"+name;
	var row = jQuery(document.createElement("tr"))
		.addClass(typeof this.widget[set_function_name] == 'function' ? 'ui-state-default':'ui-state-disabled')
		// Human Name
		.append(jQuery(document.createElement('td'))
			.text(settings.name)
		)
		// Data type
		.append(jQuery(document.createElement('td'))
			.text(settings.type)
		);
	// Add attribute name & description as a tooltip
	if(settings.description)
	{
		egw().tooltipBind(row,settings.description);
	}

	// Value
	var value = jQuery(document.createElement('td')).appendTo(row);
	if(row.hasClass('ui-state-disabled'))
	{
		// No setter - just use text
		value.text(this.widget.options[name]);
		return row;
	}

	// Setter function - maybe editable?
	var self = this;
	var input = null;
	switch(settings.type)
	{
		case 'string':
			input = jQuery('<input/>')
				.change(function(e) {
					self.widget[set_function_name].apply(self.widget, [jQuery(e.target).val()]);
				});
			input.val(this.widget.options[name]);
			break;
		case 'boolean':
			input = jQuery('<input type="checkbox"/>')
				.attr("checked", this.widget.options[name])
				.change(function(e) {
					self.widget[set_function_name].apply(self.widget, [e.target.checked]);
				});
			break;
		default:
			value.text(this.widget.options[name]);
			return row;
	}
	input.appendTo(value);

	return row;
};

/**
 * Initialise the DTD generator
 */
widget_browser.prototype._init_dtd = function ()
{
	//Contains all widgets
	this.widgets = [];

	//Contains not readonly widgets
	this.dtd_widgets = [];

	//Contians readonly widgets
	this.dtd_widgets_ro = [];

	// Contains the whole DTD string
	this.dtd = "";

	var self = this;

	// Create DTD Generator button and bind click handler on it
	var dtd_btn = jQuery(document.createElement('button'))
			.attr({id:'dtd_btn', title:'Generates Document Type Definition (DTD) for all widgets'})
			.click(function(){
				self._dtd_builder();
			})
			.addClass('dtd_btn')
			.appendTo('body');
	dtd_btn.text('DTD Generator');
}

/**
 * Iterates over all et2_widget to build DTD tags
 * and display them as string
 *
 */
widget_browser.prototype._dtd_builder = function()
{
	var dtdContentW = "";
	var i = 0;
	for (var widget_type in et2_registry)
	{
		var attrs = {};

		// creating a dialog popups an empty dialog,
		// which we don't want therefore
		// we eliminate dialog tag from dtd ATM.
		if (widget_type.match(/dialog/,'i')) continue;

		if (!widget_type.match(/nextmatch/,'i'))
		{

			this.widgets[i] = et2_createWidget(widget_type ,attrs, this.et2.widgetContainer)
			if (widget_type.match(/_ro/,'i'))
			{
				this.dtd_widgets_ro.push( widget_type.replace('_ro',''));
			}
			else
			{
				this.dtd_widgets.push(widget_type);
				dtdContentW += this._dtd_widgets(widget_type, this.widgets[i])
			}
			i++;
		}
	}
	// DTD Final Content
	this.dtd = this._dtd_header() + dtdContentW;

	//Display DTD resault and UI to copy/download them
	et2_createWidget("dialog", {
			callback: function() {},
			title: egw.lang('DTD Result'),
			buttons:et2_dialog.BUTTONS_OK,
			value: {
				content: {
					value: this.dtd,
					message: egw.lang('DTD Content')
				}
			},
			template: egw.webserverUrl+'/api/templates/default/dtd.xet',
			modal:true,
			resizable:false
		});
}

/**
 * Builds some specific header DTD tags (e.g. ENTITY)
 *
 * @returns {String} returns dtd header tags as string
 */
widget_browser.prototype._dtd_header = function ()
{
	var dtd = '';
	dtd = '<!ENTITY % Widgets "' + this.dtd_widgets.join('|') + '">\r\n';
	dtd += '<!ELEMENT overlay (%Widgets;)*>\r\n';
	return dtd;
}

/**
 * Builds DTD ELEMENTS and teir ATTRLIST for given widget
 *
 * @param {string} _type widget type
 * @param {object} _widget widget object
 * @returns {String} returns generated dtd tags in string
 */
widget_browser.prototype._dtd_widgets = function (_type, _widget)
{
	var dtd = '';
	switch (_type)
	{
		// Special handling for menulist widget as it has a complicated structure
		case 'menulist':
			dtd = '<!ELEMENT menulist (menupopup)>\r\n';
			break;

		// Special handling for grid widget as it has a complicated structure
		case 'grid':
			dtd += '<!ELEMENT grid (columns,rows)>\r\n';
			dtd += '<!ELEMENT columns (column)*>\r\n\
					<!ELEMENT column EMPTY >\n\
					<!ATTLIST column\n\
						disabled CDATA #IMPLIED\n\
						class CDATA #IMPLIED\n\
						width CDATA #IMPLIED>\n\
					<!ELEMENT rows (row)*>\n\
					<!ELEMENT row (%Widgets;)>\n\
					<!ATTLIST row\n\
						class CDATA #IMPLIED\n\
						height CDATA #IMPLIED\n\
						valign CDATA #IMPLIED\n\
						disabled CDATA #IMPLIED\n\
						part CDATA #IMPLIED\n\
					>\r\n';
			break;

		// Special handling for tabbox widget as it has a complicated structure
		case 'tabbox':
			dtd += '<!ELEMENT tabbox (tabs,tabpanels)>\r\n';
			dtd += '<!ELEMENT tabs (tab)>\r\n';
			dtd += '<!ELEMENT tabpanels (template)>\r\n';
			break;

		// Widget which can be a parent
		case 'vbox':
		case 'hbox':
		case 'box':
		case 'groupbox':
		case 'template':
			dtd = '<!ELEMENT '+ _type + ' (%Widgets;)*>\r\n';
			break;

		// Other widgets which only can be used as child
		default:
			dtd = '<!ELEMENT '+ _type + ' EMPTY>\r\n';
	}

	dtd +='<!ATTLIST ' + _type + '\r\n';
	for(var attr in _widget.attributes)
	{
		//DTD attribute helper object
		var dtdAttrObj = {attrType:'CDATA',attrVal:'', attrReq:' #IMPLIED'};

		//if(_widget.attributes[attr].ignore) continue;
		switch (_widget.attributes[attr].type)
		{
			case 'boolean':
				dtdAttrObj.attrType = ' (true|false)';
				dtdAttrObj.attrVal = ' "' + _widget.attributes[attr].default + '"';
				dtdAttrObj.attrReq = '';
				break;
			default:
				dtdAttrObj.attrType = ' CDATA';

				if (_widget.attributes[attr].default !="" &&
						typeof _widget.attributes[attr].default != 'undefined' &&
						!jQuery.isEmptyObject(_widget.attributes[attr].default))
				{
					dtdAttrObj.attrReq = '';
					dtdAttrObj.attrVal  = ' "' + _widget.attributes[attr].default + '"';
				}
				else
				{
					dtdAttrObj.attrVal  = "";
				}

		}
		dtd += attr + dtdAttrObj.attrType +
				(dtdAttrObj.attrVal !=""?dtdAttrObj.attrVal:'') +
				dtdAttrObj.attrReq +'\r\n';
	}
	dtd += '>\r\n';
	return dtd;
}

egw_LAB.wait(function() {
	var wb = new widget_browser(
	document.getElementById("widget_list"),
	document.getElementById("widget_container")
	);
});
