import sublime, sublime_plugin
import subprocess
import os

class TranspileCommand(sublime_plugin.TextCommand):

	def run(self, edit, entireFile=False):

		if entireFile:
			contentRegion = sublime.Region(0, self.view.size())
			coffeeStr = self.view.substr(contentRegion)
		else:
			coffeeStr = getSelection(self.view)

		transpiledJS = transpile(coffeeStr)
		if not transpiledJS:
			showResult("An unknown error occured while transpiling.")
		else:
			showResult(transpiledJS)



class RunCommand(sublime_plugin.TextCommand):

	def run(self, edit):

		view = self.view
		codeStr = getSelection(view)
		syntax = view.settings().get('syntax')
		output = None

		if "Python" in syntax:
			output = runPython(codeStr)
		elif "JavaScript" in syntax:
			# TODO
			output = run()
		elif "CoffeeScript" in syntax:
			transpiledCode = transpile(codeStr)
			output = run()

		showResult(output)



class EnterLiveSession(sublime_plugin.TextCommand):

	def run(self, edit):

		toggledValue = not self.view.settings().get("isEvalPrinterLiveSession", False)
		self.view.settings().set("isEvalPrinterLiveSession", toggledValue)
		sublime.status_message("EvalPrinter's Live Session is " + ("on" if toggledValue else "off"))



class ModifyListener(sublime_plugin.EventListener):

	def on_modified_async(self, view):

		if view.settings().get("isEvalPrinterLiveSession", False):
			view.run_command("transpile", dict(entireFile = True))



class TestEvalPrinterCommand(sublime_plugin.TextCommand):

	def run(self, edit, action, codeStr):

		if action == "transpile":
			output = transpile(codeStr)
		else:
			transpile(codeStr)
			output = run()

		self.view.run_command("append", {"characters": output})


def getSelection(view):

	codeParts = []

	for region in view.sel():

		if region.a == region.b:
			region = view.line(region)

		code = view.substr(region)
		codeParts.append(code)

	return "\n".join(codeParts)


def runPython(codeStr):

	output = None
	testStr = ""

	# TODO: hook print function and add it to output

	try:
		output = str(eval(codeStr))
	except SyntaxError as e:
		try:
			# code has to end with a new line
			codeStr += "\n"
			output = str(exec(codeStr))
		except BaseException as e:
			print("An exception occured while evaluating python code", e)
			output = str(e)

	return output


def showResult(resultStr):

	myOutput = sublime.active_window().create_output_panel("myOutput")
	sublime.active_window().run_command("show_panel", {"panel": "output.myOutput"})

	myOutput.run_command("append", {"characters": resultStr})
	myOutput.set_syntax_file("Packages/JavaScript/JavaScript.tmLanguage")


def markFaultyCode():

	pass


def executeCommand(cmd):

	startupinfo = None
	if sublime.platform() == "windows":
		startupinfo = subprocess.STARTUPINFO()
		startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW

	sp = subprocess.Popen(cmd,
		startupinfo=startupinfo,
		stderr=subprocess.PIPE,
		stdout=subprocess.PIPE,
		shell=True)

	out, err = sp.communicate()
	out = out.decode("ascii")
	err = err.decode("ascii")

	if err or sp.returncode != 0:
		return out + err.replace("\r", "")

	return out


def getCodeFilePath():

	epPath = os.path.join(sublime.packages_path(), "EvalPrinter")
	fileName = "code.coffee"
	filePath = os.path.join(epPath, fileName)

	return filePath


def transpile(coffeeStr):

	filePath = getCodeFilePath()

	with open(filePath, "wt") as out_file:
		out_file.write(coffeeStr)

	cmd = 'coffee -p -b "' + filePath + '"'
	transpiledJS = executeCommand(cmd)

	return transpiledJS


def run():

	filePath = getCodeFilePath()

	return executeCommand('coffee -p -b "' + filePath + '" | node -p')

@@ -2023,388 +2023,129 @@
 %0A%0D%0A%09
-output = None%0D%0A%09testStr = %22%22%0D%0A%0D%0A%09# TODO: hook print function and add it to output%0D%0A%0D%0A%09try:%0D%0A%09%09output = str(eval(codeStr))%0D%0A%09except SyntaxError as e:%0D%0A%09%09try:%0D%0A%09%09%09# code has to end with a new line%0D%0A%09%09%09codeStr += %22%5Cn%22%0D%0A%09%09%09output = str(exec(codeStr))%0D%0A%09%09except BaseException as e:%0D%0A%09%09%09print(%22An exception occured while evaluating python code%22, e)%0D%0A%09%09%09output = str(e)%0D%0A%0D%0A%09return output
+# TODO: lstrip the minimum amount of whitespace each line has%0D%0A%0D%0A%09return executeCommand(%5B%22python%22, %22-c%22, codeStr%5D, False)
 %0D%0A%0D%0A
@@ -2523,16 +2523,29 @@
 mand(cmd
+, shell=False
 ):%0D%0A%0D%0A%09s
@@ -2822,20 +2822,21 @@
 %09%09shell=
-True
+shell
 )%0D%0A%0D%0A%09ou
@@ -2848,79 +2848,75 @@
 r = 
-sp.communicate()%0D%0A%09out = out.decode(%22ascii%22)%0D%0A%09err = err.decode(%22ascii%22
+map(lambda x: x.decode(%22ascii%22).replace(%22%5Cr%22, %22%22), sp.communicate()
 )%0D%0A%0D
@@ -2966,34 +2966,16 @@
 ut + err
-.replace(%22%5Cr%22, %22%22)
 %0D%0A%0D%0A%09ret

use popen for python evaluation to isolate execution environment and to capture output