/* jslint verified 2008.09.24 */
/*jslint browser: true, onevar: true, undef: true, white: false, eqeqeq: true */
/*global document, $, $$, Class, Ajax, Constants, MMToolTips, DateChooser, Genres, Instruments, Keys, MbitBox, Tempo, MbitLinks, Result, isset, results, JSON, mBitAdmin, $_GET, Flash, Song, User, dhtmlXComboFromSelect */
var Query = new Class({
	initialize: function (text) {
		this.txt = "{";
		this.count = 0;
		if (isset(typeof(text))) { this.setText(text); }
	},
	getObject: function () {
		var qObj = {}, i, tmp,
			qArr = this.txt.replace(/{|}/g, '').split(',');
		for (i = 0; i < qArr.length; ++i) {
			tmp = qArr[i].split(':');
			if (isset(typeof(qObj[tmp[0]]))) {
				if (!Array.is_a(qObj[tmp[0]])) { qObj[tmp[0]] = [qObj[tmp[0]]]; }
				qObj[tmp[0]].push(tmp[1]);
			} else { qObj[tmp[0]] = tmp[1]; }
		}
		return qObj;
	},
	add: function (param, value) {
		if (this.count > 0) { this.txt += ","; }
		this.txt += param + ":" + value;
		this.count++;
	},
	addKeywords: function (keywords) {
		keywords = keywords.replace(/,/g, " ");
		keywords = keywords.replace(/;/g, " ");
		keywords = keywords.replace(/:/g, " ");
		keywords = keywords.replace(/\[/g, " ");
		keywords = keywords.replace(/\]/g, " ");
		keywords = keywords.replace(/\{/g, " ");
		keywords = keywords.replace(/\}/g, " ");
		keywords = keywords.replace(/&/g, " ");
		this.add('text', keywords);
	},
	addArray: function (param, array) {
		this.add(param, '['+array+']');
	},
	addNotEmpty: function (param, value) {
		if (value !== '') { this.add(param, value); }
	},
	finalize: function () { this.txt += "}"; },
	getText: function () { return this.txt; },
	setText: function (txt) {
		this.txt = txt;
		if (txt.indexOf(",") >= 0) {
			this.count = 1;	// just needs to be greater than 0
		}
	}
});

var Search = new Class({
	initialize: function (options) {
		// Get page element pointers
		this.searchResults = $('searchResults');
		this.searchBox = $('searchBox');
		this.searchQ = $('search_q');
		this.searchL = $('search_L');
		this.searchF = $('search_f');
		var userSelect = $('userSelect'), form, q,
			remoteSearch, rS_searchQ, rS_searchB;
		if (this.searchQ && this.searchL && this.searchBox && this.searchF) {
			remoteSearch = function (boxWins) {
				if (!!boxWins) { this.searchQ.xerox(this.searchBox); }
				else { this.searchBox.xerox(this.searchQ); }
				this._search();
				return false;
			};
			rS_searchQ = remoteSearch.bind(this, false);
			rS_searchB = remoteSearch.bind(this, true);
			this.searchL.setClick(rS_searchQ);
			this.searchQ.setEvent("keypress", function (e) { if (window.enterKey(e)) { rS_searchQ(); } });
			this.searchBox.setEvent("keypress", function (e) { if (window.enterKey(e)) { rS_searchB(); } });
		}
		if (isset(typeof(MMToolTips))) {
			MMToolTips.dip(this.searchBox.id, 2);
			MMToolTips.dip('searchBoxLbl', 2);
		}
		if (userSelect && isset(typeof(dhtmlXComboFromSelect))) {
			userSelect.update('<select name="userSuggest" id="userSuggest" ></select>');
			window.dhx_globalImgPath = Constants.images()+"mmmail/";
			this._comboBox = dhtmlXComboFromSelect($('userSuggest'));
			this._comboBox.enableFilteringMode(true,Constants.ajax()+"usernamesuggest", true, true);
			this._comboBox.setEnterKeyEventPropagate(true);
			form = $('searchForm');
			if (form) { this._user = $$(form.userSuggest); }
		}
		this.isSearch = !!options.isSearch;
		this.useNewResults = !!options.useNewResults;

		// Private variables
		this._date = !!options.date ? new DateChooser(options.date.launcher, options.date.display) : null;
		this._genres = !!options.genres ? new Genres(options.genres.launcher, options.genres.display) : null;
		this._instruments = !!options.instruments ? new Instruments(options.instruments.launcher, options.instruments.display) : null;
		this._keys = !!options.keys ? new Keys(options.keys.launcher, options.keys.display) : null;
		this._mbitBox = !!options.mbitBox ? new MbitBox(options.mbitBox.launcher, options.mbitBox.display, this.isSearch) : null;
		this._tempo = !!options.tempo ? new Tempo(options.tempo.launcher, options.tempo.display) : null;
		this._resultsPerPage = 10;
		this._lastQuery = "";
		this._lastPage = 1;
		this._seenPages = [];
		this._ajax = null;
		this._url = Constants.ajax() + 'serveResults';
		
		if (!window.location.href.match(/sequencer/)) {
			q = $_GET('q');
			if (q) { q = decodeURIComponent(q).replace('+',' '); }
			if (this.searchBox) { this.searchBox.update(q); }
			if ($_GET('q') !== null) { this._search(); }
		}
	},
	search: function () {
		var me = this;
		return me._search.bind(me);
	},
	browse: function () {
		var me = this;
		return me._browse.bind(me);
	},
	clearOptions: function () {
		if (this._genres) { this._genres.clear(); }
		if (this._instruments) { this._instruments.clear(); }
		if (this._mbitBox) { this._mbitBox.clear(); }
		if (this._tempo) { this._tempo.clear(); }
		if (this._keys) { this._keys.clear(); }
		if (this._date) { this._date.clear(); }
		if (this._user) { this._user.empty(); }
		if (this._comboBox) {
			this._comboBox.clearAll();
			this._comboBox.setComboText('');
		}
		if (this.searchBox) {
			this.searchBox.empty();
			this.searchBox.focus();
		}
	},
	_browse: function () {
		var query = new Query();
		query.add('num', this._resultsPerPage);
		query.add('page', 1);
		this._lastSearch = '';
		this._lastPage = 1;
		query.finalize();
		this._seenPages = [];
		this.requestResults('');
	},
	_search: function (pageNum) {
		Flash.stop('smallPlayerHidden');
		var query = new Query();
		if (this.searchBox.value) {
			query.addKeywords(this.searchBox.value);
		}
		if (this.searchQ) { this.searchQ.update(this.searchBox.value || ''); }
		if (this._mbitBox) {
			if (this._mbitBox.getType() !== '') {
				query.add('type', this._mbitBox.getType());
			}
			if (this._mbitBox.getSongCompIds() !== '')
				{ query.addArray('songcomp', this._mbitBox.getSongCompIds()); }
			if (this._mbitBox.getContinuous() !== '')
				{ query.add('flag_loop', (this._mbitBox.getContinuous() === 'yes')?1:0); }
			query.addNotEmpty('channels', this._mbitBox.getAudio());
			if (this._mbitBox.getEffectsIds() !== '')
				{ query.addArray('effects', this._mbitBox.getEffectsIds()); }
		}
		if (this._tempo) {
			if (this._tempo.getLow() !== '') {
				if (this._tempo.getType() !== 'specific' && this._tempo.getHigh() !== '') {
					query.add('tempo', this._tempo.getRange());
					query.add('tempo_range', 1);
				} else {
					query.add('tempo', this._tempo.getLow());
					query.add('tempo_range', 0);
				}
			}
			query.addNotEmpty('tempo_type', this._tempo.getStyle());
		}
		if (this._keys) {
			if (this._keys.getLetter() !== '') {
				query.add('key_chroma', this._keys.getLetter());
				query.addNotEmpty('key_shift', this._keys.getShift());
			}
			query.addNotEmpty('id_key_scales', this._keys.getScale());
			query.addNotEmpty('tuning_type', this._keys.getTuning());
		}
		if (this._genres && this._genres.getIds() !== '') {
			query.addArray('genres', this._genres.getIds());
		}
		if (this._instruments && this._instruments.getIds() !== '') {
			query.addArray('instruments', this._instruments.getIds());
		}
		if (this._user && this._user.value) {
			query.add('user', this._user.value);
		}
		if (this._date) {
			query.addNotEmpty('startDate', this._date.getStart());
			query.addNotEmpty('endDate', this._date.getEnd());
		}
		query.add('num', this._resultsPerPage);
		if (isset(typeof(mBitAdmin))) { mBitAdmin.enhance(query); }
		
		this._lastSearch = query.getText();
		pageNum = isNaN(pageNum) ? 1 : parseInt(pageNum, 10);
		this._lastPage = pageNum;
		query.add('page', pageNum);
		query.finalize();
		this._seenPages = [];
		this.requestResults(query.getText());
	},
	requestResults: function (query) {
		this._displayMessage("Searching...<br /><img src='"+Constants.images()+"blueLoadingBar.gif' alt='loading' />");
		var pars = "q=" + query,
			me = this;
		this._ajax = new Ajax(
			this._url, 
			{	method: 'get', 
				parameters: pars,
				onSuccess: function (request) { me._resultsSucceeded.bind(me, request)(); },
				onFailure: function (request) { me._resultsFailed.bind(me, request)(); }
			});
		this._ajax.send();
	},
	requestPage: function (page) {
		var mbl, seen, query;
		if (isset(typeof(MbitLinks))) {
			mbl = new MbitLinks();
			if (mbl) { mbl.hideLinks(true); }
			Flash.stop('smallPlayerHidden');
		}
		this._lastPage = page;
		seen = this._seenPages[page];
		if (!isset(typeof(seen)) || seen === null) {
			query = new Query();
			query.setText(this._lastSearch);
			query.add('page', page);
			query.finalize();
			this.requestResults(query.getText());
		}
		else { this._resultsSucceeded(seen); }
	},
	_resultsSucceeded: function (request) {
		this._seenPages[this._lastPage] = request;
		var response = JSON.parse(request.responseText), added;

		this._clearResults();
		if (this.searchResults) {
			if (response.total === 0) {
				this._displayMessage("No matching search results.<br />Please try again");
			} else {
				added = 0;
				this._setupPageHolder(response.pages);
				if (response.total > 0) {
					added = this._addResultsToPage(response.results);
				}
				this._addBlankToPage(this._resultsPerPage - added);
				this._setupPageHolder(response.pages);
			}
		}
	},
	_addResultsToPage: function (results) {
		var i = 0, result, thisResult;
		for (result in results) {
			if (results.hasOwnProperty(result)) {
				thisResult = results[result];
				if (typeof(thisResult) === 'object') {
					thisResult.id = result;
					this._addToPage(thisResult);
					++i;
				}
			}
		}
		return i;
	},
	_addBlankToPage: function (num) {
		var i, thisResult;
		for (i=0; i<num; ++i) {
			if (!this.useNewResults) {
				thisResult = {un:'',name:'',genre:'',inst:'',tempo:'',key:'',id:''};
				this._addToPage(thisResult,'');
			} else {
				this.searchResults.appendChild(document.create('div').classify('blankResult','song'));
			}
		}
	},
	_addToPage: function (result) {
		if (!this.useNewResults) {
			var newResult = new Result(result);
			this.searchResults.appendChild(newResult.getEl());
			this.searchResults.create('div').classify('searchSep');
		} else {
			if (result.type === 'stem' || result.type === 'song') {
				this.searchResults.appendChild(new Song(result.id, result, (result.type === 'stem')));
			} else if (result.type === 'user') {
				this.searchResults.appendChild(new User(result.id, result));
			}
		}
	},
	_setupPageHolder: function (numPages) {
		var pageSelectHolder = this.searchResults.create('div', 'pageSelectHolder'),
			prevPage = pageSelectHolder.create('span', 'prevPage').update("&lt;&lt;previous "),
			me = this, nextPage,
			startI, endI, i;
		if (this._lastPage !== 1) { prevPage.addClick(me.requestPage.bind(me, me._lastPage-1)); }
		else { prevPage.addClassName('disabled'); }
		pageSelectHolder.appendChild(prevPage);
		startI = Math.max(1,Math.min(numPages-3,this._lastPage-1));
		endI = Math.min(startI+2,numPages-1);
		if (startI > 1) { pageSelectHolder.appendChild(this._addPageSelect(1)); }
		if (startI === 2) { pageSelectHolder.createText(', '); }
		if (startI > 2) { pageSelectHolder.createText(' ...'); }
		for (i = startI; i <= endI; ++i) {
			pageSelectHolder.appendChild(this._addPageSelect(i));
			if (i !== endI) { pageSelectHolder.createText(', '); }
		}
		if (endI < (numPages-1)) { pageSelectHolder.createText('... '); }
		else if (endI >= startI) { pageSelectHolder.createText(', '); }
		pageSelectHolder.appendChild(this._addPageSelect(numPages));
		pageSelectHolder.createText(' ');
		nextPage = pageSelectHolder.create('span', 'nextPage', null, " next&gt;&gt;");
		if (this._lastPage !== numPages)
			{ nextPage.addClick(me.requestPage.bind(me, me._lastPage+1)); }
		else { nextPage.addClassName('disabled'); }
	},
	_addPageSelect: function (page) {
		var me = this,
			span = document.create('span', null, 'pageSelect', page);
		if (page === this._lastPage) { span.addClassName('thisPage'); }
		else { span.addClick(me.requestPage.bind(me, page)); }
		return span;
	},
	_resultsFailed: function (request) {
		this._displayMessage("Search failed. Please try again");
	},
	_displayMessage: function (msg) {
		if (this.searchResults) {
			this._clearResults();
			var row = this.searchResults.create('div', null, 'row'),
				col = row.create('div', null, 'middle');
			col.create('div').create('div').create('div').update(msg);
			col.style.textAlign = 'center';
			if (!this.useNewResults) {
				row.style.height = '400px';
				col.style.width = '260px';
			} else {
				row.style.height = '534px';
				col.style.width = '584px';
			}
		}
	},
	_clearResults: function () {
		if (this.searchResults) {
			// remove old results
			while (this.searchResults.childNodes[0]) {
				this.searchResults.removeChild(this.searchResults.childNodes[0]);
			}
		}
	}
});

var Results = new Class({
	initialize: function (isSequencer) {
		this.isSequencer = isSequencer;
		this.results = [];
		this.resultIds = [];
		if (isset(typeof(MbitLinks))) {
			this.mbitLinks = new MbitLinks({
				isSequencer:isSequencer,
				topOffset:(isSequencer ? 10 : 202),
				topBgndOffset:(isSequencer ? 9 : 200),
				leftOffset:(isSequencer ? 198 : 172),
				leftBgndOffset:(isSequencer ? 198 : 172)
			});
		}
	},
	createResult: function (result) {
		if (this._isBlank(result)) {
			return this._buildBlankResult();
		}
		if (!this._inCache(result)) {
			this._buildResult(result);
		}
		return this._getResult(result);
	},
	registerForEvents: function (result) {
		if (!result.el.registered) {
			var me = this;
			if (isset(typeof(MbitLinks))) {
				result.el.addEvent('mouseover', this.mbitLinks.hoverResult.bind(this.mbitLinks, result.el, result.id));
				result.el.addEvent('mousemove', this.mbitLinks.prolong);
				result.el.addEvent('mouseout', this.mbitLinks.closeResult);
			}
			result.el.registered = true;
		}
	},
	selected: function () {
		return this._selectedId;
	},
	_isBlank: function (result) {
		return (result.id === '');
	},
	_inCache: function (result) {
		return (this.resultIds.indexOf(result.id) > -1);
	},
	_getResult: function (result) {
		return this.results[result.id];
	},
	_buildBlankResult: function () {
		return this._buildResult({id:'',username:''});
	},
	_buildResult: function (result) {
		var admin = $('adminSrch'),
			div = document.create('div').classify('searchResult'),
			mainInfo = div.create('div').classify('searchMainInfo'),
			secondaryInfo = div.create('div').classify('searchSecondaryInfo'),
			txt, something,
			UNlink, txt2, span, BNlink;
		if (result.username !== "") {
			UNlink = mainInfo.create('a', null, 'un', result.username);
			txt2 = mainInfo.createText(' . ');
			span = mainInfo.create('span').classify('searchTitle');
			BNlink = span.create('a', result.id+'_name', 'bit', result.name);
			if (admin) {
				UNlink.setClick( function () { UNlink.href = 'users?un='+result.username; } );
				BNlink.setClick( function (e) { if (isset(typeof(mBitAdmin))) { mBitAdmin.load(result.id, e); BNlink.removeAttribute("href"); return false; } } );
			}
			UNlink.href = Constants.profileLink(false, result.username);
			BNlink.href = Constants.profileLink(result.id);
//			mainInfo.update('<a class="un" href="'+Constants.profileLink(false,result.username)+'">' + result.username + '</a> . <span class="searchTitle"><a id="'+result.id+'_name" class="bit" href="'+Constants.profileLink(result.id)+'">' + result.name + '</a></span>');
		} else { mainInfo.update("&nbsp;"); }
		if (result.username !== "") {
			txt = result.genre;
			something = (result.genre !== "");
			if (result.instrument !== "") {
				if (something) { txt += ' . '; }
				else { something = true; }
				txt += result.instrument;
			}
			if (result.tempo !== "") {
				if (something) { txt += ' . '; }
				else { something = true; }
				txt += result.tempo + 'bpm';
			}
			if (result.key !== "") {
				if (something) { txt += ' . '; }
				else { something = true; }
				txt += result.key;
			}
			secondaryInfo.update(txt);
		} else { secondaryInfo.update("&nbsp;"); }
		if (result.id !== '') {
			div.id = result.id;
			this.results[result.id] = div;
			this.resultIds.push(result.id);
		}
		return div;
	}
});

var MbitInfo = {};

var Result = new Class({
	initialize: function (params) {
		this.id = params.id;
		this.score = params.score;
		this.username = params.un;
		this.name = params.name;
		this.genre = params.genre;
		this.instrument = params.inst;
		this.tempo = params.tempo;
		this.key = params.key;
		this.mine = params.mine;
		this.canplay = params.canplay;
		this.canseq = params.canseq;
		this.ispinned = params.pin;
		this.isseq = params.isseq;
		
		this.el = results.createResult(this);
		if (this.id !== '') {
			results.registerForEvents(this);
		}

		if (!MbitInfo[params.id]) { MbitInfo[params.id] = {}; }
		MbitInfo[params.id].canplay = params.canplay;
		MbitInfo[params.id].canseq = params.canseq;
		MbitInfo[params.id].mine = params.mine;
		MbitInfo[params.id].ispinned = params.pin;
		MbitInfo[params.id].isseq = params.isseq;
	},
	getEl: function () { return this.el; }
});