# Copyright (c) 2017 Alex Socha
# http://www.alexsocha.com/pynode

import subprocess
import time
import traceback
import sys
import os
import json
import uuid
from threading import Thread

from pynode.src import update
from pynode.src import pynode_core

# The location of the main.py file
APP_DIR = os.path.join(os.path.dirname(__file__), "../")

operating_system = None
pynode_process = None

monitor_thread = None
update_thread = None
run_thread = None

is_running = True

response_data = {}

def set_run_function(func):
    global run_function
    run_function = func

def execute_run_function():
    try:
        pynode_core.reset()
        run_function()
        time.sleep(0.1)
        pynode_core.run_javascript_func("end_running")
    except: traceback.print_exc(file=sys.stderr)

def send_data(s):
    # Format string correctly before it is passed to JavaScript
    s = s.replace("\\", "\\\\")
    s = s.replace("'", "\\'")
    s = s.replace('"', '\\"')
    pynode_process.stdin.write(("pynode:" + s + "\n").encode())
    pynode_process.stdin.flush()

def send_data_with_response(s, args):
    request_id = str(uuid.uuid4())
    args.insert(1, request_id)
    send_data(s + json.dumps(args))

    response_data[request_id] = None
    for i in range(0, 500):
        time.sleep(0.01)
        if response_data[request_id] is not None: break

    result = json.loads(response_data[request_id])
    response_data.pop(request_id, None)
    return result

def recieve_data(s):
    try:
        if s.startswith("pynode:"):
            data = s[len("pynode:"):].strip()
            if data == "run":
                global run_thread
                run_thread = Thread(target=execute_run_function)
                run_thread.daemon = True
                run_thread.start()
            if data == "exit":
                pynode_process.kill()
                global is_running
                is_running = False
                return False
            if data.startswith("click:"):
                args = data.split(":")
                pynode_core.node_click(int(args[1]))
            if data.startswith("response:"):
                args = data.split(":")
                response_id = args[1]
                response_data[response_id] = data[len("response:" + response_id + ":"):]

    except: pass
    return True

            
def monitor_data():
    try:
        while True:
            line = pynode_process.stdout.readline()
            if line is not None and line != "":
                if recieve_data(line.decode()) == False:
                    break
    except: pass
    wait_for_close()

def wait_for_close():
    try:
        pynode_process.wait()
        if update_thread is not None and update.is_updating:
            update_thread.join()
    except Exception as e:
        print(e)
    sys.exit(0)


def open_connection():
    try:
        file = open(os.path.join(os.path.dirname(__file__), "../cef/os.txt"))
        operating_system = file.readlines()[0].strip()
        file.close()

        global update_thread
        update_thread = Thread(target=update.check_update)
        update_thread.daemon = True
        update_thread.start()

        global pynode_process
        if operating_system == "win64":
            pynode_process = subprocess.Popen([os.path.join(APP_DIR, "cef/win64/pynode.exe")], shell=False, cwd=APP_DIR, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        elif operating_system == "win32":
            pynode_process = subprocess.Popen([os.path.join(APP_DIR, "cef/win32/pynode.exe")], shell=False, cwd=APP_DIR, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        elif operating_system == "macosx":
            pynode_process = subprocess.Popen([os.path.join(APP_DIR, "cef/macosx/pynode.app/Contents/MacOS/pynode")], shell=False, cwd=APP_DIR, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
            # Bring window to foreground
            try:
                DEVNULL = open(os.devnull, 'w')
                subprocess.call(["/usr/bin/osascript -e 'activate application \"PyNode\"'"], shell=True, stdout=DEVNULL, stderr=DEVNULL, close_fds=True)
            except: pass
        elif operating_system == "linux":
            pynode_process = subprocess.Popen([os.path.join(APP_DIR, "cef/linux/pynode")], shell=False, cwd=APP_DIR, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        time.sleep(1)

        global monitor_thread
        monitor_thread = Thread(target=monitor_data)
        monitor_thread.start()
    except Exception as e:
        traceback.print_exc(file=sys.stderr)
