/*  ------------------------------------------------------------------

MFF UI
Common User Interface Helpers

Dependencies:
- jquery

------------------------------------------------------------------ */

var MFF = {};


/*  ------------------------------------------------------------------

jQuery plugins

------------------------------------------------------------------ */

/*
 * 
 * TableSorter 2.0 - Client-side table sorting with ease!
 * Version 2.0.3
 * @requires jQuery v1.2.3
 * 
 * Copyright (c) 2007 Christian Bach
 * Examples and docs at: http://tablesorter.com
 * Dual licensed under the MIT and GPL licenses:
 * http://www.opensource.org/licenses/mit-license.php
 * http://www.gnu.org/licenses/gpl.html
 * 
 */
/**
 *
 * @description Create a sortable table with multi-column sorting capabilitys
 * 
 * @example $('table').tablesorter();
 * @desc Create a simple tablesorter interface.
 *
 * @example $('table').tablesorter({ sortList:[[0,0],[1,0]] });
 * @desc Create a tablesorter interface and sort on the first and secound column in ascending order.
 * 
 * @example $('table').tablesorter({ headers: { 0: { sorter: false}, 1: {sorter: false} } });
 * @desc Create a tablesorter interface and disableing the first and secound column headers.
 * 
 * @example $('table').tablesorter({ 0: {sorter:"integer"}, 1: {sorter:"currency"} });
 * @desc Create a tablesorter interface and set a column parser for the first and secound column.
 * 
 * 
 * @param Object settings An object literal containing key/value pairs to provide optional settings.
 * 
 * @option String cssHeader (optional) 			A string of the class name to be appended to sortable tr elements in the thead of the table. 
 * 												Default value: "header"
 * 
 * @option String cssAsc (optional) 			A string of the class name to be appended to sortable tr elements in the thead on a ascending sort. 
 * 												Default value: "headerSortUp"
 * 
 * @option String cssDesc (optional) 			A string of the class name to be appended to sortable tr elements in the thead on a descending sort. 
 * 												Default value: "headerSortDown"
 * 
 * @option String sortInitialOrder (optional) 	A string of the inital sorting order can be asc or desc. 
 * 												Default value: "asc"
 * 
 * @option String sortMultisortKey (optional) 	A string of the multi-column sort key. 
 * 												Default value: "shiftKey"
 * 
 * @option String textExtraction (optional) 	A string of the text-extraction method to use. 
 * 												For complex html structures inside td cell set this option to "complex", 
 * 												on large tables the complex option can be slow. 
 * 												Default value: "simple"
 * 
 * @option Object headers (optional) 			An array containing the forces sorting rules. 
 * 												This option let's you specify a default sorting rule. 
 * 												Default value: null
 * 
 * @option Array sortList (optional) 			An array containing the forces sorting rules. 
 * 												This option let's you specify a default sorting rule. 
 * 												Default value: null
 * 
 * @option Array sortForce (optional) 			An array containing forced sorting rules. 
 * 												This option let's you specify a default sorting rule, which is prepended to user-selected rules.
 * 												Default value: null
 *  
  * @option Array sortAppend (optional) 			An array containing forced sorting rules. 
 * 												This option let's you specify a default sorting rule, which is appended to user-selected rules.
 * 												Default value: null
 * 
 * @option Boolean widthFixed (optional) 		Boolean flag indicating if tablesorter should apply fixed widths to the table columns.
 * 												This is usefull when using the pager companion plugin.
 * 												This options requires the dimension jquery plugin.
 * 												Default value: false
 *
 * @option Boolean cancelSelection (optional) 	Boolean flag indicating if tablesorter should cancel selection of the table headers text.
 * 												Default value: true
 *
 * @option Boolean debug (optional) 			Boolean flag indicating if tablesorter should display debuging information usefull for development.
 *
 * @type jQuery
 *
 * @name tablesorter
 * 
 * @cat Plugins/Tablesorter
 * 
 * @author Christian Bach/christian.bach@polyester.se
 */

(function($) {
	$.extend({
		tablesorter: new function() {
			
			var parsers = [], widgets = [];
			
			this.defaults = {
				cssHeader: "header",
				cssAsc: "header-sort-up",
				cssDesc: "header-sort-down",
				sortInitialOrder: "asc",
				sortMultiSortKey: "shiftKey",
				sortForce: null,
				sortAppend: null,
				textExtraction: "simple",
				parsers: {}, 
				widgets: [],		
				widgetZebra: {css: ["even","odd"]},
				headers: {},
				widthFixed: false,
				cancelSelection: true,
				sortList: [],
				headerList: [],
				dateFormat: "dd-mm-yyyy",
				decimal: '.',
				debug: false
			};
			
			/* debuging utils */
			function benchmark(s,d) {
				log(s + "," + (new Date().getTime() - d.getTime()) + "ms");
			}
			
			this.benchmark = benchmark;
			
			function log(s) {
				if (typeof console != "undefined" && typeof console.debug != "undefined") {
					console.log(s);
				} else {
					alert(s);
				}
			}
						
			/* parsers utils */
			function buildParserCache(table,$headers) {
				
				if(table.config.debug) { var parsersDebug = ""; }
				
				var rows = table.tBodies[0].rows;
				
				if(table.tBodies[0].rows[0]) {

					var list = [], cells = rows[0].cells, l = cells.length;
					
					for (var i=0;i < l; i++) {
						var p = false;
						
						if($.metadata && ($($headers[i]).metadata() && $($headers[i]).metadata().sorter)  ) {
						
							p = getParserById($($headers[i]).metadata().sorter);	
						
						} else if((table.config.headers[i] && table.config.headers[i].sorter)) {
	
							p = getParserById(table.config.headers[i].sorter);
						}
						if(!p) {
							p = detectParserForColumn(table,cells[i]);
						}
	
						if(table.config.debug) { parsersDebug += "column:" + i + " parser:" +p.id + "\n"; }
	
						list.push(p);
					}
				}
				
				if(table.config.debug) { log(parsersDebug); }

				return list;
			};
			
			function detectParserForColumn(table,node) {
				var l = parsers.length;
				for(var i=1; i < l; i++) {
					if(parsers[i].is($.trim(getElementText(table.config,node)),table,node)) {
						return parsers[i];
					}
				}
				// 0 is always the generic parser (text)
				return parsers[0];
			}
			
			function getParserById(name) {
				var l = parsers.length;
				for(var i=0; i < l; i++) {
					if(parsers[i].id.toLowerCase() == name.toLowerCase()) {	
						return parsers[i];
					}
				}
				return false;
			}
			
			/* utils */
			function buildCache(table) {
				
				if(table.config.debug) { var cacheTime = new Date(); }
				
				
				var totalRows = (table.tBodies[0] && table.tBodies[0].rows.length) || 0,
					totalCells = (table.tBodies[0].rows[0] && table.tBodies[0].rows[0].cells.length) || 0,
					parsers = table.config.parsers, 
					cache = {row: [], normalized: []};
				
					for (var i=0;i < totalRows; ++i) {
					
						/** Add the table data to main data array */
						var c = table.tBodies[0].rows[i], cols = [];
					
						cache.row.push($(c));
						
						for(var j=0; j < totalCells; ++j) {
							cols.push(parsers[j].format(getElementText(table.config,c.cells[j]),table,c.cells[j]));	
						}
												
						cols.push(i); // add position for rowCache
						cache.normalized.push(cols);
						cols = null;
					};
				
				if(table.config.debug) { benchmark("Building cache for " + totalRows + " rows:", cacheTime); }
				
				return cache;
			};
			
			function getElementText(config,node) {
				
				if(!node) return "";
								
				var t = "";
				
				if(config.textExtraction == "simple") {
					if(node.childNodes[0] && node.childNodes[0].hasChildNodes()) {
						t = node.childNodes[0].innerHTML;
					} else {
						t = node.innerHTML;
					}
				} else {
					if(typeof(config.textExtraction) == "function") {
						t = config.textExtraction(node);
					} else { 
						t = $(node).text();
					}	
				}
				return t;
			}
			
			function appendToTable(table,cache) {
				
				if(table.config.debug) {var appendTime = new Date()}
				
				var c = cache, 
					r = c.row, 
					n= c.normalized, 
					totalRows = n.length, 
					checkCell = (n[0].length-1), 
					tableBody = $(table.tBodies[0]),
					rows = [];
				
				for (var i=0;i < totalRows; i++) {
					rows.push(r[n[i][checkCell]]);	
					if(!table.config.appender) {
						
						var o = r[n[i][checkCell]];
						var l = o.length;
						for(var j=0; j < l; j++) {
							
							tableBody[0].appendChild(o[j]);
						
						}
						
						//tableBody.append(r[n[i][checkCell]]);
					}
				}	
				
				if(table.config.appender) {
				
					table.config.appender(table,rows);	
				}
				
				rows = null;
				
				if(table.config.debug) { benchmark("Rebuilt table:", appendTime); }
								
				//apply table widgets
				applyWidget(table);
				
				// trigger sortend
				setTimeout(function() {
					$(table).trigger("sortEnd");	
				},0);
				
			};
			
			function buildHeaders(table) {
				
				if(table.config.debug) { var time = new Date(); }
				
				var meta = ($.metadata) ? true : false, tableHeadersRows = [];
			
				for(var i = 0; i < table.tHead.rows.length; i++) { tableHeadersRows[i]=0; };
				
				$tableHeaders = $("thead th",table);
		
				$tableHeaders.each(function(index) {
							
					this.count = 0;
					this.column = index;
					this.order = formatSortingOrder(table.config.sortInitialOrder);
					
					if(checkHeaderMetadata(this) || checkHeaderOptions(table,index)) this.sortDisabled = true;
					
					if(!this.sortDisabled) {
						$(this).addClass(table.config.cssHeader);
					}
					
					// add cell to headerList
					table.config.headerList[index]= this;
				});
				
				if(table.config.debug) { benchmark("Built headers:", time); log($tableHeaders); }
				
				return $tableHeaders;
				
			};
						
		   	function checkCellColSpan(table, rows, row) {
                var arr = [], r = table.tHead.rows, c = r[row].cells;
				
				for(var i=0; i < c.length; i++) {
					var cell = c[i];
					
					if ( cell.colSpan > 1) { 
						arr = arr.concat(checkCellColSpan(table, headerArr,row++));
					} else  {
						if(table.tHead.length == 1 || (cell.rowSpan > 1 || !r[row+1])) {
							arr.push(cell);
						}
						//headerArr[row] = (i+row);
					}
				}
				return arr;
			};
			
			function checkHeaderMetadata(cell) {
				if(($.metadata) && ($(cell).metadata().sorter === false)) { return true; };
				return false;
			}
			
			function checkHeaderOptions(table,i) {	
				if((table.config.headers[i]) && (table.config.headers[i].sorter === false)) { return true; };
				return false;
			}
			
			function applyWidget(table) {
				var c = table.config.widgets;
				var l = c.length;
				for(var i=0; i < l; i++) {
					
					getWidgetById(c[i]).format(table);
				}
				
			}
			
			function getWidgetById(name) {
				var l = widgets.length;
				for(var i=0; i < l; i++) {
					if(widgets[i].id.toLowerCase() == name.toLowerCase() ) {
						return widgets[i]; 
					}
				}
			};
			
			function formatSortingOrder(v) {
				
				if(typeof(v) != "Number") {
					i = (v.toLowerCase() == "desc") ? 1 : 0;
				} else {
					i = (v == (0 || 1)) ? v : 0;
				}
				return i;
			}
			
			function isValueInArray(v, a) {
				var l = a.length;
				for(var i=0; i < l; i++) {
					if(a[i][0] == v) {
						return true;	
					}
				}
				return false;
			}
				
			function setHeadersCss(table,$headers, list, css) {
				// remove all header information
				$headers.removeClass(css[0]).removeClass(css[1]);
				
				var h = [];
				$headers.each(function(offset) {
						if(!this.sortDisabled) {
							h[this.column] = $(this);					
						}
				});
				
				var l = list.length; 
				for(var i=0; i < l; i++) {
					h[list[i][0]].addClass(css[list[i][1]]);
				}
			}
			
			function fixColumnWidth(table,$headers) {
				var c = table.config;
				if(c.widthFixed) {
					var colgroup = $('<colgroup>');
					$("tr:first td",table.tBodies[0]).each(function() {
						colgroup.append($('<col>').css('width',$(this).width()));
					});
					$(table).prepend(colgroup);
				};
			}
			
			function updateHeaderSortCount(table,sortList) {
				var c = table.config, l = sortList.length;
				for(var i=0; i < l; i++) {
					var s = sortList[i], o = c.headerList[s[0]];
					o.count = s[1];
					o.count++;
				}
			}
			
			/* sorting methods */
			function multisort(table,sortList,cache) {
				
				if(table.config.debug) { var sortTime = new Date(); }
				
				var dynamicExp = "var sortWrapper = function(a,b) {", l = sortList.length;
					
				for(var i=0; i < l; i++) {
					
					var c = sortList[i][0];
					var order = sortList[i][1];
					var s = (getCachedSortType(table.config.parsers,c) == "text") ? ((order == 0) ? "sortText" : "sortTextDesc") : ((order == 0) ? "sortNumeric" : "sortNumericDesc");
					
					var e = "e" + i;
					
					dynamicExp += "var " + e + " = " + s + "(a[" + c + "],b[" + c + "]); ";
					dynamicExp += "if(" + e + ") { return " + e + "; } ";
					dynamicExp += "else { ";
				}
				
				// if value is the same keep orignal order	
				var orgOrderCol = cache.normalized[0].length - 1;
				dynamicExp += "return a[" + orgOrderCol + "]-b[" + orgOrderCol + "];";
						
				for(var i=0; i < l; i++) {
					dynamicExp += "}; ";
				}
				
				dynamicExp += "return 0; ";	
				dynamicExp += "}; ";	
				
				eval(dynamicExp);
				
				cache.normalized.sort(sortWrapper);
				
				if(table.config.debug) { benchmark("Sorting on " + sortList.toString() + " and dir " + order+ " time:", sortTime); }
				
				return cache;
			};
			
			function sortText(a,b) {
				return ((a < b) ? -1 : ((a > b) ? 1 : 0));
			};
			
			function sortTextDesc(a,b) {
				return ((b < a) ? -1 : ((b > a) ? 1 : 0));
			};	
			
	 		function sortNumeric(a,b) {
				return a-b;
			};
			
			function sortNumericDesc(a,b) {
				return b-a;
			};
			
			function getCachedSortType(parsers,i) {
				return parsers[i].type;
			};
			
			/* public methods */
			this.construct = function(settings) {

				return this.each(function() {
					
					if(!this.tHead || !this.tBodies) return;
					
					var $this, $document,$headers, cache, config, shiftDown = 0, sortOrder;
					
					this.config = {};
					
					config = $.extend(this.config, $.tablesorter.defaults, settings);
					
					// store common expression for speed					
					$this = $(this);
					
					// build headers
					$headers = buildHeaders(this);
					
					// try to auto detect column type, and store in tables config
					this.config.parsers = buildParserCache(this,$headers);
					
					
					// build the cache for the tbody cells
					cache = buildCache(this);
					
					// get the css class names, could be done else where.
					var sortCSS = [config.cssDesc,config.cssAsc];
					
					// fixate columns if the users supplies the fixedWidth option
					fixColumnWidth(this);
					
					// apply event handling to headers
					// this is to big, perhaps break it out?
					$headers.click(function(e) {
						
						$this.trigger("sortStart");
						
						var totalRows = ($this[0].tBodies[0] && $this[0].tBodies[0].rows.length) || 0;
						
						if(!this.sortDisabled && totalRows > 0) {
							
							
							// store exp, for speed
							var $cell = $(this);
	
							// get current column index
							var i = this.column;
							
							// get current column sort order
							this.order = this.count++ % 2;
							
							// user only whants to sort on one column
							if(!e[config.sortMultiSortKey]) {
								
								// flush the sort list
								config.sortList = [];
								
								if(config.sortForce != null) {
									var a = config.sortForce; 
									for(var j=0; j < a.length; j++) {
										if(a[j][0] != i) {
											config.sortList.push(a[j]);
										}
									}
								}
								
								// add column to sort list
								config.sortList.push([i,this.order]);
							
							// multi column sorting
							} else {
								// the user has clicked on an all ready sortet column.
								if(isValueInArray(i,config.sortList)) {	 
									
									// revers the sorting direction for all tables.
									for(var j=0; j < config.sortList.length; j++) {
										var s = config.sortList[j], o = config.headerList[s[0]];
										if(s[0] == i) {
											o.count = s[1];
											o.count++;
											s[1] = o.count % 2;
										}
									}	
								} else {
									// add column to sort list array
									config.sortList.push([i,this.order]);
								}
							};
							setTimeout(function() {
								//set css for headers
								setHeadersCss($this[0],$headers,config.sortList,sortCSS);
								appendToTable($this[0],multisort($this[0],config.sortList,cache));
							},1);
							// stop normal event by returning false
							return false;
						}
					// cancel selection	
					}).mousedown(function() {
						if(config.cancelSelection) {
							this.onselectstart = function() {return false};
							return false;
						}
					});
					
					// apply easy methods that trigger binded events
					$this.bind("update",function() {
						
						// rebuild parsers.
						this.config.parsers = buildParserCache(this,$headers);
						
						// rebuild the cache map
						cache = buildCache(this);
						
					}).bind("sorton",function(e,list) {
						
						$(this).trigger("sortStart");
						
						config.sortList = list;
						
						// update and store the sortlist
						var sortList = config.sortList;
						
						// update header count index
						updateHeaderSortCount(this,sortList);
						
						//set css for headers
						setHeadersCss(this,$headers,sortList,sortCSS);
						
						
						// sort the table and append it to the dom
						appendToTable(this,multisort(this,sortList,cache));

					}).bind("appendCache",function() {
						
						appendToTable(this,cache);
					
					}).bind("applyWidgetId",function(e,id) {
						
						getWidgetById(id).format(this);
						
					}).bind("applyWidgets",function() {
						// apply widgets
						applyWidget(this);
					});
					
					if($.metadata && ($(this).metadata() && $(this).metadata().sortlist)) {
						config.sortList = $(this).metadata().sortlist;
					}
					// if user has supplied a sort list to constructor.
					if(config.sortList.length > 0) {
						$this.trigger("sorton",[config.sortList]);	
					}
					
					// apply widgets
					applyWidget(this);
				});
			};
			
			this.addParser = function(parser) {
				var l = parsers.length, a = true;
				for(var i=0; i < l; i++) {
					if(parsers[i].id.toLowerCase() == parser.id.toLowerCase()) {
						a = false;
					}
				}
				if(a) { parsers.push(parser); };
			};
			
			this.addWidget = function(widget) {
				widgets.push(widget);
			};
			
			this.formatFloat = function(s) {
				var i = parseFloat(s);
				return (isNaN(i)) ? 0 : i;
			};
			this.formatInt = function(s) {
				var i = parseInt(s);
				return (isNaN(i)) ? 0 : i;
			};
			
			this.isDigit = function(s,config) {
				var DECIMAL = '\\' + config.decimal;
				var exp = '/(^[+]?0(' + DECIMAL +'0+)?$)|(^([-+]?[1-9][0-9]*)$)|(^([-+]?((0?|[1-9][0-9]*)' + DECIMAL +'(0*[1-9][0-9]*)))$)|(^[-+]?[1-9]+[0-9]*' + DECIMAL +'0+$)/';
				return RegExp(exp).test($.trim(s));
			};
			
			this.clearTableBody = function(table) {
				if($.browser.msie) {
					function empty() {
						while ( this.firstChild ) this.removeChild( this.firstChild );
					}
					empty.apply(table.tBodies[0]);
				} else {
					table.tBodies[0].innerHTML = "";
				}
			};
		}
	});
	
	// extend plugin scope
	$.fn.extend({
        tablesorter: $.tablesorter.construct
	});
	
	var ts = $.tablesorter;
	
	// add default parsers
	ts.addParser({
		id: "text",
		is: function(s) {
			return true;
		},
		format: function(s) {
			return $.trim(s.toLowerCase());
		},
		type: "text"
	});
	
	ts.addParser({
		id: "digit",
		is: function(s,table) {
			var c = table.config;
			return $.tablesorter.isDigit(s,c);
		},
		format: function(s) {
			return $.tablesorter.formatFloat(s);
		},
		type: "numeric"
	});
	
	ts.addParser({
		id: "currency",
		is: function(s) {
			return /^[Â£$â‚¬?.]/.test(s);
		},
		format: function(s) {
			return $.tablesorter.formatFloat(s.replace(new RegExp(/[^0-9.]/g),""));
		},
		type: "numeric"
	});
	
	ts.addParser({
		id: "ipAddress",
		is: function(s) {
			return /^\d{2,3}[\.]\d{2,3}[\.]\d{2,3}[\.]\d{2,3}$/.test(s);
		},
		format: function(s) {
			var a = s.split("."), r = "", l = a.length;
			for(var i = 0; i < l; i++) {
				var item = a[i];
			   	if(item.length == 2) {
					r += "0" + item;
			   	} else {
					r += item;
			   	}
			}
			return $.tablesorter.formatFloat(r);
		},
		type: "numeric"
	});
	
	ts.addParser({
		id: "url",
		is: function(s) {
			return /^(https?|ftp|file):\/\/$/.test(s);
		},
		format: function(s) {
			return jQuery.trim(s.replace(new RegExp(/(https?|ftp|file):\/\//),''));
		},
		type: "text"
	});
	
	ts.addParser({
		id: "isoDate",
		is: function(s) {
			return /^\d{4}[\/-]\d{1,2}[\/-]\d{1,2}$/.test(s);
		},
		format: function(s) {
			return $.tablesorter.formatFloat((s != "") ? new Date(s.replace(new RegExp(/-/g),"/")).getTime() : "0");
		},
		type: "numeric"
	});
		
	ts.addParser({
		id: "percent",
		is: function(s) { 
			return /\%$/.test($.trim(s));
		},
		format: function(s) {
			return $.tablesorter.formatFloat(s.replace(new RegExp(/%/g),""));
		},
		type: "numeric"
	});

	ts.addParser({
		id: "usLongDate",
		is: function(s) {
			return s.match(new RegExp(/^[A-Za-z]{3,10}\.? [0-9]{1,2}, ([0-9]{4}|'?[0-9]{2}) (([0-2]?[0-9]:[0-5][0-9])|([0-1]?[0-9]:[0-5][0-9]\s(AM|PM)))$/));
		},
		format: function(s) {
			return $.tablesorter.formatFloat(new Date(s).getTime());
		},
		type: "numeric"
	});
	/*
	ts.addParser({
		id: "shortDate",
		is: function(s) {
			return /\d{1,2}[\/\-]\d{1,2}[\/\-]\d{2,4}/.test(s);
		},
		format: function(s,table) {
			var c = table.config;
			s = s.replace(/\-/g,"/");
			if(c.dateFormat == "us") {
				// reformat the string in ISO format
				s = s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{4})/, "$3/$1/$2");
			} else if(c.dateFormat == "uk") {
				//reformat the string in ISO format
				s = s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{4})/, "$3/$2/$1");
			} else if(c.dateFormat == "dd/mm/yy" || c.dateFormat == "dd-mm-yy") {
				s = s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{2})/, "$1/$2/$3");	
			}
			return $.tablesorter.formatFloat(new Date(s).getTime());
		},
		type: "numeric"
	});
	*/
	ts.addParser({
		id: "shortDate",
		is: function(s) {
			return /\d{1,2}[\/-]\d{1,2}[\/-]\d{2,4}/.test(s);
		},
		format: function(s,table) {
			var c = table.config;
			s = s.replace(new RegExp(/-/g),"/");
			if(c.dateFormat == "mm/dd/yyyy" || c.dateFormat == "mm-dd-yyyy") {
				/** reformat the string in ISO format */
				s = s.replace(new RegExp(/(\d{1,2})[\/-](\d{1,2})[\/-](\d{4})/), "$3/$1/$2");
			} 
			else if(c.dateFormat == "dd/mm/yyyy" || c.dateFormat == "dd-mm-yyyy") {
				/** reformat the string in ISO format */
				s = s.replace(new RegExp(/(\d{1,2})[\/-](\d{1,2})[\/-](\d{4})/), "$3/$2/$1");
			} 
			else if(c.dateFormat == "dd/mm/yy" || c.dateFormat == "dd-mm-yy") {
				s = s.replace(new RegExp(/(\d{1,2})[\/-](\d{1,2})[\/-](\d{2})/), "$1/$2/$3");   
			}
			return $.tablesorter.formatFloat(new Date(s).getTime());
		},
		type: "numeric"
	}); 
	

	ts.addParser({
	    id: "time",
	    is: function(s) {
	        return /^(([0-2]?[0-9]:[0-5][0-9])|([0-1]?[0-9]:[0-5][0-9]\s(am|pm)))$/.test(s);
	    },
	    format: function(s) {
	        return $.tablesorter.formatFloat(new Date("2000/01/01 " + s).getTime());
	    },
	  type: "numeric"
	});
	
	
	ts.addParser({
	    id: "metadata",
	    is: function(s) {
	        return false;
	    },
	    format: function(s,table,cell) {
			var c = table.config, p = (!c.parserMetadataName) ? 'sortValue' : c.parserMetadataName;
	        return $(cell).metadata()[p];
	    },
	  type: "numeric"
	});
	
	// add default widgets
	ts.addWidget({
		id: "zebra",
		format: function(table) {
			if(table.config.debug) { var time = new Date(); }
			$("tr:visible",table.tBodies[0])
	        .filter(':even')
	        .removeClass(table.config.widgetZebra.css[1]).addClass(table.config.widgetZebra.css[0])
	        .end().filter(':odd')
	        .removeClass(table.config.widgetZebra.css[0]).addClass(table.config.widgetZebra.css[1]);
			if(table.config.debug) { $.tablesorter.benchmark("Applying Zebra widget", time); }
		}
	});	
})(jQuery);


/* ------------------------------------------------------------------

Check if DOM has finished loading

------------------------------------------------------------------ */

$(function() {

	/* ------------------------------------------------------------------

	Current language

	------------------------------------------------------------------ */

	(function getCurrentLang() {
		MFF.CURRENT_LANGUAGE = $('html').attr('lang');
	})();
	
	/* ------------------------------------------------------------------

	Video and audio player functions

	------------------------------------------------------------------ */

	MFF.Players = function() {

		var VIDEOPLAYER = document.getElementById('video-player'),
			AUDIOPLAYER = document.getElementById('audio-player'),
			SELECTED_TRACK,
			PLAYLIST,
			CALLBACK,
			PLAYLIST_ITEMS = [],
			TIMEOUT_ID,
			ITEM_CHANGED = true,
			CURRENT_ID,
			CURRENT_STATE,
			PREVIOUS_STATE;
		
		function createAudioPlayer() {
			
			// Audio player configuration
			var audioXmlFileName = null,
				frontpage = 0,
				audioFlashvars = {
					file: '/flashfiles/'+ AUDIOPLAYER.className.split('player-for-')[1] +'.xml',
					displayheight: '0',
					autostart: 'false',
					height: '90',
					thumbsinplaylist: 'false',
					width: '570',
					frontcolor: '0xffffff',
					autostart: 'false',
					backcolor: '0x000000',
					lightcolor: '0xcccccc',
					repeat: 'list',
					callback: '/flashfiles/mffstat.cfm?frontpage=' + ((document.getElementById('mff').className === 'mff-frontpage') ? 1 : 0) + ''
				},
				audioParams = {
					allowfullscreen:'false'
				};

			swfobject.embedSWF('/flashfiles/mp3player2.swf', AUDIOPLAYER.id, audioFlashvars.width, audioFlashvars.height, '7','false', audioFlashvars, audioParams);
		}
		
		function createVideoPlayer() {
			
			PLAYLIST = '/flashfiles/videofiles/videos_'+ VIDEOPLAYER.className.split('band-')[1].split(' ')[0] +'.xml';
			//CALLBACK = setCallBack(VIDEOPLAYER.className.split('videoid-')[1].split(' ')[0]);

			$.ajax({
				type: 'GET',
				url: PLAYLIST,
				dataType: 'xml',
				success: function(xml){
					
					// can't get player to return id (<identifier>). Build new playlist instead
					$('track',xml).each(function(i){
						PLAYLIST_ITEMS.push({index: i, id: $(this).find('identifier').text()});
					});
						
					// Video player configuration
					var videoXmlFileName = 0,
						videoFlashvars = {
							file: PLAYLIST,  
							width: '550',					
							frontcolor: 'ffffff',
							backcolor: '000000',
							lightcolor: 'ffffff',
							repeat: 'list',
							height: '600',
							playlist: 'bottom',
							playlistsize: '180',
							autostart: false
						},
						videoParams = {
							allowscriptaccess:'always',
							allowfullscreen:'true'
						},
						counter = 0,
						interval;

					// get track 
					SELECTED_TRACK = VIDEOPLAYER.className.split('track-')[1].split(' ')[0].toString() || null;
			
					// create player
					swfobject.embedSWF('/flashfiles/player.swf', VIDEOPLAYER.id, videoFlashvars.width, videoFlashvars.height, '9.0.115','false', videoFlashvars, videoParams);
					
					// kludge - trying to circumvent loading issues with player & playlist
					interval = window.setInterval(function () {
						
						counter += 1;

						if($('#video-player').length > 0 && document.getElementById('video-player').getPlaylist() !== null) {
							window.clearInterval(interval);
							MFF.Players.PlayTrack();
						}
						if(counter === 15) {
							window.clearInterval(interval);
							return;
						}
					
					},500)
						
				},
				error: function(msg){
					
					VIDEOPLAYER.innerHTML = 'An error occurred while loading the video. Sorry.';
				
				}
			 });
			
		}
		
		function stateListener(obj) { //IDLE, BUFFERING, PLAYING, PAUSED, COMPLETED
	
			CURRENT_STATE = obj.newstate,
			PREVIOUS_STATE = obj.oldstate; 
		
			/*
			if ((currentState == "COMPLETED")&&(previousState == "PLAYING")) {
				
			}*/
			
		}

		function playTrack() {
		
			var player = document.getElementById('video-player'), 
				playList = player.getPlaylist() || null,
				i;

			// load playlist to player
			if(playList === null) {	
				player.sendEvent('LOAD',PLAYLIST);
				playList = player.getPlaylist();
			}

			// add listener for item changes
			player.addControllerListener("ITEM", "MFF.Players.ItemListener");
			player.addModelListener("STATE", "MFF.Players.StateListener");
			//player.addModelListener("TIME", "MFF.Players.StateListener");

			// If no track is selected (Url ends with /bandname/videos/ don't start playing any tracks nor send statistics data
			if(SELECTED_TRACK === null) {
				return;
			}
			
			// match item from playlist
			for(i=0; i < playList.length; i++) {
			
				if (playList[i].file === SELECTED_TRACK) {
					player.sendEvent('ITEM',i);
					break;
				}
			
			}

		}

		function itemListener(obj) {

			// fired on track changes

			// clear all previus timeouts if timeout is set
			if (typeof TIMEOUT_ID !== 'undefined') {
				
				window.clearTimeout(TIMEOUT_ID);
				
				// check if video has changed 
				if (CURRENT_ID !== PLAYLIST_ITEMS[obj.index].id) {
					ITEM_CHANGED = true;
				}
				else {
					
					// the player seems bugged. 
					//If you click again on a video that was not found on youtube no other videos will work. 
					// Trying to circumvent the issue here by reloading the page if the video is still in 'buffering' state when the same item is clicked again
					if(CURRENT_STATE === 'BUFFERING') {
						window.location.reload();
					}
					
				}

			}

			// log stats after video has played for 30 secounds
			if(ITEM_CHANGED) {
			
				ITEM_CHANGED = false;
				CURRENT_ID = PLAYLIST_ITEMS[obj.index].id;
				
				TIMEOUT_ID = window.setTimeout(function(){
					
					// log stats
					$.get('/flashfiles/vidstat.cfm?id='+CURRENT_ID);
					
					// clear timeout
					window.clearTimeout(TIMEOUT_ID);	
					
				},30000);
			
			}
			
			/*
			var d = document.location.href,
				re = d.substring(d.lastIndexOf('/'),d.length);
		
			d.replace(re,'/' + PLAYLIST_ITEMS[obj.index].id);
			*/

		}
		
		function init() {
						
			if(VIDEOPLAYER) {
				createVideoPlayer();

			}
			if(AUDIOPLAYER) {
				createAudioPlayer();
			}
			
		}
		
		return {
			
			Init: function() {
				return init();
			},
			PlayTrack: function() {
				return playTrack();
			},
			ItemListener: function(obj) {
				return itemListener(obj);
			},
			StateListener: function(obj) {
				return stateListener(obj);
			}
			
		}

	}();
	
	/* ------------------------------------------------------------------

	Internalization methods

	------------------------------------------------------------------ */	

	MFF.i18n = {

		dictionary: {	
			
			/* ------------------------------------------------------------------
				
				
				
			------------------------------------------------------------------ */
			
			all: {
				'en': 'Everything',
				'fi': 'Kaikki'
			},
			next: {
				'en': 'next',
				'fi': 'seuraavat',
				'en plural': 'next',
				'fi plural': 'seuraavat'
			},
			prev: {
				'en': 'previous',
				'fi': 'edelliset',
				'en plural': 'previous',
				'fi plural': 'edelliset'
			},
			loading: {
				'en': 'Loading..',
				'fi': 'Lataan...'
			},
			email_not_valid: {
				'en': 'Your email address is not valid',
				'fi': 'Sähköpostiosoitteesi on virheellinen'
			},
			clear_search: {
				'en': 'Clear search field',
				'fi':'Tyhjennä haku'
			},
			photos_provided_by_flickr: {
				'en': 'Photos provided by Flickr',
				'fi': 'Kuvat tarjoaa Flickr'
			}
			
		},
		
		translate: function(key) {
		
			/* ------------------------------------------------------------------
						
						
						
			------------------------------------------------------------------ */
			
			return MFF.i18n.dictionary[key] ? MFF.i18n.dictionary[key][MFF.CURRENT_LANGUAGE] : 'TRANSLATION NOT FOUND';
			
		},
		
		pluralize: function(key, number) {
			
			/* ------------------------------------------------------------------
								
								
								
			------------------------------------------------------------------ */
		
			return MFF.i18n.dictionary[key][MFF.CURRENT_LANGUAGE_ID + (number != 0 ? ' plural' : '')];
			
		}
		
	};

	/* ------------------------------------------------------------------

	General UI funcitons

	------------------------------------------------------------------ */
	
	MFF.ui = {

		initTopSearchEvents: function() {

			/* ------------------------------------------------------------------

			Top search

			------------------------------------------------------------------ */

			var searchLabel = $('#search label:first');
			searchLabel.addClass('hide');

			var searchTextBox = $('#search input:first');
			var defaultValue = searchLabel.text();

			searchTextBox.val(defaultValue);
			
			// IE Bugfix 
			searchTextBox.bind('click', function() {
				searchTextBox.focus();	
			});
			
			searchTextBox.bind('focus', function() {
				if(searchTextBox.val() == defaultValue)
					searchTextBox.val('');	
			});
			searchTextBox.bind('keyup', function() {

				if(searchTextBox.val() != 0 && searchTextBox.val() != defaultValue && $('#clear-search').length == 0) {

					$('#search button:last').after('<a href="#" class="help" id="clear-search" title="' + MFF.i18n.translate('clear_search') + '"></a>');
					searchTextBox.addClass('clearable');

					//MFF.ui.helpTooltips();

					$('#clear-search').bind('click', function() {

						searchTextBox.val('');
						$(this).remove();
						searchTextBox.removeClass('clearable');
						searchTextBox.focus();

						//$('.tooltip').remove();

						return false;

					});

				}
				else if(searchTextBox.val() == 0)
					removeClearSearch(searchTextBox);

			});
			searchTextBox.bind('blur', function() {
				if(searchTextBox.val() == 0) {
					searchTextBox.val(defaultValue);
					removeClearSearch(searchTextBox);
				}
			});

			function removeClearSearch(el) {
				if($('#clear-search').length) {
					$('#clear-search').remove();
					el.removeClass('clearable');
					$('.tooltip').remove();
				}
			}
		},

		createBoxedElements: function() {

			/* ------------------------------------------------------------------

			Create HTML for rounded corners where needed

			------------------------------------------------------------------ */
			
			function createHTML() {
				
				/* Extra containers for boxed elements */
				if($(this).hasClass('boxed'))
					$(this).wrapInner('<div class="highlight_body_outer_container"><div class="highlight_body_inner_container"><div class="highlight_body"></div></div></div>');
				else
					$(this).wrapInner('<div class="highlight_body"></div>');
					
				$(this).prepend('<div class="highlight_head"><span></span></div>');
				
				/* No footer for search */
				if(!$(this).hasClass('search'))
					$(this).append('<div class="highlight_foot"><span></span></div>');
				
			}
			
			/* Navigation */
			$('#navigation').addClass('enhance');
			$('#navigation > li').each(function () {	
				$(this).prepend('<span class="highlight_head"><span></span></span>');
				//if($.browser.msie)
				//	$(this).parent().append('<span class="ie-fix"></span>');
			});
			
			$('#navigation > li a').each(function () {	
				$(this).html('<span>' + $(this).html() + '</span>');
			});
			
			/* Search */
			$('#search').addClass('enhance');
			$('#search .highlight').addClass('enhance');
			$('#search .enhance').each(createHTML);
			
			/* Sitemap */
			$('#sitemap').addClass('enhance');
			$('#sitemap').each(createHTML);

			/* Highlights */
			$('#content div.highlight').addClass('highlight-enhanced').each(createHTML);

		},

		initPagination: function() {

			/* ------------------------------------------------------------------

			Paginate list when CSS class 'paginated' is present

			 -> Pagenumbers added quick & dirty - needs refactoring

			------------------------------------------------------------------ */
			
			if($('#content ol.paginated').length == 0)
				return;
			
			function toggleList(id, dir, count) {

				var list = document.getElementById(id);
				var items = list.getElementsByTagName('li');

				var index = list.index;

				if (!index)
					index = 0;

				index += dir;

				if (index < 0)
					index = 0;
				else if (index >= items.length / count)
					index = Math.floor(items.length / count);

				var first = index * count;
				var last = first + count;

				for (var i=0; i < items.length; i++)
					items[i].style.display = (i < first || i >= last)?'none':'block';

				/* current page  */
				$('#pages_' + id + ' a').each(function () {	
					(parseInt($(this).attr('href').split('_page')[1]) != index + 1) ? $(this).removeClass('current') : $(this).addClass('current');
				});

				/* change page */
				$('#pages_' + id).unbind('click');
				$('#pages_' + id).bind('click', function(e) {

					if($(e.target).is('a')) {

						var page = parseInt($(e.target).attr('href').split('_page')[1]);
						index += 1;
						dir = page-index;
						toggleList(id,dir,count);
						return false;

					}

				});

				list.index = index;

				/* toggle next / prev visibility */
				document.getElementById(id + '_page_prev').style.display = (index == 0) ? 'none' : 'inline';
				document.getElementById(id + '_page_next').style.display = (items.length <= last) ? 'none' : 'inline';

			};

			$('#content ol.paginated').each(function () {	
			
				var list = this; //lists[i];
				var id = this.id; //list.id
				var items = list.getElementsByTagName('li');
				var count = 4; // items per page

				var p = items.nextSibling;
				while (p) {
					if (p.nodeType == 1 && p.tagName.toLowerCase() == 'p')
						break;
					p = p.nextSibling;
				}
				if(!p && list.nextSibling.className != 'pagination'){

					p = $('<p class="pagination"></p>');
					(list == list.parentNode.lastChild)?p.appendTo(list):p.insertAfter(list);

					/* prev */
					var a = $('<a href="#" id="' + id + '_page_prev' +'">' + MFF.i18n.translate('prev') +'</a> ');
					a.appendTo(p);

					a.bind('click', function(e) {
						var parent = e.target.parentNode.previousSibling;

						while(parent.tagName.toLowerCase() != 'ol')
							parent = tp.previousSibling;

						var id = parent.id;
						toggleList(id, -1, count); 
						return false;
					});

					p.append(' ');

					/* pagination */
					var pages =  Math.ceil(items.length / count);
					var pagination = $('<span id="' + 'pages_' + id +'"></span>');
					pagination.appendTo(p);	

					for(var j=0; j < pages; j++)
						pagination.append('<a href="#' + id + '_page' + (j+1) +'">' + (j+1) + '</a>' + ((pages > j+1)?' | ':' '));

					/* next */
					a = $('<a href="#" id="' + id + '_page_next' +'">' + MFF.i18n.translate('next') +'</a>');
					a.appendTo(p);

					a.bind('click', function(e) {
						var parent = e.target.parentNode.previousSibling;

						while(parent.tagName.toLowerCase() != 'ol')
							parent = parent.previousSibling;

						var id = parent.id;
						toggleList(id, 1, count); 
						return false;
					});

				}
				toggleList(id, 0, count);

			});

		},
		
		initTabbedContent: function() {
		
			/* ------------------------------------------------------------------



			------------------------------------------------------------------ */
			
			if($('.tabs').length == 0)
				return;
			
			/* Bind click event to tab anchors */
			$('.tabs').bind('click', function(e) {

				if($(e.target).is('a')) {
					MFF.ui.togglePage($(e.target), $(this));
					return false;
				}

			});
			
			/* */
			$('.paginated').addClass('group');

			/* Set seleted tab from url */
			var origUrl = document.location.href.split('#');
			var url = origUrl[1];
			var base;

			if(url && url != 'undefined') {

				/* multiple pages definded in url by comma */
				if(url.match(',')) {
					url = url.split(',');
					base = url[0];
				}

				if(typeof(url) != 'object')
					url = [url];

				/* no more than 5 tabsgroups per page */
				if(url.length > 5)
					return;

				$('.tabs').find('a').each(function(i) {

					for(var i=0; i<url.length; i++) {

						if($(this).attr('href').toString().split('#')[1] == url[i]) {
							MFF.ui.togglePage($(this), $(this).parent().parent());
							$(this).focus();
							break;
						}

					}

				});

				/* modify url if multiple pages are defined to take focus to the first anchor defined  */
				if(base && base != 'undefined') {

					document.location.href = origUrl[0] + '#' + base;

				}

			}

		}, 

		togglePage: function (obj, parent) {
		
			/* ------------------------------------------------------------------

			

			------------------------------------------------------------------ */

			var id = obj.attr('href').substring(obj.attr('href').indexOf('#') + 1);
			var activePage = $('#' + id);

			if(activePage.length == 0 || activePage.length > 1)
				return;

			var activeCssClass = 'current-page';
			var containerClass = 'pages';

			parent.find('li').removeClass(activeCssClass);
			obj.parent().addClass(activeCssClass);

			var match = /\bgroup-\S+\b/.exec(activePage.attr('className'));

			if(!match)
				return;

			$('.' + containerClass + ' ' + activePage.attr('tagName')).each(function() {

				if($(this).hasClass(match[0])) {

					if ($(this).attr('id') == id) {
						$(this).addClass(activeCssClass);
						
						/* IE6 bug fix*/
						if($.browser.msie && $.browser.version <= 6) {
							$(this).find('.list').attr('style','min-height: 1%;');
						}
							
					}
					else {
						$(this).removeClass(activeCssClass);
					}

				}
				
				

			});

		},
		initTabbedFiltering: function() {
		
			/* ------------------------------------------------------------------



			------------------------------------------------------------------ */
			
			if($('.tabs-sortable').length == 0)
				return;
			
			function oc(a)
			{
			  var o = {};
			  for(var i=0;i<a.length;i++)
			  {
			    o[a[i]]='';
			  }
			  return o;
			}
			
			/* everything tab */
			var tabs = '<li class="current-page"><a href="#" class="all">' + MFF.i18n.translate('all') + '</a></li>';
			var names = [];
			
			$('.tabs-sortable li').each(function(i){
				
				var css = $(this).attr('class');
				
				if(css in oc(names) == false) {
					names.push(css);
					tabs += '<li><a href="#" class="'+ css +'">' + css + '</a></li>';
				}
					
			});
			
			/* tabs container */
			$('.tabs-sortable').before('<ul class="tabs tabs-sorting">' + tabs + '</ul>');
		
			/* bind created tabs click event */
			$('.tabs-sorting').bind('click', function(e){
				
				if($(e.target).is('a')) {
					
					/* selected type */
					var css = '.' + $(e.target).attr('class');
					
					if(css != '.all') {
					
						/* current active tab */
						$(this).find('li').removeClass('current-page');
						$(e.target).parent().addClass('current-page');

						$(this).next().find('li').hide();
						$(this).next().find('.row').show();
						$(this).next().find(css).show();

						$(this).next().find('.row').each(function(){

							/* hide rows if all links are hidden */
							if($(this).find('li:hidden').length == $(this).find('li').length && $(this).find('li:hidden').length > 0)
								$(this).hide();

						});
					
					}
					else {
						
						/* current active tab */
						$(this).find('li').removeClass('current-page');
						$(e.target).parent().addClass('current-page');
					
						/* show rows and items */
						$(this).next().find('.row').show();
						$(this).next().find('li').show();
					}
					
				}
				return false;
			
			});
			
			
			
		},
		stripeTables: function() {

			/* ------------------------------------------------------------------

			Zebra Striping for tables

			------------------------------------------------------------------ */

			if($('table.stripe').length == 0)
				return;
			
			$('table.stripe tr').bind('mouseover', function(){$(this).addClass('over');}).bind('mouseout', function(){$(this).removeClass('over');});
			$('table.stripe tr:even').addClass('even');
			
		},
		helpTooltips: function() {

			/* ------------------------------------------------------------------

			Create Tooltips from links with CSS class 'help'

			------------------------------------------------------------------ */

			var t;

			$('.help')
				.bind('mouseover', createTooltip)
				.bind('mouseout', removeTooltip)
				.bind('focus', createTooltip)
				.bind('blur', removeTooltip);

				function createTooltip() {
					t = $(this).attr('title');
					$(this).parent().attr('style', 'position: relative;');
					$(this).after($('<div class="tooltip highlight"><div class="highlight_head"><span></span></div><div class="highlight_body">' + t + '</div><div class="highlight_foot"><span></span></div></div>'));
					$(this).attr('title', '');
				};

				function removeTooltip() {
					$(this).parent().attr('style', '');	
					$('.tooltip').remove();
					$(this).attr('title', t);
				};

		},
		createFlashElements: function() {
			
			/* ------------------------------------------------------------------

			

			------------------------------------------------------------------ */
			
			var bandList = $('#bandlist');
			
			// Bandimage stack
			if(bandList.length > 0) {
				
				var d = document.getElementById('bandlist').getElementsByTagName('li'),
					str = '';
				
				for(var i=0; i<d.length; i++) {
					str += '<li><a href="' + d[i].getElementsByTagName('a')[0].href + '" class="' + d[i].getElementsByTagName('a')[0].className + '" title="' + d[i].getElementsByTagName('a')[0].title + '"><img src="' + d[i].getElementsByTagName('img')[0].src +'" alt="' +  d[i].getElementsByTagName('img')[0].alt + '"/></a></li>';
				
					if(i == d.length-1) {
						
						str = '<ul id="bandlist">' + str + '</ul>';

						// Bandphotos
						var	bandFlashvars = {
							id: 'bandlist',
							myWidth: 890,
							myHeight: 500,
							marginX: 20,
							marginY: 20,
							overlap: 0.6,
							content: encodeURI(str),
							shuffle: true						
						};
						
						//create
						swfobject.embedSWF('/flash/bandlist.swf', bandFlashvars.id, bandFlashvars.myWidth, bandFlashvars.myHeight, '9.0.115', 'false', bandFlashvars, {wmode: 'transparent'}, {id: bandFlashvars.id});

					}
				}
				
			}
			
		},
		changeFlickrImages: function() {
			
			/* ------------------------------------------------------------------

			

			------------------------------------------------------------------ */
			
			var GET_PICS = $('#form-get-flickr-pictures');
			
			if(GET_PICS.length == 0) {
				return;
			}
			
			GET_PICS.find('button').addClass('hide');
			GET_PICS.find('input[type="radio"]').addClass('hide');
			GET_PICS.find('label').addClass('enhance');
			GET_PICS.find('label').bind('click', function(){
				
				var tag = $(this).attr('for'),
					tags = '',
					photoset = $('.photoset-flickr-images');
				
				if(tag != 'buildings' && tag != 'sightseeing')
					tags = 'finland,nature,' + tag + '';
				else
					tags = 'finland,' + tag + '';
				
				$.getJSON('http://api.flickr.com/services/feeds/photos_public.gne?tags='+ tags +'&tagmode=all&format=json&jsoncallback=?', function(data){
					
					photoset.empty();
					photoset.append('<li class="loading">'+ MFF.i18n.translate('loading') +'</li>')

					var pics = '';
					
					$.each(data.items, function(i,item){
						var url = item.media.m.split('_m.')[0];
						var sfx = item.media.m.split('_m.')[1];
						
						var thumbUrl = url + '_s.' + sfx;
						url = url + '.' + sfx;
						
						pics += '<li><a href="' + url + '" class="thickbox" rel="' + tag + '" title="' + MFF.i18n.translate('photos_provided_by_flickr') + '"><img src="' + thumbUrl + '" alt=""  /></a></li>';
					});
					
					photoset.find('.loading').remove();
					photoset.append(pics);
					
					/* init thickbox again */
					if(typeof(tb_init) == 'function') {
						tb_init('.photoset-flickr-images a.thickbox');
					}
					
				});
				
				return false;
			
			});

			
		},
		addToMySpace: function(T, C, U, L) {
		
			/* ------------------------------------------------------------------
			
			
			
			------------------------------------------------------------------ */
		
			var targetUrl = 'http://www.myspace.com/Modules/PostTo/Pages/?' + 't=' + encodeURIComponent(T) + '&c=' + encodeURIComponent(C) + '&u=' + encodeURIComponent(U) + '&l='+ L;
			window.open(targetUrl);
		
		},
		initListFilters: function() {
			
			/* ------------------------------------------------------------------
			
			Creates an input field with page url
			
			------------------------------------------------------------------ */
			
			var filters = $('.form-filter') || null;
			
			if(filters == null)
				return;
			
			// remove buttons
			filters.find('button').hide();
			
			var field;
			
			// tourdates
			if($('#form-tours').length > 0) {
				
				field = filters.find('input');
				initDataFiltering(filters, $('.list-of-tourdates'));
				
			}
			
			// get data 
			function initDataFiltering(el, data) {
				
				filters.find('input').bind('keyup', function(e){
					
					// add loading image 
					$(this).addClass('loading');
					
					var target = e.target;
					var timeoutId;

					window.clearTimeout(target.timeoutId);
					target.timeoutId = window.setTimeout(function() {
						

						filterData(target, data, target.value);

					}, 400);
					
				});
				
				filters.find('select').bind('change', function(e){

					filterData(e.target, data, e.target.options[e.target.options.selectedIndex].value);
					return false;
					
				});
				
				
			}
			
			// filter data
			function filterData(el, data, key) {
			
				// no results! 
				
				if(el.tagName.toLowerCase() == 'input') {
				
					// bands
					data.find('.band').each(function(){
						
						//
						//if($(this).parent().is('tr:visible')) {
						
							//no match
							(!$(this).text().toLowerCase().match(key.toLowerCase())) ? $(this).parent().hide() : $(this).parent().show();
						
						//}
							
					});
				
				}
				else if(el.tagName.toLowerCase() == 'select') {
					
					// all countries
					if(key.toLowerCase() == 'all') {
						
						data.find('div').find('tr').show();
						
					}
					else {
					
						// countries
						data.find('.country').each(function(){
							
							//
							//if($(this).parent().is('tr:visible')) {
							
								//no match
								(!$(this).text().toLowerCase().match(key.toLowerCase())) ? $(this).parent().hide() : $(this).parent().show();
							
							//}
								
						});
					
					}
				
				}

				// hide all dates that have no results
				data.find('.row').each(function(){
					
					($(this).find('tr:hidden').length + 1 == $(this).find('tr').length && $(this).find('tr:hidden').length > 0) ? $(this).hide() : $(this).show();
					
				});
				
				
				// hide all months that have no results
				data.find('h2').each(function(){
					
					($(this).next().find('div.row:hidden').length == $(this).next().find('div.row').length && $(this).next().find('div.row:hidden').length > 0) ? $(this).hide() : $(this).show();
					
				});
				
				// add loading image 
				field.removeClass('loading');
				
				
			}
			
			
		},
		initPermaLinkClicks: function() {
		
			/* ------------------------------------------------------------------
			
			Creates an input field with page url
			
			------------------------------------------------------------------ */
			
			if($('#permalink').length == 0)
				return;
			
			$('#permalink').bind('click', function(){
				
				if($('#article-link').length > 0)
					$('#article-link').remove();
				
				$(this).after('<input type="text" id="article-link" value="'+ $(this).attr('href') +'"/>');
				$('#article-link').bind('blur', function(){$(this).remove();}).bind('click', function(){$(this).select();}).select();
				return false;
			});
			
		
		},
		initEmbedCodeClicks: function() {
		
			/* ------------------------------------------------------------------
			
			Creates an input field with page url
			
			------------------------------------------------------------------ */
			
			if($('.embed-code').length == 0)
				return;
			
			$('.embed-code').bind('click', function(){
				$(this).select();
			});
			
		
		},
		fixListItemHeight: function() {
		
			/* ------------------------------------------------------------------
			
			Fix floated list item height in fanart
			
			------------------------------------------------------------------ */
			
			if($('.list-of-fanart').length == 0 && $('.list-of-videos').length == 0 && $('.list-of-popular-bands').length == 0 && $('.list-of-products').length == 0) 
				return;

			function modifyListItemHeight(){
					
				var h = 0;

				$(this).find('li').each(function(){

					if($(this).height() > h) {
						h = $(this).height();
					}
							
				});
				
				if(h > 0) {
					$(this).find('li').height(h);
				}
				
				// browser rendering glitch fix
				$(this).attr('style','min-height:auto;');
				
			}
			
			if($('.list-of-videos').length > 0)
				$('.list-of-videos').each(modifyListItemHeight);
				
			if($('.list-of-fanart').length > 0)
				$('.list-of-fanart').each(modifyListItemHeight);
			
			if($('.list-of-popular-bands').length > 0)			
				$('.list-of-popular-bands').each(modifyListItemHeight);
			
			if($('.list-of-products').length > 0)	
				$('.list-of-products').each(modifyListItemHeight);
			
		
		},
		runIeFixes: function() {
		
			/* ------------------------------------------------------------------
			
			Quick & dirty fixes for IE6
			
			------------------------------------------------------------------ */
			
			// Not for others than IE6
			if(!$.browser.msie) 
				return;

			if($.browser.version <= 6) {
			
				// replace calendar icon images
				$('.list .date').each(function(){
					
					if($(this).attr('style').length > 0) {
						var imgPath = ($(this).attr('style').split('(')[1].toString()).split(')')[0];
						$(this).attr('style','background-image: none; filter:progid:DXImageTransform.Microsoft.AlphaImageLoader\( src=\''+imgPath+'\', sizingMethod=\'image\' \);');
					}
					
				});
			
				// hardcoding some CSS for IE6 .. ugh
				$('p + h2, p + h3, p + h4, p + h5, p + h6, ul + h2, ul + h3, ul + h4, ul + h5, ul + h6, dl + h2, dl + h3, dl + h4, dl + h5, dl + h6, table + h2, table + h3, table + h4, table + h5, table + h6').attr('style','margin-top: 1em;');
				$('p  + .highlight, ul + .highlight, ul + .bookmarks').attr('style', 'padding-top: 1em;');
		
			}
			
		},
		makeTablesSortable: function() {
			
			/* ------------------------------------------------------------------

			Use jQuery tablesorter plugin to make data tables sortable

			------------------------------------------------------------------ */	
			
		    // table of future releses -  sort by fist column  - call the tablesorter plugin 
		    $(".table-of-future-releases").tablesorter({ 
				 headers: {
					 0: {sorter:"shortDate"}, 
					 4: {sorter:"currency"},
					 5: {sorter:false}
				 },
				 sortList: [[0,0]]
		    }); 

		},
		initMetalMaps: function() {
			
			/* ------------------------------------------------------------------

			

			------------------------------------------------------------------ */	
		
			if($('#metalmap').length == 0)
				return;
			
			if (GBrowserIsCompatible()) {
				
				
				// fix memory leaks
				$('body').bind('unload', GUnload);
			
				var map = new GMap2(document.getElementById('metalmap'));
				
				map.setCenter(new GLatLng(64.557881,26.323242), 5); // FINLAND location from Wikipedio
				//map.setCenter(new GLatLng(60.166667,24.933333), 5); // HELSINKI
				
				map.addControl(new GLargeMapControl());
		        map.addControl(new GMapTypeControl());
				
				// Enable mousewheel zoom
				map.enableScrollWheelZoom();

			}
			
		},
		init: function() {

			/* ------------------------------------------------------------------

			Initialize all component functions

			------------------------------------------------------------------ */
			
			// IE version lower than 6 get non javascript version
			if($.browser.msie && $.browser.version < 6)
				return;
			
			MFF.ui.createBoxedElements();
			MFF.ui.initTopSearchEvents();
			MFF.ui.initListFilters();
			MFF.ui.initPagination();
			MFF.ui.fixListItemHeight();
			MFF.ui.initTabbedContent();
			MFF.ui.initTabbedFiltering();
			MFF.ui.stripeTables();
			MFF.ui.helpTooltips();
			MFF.ui.createFlashElements();
			MFF.ui.initPermaLinkClicks();
			MFF.ui.changeFlickrImages();
			MFF.ui.initEmbedCodeClicks();
			MFF.ui.makeTablesSortable();
			MFF.ui.initMetalMaps();
			MFF.ui.runIeFixes();

		}

	};
	
	/* ------------------------------------------------------------------



	------------------------------------------------------------------ */

	//MFF.componentAvailable('ui');
	
	// Init General Ui components
	MFF.ui.init();
	
	MFF.Players.Init();
	
});




