# Evan Widloski - 2019-02-23
# Use reMarkable as mouse input

import threading

import argparse
import logging
import os
import sys
import struct
from getpass import getpass

import paramiko
import paramiko.agent

logging.basicConfig(format='%(message)s')
log = logging.getLogger(__name__)


def open_remote_device(args, file='/dev/input/event0'):
    """
    Open a remote input device via SSH.

    Args:
        args: argparse arguments
        file (str): path to the input device on the device
    Returns:
        (paramiko.ChannelFile): read-only stream of input events
    """
    log.info("Connecting to input '{}' on '{}'".format(file, args.address))

    client = paramiko.SSHClient()
    client.set_missing_host_key_policy(paramiko.AutoAddPolicy())

    pkey = None
    password = None

    agent = paramiko.agent.Agent()

    if args.key is not None:
        password = None
        try:
            pkey = paramiko.RSAKey.from_private_key_file(os.path.expanduser(args.key))
        except paramiko.ssh_exception.PasswordRequiredException:
            passphrase = getpass(
                "Enter passphrase for key '{}': ".format(os.path.expanduser(args.key))
            )
            pkey = paramiko.RSAKey.from_private_key_file(
                os.path.expanduser(args.key),
                password=passphrase
            )
    elif args.password:
        password = args.password
        pkey = None
    elif not agent.get_keys():
        password = getpass(
            "Password for '{}': ".format(args.address)
        )
        pkey = None

    client.connect(
        args.address,
        username='root',
        password=password,
        pkey=pkey,
        look_for_keys=False
    )

    session = client.get_transport().open_session()

    paramiko.agent.AgentRequestHandler(session)

    # Start reading events
    _, stdout, _ = client.exec_command('cat ' + file)

    print("connected to", args.address)

    return stdout


def main():
    try:
        parser = argparse.ArgumentParser(description="use reMarkable tablet as a mouse input")
        parser.add_argument('--debug', action='store_true', default=False, help="enable debug messages")
        parser.add_argument('--key', type=str, metavar='PATH', help="ssh private key")
        parser.add_argument('--password', default=None, type=str, help="ssh password")
        parser.add_argument('--address', default='10.11.99.1', type=str, help="device address")
        parser.add_argument('--mode', default='fill', choices=['fit', 'fill'], help="scale setting")
        parser.add_argument('--orientation', default='right', choices=['top', 'left', 'right', 'bottom'], help="position of tablet buttons")
        parser.add_argument('--monitor', default=0, type=int, metavar='NUM', help="monitor to output to")
        parser.add_argument('--threshold', metavar='THRESH', default=600, type=int, help="stylus pressure threshold (default 600)")
        parser.add_argument('--evdev', action='store_true', default=False, help="use evdev to support pen pressure (requires root, Linux only)")

        args = parser.parse_args()

        remote_stylus = open_remote_device(args, '/dev/input/event0')
        remote_finger = open_remote_device(args, '/dev/input/event1')

        if args.debug:
            logging.getLogger('').setLevel(logging.DEBUG)
            log.setLevel(logging.DEBUG)
            log.info('Debugging enabled...')
        else:
            log.setLevel(logging.INFO)

        if args.evdev:
            from remarkable_mouse.evdev import create_local_device, pipe_device

            try:
                local_device = create_local_device()
                log.info("Created virtual input device '{}'".format(local_device.devnode))
            except PermissionError:
                log.error('Insufficient permissions for creating a virtual input device')
                log.error('Make sure you run this program as root')
                sys.exit(1)

            pipe_device(args, remote_device, local_device)

        else:
            from remarkable_mouse.pynput import read_tablet
            from remarkable_mouse.pynput import read_finger
            stylus_thread = threading.Thread(target=read_tablet, args=(args, remote_stylus))
            finger_thread = threading.Thread(target=read_finger, args=(args, remote_finger))

            stylus_thread.start()
            finger_thread.start()


    except KeyboardInterrupt:
        pass
    except EOFError:
        pass

if __name__ == '__main__':
    main()
