underscore = require 'underscore'
EventEmitter = require('events').EventEmitter

Freebase = require('./providers/Freebase')
Wikipedia = require ('./providers/Wikipedia')
PriceCharting = require './providers/PriceCharting'
FindTheBest = require './providers/FindTheBest'
AllPrices = require './providers/AllPrices'
Metacritic = require './providers/Metacritic'
AllRatings = require './providers/AllRatings'

async = require 'async'
sigmund = require 'sigmund'
_ = require 'underscore'

class Gamefinder extends EventEmitter
	constructor: (game, @cache = require('levelup')('/does/not/matter', { db: require('memdown') }), concurrency = 1) ->
		if typeof(game) is 'string'
			@data = 
				title: game
		else 
			@data = game

		@.internal_queue = async.priorityQueue(((item, callback) =>
				property = item.args[0]
				args = item.args[1]
				Provider = item.args[2]
				@cache.get sigmund({
					data: (@data.freebase_id or @data.title)
					provider: Provider.name
					property: property
				}), (E, additonal_data) =>
					if additonal_data
						additonal_data = JSON.parse(additonal_data)
						if (typeof additonal_data) == 'object'
							@data = _.extend @data, additonal_data
						else
							@[property] = additonal_data
						@.emit 'property', property, @data[property], @data
						@.emit property, @data[property], @data
						callback()
					else 
						provider = new Provider @data
						provider[property] args, (error, additonal_data) =>
							if error
								@.emit 'error', error
								return callback()
							else
								@cache.put sigmund({
									data: @data
									provider: Provider.name
									property: property
								}), JSON.stringify(additonal_data), (E) =>
									if (typeof additonal_data) isnt 'string'
										@data = _.extend @data, additonal_data
									else
										@data[property] = additonal_data
									@.emit 'property', property, @data[property], @data
									@.emit property, @data[property], @data
									callback()
			
		), concurrency)

	property: (property, args, priority = 0, Provider = Freebase) ->
		@internal_queue.push({ args: [ property, args, Provider ]}, priority)
		return @

	all: (Provider = Freebase, use_defaults = true) ->
		@.internal_queue.kill()
		funcs = Object.keys(Gamefinder.prototype).filter (x) -> x isnt 'constructor' and x isnt 'all' and x isnt 'property' and x isnt 'internal_queue'
		async.each funcs, (func, next) =>
			@[func]((if use_defaults then undefined else Provider))
			next()
		, (E) => 
			if E
				@.emit 'error', E

			@.internal_queue.drain = () => 
				@.internal_queue.drain = () ->

				@.emit('all', @data)

		
		return @

	freebase_id: (Provider = Freebase) -> 
		@.property 'freebase_id', [], 0, Provider
		return @

	title: (Provider = Freebase) -> 
		@.property 'title', [], 1, Provider
		return @

	description: (Provider = Wikipedia, args) -> 
		@.property 'description', (args or {}), 5, Provider
		return @

	cover_art: (Provider = Wikipedia) -> 
		@.property 'cover_art', [], 2, Provider
		return @

	platforms: (Provider = Freebase) -> 
		@.property 'platforms', [], 4, Provider
		return @

	genres: (Provider = Freebase) ->
		@.property 'genres', [], 3, Provider
		return @

	series: (Provider = Freebase) ->
		@.property 'series', [], 4, Provider
		return @

	developer: (Provider = Freebase) ->
		@.property 'developer', [], 4, Provider
		return @

	publisher: (Provider = Freebase) ->
		@.property 'publisher', [], 2, Provider
		return @

	release_date: (Provider = Freebase) ->
		@.property 'release_date', [], 2, Provider
		return @

	gameplay_modes: (Provider = Freebase) ->
		@.property 'gameplay_modes', [], 2, Provider
		return @

	prices: (Provider = AllPrices) ->
		@.property 'prices', [], 2, Provider
		return @

	ratings: (Provider = AllRatings) ->
		@.property 'ratings', [], 2, Provider
		return @

module.exports = Gamefinder
