################################################################################
#
# Ind.ie Pulse Process
#
# Starts and manages a pulse process. Informs the delegate of events.
#
# Usage: See test.coffee
#
# This is independent technology. See ind.ie/manifesto
#
# Copyright © 2014, Aral Balkan.
# Free as in freedom. Released under GNU GPLv3 (or any later version).
#
################################################################################

os = require 'os'
assert = require 'assert'

spawn = require('child_process').spawn

class Main
	@pulseProcess = null

	#
	# Pulse Process Delegate interface.
	# (All delegate methods are optional.)
	#
	# pulseProcessRestApiIsReady
	# pulseProcessFailedToStartProcess (data)
	# pulseProcessDidSendData (data)
	# pulseProcessDidSendErrorData (data)
	# pulseProcessDidExitWithCode (data)
	#
	# A delegate is not required but you should really have one set
	# to have control over the process.
	#

	delegate: {}
	quiet: false

	# The version of Pulse that is currently supported.
	version: '0.1.1'

	constructor: (delegate={}) ->
		@delegate = delegate

	log: (message) =>
		if !@quiet
			console.log message

	start: =>
		#
		# Start Pulse.
		#

		# Load the correct binary
		# Currently supported: x64 Mac and Linux (more to be added)
		supportedPlatforms = [
			{platform: 'linux', architecture: 'x64', binary: 'linux-amd64'},
			{platform: 'darwin', architecture: 'x64', binary: 'macosx-amd64'}
		]

		platform = os.platform()
		architecture = os.arch()

		binary = null
		for supportedPlatform in supportedPlatforms
			if (platform == supportedPlatform.platform) and (architecture == supportedPlatform.architecture)
				binary = supportedPlatform.binary

		# We can’t recover if the platform is not supported. Fail catastophically. (Shakespeare would be proud.)
		assert.notEqual null, binary, 'No binary found for platform: ' + platform + ', architecture: ' + architecture + '. Bailing.'

		binaryFilePath = __dirname + '/pulse/pulse-' + binary + '-' + @version + '/pulse'

		console.log binaryFilePath


		@pulseProcess = spawn binaryFilePath, ['--no-browser']

		@pulseProcess.stdout.on 'data', (data) =>
			#
			# Generic data callback.
			#
			@log '🌏 ' + data
			if @delegate.pulseProcessDidSendData != undefined
				@delegate.pulseProcessDidSendData(data)

			#
			# Specific callback for when the REST API is ready.
			#
			if /INFO: Starting web GUI/.test(data)
				@log '🌏 Pulse REST API is ready.'
				if @delegate.pulseProcessRestApiIsReady != undefined
					@delegate.pulseProcessRestApiIsReady()

			else if /Is another copy of pulse already running\?/.test(data)
				log '🌏 Pulse was already running, shutting it down via the API before retrying.'
				# TODO: Update to latest pulse-API and implement this [ ]					

		@pulseProcess.stderr.on 'data', (data) =>
			#
			# Generic error callback.
			#
			@log '🌏😩 ' + data
			if @delegate.pulseProcessDidSendErrorData != undefined
				@delegate.pulseProcessDidSendErrorData data

			#
			# Specific error callback when child process fails to start.
			#
			if /^execvp\(\)/.test(data)
				@log '🌏😱 Failed to start child process.'
				if @delegate.pulseProcessFailedToStartProcess != undefined
					@delegate.pulseProcessFailedToStartProcess data


		@pulseProcess.on 'close', (code) =>
			@log '🌏👋 Exited with code ' + code

			if @delegate.pulseProcessDidExitWithCode != undefined
				@delegate.pulseProcessDidExitWithCode code

	stop: =>
		#
		# Stop the Pulse process.
		#
		@pulseProcess.kill()

module.exports = Main