
/* ================================================================================================================================================== DATE/TIMES CONTROL ====
*/
		function DatetimesControl(options)
			{
			this.rangeMin = 2;

			this.setOptions(options);
			}

	// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
			DatetimesControl.prototype.create			= function()
																								{
																								var dts = this.dtsbox.valDTs;

																								this.$control = $('<div/>').addClass('pick-date');

																								if (dts.useDate())
																									{
																									this.$control.datepicker( { defaultDate	: (new Date).setShort(dts.datePart),
																																							onSelect		: function(vl) { $(this).trigger({ type: 'dateSelect', value: vl }); }
																																							}).
																																					bind('dateSelect', { ctrl: this }, function(ev)
																																						{
																																						var ctrl = ev.data.ctrl , dts = ctrl.dtsbox.valDTs;
																																						dts.datePart = ev.value;
																																						ctrl.value = ctrl.dtsbox.setValue(dts.toString());
																																						if (dts.useDate() & !dts.useTime()) { ctrl.popup.callEvent('dateSelect', ev); }
																																						});
																									}

																								this.$control.append( $('<div/>').append( this.dtsbox.create() ) );

																								if (dts.useTime())
																									{
																									var cell    = '<td><div></div></td>',
																											$slider = $('<div><table><tr>' + cell.repeat(4) + '</tr></table></div>'),
																											$handle = $('<div/>').addClass('ui-slider-handle').
																																						html('|');

																									if (dts.useRange())
																										{
																										$slider.append( $handle.clone(true).addClass('lower-handle').attr('handle', 'From') ).
																														append( $handle.addClass('upper-handle').attr('handle', 'To') ).
																														slider( { range	: true,
																																			max		: dts.timeFrom.stepsPerDay(),
																																			values: [dts.timeFrom.value, dts.timeTo.value]
																																			}).
																														bind('slide', { ctrl: this }, function(ev, ui)
																															{
																															var ctrl = ev.data.ctrl,
																																	dts  = ctrl.dtsbox.valDTs,
																																	hnd  = ui.handle.getAttribute('handle');

																															if (dts['time' + ((hnd == 'To') ? 'From' : 'To')].value.diff(ui.value) < ctrl.rangeMin) { return false; }
																															else
																																{
																																dts['time' + hnd].value = ui.value;
																																ctrl.value = ctrl.dtsbox.setValue(dts.toString());
																																return true;
																																}
																															});
																										}
																									else
																										{
																										$slider.append($handle).slider({ max: 96, value: dts.timeFrom.value }).
																														bind('slide', { ctrl: this }, function(ev, ui)
																															{
																															var ctrl = ev.data.ctrl;

																															ctrl.dtsbox.valDTs.timeFrom.value = ui.value;
																															ctrl.value = ctrl.dtsbox.setValue(ctrl.dtsbox.valDTs.toString());
																															});
																										}

																									this.$control.append($slider);
																									$slider.find('.ui-slider-handle').hover(function() { $(this).addClass('block-hover'); },
																																													function() { $(this).removeClass('block-hover'); });
																									}

																								return this.$control.append( $('<div/>').addClass('spacing') );
																								};
	// ------------------------------------------------------------------------------------------------------------------------------------------------
			DatetimesControl.prototype.destroy		= function()
																								{
																								if (this.dtsbox.valDTs.useDate()) { this.$control.datepicker('destroy'); }

																								this.$control.remove();
																								this.$control = null;
																								};
	// ------------------------------------------------------------------------------------------------------------------------------------------------
			DatetimesControl.prototype.setOptions	= function(options)
																								{
																								var opts = options || {};

																								this.value  = opts.value || opts.defaultVal;
																								this.dtsbox	= new DatetimesboxControl({ dataType: opts.dataType, readOnly: true, value: this.value });
																								};
	// ________________________________________________________________________________________________________________________________________________


/* ================================================================================================================================================== DATE/TIMES POPUP ====
*/
		function DatetimesPopup(options)
			{
			this.setOptions(options);
			}

	// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
			DatetimesPopup.prototype = new PopupControl();
			DatetimesPopup.prototype.constructor = DatetimesPopup;
	// ------------------------------------------------------------------------------------------------------------------------------------------------
			DatetimesPopup.prototype.setOptions	= function(options)
																							{
																							var opts = options || {};

																							opts.content		 = new DatetimesControl(opts);
																							opts.showConfirm = true;

																							PopupControl.prototype.setOptions.call(this, opts);

																							var dts = this.content.dtsbox.valDTs;
																							if (dts.useDate() & !dts.useTime())
																								{
																								this.content.popup = this;
																								this.dateSelect = { act	: function(data, ev) { data.close('onConfirm', ev); }, data: this };
																								}
																							};
	// ________________________________________________________________________________________________________________________________________________


/* ================================================================================================================================================== MENU POPUP ====
*/
		function MenuPopup(options)
			{
			this.autoClose	 = true;
			this.cssName		 = 'ctrl-menu';
			this.cssSelected = 'block-picked';
			this.values = [];

			this.setOptions(options);
			}

	// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
			MenuPopup.prototype = new PopupControl();
			MenuPopup.prototype.constructor = MenuPopup;
	// ------------------------------------------------------------------------------------------------------------------------------------------------
			MenuPopup.prototype.addEntries		= function(entries)
																						{
																						for (var i = 0; i < entries.length; i++)
																							{
																							this.content.body.appendRow().appendCell({ content: entries[i].text }).enableSelected = entries[i].enableSelected;
																							this.values.push(entries[i].value);
																							}

																						return this;
																						};
	// ------------------------------------------------------------------------------------------------------------------------------------------------
			MenuPopup.prototype.addTexts			= function(texts)
																						{
																						for (var i = 0; i < texts.length; i++)
																							{
																							this.content.body.appendRow().appendCell({ content: texts[i] });
																							}

																						return this;
																						};
	// ------------------------------------------------------------------------------------------------------------------------------------------------
			MenuPopup.prototype.deselectValue	= function(val)
																						{
																						var cell = this.getValueCell(val);

																						if (cell)
																							{
																							cell.cssName = '';
																							cell.disabled = false;
																							}
																						};
	// ------------------------------------------------------------------------------------------------------------------------------------------------
			MenuPopup.prototype.getValueIndex	= function(val) { return this.values.indexOfItem(val); };
	// ------------------------------------------------------------------------------------------------------------------------------------------------
			MenuPopup.prototype.getValueCell	= function(val)
																						{
																						var i = this.values.indexOfItem(val);

																						return (i == -1) ? null : this.content.body.rows[i].cells[0];
																						};
	// ------------------------------------------------------------------------------------------------------------------------------------------------
			MenuPopup.prototype.getValueText	= function(val)
																						{
																						var i = this.values.indexOfItem(val);

																						return (i == -1) ? '---' : this.content.body.rows[i].cells[0].content;
																						};
	// ------------------------------------------------------------------------------------------------------------------------------------------------
			MenuPopup.prototype.onOpen				= { act	: function()
																										{
																										var wd = this.$body.width();
																										if (this.content.$control.width() < wd) { this.content.$control.width(wd); }
																										} };
	// ------------------------------------------------------------------------------------------------------------------------------------------------
			MenuPopup.prototype.selectValue		= function(val)
																						{
																						var cell = this.getValueCell(val);

																						if (cell)
																							{
																							cell.cssName = this.cssSelected;
																							cell.disabled = !cell.enableSelected;
																							}
																						};
	// ------------------------------------------------------------------------------------------------------------------------------------------------
			MenuPopup.prototype.setOptions		= function(options)
																						{
																						var opts = options || {};

																						opts.content = new TableControl(opts);

																						PopupControl.prototype.setOptions.call(this, opts);

																						if ('autoClose' in opts) { this.autoClose = opts.autoClose; }

																						if (opts.texts)
																							{
																							this.values = opts.values || opts.texts;
																							this.addTexts(opts.texts);
																							}
																						else if (opts.entries) { this.addEntries(opts.entries); }

																						this.content.body.onClick =
																							{
																							act	: function(data, ev)
																											{
																											data.selected = this.overCell.rowIndex();
																											data.text  = this.overCell.content;
																											data.value = data.values[data.selected];
																											data.callEvent('onSelect', ev);
																											data[(data.autoClose) ? 'close' : 'callEvent']('onConfirm', ev);
																											},
																							data: this
																							};
																						};
	// ________________________________________________________________________________________________________________________________________________


/* ================================================================================================================================================== PAGING CONTROL ====
*/
		function PagingControl(options)
			{
			this.pageNo				=  1;
			this.pageCount		=  0;
			this.rowsPerPage	= 10;

			this.iconFirst	= new IconControl({ cssIcon	: 'icon-first',
																					title		: 'Click to view the first page',
																					onClick	: { act: function(data) { data.movePage(1); }, data: this }
																					});

			this.iconPrev		= new IconControl({ cssIcon	: 'icon-prev',
																					title		: 'Click to view the previous page',
																					onClick	: { act: function(data) { data.movePage(data.pageNo - 1); }, data: this }
																					});

			this.iconNext		= new IconControl({ cssIcon	: 'icon-next',
																					title		: 'Click to view the next page',
																					onClick	: { act: function(data) { data.movePage(data.pageNo + 1); }, data: this }
																					});

			this.iconLast		= new IconControl({ cssIcon	: 'icon-last',
																					title		: 'Click to view the last page',
																					onClick	: { act: function(data) { data.movePage(data.pageCount); }, data: this }
																					});

			this.pageBox		= new TextboxControl({ dataType: 'int', size: 6, onChange: { act: function(data) { data.movePage(this.value); }, data: this } });

			this.pickRPP		= new SelectorControl({ entries	: [	{ text: 'One row' , value:  1 },
																													{ text: '10 rows' , value: 10 },
																													{ text: '25 rows' , value: 25 },
																													{ text: '50 rows' , value: 50 },
																													{ text: 'One page', value:  0 } ],
																							size		: 7,
																							value		: this.rowsPerPage,
																							onSelect: { act	: function(data, ev)
																																	{
																																	data.rowsPerPage = this.value;
																																	data.callEvent('onChange', ev);
																																	},
																													data: this } });

			ControlBase.prototype.setOptions.call(this, options);
			}

	// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
			PagingControl.prototype = new ControlBase();
			PagingControl.prototype.constructor = PagingControl;
	// ------------------------------------------------------------------------------------------------------------------------------------------------
			PagingControl.prototype.create		= function()
																						{
																						this.$ctrlNav  = $('<span/>').addClass('ctrl-paging-nav').
																																					append(	this.iconFirst.create(),
																																									this.iconPrev.create(),
																																									this.pageBox.create().
																																										attr('autocomplete', 'off').
																																										bind('focus blur', { pgCtrl: this }, function(ev)
																																											{
																																											var pgCtrl = ev.data.pgCtrl, pgBox = pgCtrl.pageBox;

																																											if ((ev.type == 'focus') && !pgBox.readOnly)
																																												{
																																												this.value = pgCtrl.pageNo;
																																												this.select();
																																												pgBox.needsPages = true;
																																												}
																																											else if ((ev.type == 'blur') && pgBox.needsPages)
																																												{
																																												this.value += ' / ' + pgCtrl.pageCount;
																																												pgBox.needsPages = false;
																																												}
																																											}),
																																									this.iconNext.create(),
																																									this.iconLast.create() );

																						this.$control  = $('<span/>').addClass('ctrl-paging').
																																					append( this.$ctrlNav, this.pickRPP.create() );
																						return this.$control;
																						};
	// ------------------------------------------------------------------------------------------------------------------------------------------------
			PagingControl.prototype.movePage	= function(pageNo)
																						{
																						this.pageNo = pageNo;
																						this.onChange.act.call(this, this.onChange.data);
																						};
	// ------------------------------------------------------------------------------------------------------------------------------------------------
			PagingControl.prototype.update		= function(pgInfo)
																						{
																						this.pageNo		 = pgInfo.pageNo;
																						this.pageCount = pgInfo.pageCount;

																						if (this.pageCount > 1)
																							{
																							this.iconFirst.disable(this.pageNo == 1);
																							this.iconPrev.disable( this.pageNo == 1);
																							this.iconNext.disable( this.pageNo == this.pageCount);
																							this.iconLast.disable( this.pageNo == this.pageCount);

																							this.pageBox.setValue(this.pageNo + ' / ' + this.pageCount);
																							this.pageBox.setAttr('maxlength', this.pageCount.toString().length);

																							this.$ctrlNav.css('visibility', 'visible');
																							}
																						else { this.$ctrlNav.css('visibility', 'hidden'); }
																						};
	// ________________________________________________________________________________________________________________________________________________


/* ================================================================================================================================================== PERIOD CONTROL ====
*/
		function PeriodControl(options)
			{
			this.prevYear	=	new IconControl({ cssIcon	: 'icon-up',
																				title		: 'Click to move back a year',
																				onClick	: { act	: function(data, ev) { data.moveYear(-1); },
																										data: this } });

			this.nextYear	=	new IconControl({ cssIcon	: 'icon-down',
																				title		: 'Click to move ahead a year',
																				onClick	: { act	: function(data, ev) { data.moveYear(1); },
																										data: this } });

			this.pickTable = new TableControl({ onMouseDown	:
																						{
																						act	: function(data, ev)
																										{
																										data.markRange('remove');
																										data.firstCell = { ctrl: this.overCell, cellI: this.overCell.cellIndex(), rowI: this.overCell.rowIndex() };
																										data.finalCell = null;
																										data.periodBox.setValue(data.markRange('add'));
																										},
																						data: this
																						},
																					onHover			:
																						{
																						act	: function(data, ev)
																										{
																										var oc = this.overCell;

																										if (this.mouseDown && (data.unitsInfo(oc.cellIndex()).units == data.periodBox.valCP.units))
																											{
																											data.markRange('remove');
																											data.finalCell = (oc === data.firstCell.ctrl) ? null : { ctrl: oc, cellI: oc.cellIndex(), rowI: oc.rowIndex() };
																											data.periodBox.setValue(data.markRange('add'));
																											}
																										},
																						data: this } });

			this.setOptions(options);
			}

	// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
			PeriodControl.prototype.buildTable		= function()
																								{
																								var i, qtr, j, row, yrs = [], yr = this.firstYear;

																								for (i = 0, qtr = 2; i < 8; i++, qtr = (++qtr % 4))
																									{
																									row = this.pickTable.body.appendRow();

																									if ((qtr == 0) || (i == 0))
																										{
																										yrs.push(row.appendCell({ content: yr, cssName: 'year' }));

																										if (qtr == 0) { row.cssName = 'newYear'; }
																										}
																									else { yrs.push(row.appendCell({ content: '', cssName: 'year-empty' })); }

																									row.appendCell({ content: 'Q' + (qtr + 1), cssName: 'quarter' });

																									for (j = 0; j <  3; j++) { row.appendCell({ content: Date.monthNames[ 3 * qtr + j], cssName: 'month' }); }
																									for (j = 1; j < 14; j++) { row.appendCell({ content: 13 * qtr + j }); }

																									if ((qtr == 3) && Date.isLongYear(yr++)) { row.appendCell({ content: 53 }); }
																																											else { row.appendCell({ content: '', disabled: true }); }
																									}

																								yrs[0].childCells = [yrs[1]];
																								yrs[2].childCells = [yrs[3], yrs[4], yrs[5]];
																								yrs[6].childCells = [yrs[7]];

																								yrs[1].parentCell = yrs[0];
																								yrs[3].parentCell = yrs[4].parentCell = yrs[5].parentCell = yrs[2];
																								yrs[7].parentCell = yrs[6];
																								};
	// ------------------------------------------------------------------------------------------------------------------------------------------------
			PeriodControl.prototype.create				= function()
																								{
																								this.$control = $('<div/>').addClass('pick-period').
																																						append( this.pickTable.create(),
																																										$('<div/>').addClass('icons-box').
																																																append(	this.prevYear.create(),
																																																				this.nextYear.create() ),
																																										$('<div/>').addClass('ctrls-box').
																																																append(	this.periodBox.create() ),
																																										$('<div/>').addClass('float-fix') );
																								this.setPeriodCell('first');
																								this.setPeriodCell('final');
																								this.markRange('add');

																								return this.$control;
																								};
	// ------------------------------------------------------------------------------------------------------------------------------------------------
			PeriodControl.prototype.destroy				= function()
																								{
																								this.$control.remove();
																								this.$control = this.finalCell = this.firstCell = null;
																								};
	// ------------------------------------------------------------------------------------------------------------------------------------------------
			PeriodControl.prototype.markRange			= function(mode)
																								{
																								var fc = this.firstCell, lc = this.finalCell;

																								if (fc.ctrl || lc && lc.ctrl)
																									{
																									var u = this.unitsInfo(fc.cellI), cp = { units: u.units };

																									if (!lc)
																										{
																										fc.ctrl.markClass(mode, this.cssRange);
																										cp.interval = 1;
																										}
																									else
																										{
																										var rows = this.pickTable.body.rows, r, rF, rL, cF, cL, marked;

																										if ((19 * fc.rowI + fc.cellI) > (19 * lc.rowI + lc.cellI)) { fc = this.finalCell; lc = this.firstCell; }

																										if (fc.rowI < 0) { rF = 0; cF = u.cMin; } else { rF = fc.rowI; cF = fc.cellI; }
																										if (lc.rowI > 7) { rL = 7; cL = u.cMax; } else { rL = lc.rowI; cL = lc.cellI; }

																										if (rF == rL) { marked = rows[rF].markRange(mode, this.cssRange, cF, cL); }
																										else
																											{
																											marked  = rows[rF].markRange(mode, this.cssRange, cF, u.cMax);

																											for (r = rF + 1; r < rL; r++) { marked += rows[r].markRange(mode, this.cssRange, u.cMin, u.cMax); }

																											marked += rows[rL].markRange(mode, this.cssRange, u.cMin, cL);
																											}

																										cp.interval = marked;
																										}

																									cp.firstYear   = this.firstYear + (fc.rowI + 2).intDiv(4);
																									cp.firstPeriod = ((fc.rowI + 2) % 4) * u.rMul + fc.cellI - u.cMin;

																									return cp;
																									}
																								else { return null; }
																								};
	// ------------------------------------------------------------------------------------------------------------------------------------------------
			PeriodControl.prototype.moveCell			= function(period, dir)
																								{
																								var fc = this[period + 'Cell'];

																								fc.rowI -= dir * (4 - 2 * ((fc.cellI == 0) && (fc.rowI - dir == 1)));

																								if ((fc.rowI >= 0) && (fc.rowI <= 7)) { fc.ctrl = this.pickTable.body.rows[fc.rowI].cells[fc.cellI]; }
																																								else 	{ fc.ctrl = null; }
																								};
	// ------------------------------------------------------------------------------------------------------------------------------------------------
			PeriodControl.prototype.moveYear			= function(dir)
																								{
																								this.markRange('remove');

																								this.moveCell('first', dir);
																								if (this.finalCell) { this.moveCell('final', dir); }

																								this.firstYear += dir;
																								var rows = this.pickTable.body.rows;

																								for (var i = 0, r = 0, w = 1; i < 3; i++, r += r + 2, w += 4)
																									{
																									rows[r].cells[0].setContent(this.firstYear + i);

																									if (i < 2)
																										{
																										var cel = rows[w].cells[18].disable(!Date.isLongYear(this.firstYear + i));

																										cel.setContent((cel.disabled) ? '' : 53);
																										}
																									}

																								this.markRange('add');
																								};
	// ------------------------------------------------------------------------------------------------------------------------------------------------
			PeriodControl.prototype.setOptions		= function(options)
																								{
																								var opts = options || {};

																								this.cssRange = opts.cssRange || 'block-picked';

																								this.periodBox = new PeriodboxControl(opts);
																								var val = this.value = this.periodBox.valCP,
																											d = val.finalYear - val.firstYear,
																											u = val.units,
																											p = val.firstPeriod;

																								this.firstYear = val.firstYear - ((d == 0) || ((u == 'yyyy') && (d <  2)) ||
																																															((u == 'q'   ) && (p <  2)) ||
																																															((u == 'm'   ) && (p <  6)) ||
																																															((u == 'ww'  ) && (p < 26)));

																								this.buildTable();
																								};
	// ------------------------------------------------------------------------------------------------------------------------------------------------
			PeriodControl.prototype.setPeriodCell	= function(period)
																								{
																								var val = this.value;

																								if (period == 'final' && val.interval == 1) { this.finalCell = null; }
																								else
																									{
																									var r = 4 * (val[period + 'Year'] - this.firstYear), c = 0;

																									if (val.units != 'yyyy')
																										{
																										var p = val[period + 'Period'];

																										switch (val.units)
																											{
																											case 'q'	: r += p; c = 1;
																																	break;

																											case 'm'	: r += p.intDiv(3); c = 2 + p % 3;
																																	break;

																											case 'ww'	: if (p == 52) { r += 3           ; c = 18; }
																																					else { r += p.intDiv(13); c =  5 + p % 13; }
																																	break;
																											}
																										}

																									this[period + 'Cell'] = { cellI: c, rowI: r - 2 };
																									if ((r >= 2) && (r <= 9)) { this[period + 'Cell'].ctrl = this.pickTable.body.rows[r - 2].cells[c]; }
																																			else	{ this[period + 'Cell'].ctrl = null; }
																									}
																								};
	// ------------------------------------------------------------------------------------------------------------------------------------------------
			PeriodControl.prototype.unitsInfo			= function(cellI)
																								{
																								if (cellI > 4) { return { units: 'ww', cMin: 5, cMax: 18, rMul: 13 }; } else
																								if (cellI > 1) { return { units:  'm', cMin: 2, cMax:  4, rMul:  3 }; } else
																								if (cellI > 0) { return { units:  'q', cMin: 1, cMax:  1, rMul:  1 }; } else
																														 { return { units: 'yyyy', cMin: 0, cMax:  0, rMul:  0 }; }
																								};
	// ________________________________________________________________________________________________________________________________________________


/* ================================================================================================================================================== PERIOD POPUP ====
*/
		function PeriodPopup(options)
			{
			this.setOptions(options);
			}

	// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
			PeriodPopup.prototype = new PopupControl();
			PeriodPopup.prototype.constructor = PeriodPopup;
	// ------------------------------------------------------------------------------------------------------------------------------------------------
			PeriodPopup.prototype.setOptions	= function(options)
																						{
																						var opts = options || {};

																						opts.showConfirm = true;
																						opts.content		 = new PeriodControl({ value: { firstDate	: opts.value.firstDate,
																																														interval	: opts.value.interval,
																																														units			: opts.value.units		} });

																						PopupControl.prototype.setOptions.call(this, opts);
																						};
	// ________________________________________________________________________________________________________________________________________________


/* ================================================================================================================================================== PERIOD NAVIGATOR ====
*/
		function PeriodNavigator(options)
			{
			this.periodBox = new PeriodboxControl(options);

			this.iconPrev	= new IconControl({ cssIcon	: 'icon-prev',
																				title		: 'Click to view the previous period',
																				onClick	: { act: function(data) { data.moveRange(-1); }, data: this.periodBox }
																				});

			this.iconNext	= new IconControl({ cssIcon	: 'icon-next',
																				title		: 'Click to view the next period',
																				onClick	: { act: function(data) { data.moveRange( 1); }, data: this.periodBox }
																				});
			}

	// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
			PeriodNavigator.prototype.create	= function()
																						{
																						this.$control  = $('<span/>').addClass('ctrl-nav-period').
																																					append( this.iconPrev.create(),
																																									this.periodBox.create(),
																																									this.iconNext.create() );
																						return this.$control;
																						};
	// ________________________________________________________________________________________________________________________________________________


/* ================================================================================================================================================== SELECTOR CONTROL ====
*/
		function SelectorControl(options)
			{
			this.setOptions(options);
			}

	// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
			SelectorControl.prototype = new IconControl();
			SelectorControl.prototype.constructor = SelectorControl;
	// ------------------------------------------------------------------------------------------------------------------------------------------------
			SelectorControl.prototype.attach			= function($ctrlIcon, $ctrlTxt, $ctrlVal)
																								{
																								if ($ctrlVal) { this.menu.deselectValue(this.value); }

																								ControlBase.prototype.attach.call(this, $ctrlIcon, $ctrlVal);
																								this.menu.target = this.$control;

																								if ($ctrlTxt) { this.textbox.attach($ctrlTxt).setValue(this.menu.getValueText(this.value)); }
																								if ($ctrlVal) { this.menu.selectValue(this.value); }

																								return this;
																								};
	// ------------------------------------------------------------------------------------------------------------------------------------------------
			SelectorControl.prototype.create			= function()
																								{
																								this.content = this.textbox.create();
																								IconControl.prototype.create.call(this);

																								return this.$control;
																								};
	// ------------------------------------------------------------------------------------------------------------------------------------------------
			SelectorControl.prototype.restore			= function() { this.setValue(this.backedValue); };
	// ------------------------------------------------------------------------------------------------------------------------------------------------
			SelectorControl.prototype.setOptions	= function(options)
																								{
																								var opts = options || {};

																								this.menu = new MenuPopup(
																																	{
																																	entries	: opts.entries,
																																	texts		: opts.texts,
																																	values	: opts.values,
																																	onOpen	: { act	: function(data) { this.content.$control.width(data.$control.outerWidth() - 2); },
																																							data: this },
																																	onSelect: { act	: function(data) { data.setValue(this.value, 'onSelect'); },
																																							data: this }
																																	});

																								this.textbox = new TextboxControl({ readOnly: true,
																																										size		: opts.size,
																																										value		: this.menu.getValueText(opts.value) });

																								opts.cssIcon	= 'icon-selector';
																								opts.title		= 'Click to select an option from a list';
																								opts.onClick	= { act	: function(data) { data.menu.show(); }, data: this };

																								IconControl.prototype.setOptions.call(this, opts);
																								this.menu.selectValue(this.value);
																								};
	// ------------------------------------------------------------------------------------------------------------------------------------------------
			SelectorControl.prototype.setValue		= function(value, eventName, ev)
																								{
																								this.menu.deselectValue(this.value);
																								this.backedValue = this.value;
																								this.textbox.setValue(this.menu.getValueText(value));

																								ControlBase.prototype.setValue.call(this, value, eventName, ev);
																								this.menu.selectValue(this.value);

																								return this.value;
																								};
	// ________________________________________________________________________________________________________________________________________________


/* ================================================================================================================================================== TEXTBOX POPUP ====
*/
		function TextboxPopup(options)
			{
			this.setOptions(options);
			}

	// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
			TextboxPopup.prototype = new PopupControl();
			TextboxPopup.prototype.constructor = TextboxPopup;
	// ------------------------------------------------------------------------------------------------------------------------------------------------
			TextboxPopup.prototype.onOpen			= { act: function() { this.content.$control.focus(); } };
	// ------------------------------------------------------------------------------------------------------------------------------------------------
			TextboxPopup.prototype.setOptions	= function(options)
																						{
																						var opts = options || {};

																						opts.content = new TextboxControl(opts);
																						opts.content.onChange = { act	: function(data, ev) { data.close('onConfirm', ev); }, data: this };

																						opts.preConfirm  = { act: function(data, ev) { data.content.setValue(data.content.$control.val()); }, data: this };
																						opts.showConfirm = true;

																						PopupControl.prototype.setOptions.call(this, opts);

																						this.iconConfirm.title = 'Click to submit your input (or press Enter on your keyboard)';
																						};
	// ________________________________________________________________________________________________________________________________________________


/* ================================================================================================================================================== VAT AMOUNT CONTROL ====
*/
		function VATAmountControl(options)
			{
			this.ctrlAmount = options.ctrlAmount;
			this.ctrlVAT    = options.ctrlVAT;

			this.$netAmount = options.$netAmount;
			this.$vatRate   = options.$vatRate;
			this.$txtAmount = this.ctrlAmount.$control.after($('<span/>')).next();

			this.ctrlVAT.onSelect = this.ctrlAmount.onChange =
				{
				act	: function(data, ev)
								{
								var vatRate = parseFloat(data.ctrlVAT.value),
										amount  = data.ctrlAmount.value;

								if (vatRate < 0)
									{
									vatRate = -vatRate;
									amount  = (amount * 100 / (100 + vatRate)).toFixed(2);
									data.$txtAmount.html('(&pound;' + amount + ' ex. VAT)');
									}
								else if (vatRate > 0)
									{
									data.$txtAmount.html('(&pound;' + (amount * (100 + vatRate) / 100).toFixed(2) + ' inc. VAT)');
									}
								else { data.$txtAmount.empty(); }

								data.$netAmount.val(amount);
								data.$vatRate.val(vatRate);
								},
				data: this
				};
			this.ctrlVAT.callEvent('onSelect');
			}
	// ________________________________________________________________________________________________________________________________________________


