Promise.config 'longStackTraces':false
do ($=jQuery)->
	import 'testSuite-markup.coffee'
	import 'testSuite-timeunits.coffee'
	TestSuite = ({@title, @subtitle, @measureMethod='sync', @setupFn, @testFn, @teardownFn, @timesToRun=1, @warmUps=1, @manualTiming, @nonSharedTest})->
		if @constructor isnt TestSuite
			return new TestSuite(arguments[0])
		
		@runCount = 0
		@els = {}
		@results = []
		@testScope = {}
		@teardownFn ?= ()=> @els.setup.empty()
		@testFn = @testFn.bind(@testScope) or (()->).bind(@testScope)
		
		title$ = $('.testSuite_heading-title')
		@libraryVersion = title$.children('span')[0].textContent
		@libraryName = title$[0].textContent.replace(@libraryVersion, '').replace(/\s+$/, '')


		itemMarkup = markup.item
			.replace '{{title}}', @title or ''
			.replace '{{subtitle}}', @subtitle or ''
			.replace '{{nonSharedTest}}', if @nonSharedTest then 'nonSharedTest' else ''


		@els.container = $(document.body).children('.testSuite')
		if @els.container.children().length
			@els.list = @els.container.children()
		else
			@els.list = $(markup.list).appendTo(@els.container)
			setTimeout ()=> @els.list.append(markup.gap).append(markup.gap)

		@els.item = $(itemMarkup).appendTo(@els.list).after(' ')
		@els.button = @els.item.find('.__execute')
		@els.results = @els.item.find('.__results')
		@els.resultsTime = @els.results.find('.__results-time')
		@els.resultsResult = @els.results.find('.__results-result')
		@els.resultsAvg = @els.results.find('.__results-avg')
		@els.setup = @els.item.find('.__setup')

		@els.button.on 'click', ()=> @run()

		@els.item.data 'TestSuite', @
		return @




	TestSuite::setup = ()-> new Promise (resolve)=>
		if @setupFn
			@setupFn.call(@testScope, @els.setup)

		resolve()


	TestSuite::teardown = ()-> if @setupFn
		@teardownFn.call(@testScope, @els.setup)



	TestSuite::storeResults = (force)-> if location.hostname and (@results.length >= 5 or force) and window.storeResults
		postData = 
			'library': @libraryName
			'version': @libraryVersion
			'testName': @title
			'testDesc': @subtitle
			'result': @average
			'UA': navigator.userAgent
			'nonSharedTest': @nonSharedTest or false
		
		$.post('/set', postData)



	TestSuite::run = ()-> unless @running
		@running = true
		@runCount += 1
		
		performIteration = (timesToRun)=> new Promise (resolve)=> switch @measureMethod
			when 'sync'
				totalTime = 0
				iteration = 0

				while iteration++ < timesToRun
					if @manualTiming
						{startTime, endTime} = @testFn()
					else
						startTime = performance.now()
						@testFn()
						endTime = performance.now()

					totalTime += endTime-startTime
					
					if iteration is timesToRun
						resolve(totalTime)
			


			when 'async'
				totalTime = 0
				iteration = 0
				
				while iteration++ < timesToRun
					do (iteration)=> setTimeout ()=>
						if @manualTiming
							{startTime, endTime} = @testFn()
						else
							startTime = performance.now()
							@testFn()
							endTime = performance.now()

						totalTime += endTime-startTime
						
						if iteration is timesToRun
							resolve(totalTime)
				

		warmUp = ()=> performIteration(@warmUps)
		beginTest = ()=> performIteration(@timesToRun)


		@setup()
			.then(warmUp)
			.then(beginTest)
			.then (result)=>
				formatTime = (time, returnTime)=>
					if returnTime
						split = time.toString().split '.'

						if split.length > 1
							return "#{split[0]}.#{split[1].slice(0,3)} ms"
						else
							return "#{time} ms"

					else
						time = time/@timesToRun
						perSec = timeUnits.minute / time
						humanize.numberFormat(perSec, 0)+' op/s'


				if @runCount <= 2
					average = '---------'
				else
					@results.push(result)
					average = @results.reduce((a,b)->a+b) / @results.length

				@els.resultsTime.html formatTime(result, true)
				@els.resultsResult.html formatTime(result)
				@els.resultsAvg.html @average = if @runCount <= 2 then average else formatTime(average)
				@els.results.addClass 'hasResults'

				@teardown()
				@storeResults(result > 10000)
				@running = false















	window.storeResults = true
	
	$('#storeResults').on 'click', ()->
		window.storeResults = !window.storeResults
		$(@).toggleClass('enabled')


















	window.TestSuite = TestSuite
