var _ = require('lodash'),
	Events = require(__dirname + '/irc').Events;

function ListCache() {
	this.lists = {};
};

// ========================================
// this object manages list caching, in a normal single client
// scenario, grabbing the list on request is fine, but irc-factory
// isnt really designed for single client usage
// the ircanywhere use case requires lists to be available to all, for
// all networks.

ListCache.prototype.requestList = function(ircObject, search, page, limit) {
	if (!Events) {
		Events = require(__dirname + '/irc').Events;
	}

	var self = this,
		key = ircObject.key;

	if (key === '') {
		return false;
	}

	if (!this.lists[key]) {
		this.createList(ircObject);
		ircObject.raw(['LIST']);
		
		Events.once([ircObject.key, 'listend'], function() {
			self.filterList(ircObject, search, page, limit);
		});
		// no cache is available? request one and wait to filter it
	} else {
		self.filterList(ircObject, search, page, limit);
		// looks like we already have a cached list, pass it straight to filter
	}

	clearTimeout(this.lists[key].deleteTimer);
	this.lists[key].deleteTimer = setTimeout(function() {
		delete self.lists[key];
	}, 600000);
	// lets set a timer to trash this data if its not been requested in a while (10min)
	// the only reason we cache it is to prevent people doing /list then /list, then /list
	// and blocking the process
};

ListCache.prototype.filterList = function(ircObject, search, page, limit) {
	var key = ircObject.key,
		regex = new RegExp('(' + search + ')', 'i'),
		list = this.lists[key];

	if (key === '' || !list) {
		return false;
	}
	// make sure the list exists

	var output = {
		list: [],
		raw: [],
		search: search.replace(/[-[\]{}()+?.,\\^$|#\s]/g, "\$&").replace(/\(\.\*\)/g, '*'),
		page: page,
		limit: limit,
		time: new Date()
	};

	var clone = _.cloneDeep(list.list);
	var buffer = _.sortBy(clone, function(channel) {
		return 0 - channel.users;
	});
	// sort it

	buffer = _.filter(buffer, function(channel) {
		return regex.test(channel.channel);
	});
	// filter via the search parameters

	buffer = _.take(_.rest(buffer, (page - 1) * limit), limit);
	// paginate

	for (var c in buffer) {
		var channel = buffer[c];
		output.raw.push(channel.raw);
		delete buffer[c].raw;
	}
	// i don't really like this, but we pull .raw from channel objects
	// and push it into the output

	Events.emit([ircObject.key, 'list'], _.extend(output, {
		list: buffer
	}));
	// emit the list event
};

ListCache.prototype.createList = function(ircObject) {
	var key = ircObject.key;
	if (key === '' || this.lists[key]) {
		return false;
	}

	this.lists[key] = {
		key: key,
		requestedAt: new Date(),
		deleteTimer: null,
		list: []
	};
};

ListCache.prototype.insertListData = function(ircObject, message) {
	var key = ircObject.key;
	if (key !== '' && !this.lists[key]) {
		this.createList(key);
	}

	this.lists[key].list.push({
		channel: message.params[1],
		users: message.params[2],
		topic: message.params[3],
		raw: message.raw
	});
};
// ========================================

exports.ListCache = new ListCache();