from __future__ import print_function

from metakernel import MetaKernel

import sys
import signal
import yap
import yapex

import ipywidgets as widgets


def eprint(*args, **kwargs):
    print(*args, file=sys.stderr, **kwargs)


class MetaKernelyap(MetaKernel):
    implementation = 'MetaKernel YAP'
    implementation_version = '1.0'
    language = 'text'
    language_version = '0.1'
    banner = "MetaKernel YAP"
    language_info = {
        'mimetype': 'text/prolog',
        'name': 'text',
        # ------ If different from 'language':
         'codemirror_mode': {
            "version": 2,
            "name": "prolog"
         },
         'pygments_lexer': 'prolog',
         'version'       : "0.0.1",
        'file_extension': '.yap',
        'help_links': MetaKernel.help_links,
    }

    def __init__(self, **kwargs):
        MetaKernel.__init__(self, **kwargs)
        self._start_yap(**kwargs)
        self.olines = ""
        self.ask = True

    def _start_yap(self, **kwargs):
        # Signal handlers are inherited by forked processes, and we can't easily
        # reset it from the subprocess. Since kernelapp ignores SIGINT except in
        # message handlers, we need to temporarily reset the SIGINT handler here
        # so that yap and its children are interruptible.
        sig = signal.signal(signal.SIGINT, signal.SIG_DFL)
        try:
            self.engine = yap.YAPEngine()
            self.q = None
            self.engine.query("load_files(library(python), [])").command()
            self.engine.query("load_files(library(jupyter), [])").command()
            banner = "YAP {0} Kernel".format(self.engine.version())
            self.olines = banner
        finally:
             signal.signal(signal.SIGINT, sig)

        # Register Yap function to write image data to temporary file
        #self.yapwrapper.run_command(image_setup_cmd)

    def get_usage(self):
        return "This is the YAP kernel."

    def query_prolog(self, s):

        if not self.q:
            self.q = self.engine.query(s)
        if self.q.next():
            myvs = self.q.namedVarsCopy()
            wrote = False
            if myvs:
                i = 0
                for peq in myvs:
                    name = peq[0]
                    bind = peq[1]
                    if bind.isVar():
                        var = yap.YAPAtom('$VAR')
                        f = yap.YAPFunctor(var, 1)
                        bind.unify(yap.YAPApplTerm(f, (name)))
                    else:
                        i = bind.numberVars(i, True)
                        print(name.text() + " = " + bind.text())
                        wrote = True
            print("yes")
            if self.q.deterministic():
                self.closeq()
            return
        print("No (more) answers")
        self.closeq()
        return

    def closeq( self):
        if self.q:
            self.q.close()
            self.q = None

    def do_execute_direct(self, code):
        if not code.strip():
            return ""
        lines = code.split("\n")
        interrupted = False
        self.doReset = True
        nlines = ""
        try:
            for line in lines:
                line = line.strip()
                if line.startswith('#'):
                    # wait
                    print( "comment")
                elif line.startswith('%'):
                    # wait
                    call_magic( line )
                elif line.endswith(';'):
                    nlines += line.rstrip(';').rstrip()
                    self.doReset = False
                    break
                elif line.endswith('!'):
                    nlines += line.rstrip('!').rstrip()
                    self.ask = False
                    self.doReset = False
                    break
                else:
                    line = line.rstrip()
                    if line:
                        nlines += line + "\n"
            if nlines != self.olines:
                self.closeq( )
                self.olines = nlines
            elif self.doReset:
                opt = widgets.ToggleButtons(
                    description='Query Solutions:',
                    options=['First', 'Next', 'All'],
                )
                print( opt )
                if opt == 'First':
                    self.closeq( )
                elif  opt == 'Next':
                    self.doReset = False
                else:
                    self.ask = False
                    self.doReset = False
            self.query_prolog( nlines )
            while not self.ask and self.q:
                self.query_prolog( nlines )

        except SyntaxError as err:
            print("Syntax Error error: {0}".format(err))
        except EOFError:
            return
        except RuntimeError as err:
            print("YAP Execution Error: {0}".format(err))
        except ValueError:
            print("Could not convert data to an integer.")
        except KeyboardInterrupt:
            return 'stopped by user'
        except:
            print("Unexpected error:", sys.exc_info()[0])
            raise

    def do_complete(self, code, cursor_pos):
        print(code)
        print(cursor_pos)
        eprint( code, " -- ", str(cursor_pos ) )
        # code = code[:cursor_pos]
        # default = {'matches': [], 'cursor_start': 0,
        #            'cursor_end': cursor_pos, 'metadata': dict(),
        #            'status': 'ok'}

        # if not code or code[-1] == ' ':
        #     return default

        # tokens = code.replace(';', ' ').split()
        # if not tokens:
        #     return default

        # matches = []
        # token = tokens[-1]
        # start = cursor_pos - len(token)

        # if token[0] == '$':
        #     # complete variables
        #     cmd = 'compgen -A arrayvar -A export \
        #     -A variable %s' % token[1:] # strip leading $
        #     output = self.bashwrapper.run_command(cmd).rstrip()
        #     completions = set(output.split())
        #     # append matches including leading $
        #     matches.extend(['$'+c for c in completions])
        # else:
        #     # complete functions and builtins
        #     cmd = 'compgen -cdfa %s' % token
        #     output = self.bashwrapper.run_command(cmd).rstrip()
        #     matches.extend(output.split())

        # if not matches:
        #     return default
        # matches = [m for m in matches if m.startswith(token)]

        # return {'matches': sorted(matches), 'cursor_start': start,
        #         'cursor_end': cursor_pos, 'metadata': dict(),
        #         'status': 'ok'}

    def repr(self, data):
        return repr(data)

if __name__ == '__main__':
    try:
        from ipykernel.kernelapp import IPKernelApp
    except ImportError:
        from jupyter_client.zmq.kernelapp import IPKernelApp
    IPKernelApp.launch_instance(kernel_class=MetaKernelyap)