import os
import subprocess
import sys
import tempfile

from time import sleep, time

from abl.vpath.base import URI
from AbletonIPC import create_ipc_channel


def MCerrDebug(*args):
    ## ts = int(time() * 1000000)
    ## sys.stderr.write("PID:%i:%s:" % (os.getpid(), ts, ))
    ## for arg in args:
    ##     sys.stderr.write(str(arg))
    ## sys.stderr.write("\n")
    pass


WAIT = 600 * 5  # 5 mins


class IPCTests(object):
    def setUp(self):
        ipc_channel_name = os.path.basename(tempfile.mktemp())
        MCerrDebug("ipc_channel_name ", ipc_channel_name)
        self.channel = create_ipc_channel(ipc_channel_name, True)
        client_script = URI(__file__).directory() / "ipc_client.py"
        self.started_sentinel_file = URI(tempfile.mktemp())
        MCerrDebug("sentinel file ", self.started_sentinel_file)
        cmd = [
            sys.executable,
            str(client_script),
            str(self.started_sentinel_file),
            ipc_channel_name,
        ]
        self.client = subprocess.Popen(
            cmd
        )  # , stdout=open(os.devnull, "w"), stderr=open(os.devnull, "w"), stdin=open(os.devnull))

        for _ in xrange(WAIT):
            if self.started_sentinel_file.exists():
                MCerrDebug("sentinel found ", self.started_sentinel_file)
                break
            sleep(0.1)
        else:
            self.channel = None
            raise Exception("IPC connection wasn't established")

    def tearDown(self):
        self.channel.send("terminate", "foobar")
        try:
            for _ in xrange(WAIT):
                if self.client.poll() is not None:
                    break
                sleep(0.1)
            else:
                raise Exception("Don't know how to kill yet")
        finally:
            # garbage collect server channel object
            self.channel = None

            if self.started_sentinel_file.exists():
                self.started_sentinel_file.remove()

    def test_echo(self):
        payloads = []

        def echo_callback(_, payload):
            payloads.append(payload)

        self.channel.register_event("echo", echo_callback)
        self.channel.send("echo", "test_echo")

        for _ in xrange(10):
            self.channel.poll()
            sleep(0.1)
            if payloads:
                break

        self.assertEqual(payloads, ["test_echo"])

    def test_echo_removed(self):
        payloads = []

        def echo_callback(_, payload):
            payloads.append(payload)

        self.channel.register_event("echo", echo_callback)
        self.channel.send("remove_echo", "foobar")
        self.channel.send("echo", "test_echo_removed")

        for _ in xrange(10):
            self.channel.poll()
            sleep(0.1)
            if payloads:
                break

        self.assertEqual(payloads, [])

    def assertEqual(self, left, right):
        assert left == right, (left, right)


def main():
    tc = IPCTests()
    for method in [tc.test_echo, tc.test_echo_removed]:
        try:
            tc.setUp()
            method()
        finally:
            tc.tearDown()


if __name__ == "__main__":
    main()
