#!/usr/bin/env python
# Ingen Interactive Shell
# Copyright 2011-2012 David Robillard <http://drobilla.net>
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

import ingen
import os.path
import re
import shlex
import sys
import time
try:
    import readline
except:
    pass

def print_usage():
    print('''Usage: ingenish [OPTION]... [COMMAND [ARGUMENT]...]

A command line interface to an Ingen server.  A command can be given directly
on the command line, or when run with no arguments an interactive shell is
launched.

Options:
    -s ADDRESS    The address of the Ingen server.  Default is the local server
                  at unix:///tmp/ingen.sock but remote servers can be used with
                  an address like tcp:///my-ingen-server-host:16180

Commands:
    put PATH TURTLE_FRAGMENT
    set PATH TURTLE_FRAGMENT
    connect TAIL_PATH HEAD_PATH
    disconnect TAIL_PATH HEAD_PATH
    delete PATH
    help
    exit

Paths are UNIX-style paths with strict LV2 symbol components, e.g. /foo/bar_2.
Turtle fragments are used verbatim as the body of blank nodes, the syntax is
identical to the descriptions in Ingen patch files.

Example:
    ingenish put /left_in 'a lv2:InputPort ; a lv2:AudioPort'
    ingenish put /left_out 'a lv2:OutputPort ; a lv2:AudioPort'

    ingenish put /tone 'a ingen:Block ; ingen:prototype <http://drobilla.net/plugins/mda/Shepard>'
    ingenish put /combo 'a ingen:Block ; ingen:prototype <http://drobilla.net/plugins/mda/Combo>'
    ingenish connect /left_in /tone/left_in
    ingenish connect /tone/left_out /combo/left_in
    ingenish connect /combo/left_out /left_out
    ingenish set /tone/output 'ingen:value 0.7'
''')

def run(cmd):
    if cmd[0] == 'help':
        print_usage()
    elif cmd[0] == 'exit':
        sys.exit(0)
    elif cmd[0] == 'put' and len(cmd) == 3:
        return ingen.put(cmd[1], cmd[2])
    elif cmd[0] == 'set' and len(cmd) == 3:
        return ingen.set(cmd[1], cmd[2])
    elif cmd[0] == 'connect' and len(cmd) == 3:
        return ingen.connect(cmd[1], cmd[2])
    elif cmd[0] == 'disconnect' and len(cmd) == 3:
        return ingen.disconnect(cmd[1], cmd[2])
    elif cmd[0] == 'delete' and len(cmd) == 2:
        return ingen.delete(cmd[1])
    return False

a = 1
server = 'unix:///tmp/ingen.sock'
if len(sys.argv) > 1:
    if sys.argv[a] == '-s':
        server = sys.argv[a + 1]
        a = a + 2
    elif sys.argv[a][0] == '-':
        print_usage()
        sys.exit(1)

ingen = ingen.Remote(server)

if len(sys.argv) - a == 0:
    print('Ingen server at %s' % server)
    while True:
        try:
            run(shlex.split(raw_input('> ')))
        except (EOFError, KeyboardInterrupt, SystemExit):
            break
        except:
            print('error: %s' % sys.exc_info()[1])
else:
    try:
        update = run(sys.argv[1:])
        if update:
            print(update.serialize(format='n3'))
    except:
        print('error: %s' % sys.exc_info()[1])