/**
 * 
 * GridWizard - interactive jQuery plug-in provides layout builder based on
 * table
 * 
 */

$(function($) {
	$.fn.gridWizard = function(options) {

		/***********************************************************************
		 * Default configuration
		 **********************************************************************/
		var defaults = {

			// Call mama, i didn't ever mind what is this stuff is all about!
			'id' : 'gridWizard',

			// callback
			'onRebuild' : function() {
				
			},
			
			'l' : {
				'split' : 'split',
				'px' : 'px',

				'slots' : 'slots',
				'type' : 'type',
				
				'typeI' : 'Image',
				'typeT' : 'Text',
				'typeIT' : 'Image and Text',
				'typeS' : 'Search channel',
				
				'joinright' : 'join with right cell',
				'joinup' : 'join with up cell',
				'joindown' : 'join with down cell',
				'joinleft' : 'join with left cell',

				'channel' : 'channel'
			},

			// callback
			'onChannelClick' : function() {
			},

			// internal rebuild trigger
			'rebuild' : function() {
				init(this);
			},

			// Default original layout size
			'width' : 800,

			// Default original layout size
			'height' : 600,

			// channels list
			'channels' : '',

			// foreign channels list
			'foreignChannels' : '',

			// option: toggle sizing table cells
			'resizeCells' : true,

			// option: toggle joining and table cells
			'formatTable' : true,

			// option: display table cells sizes
			'showSizes' : true,

			// option: display channels?
			'showChannels' : false,

			// option: toggle channels manipulations
			'manageChannels' : false,

			// option: toggle channels manipulations
			'callbackChannels' : true,

			// foreign channels container
			'channelsContainerId' : 'channels_list',

			// default layout scale ratio
			'scaleRatio' : 1,

			// default scaled layout
			'scaledWidth' : 300,
			'scaledHeight' : 300,

			// option: display channels?
			'obj' : this,

			// Layout Table Rows x Cols
			'maxCol' : 3,
			'maxRow' : 3,

			'matrix' : new Array(),
			'zones' : [{
						'id' : '0',
						'colspan' : 3,
						'rowspan' : 3
					}]
		};
		options.zones = (options.zones && options.zones.length) ? options.zones : defaults.zones;  
		options.width = parseInt(options.width) || defaults.width;
		options.height = parseInt(options.height) || defaults.height;

		/***********************************************************************
		 * custom configuration
		 **********************************************************************/
		
		//var options = $.extend(defaults, options);
		var options = $.extend(defaults, options);

		options.obj = this;
		

		var _top = 0;
		var _left = 0;
		var _height = 0;
		var _width = 0;

		/***********************************************************************
		 * INIT
		 **********************************************************************/
		var init = function(opts) {

			try {
				if ((opts.scaledWidth / opts.scaledHeight) >= (opts.width / opts.height)) {
					_height = opts.scaledHeight;
					_width = parseInt(_height * (opts.width / opts.height));
	
					opts.scaleRatio = _height / opts.height;
				} else {
					_width = opts.scaledWidth;
					_height = parseInt(_width * (opts.height / opts.width));
	
					opts.scaleRatio = _width / opts.width;
				}
	
				var defaultCellW = Math.round(opts.width / opts.maxCol);
				var defaultCellH = Math.round(opts.height / opts.maxRow);
	
				opts.sizesW = opts.sizesW || new Array();
				opts.sizesH = opts.sizesH || new Array();
				
				for (var i = 0; i < opts.maxCol; i++) {
					opts.sizesH[i] = parseInt(opts.sizesH[i]) || defaultCellH;  
				}
	
				for (var i = 0; i < opts.maxRow; i++) {
					opts.sizesW[i] = parseInt(opts.sizesW[i]) || defaultCellW;  
				}
				
				$(opts.obj).css('position', 'absolute').html('');
	
				_top = parseInt($(opts.obj).css('top'));
				_left = parseInt($(opts.obj).css('left'));
	
				opts.sizesW = normalizeSizes(opts.sizesW, opts.width);
				opts.sizesH = normalizeSizes(opts.sizesH, opts.height);
				opts.sizesW = convertPercents(opts.sizesW, opts.width);
				opts.sizesH = convertPercents(opts.sizesH, opts.height);
	
				$('#' + opts.channelsContainerId).empty();
				var container = containerBuilder(opts);
	
				if (opts.resizeCells)
					$(container).append(dragBuilder(opts))
	
				var table = tableBuilder(opts);
	
				if (opts.showSizes) {
					opts.table = table[2];
				} else {
					opts.table = table[0];
				}
	
				$(container).append(table);
	
				if (opts.showChannels) {
					var channels = channelsBuilder(opts);
					$(container).append(channels);
				}
	
				$(opts.obj).append(container);
				if ($.browser.msie) {
					//know why?^^^^ it's fucked up!
					$(container).hide().show();
				}
				opts.onRebuild.call(opts);			
			} catch (err) {
				
			}
			

		}

		/***********************************************************************
		 * SPREAD DELTA PX
		 **********************************************************************/
		var spreadPixels = function(arr, pixels) {
			for (var i = 0; i < arr.length; i++) {
				if (pixels == 0)
					return true;
				if (pixels > 0) {
					arr[i] = arr[i] - 1;
					pixels = pixels - 1;
				} else {
					arr[i] = arr[i] + 1;
					pixels = pixels + 1;
				}
			}
			if (pixels != 0)
				spreadPixels(arr, pixels);
		}

		/***********************************************************************
		 * ARRAY SUM
		 **********************************************************************/
		var arraySum = function(arr) {
			var sum = 0;
			$(arr).each(function() {
				if (!(/\%/.test(this))) {
					sum = sum + parseInt(this);
				} else {
					return false;
				}
			});
			return sum;
		}

		/***********************************************************************
		 * CONVERT PERCENTS
		 **********************************************************************/
		var convertPercents = function(arr, aspect) {
			var impressionSum = 0;
			for (var i = 0; i < arr.length; i++) {
				if (typeof(arr[i]) == 'string') {
					if (/\%/.test(arr[i])) {
						perc = parseFloat(arr[i]);
						arr[i] = Math.round((aspect / 100) * perc)
						impressionSum = impressionSum
								+ Math.round((aspect / 100) * perc)
								- ((aspect / 100) * perc);
					}
				}
			}

			spreadPixels(arr, Math.round(impressionSum));
			return arr;
		}

		/***********************************************************************
		 * NORMALISE SIZES
		 **********************************************************************/
		var normalizeSizes = function(sizes, aspect) {
			var real = arraySum(sizes);
			if (real && real != aspect) {
				for (var i = 0; i < sizes.length; i++) {
					sizes[i] = (100 / (real / sizes[i])) + '%';
				}
			}
			return sizes;

		}
		
		/***********************************************************************
		 * Simplify
		 **********************************************************************/
		var simplifyObj = function(o) {
			//o.csontainer = '';
			//o.sobj = '';
			//matrix = '';
			//o.table = '';
			
			//opts.table = '';
			//opts.container = '';
			//opts.obj = '';
			return o;
		}

		/***********************************************************************
		 * RESUZE CONTAINER
		 **********************************************************************/
		var resizeContainer = function(container, top, left, _width, _height) {
			$(container)
				.css('top', top + 'px')
				.css('left', left + 'px')
				.css('width', _width + 'px')
				.css('height', _height + 'px');
		}

		/***********************************************************************
		 * RESERVE MATRIX
		 **********************************************************************/
		var reserveMatrix = function(width, height, x, y, limCols, opts) {
			var sizeY = 0;
			for (var j = y; j <= y + height - 1; j++) {
				var sizeX = 0;
				for (var i = x; i <= x + width - 1; i++) {
					opts.matrix[j * limCols + i] = false;
					sizeX = sizeX + Math.round(opts.sizesW[i] * opts.scaleRatio);
				}
				sizeY = sizeY + Math.round(opts.sizesH[j] * opts.scaleRatio);
			}
			return {
				'x' : sizeX,
				'y' : sizeY
			};
		}

		/***********************************************************************
		 * RECALCULATE SIZES
		 **********************************************************************/
		var recalculateSizes = function(draglets, opts) {
			var dv1 = draglets[0];
			var dv2 = draglets[1];
			var dh1 = draglets[2];
			var dh2 = draglets[3];

			opts.sizesW[0] = Math.round(parseInt($(dv1).css('left')) / opts.scaleRatio);
			opts.sizesW[1] = Math.round((parseInt($(dv2).css('left')) - parseInt($(dv1).css('left')))/ opts.scaleRatio);
			opts.sizesW[2] = opts.width - Math.round(parseInt($(dv2).css('left')) / opts.scaleRatio);
			opts.sizesH[0] = Math.round(parseInt($(dh1).css('top')) / opts.scaleRatio);
			opts.sizesH[1] = Math.round((parseInt($(dh2).css('top')) - parseInt($(dh1).css('top')))/ opts.scaleRatio);
			opts.sizesH[2] = opts.height - Math.round(parseInt($(dh2).css('top')) / opts.scaleRatio);

			init(opts);
		}

		var containerBuilder = function(opts) {
			var container = document.createElement('div');
			resizeContainer(container, 0, 0, _width, _height);
			$(container).addClass('wiz-container').attr('id', 'wiz-' + opts.id);

			opts.container = container;
			return container;
		}

		/***********************************************************************
		 * DRAG BUILDER
		 **********************************************************************/
		var dragBuilder = function(opts) {
			var dragContainer = document.createElement('div');
			$(dragContainer)
					.attr('id', 'ui-layout-draglets')
					.css('height', _height)
					.css('width', _width)
					.css('z-index', 50)
					.css('position', 'absolute');

			var dragletVertical1 = document.createElement('div');
			var dragletVertical2 = document.createElement('div');
			var dragletHorizontal1 = document.createElement('div');
			var dragletHorizontal2 = document.createElement('div');

			$([dragletVertical1, dragletVertical2])
					.addClass('ui-vertical-draglets')
					.css('height', _height)
					.css('z-index', 120)
					.css('position', 'absolute');

			$([dragletHorizontal1, dragletHorizontal2])
					.addClass('ui-horizontal-draglets')
					.css('width', _width)
					.css('z-index', 120)
					.css('position', 'absolute');

			$(dragletVertical1).css('left', parseInt(opts.sizesW[0]* opts.scaleRatio) + 'px').attr('rel', 1);
			$(dragletVertical2).css('left', parseInt(opts.sizesW[0]* opts.scaleRatio + opts.sizesW[1] * opts.scaleRatio) + 'px').attr('rel', 2);
			$(dragletHorizontal1).css('top', parseInt(opts.sizesH[0]* opts.scaleRatio)	+ 'px').attr('rel', 1);
			$(dragletHorizontal2).css('top', parseInt(opts.sizesH[0]	* opts.scaleRatio + opts.sizesH[1] * opts.scaleRatio) + 'px').attr('rel', 2);

			$([dragletHorizontal1, dragletHorizontal2]).mousedown(function() {
				$(dragContainer).addClass('ui-container-drag')
				$(this).addClass('ui-draglet-inuse');
				if ($(this).attr('rel') == '1') {
					resizeContainer(dragContainer, 0, 0, _width, parseInt(opts.sizesH[0]
							* opts.scaleRatio
							+ opts.sizesH[1]
							* opts.scaleRatio));
				} else {
					resizeContainer(dragContainer, parseInt(opts.sizesH[0]
							* opts.scaleRatio), 0, _width, parseInt(opts.sizesH[1]
							* opts.scaleRatio
							+ opts.sizesH[2]
							* opts.scaleRatio));
				}
			})
					.mouseup(function() {
						resizeContainer(dragContainer, 0, 0, _width, _height);
						$(dragContainer).removeClass('ui-container-drag');
						$(this).removeClass('ui-draglet-inuse');
					})
					.draggable({
						axis : 'y',
						containment : $(dragContainer),
						scroll : false,
						start : function(e, ui) {
							$(opts.table).hide();
						},
						stop : function(e, ui) {
							resizeContainer(dragContainer, 0, 0, _width, _height);
							$(dragContainer).removeClass('ui-container-drag');
							recalculateSizes([dragletVertical1,
									dragletVertical2, dragletHorizontal1,
									dragletHorizontal2], opts);
						}
					});

			$([dragletVertical1, dragletVertical2]).mousedown(function() {
				$(dragContainer).addClass('ui-container-drag');
				$(this).addClass('ui-draglet-inuse');
				if ($(this).attr('rel') == '1') {
					resizeContainer(dragContainer, 0, 0, parseInt(opts.sizesW[0]
							* opts.scaleRatio
							+ opts.sizesW[1]
							* opts.scaleRatio), _height);
				} else {
					resizeContainer(dragContainer, 0, parseInt(opts.sizesW[0]
							* opts.scaleRatio), parseInt(opts.sizesW[1]
							* opts.scaleRatio + opts.sizesW[2]
							* opts.scaleRatio), _height);
				}
			})
					.mouseup(function() {
						resizeContainer(dragContainer, 0, 0, _width, _height);
						$(dragContainer).removeClass('ui-container-drag');
						$(this).removeClass('ui-draglet-inuse');
					})
					.draggable({
						axis : 'x',
						containment : $(dragContainer),
						scroll : false,
						start : function(e, ui) {
							$(opts.table).hide();
						},
						stop : function(e, ui) {
							resizeContainer(dragContainer, 0, 0, _width, _height);
							$(dragContainer).removeClass('ui-container-drag');
							recalculateSizes([dragletVertical1,
									dragletVertical2, dragletHorizontal1,
									dragletHorizontal2], opts);
						}
					});

			return [dragContainer, dragletVertical1, dragletVertical2,
					dragletHorizontal1, dragletHorizontal2];
		}

		/***********************************************************************
		 * CHANNELS BUILDER
		 **********************************************************************/
		var channelsBuilder = function(opts) {
			
			/* verify channels in layout bounds	 */
			var newChannels = new Array();
			  for (var i = 0; i < opts.channels.length; i++) {
				if ((parseInt(opts.channels[i].x) + parseInt(opts.channels[i].width)) > parseInt(opts.width) || (parseInt(opts.channels[i].y) + parseInt(opts.channels[i].height)) > parseInt(opts.height)) {
					opts.foreignChannels[opts.foreignChannels.length] = opts.channels[i];
					continue;
				} 
				newChannels[newChannels.length] = opts.channels[i];
			}
			
			opts.channels = newChannels;
			
			var channels = new Array();
			for (var i = 0; i < opts.channels.length; i++) {
				var newChannel = document.createElement('div');
				if (opts.manageChannels) {
					var closeButton = document.createElement('div');
					$(closeButton)
							.addClass('ui-channel-closeBtn floatr center')
							.append('x')
							.attr('title', 'Remove channel from the Layout')
							.bind('click', {
								'options' : opts,
								'removeId' : parseInt(opts.channels[i].id)
							}, function(e) {

								opts = e.data.options;
								var newChannels = new Array();
								var newForeignChannel = {};

								for (var i = 0; i < opts.channels.length; i++) {
									if (parseInt(opts.channels[i].id) != e.data.removeId) {
										newChannels[newChannels.length] = opts.channels[i];
									} else {
										newForeignChannel = e.data.options.channels[i];
									}
								}
								opts.channels = newChannels;
								opts.foreignChannels[opts.foreignChannels.length] = newForeignChannel;
								opts.rebuild(opts);
							});
				}
				
				if (opts.channels[i].ad_type == 'search') {
					$(newChannel)
					.append('<div class="n">' + opts.channels[i].ad_type + '</div>')
					.addClass('search-channel');
				} else {
					$(newChannel)
					.append('<div class="n">'
						+ opts.channels[i].width + ' x '
						+ opts.channels[i].height + '</div>');
				}
				
				
				$(newChannel)
						.css('position', 'absolute')
						.css('z-index', '2002')
						//.addClass('')
						.attr('id', 'channel' + opts.channels[i].id)
						.attr('title', opts.channels[i].title + (opts.channels[i].ad_type!='search' ? (' ('
								+ opts.channels[i].width + 'x'
								+ opts.channels[i].height + ')') : ''))
						.css('width', Math.round(opts.channels[i].width
								* opts.scaleRatio)
								+ 'px')
						.css('height', Math.round(opts.channels[i].height
								* opts.scaleRatio)
								+ 'px')
						.css('top', Math.round(opts.channels[i].y
								* opts.scaleRatio)
								+ 'px')
						.css('left', Math.round(opts.channels[i].x
								* opts.scaleRatio)
								+ 'px')
						.addClass('ovh b f9px ui-channel iu-ready-to-drop');

				if (opts.manageChannels) {
					$(newChannel)
						.prepend(closeButton)
						.hover(function(){
							$(this).css('z-index', '9999');
						}, function(){
							$(this).css('z-index', '1000');
						})
						.draggable({
							//containment : $('.ui-zone-fill'),//$('#zone' + opts.channels[i].zone + ' .ui-zone-fill', opts.table),
							//cursor: 'move',
							revert: 'invalid',
							cursorAt : { top : -1, left : -1}
						})
						
						.bind('dragstart', {o : opts, i : i}, function(e, ui) {
							var d = e.data;
							$(this)
								.removeClass('ui-channel')
								.addClass('ui-dragChannel')
								//.css('position', 'absolute')
								.css('width', Math.round(d.o.channels[d.i].width * d.o.scaleRatio) + 'px')
								.css('height', Math.round(d.o.channels[d.i].height* d.o.scaleRatio) + 'px');
						})
						/*.bind('mouseup', function(e) {
							$(this)
								.removeClass('ui-dragChannel')
								//.css('position', '')
								.addClass('ui-foreignChannel')
								.css('width', '')
								.css('height', '');
						})
						*/
						.bind('dragstop', opts, function(e, ui){
								$(this)
									.removeClass('ui-dragChannel')
									.addClass('ui-channel');
							
							/*channel_id = parseInt($(ui.helper.context).attr('id').substring(7, $(ui.helper.context).attr('id').length));
							var index = 0;
							for (var i = 0; i< e.data.channels.length; i++) {
								if (parseInt(e.data.channels[i].id) == channel_id) {
									index = i;
								}
							}
							
							channel = e.data.channels[index];
							channel.x = Math.round((ui.absolutePosition.left - $(e.data.obj).offset().left) / e.data.scaleRatio);
							channel.y = Math.round((ui.absolutePosition.top - $(e.data.obj).offset().top)	/ e.data.scaleRatio); 							
							
							e.data.channels[index] = channel;
							e.data.rebuild(e.data);*/							
						});
				}

				if (opts.callbackChannels)
					$(newChannel).css('cursor', 'pointer').bind('click', {
						options : opts,
						el : opts.channels[i]
					}, function(e) {
						e.data.options.onChannelClick.call(e.data.el);
					});

				channels[channels.length] = newChannel;
			}

			if (opts.manageChannels) {
				// foreign channels
				for (var i = 0; i < opts.foreignChannels.length; i++) {
					newForeignChannel = document.createElement('div');
					var ChType = '';
					if (opts.foreignChannels[i].ad_type == 'image') {
						ChType = opts.l.typeI;
					} else if (opts.foreignChannels[i].ad_type == 'text') {
						ChType = opts.l.typeT;
					} else if (opts.foreignChannels[i].ad_type == 'search') {
						ChType = opts.l.typeS;
					} else {
						ChType = opts.l.typeIT;
					}
					
					if (opts.foreignChannels[i].ad_type == 'search') {
						opts.foreignChannels[i].width = 300;
						opts.foreignChannels[i].height = 500;
					}
					
					if (opts.foreignChannels[i].ad_type != 'search') {
						$(newForeignChannel)
							.append('' 
								+ '<div class="slot"><img src="../../../images/slots_preview/slots_' + opts.foreignChannels[i].id_dimension + ((opts.foreignChannels[i].ad_type=='text') ? '' : '_1') + '.gif"></div>' 
								+ '<div class="title">'	+ opts.foreignChannels[i].title + '</div>'
								+ '<div class="size">' + opts.foreignChannels[i].width + ' x ' + opts.foreignChannels[i].height + '</div>' 
								+ '<div class="slot2">slots: ' + opts.foreignChannels[i].max_slots_count + '</div>' 
								+ '<div class="slot2">type: ' + ChType + '</div>' 
								+ '');
					} else {
						$(newForeignChannel)
							.append('' 
								+ '<div class="title">'	+ opts.foreignChannels[i].title + '</div>'
								+ '<div class="slot2">type: ' + ChType + '</div>' 
								+ '');
					}
					
					$(newForeignChannel)
							.attr('id', 'channel' + opts.foreignChannels[i].id)
							.attr('title', opts.foreignChannels[i].title)
							.addClass('ui-ready-to-drop')
							.addClass('ovh b ui-foreignChannel')
							.draggable({
								revert : 'invalid',
								//containment: $(opts),
								//opacity : 0.7,
								// cursor: 'move',
								cursorAt : {
									top : -1,
									left : -1
								}
							})
							.bind('dragstart', {o : opts, i : i}, function(e, ui) {
								var d = e.data;
								$(this)
									.removeClass('ui-foreignChannel')
									.addClass('ui-dragChannel')
									//.css('position', 'absolute')
									.css('width', Math.round(d.o.foreignChannels[d.i].width * d.o.scaleRatio) + 'px')
									.css('height', Math.round(d.o.foreignChannels[d.i].height* d.o.scaleRatio) + 'px');
							})
							.bind('dragstop', {o : opts, index : i}, function(e, ui) {
								var d = e.data;
								$(ui.helper.context)
									.removeClass('ui-dragChannel')
									.addClass('ui-foreignChannel')
									.css('width', '')
									.css('height', '');
								d.o.rebuild(d.o);
							})
							.bind('mouseup', function(e) {
								$(this)
									.removeClass('ui-dragChannel')
									.addClass('ui-foreignChannel')
									.css('width', '')
									.css('height', '');
							});

					$('#' + opts.channelsContainerId).append(newForeignChannel);
				}
			}
			return channels;
		}

		/***********************************************************************
		 * GET CHANNEL INFO
		 **********************************************************************/
		var getChannelInfo = function(el, pos, o) {
			var channel = { id : '', width : '', title : '', height : '', x : '', y : ''};
			channel.id = parseInt(($(el).attr('id').substring(7, $(el).attr('id').length)));
			
			var foundForeign = false;
			for (var i = 0; i < o.foreignChannels.length; i++) {
				if (parseInt(o.foreignChannels[i].id) == channel.id) {
					foundForeign = true;
					fCh = o.foreignChannels[i];
					channel.title = fCh.title;
					channel.id_dimension = fCh.id_dimension;
					channel.ad_type = fCh.ad_type;
					channel.max_slots_count = fCh.max_slots_count;
					channel.width = parseInt(fCh.width);
					channel.height = parseInt(fCh.height);
				}
			}
			
			if (!foundForeign) {
				for (var i = 0; i < o.channels.length; i++) {
					if (parseInt(o.channels[i].id) == channel.id) {
						fCh = o.channels[i];
						channel.title = fCh.title;
						channel.id_dimension = fCh.id_dimension;
						channel.ad_type = fCh.ad_type;
						channel.max_slots_count = fCh.max_slots_count;
						channel.width = parseInt(fCh.width);
						channel.height = parseInt(fCh.height);
					}
				}
			}

			channel.x = Math.round((pos.left - $(o.obj).offset().left) / o.scaleRatio);
			channel.y = Math.round((pos.top - $(o.obj).offset().top) / o.scaleRatio); // Math.round((pos.top
			return channel;
		}

		/***********************************************************************
		 * TABLE BUILDER
		 **********************************************************************/
		var tableBuilder = function(opts) {
			var limitCol = opts.maxCol;
			var limitRow = opts.maxRow;
			for (j = 0; j <= (limitRow * limitCol) - 1; j++) {
				opts.matrix[j] = true;
			}


			if (opts.showSizes) {
				var WSizesTBL = document.createElement('table');
				var HSizesTBL = document.createElement('table');

				$(WSizesTBL)
						.addClass('ui-tableWsizes')
						.css('position', 'absolute')
						.css('width', _width + 'px')
						.css('top', (_height + 10) + 'px');

				$(HSizesTBL)
						.addClass('ui-tableHsizes')
						.css('position', 'absolute')
						.css('height', _height + 'px')
						.css('left', (_width + 10) + 'px');

				for (var i = 0; i < opts.sizesW.length; i++) {
					var Wtd = document.createElement('td');
					$(Wtd).css('width', parseInt(opts.sizesW[i]
							* opts.scaleRatio)
							+ 'px').css('text-align', 'center').html('<div>'
							+ opts.sizesW[i] + 'px</div>');
					$(WSizesTBL).append(Wtd);
				}
				var top = 0;
				for (var i = 0; i < opts.sizesH.length; i++) {
					var Htr = document.createElement('tr');
					var Htd = document.createElement('td');

					$(Htd)
							.css('height', parseInt(opts.sizesH[i]
									* opts.scaleRatio)
									+ 'px')
							.css('text-align', 'center')
							.html('<div style="left:'
									+ (($.browser.msie || $.browser.opera || $.browser.safari  ) ? 0 : (_width + 10))
									+ 'px; top:'
									+ (parseInt(top) + 2)
									+ 'px;position:absolute;height:'
									+ Math.round(opts.sizesH[i] * opts.scaleRatio)
									+ 'px"></div>' + opts.sizesH[i]  + 'px');
					$(Htr).append(Htd);
					top = top + parseInt(opts.sizesH[i] * opts.scaleRatio);
					$(HSizesTBL).append(Htr);
				}
			}

			var currentTBL = document.createElement('table');
			var currentTBLBody = document.createElement('tbody');
			$(currentTBL)
					.attr('width', _width)
					.attr('height', _height)
					.attr('id', 'wiz-' + opts.id)
					.attr('cellspacing', 0)
					.attr('cellpadding', 0)
					.attr('border', 0)
					.css('position', 'absolute')
					.css('z-index', 100)
					.addClass('wiz-grid');

			var currZoneIndex = 0;
			for (var y = 0; y < limitRow; y++) {
				var currentTR = document.createElement('tr');
				$(currentTR).attr('valign', 'top');
				var currentWidth = 0;
				for (var x = 0; x < limitCol; x++) {
					if (!opts.matrix[y * limitCol + x]) continue;
					var currZone = opts.zones[currZoneIndex];
					var cellSizes = reserveMatrix(parseInt(currZone.colspan), parseInt(currZone.rowspan), x, y, limitCol, opts);
					opts.matrix[y * limitCol + x] = true;
					currZoneIndex++;

					currentTD = document.createElement('td');
					$(currentTD)
							.attr('id', 'zone' + currZone.id)
							.attr('width', cellSizes.x)
							.attr('height', cellSizes.y)
							.css('width', cellSizes.x + 'px')
							.css('height', cellSizes.y + 'px')
							.addClass('ui-zone');
					$(currentTR).append(currentTD);
					
					currentTD.colSpan = currZone.colspan;
					currentTD.rowSpan = currZone.rowspan;
					
				}
				$(currentTBLBody).append(currentTR);
			}
			
			for (i = 0; i < limitCol; i++) {
				var currentCol = document.createElement('col');
				$(currentCol).css('width', Math.round(opts.sizesW[i] * opts.scaleRatio) + 'px');
				$(currentTBL).append(currentCol);
			}
			
			$(currentTBL).append(currentTBLBody);
			
			$('td', currentTBL).each(function(){
				var $this = $(this);
				var newDiv = document.createElement('div');
				$(newDiv)
					.css('position', 'absolute')
					.css('width', (parseInt($this.attr('width'))-2) + 'px')
					.css('height', (parseInt($this.attr('height'))-2) + 'px')
					.addClass('ui-zone-fill');
				$this.append(newDiv);
			});
			
			if (opts.manageChannels) {
				$('td', currentTBL).droppable({
					tolerance : 'fit',
					//revert : 'invalid',
					activeClass : 'ui-dropZone'
				}).bind('drop', {
					o : opts
				}, function(e, ui) {
					
					var d = e.data;

					var channel = getChannelInfo(ui.helper.context, ui.absolutePosition, d.o);
					channel.zone = parseInt($(e.currentTarget).attr('id').substring(4, $(e.currentTarget).attr('id').length));
					var newIndex = d.o.channels.length;
					for (var i = 0; i < d.o.channels.length; i++) {
						if (d.o.channels[i].id == channel.id) {
							newIndex = i;
							break;
						}
					}

					var newForeignChannels = new Array();
					for (var i = 0; i < d.o.foreignChannels.length; i++) {
						if (d.o.foreignChannels[i].id != channel.id) {
							newForeignChannels[newForeignChannels.length] = d.o.foreignChannels[i];
						}
					}

					d.o.channels[newIndex] = channel;
					$(ui.helper.context)
						.draggable('disable')
						.removeClass('ui-ready-to-drop');
					d.o.foreignChannels = newForeignChannels;
					d.o.rebuild(d.o);
				});

			}
			
			

			if (opts.formatTable) {

				var tds = $('td', currentTBL);

				var currZoneIndex = 0;
				
				
				var newMatrix = new Array();
				var currentIndex = 0;
				for (var y = 0; y < opts.maxRow ; y++) {
					for (var x = 0; x < opts.maxCol; x++) {
						var newNode = {};
						newNode.state = opts.matrix[y * opts.maxCol + x];
						if (opts.matrix[y * opts.maxCol + x]) {
							newNode.colspan = parseInt(opts.zones[currentIndex].colspan);
							newNode.rowspan = parseInt(opts.zones[currentIndex].rowspan);
							newNode.index = currentIndex;
							currentIndex++;
						}
						newMatrix[y * opts.maxCol + x] = $.extend(newMatrix[y * opts.maxCol + x], newNode);
					}
				}

				var currZoneIndex = 0;
				
				$(tds).each(function() {
					
					if (parseInt($(this).attr('rowspan')) > 1 || parseInt($(this).attr('colspan')) > 1) {
						$(this).prepend(createButton(this, 'split', opts, currZoneIndex));
					}
					
					var cZoneIndex = 0;
					for (var y = 0; y < opts.maxRow; y++) {
						for (var x = 0; x < opts.maxCol; x++) {
							
							var current = newMatrix[y * opts.maxCol + x];
							if (!current.state) continue;
			
							if (cZoneIndex == currZoneIndex) {
								
								var top = newMatrix[(y-1) * opts.maxCol + x];
								if (!(x + current.colspan >= opts.maxCol)) var right =  newMatrix[y * opts.maxCol + (x + parseInt(current.colspan))];
								if (!(y + current.rowspan >= opts.maxRow)) var bottom = newMatrix[(y+parseInt(current.rowspan)) * opts.maxCol + x];
								
								if (x > 0) {
									var left = newMatrix[y * opts.maxCol + (x - 1)];
								}
								
								
								// top
								if ((y > 0) && typeof(top)!='undefined' && top.state && (top.colspan == current.colspan)) {
									targetZoneIndex = top.index;
									$(this).prepend(createButton(this, 'top', opts, currZoneIndex, targetZoneIndex));
								}
								// right
								if ((x < opts.maxCol-1) && typeof(right)!='undefined' && right.state && (right.rowspan == current.rowspan)) {
									targetZoneIndex = right.index;
									$(this).prepend(createButton(this, 'right', opts, currZoneIndex, targetZoneIndex));
								}
								// left
								if ((x > 0) && typeof(left)!='undefined' && left.state && (left.rowspan == current.rowspan)) {
									targetZoneIndex = left.index;
									$(this).prepend(createButton(this, 'left', opts, currZoneIndex, targetZoneIndex));
								}
								// bottom
								if ((y < opts.maxRow-1) && typeof(bottom)!='undefined' && bottom.state && (bottom.colspan == current.colspan)) {
									targetZoneIndex = bottom.index;
									$(this).prepend(createButton(this, 'bottom', opts, currZoneIndex, targetZoneIndex));
								}
							}
							
							cZoneIndex++;
							
						}
					}

					currZoneIndex++;

				})
				.click(function() {
					$('td', currentTBL).removeClass('selected');
					$(this).addClass('selected');
				})
				.hover(function() {
					$('td', currentTBL).removeClass('selected');
					$(this).addClass('selected');
				}, function(){
					/*$(this).removeClass('selected');*/
				})
				;
			}

			if (opts.showSizes) {
				return [HSizesTBL, WSizesTBL, currentTBL];
			} else {
				return [currentTBL];
			}

		}

		/***********************************************************************
		 * CREATE BUTTON (Join/Split)
		 **********************************************************************/
		var createButton = function(el, dir, opts, index, targetIndex) {
			var button = document.createElement('div');
			$(button)
					.addClass('ui-zone-button')
					.addClass(dir)
					.css('position', 'absolute')
					.css('z-index', '1000')
					.hover(function() {
						$(this).addClass('ui-button-hover');
					}, function() {
						$(this).removeClass('ui-button-hover');
					});

			switch (dir) {
				case 'top' :
					$(button)
						.css('margin-left', Math.round(parseInt($(el).attr('width')) / 2) - 10 + 'px')
						.append("&uarr;")
						.bind('click', opts, function(e){
							rebuildZones(e.data, index, targetIndex, 'top');
						});
					break;
				case 'right' :
					$(button)
						.css('margin-left', Math.round(parseInt($(el).attr('width')) ) - 20 + 'px')
						.css('margin-top', Math.round(parseInt($(el).attr('height')) / 2) - 10 + 'px')
						.append("&rarr;")
						.bind('click', opts, function(e){
							rebuildZones(e.data, index, targetIndex, 'right');
						});
					break;
				case 'bottom' :
					$(button)
						.css('margin-left', Math.round(parseInt($(el).attr('width')) / 2) - 10 + 'px')
						.css('margin-top', Math.round(parseInt($(el).attr('height'))) - 20  + 'px')
						.append("&darr;")
						.bind('click', opts, function(e){
							rebuildZones(e.data, index, targetIndex, 'bottom');
						});
					break;
				case 'left' :
					$(button)
						.css('margin-top', Math.round(parseInt($(el).attr('height')) / 2) - 10 + 'px')
						.append("&larr;")
						.bind('click', opts, function(e){
							rebuildZones(e.data, index, targetIndex, 'left');
						});
					break;
				case 'split' :
					$(button)
						.css('margin-left', Math.round(parseInt($(el).attr('width'))/ 2) - 15 + 'px')
						.css('margin-top', Math.round(parseInt($(el).attr('height')) / 2) - 10	+ 'px')
						.text(opts.l.split)
						.bind('click', opts, function(e) {
							var currentIndex = 0;
							var newZones = new Array();
							for (var y = 0; y <= e.data.maxRow - 1; y++) {
								for (var x = 0; x <= e.data.maxCol - 1; x++) {
									if (e.data.matrix[y * e.data.maxCol + x] == false)
										continue;
	
									var currZone = e.data.zones[currentIndex];
									if (currentIndex == index) {
										for (var j = y; j <= y + parseInt(currZone.rowspan) - 1; j++) {
											for (var i = x; i <= x + parseInt(currZone.colspan) - 1; i++) {
												e.data.matrix[j * e.data.maxCol + i] = 'reserved';
											}
										}
										e.data.zones[currentIndex].colspan = 1;
										e.data.zones[currentIndex].rowspan = 1;
										e.data.matrix[y * e.data.maxCol + x] = true;
									}
									currentIndex++;
								}
							}
	
							currentIndex = 0;
							var newIndex = 0;
	
							for (var y = 0; y <= e.data.maxRow - 1; y++) {
								for (var x = 0; x <= e.data.maxCol - 1; x++) {
									var currZone = e.data.zones[currentIndex];
									if (e.data.matrix[y * e.data.maxCol + x] == true) {
										newZones[newIndex] = currZone;
										currentIndex++;
										newIndex++;
										continue;
									};
	
									if (e.data.matrix[y * e.data.maxCol + x] == 'reserved') {
										newZones[newIndex] = {
											'colspan' : 1,
											'rowspan' : 1
										};
										e.data.matrix[y * e.data.maxCol + x] = true;
										newIndex++;
										continue;
									};
								}
							}
	
							e.data.zones = newZones;
							e.data.rebuild(e.data);
	
						});
					break;
				default :
					break;
			}

			return button;
		}
		
		var deleteZone = function(arr, index) {
			var newArr = new Array();
			for(var i = 0; i < arr.length; i++) {
				if (i != index) newArr[newArr.length] = arr[i];
			}
			return newArr;
		}
		
		var rebuildZones = function(o, index, targetIndex, direction) {
			var newZones = new Array();
			switch (direction) {
				case 'bottom' :
						o.zones[index].rowspan = parseInt(o.zones[index].rowspan) + parseInt(o.zones[targetIndex].rowspan);
						o.zones = deleteZone(o.zones, targetIndex); 
					break;
				case 'top' : 
						o.zones[targetIndex].rowspan = parseInt(o.zones[index].rowspan) + parseInt(o.zones[targetIndex].rowspan);
						o.zones[targetIndex].id = o.zones[index].id;
						o.zones = deleteZone(o.zones, index);
					break;
				case 'left' :
						o.zones[targetIndex].colspan = parseInt(o.zones[index].colspan) + parseInt(o.zones[targetIndex].colspan);
						o.zones[targetIndex].id = o.zones[index].id;
						o.zones = deleteZone(o.zones, index);
					break;
				case 'right' : 
						o.zones[index].colspan = parseInt(o.zones[index].colspan) + parseInt(o.zones[targetIndex].colspan);
						o.zones = deleteZone(o.zones, targetIndex);
					break;
			}
			o.rebuild(o);
		}
		
		/***********************************************************************
		 * 
		 **********************************************************************/
		return this.each(function() {
			init(options);
		});
	};
});
