#!/usr/bin/env python3

from argparse import ArgumentParser
import dbus


class A2JControl:
    """
    Class holding all data and relevant functions to interact with the a2j dbus
    controller interface.
    """

    service_name = 'org.gna.home.a2jmidid'
    control_interface_name = service_name + '.control'
    controller_interface = None
    parser = None
    args = None

    def add_arg_parser(self):
        self.parser = ArgumentParser(
                description='Bridge ALSA MIDI to JACK MIDI')
        self.parser.add_argument(
                '--start',
                action='store_true',
                default=False,
                help='Start bridging')
        self.parser.add_argument(
                '--stop',
                action='store_true',
                default=False,
                help='Stop bridging')
        self.parser.add_argument(
                '--exit',
                action='store_true',
                default=False,
                help='Exit a2j bridge dbus service')
        self.parser.add_argument(
                '--status',
                action='store_true',
                default=False,
                help='Display bridging status')
        self.parser.add_argument(
                '--gjcn', '--jack-client-name',
                action='store_true',
                default=False,
                help='Get JACK client name')
        self.parser.add_argument(
                '--ma2jp',
                default=None,
                nargs=2,
                help='Map ALSA input port to JACK output port' +
                ' (requires ALSA client ID and JACK port ID arguments)')
        self.parser.add_argument(
                '--ma2jc',
                default=None,
                nargs=2,
                help='Map ALSA output port to JACK input port ' +
                '(requires ALSA client ID and JACK port ID arguments)')
        self.parser.add_argument(
                '--mj2a',
                default=None,
                nargs=1,
                help='Map JACK port to ALSA port (requires JACK port name)')
        self.parser.add_argument(
                '--ehw',
                action='store_true',
                default=False,
                help='Enable export of ALSA hardware ports')
        self.parser.add_argument(
                '--dhw',
                action='store_true',
                default=False,
                help='Disable export of ALSA hardware ports')
        self.parser.add_argument(
                '--aup',
                action='store_true',
                default=False,
                help='Allow unique port names')
        self.parser.add_argument(
                '--dup',
                action='store_true',
                default=False,
                help='Disallow unique port names')
        self.args = self.parser.parse_args()

    def initialize_dbus_controller_interface(self):
        controller = dbus.SessionBus().get_object(self.service_name, "/")
        self.controller_interface = dbus.Interface(
                controller,
                self.control_interface_name)

    def controller_start(self):
        print('--- start')
        self.controller_interface.start()

    def controller_stop(self):
        print('--- stop')
        self.controller_interface.stop()

    def controller_exit(self):
        print('--- exit')
        self.controller_interface.exit()

    def controller_status(self):
        print('--- status')
        if self.controller_interface.is_started():
            print('Bridging enabled')
        else:
            print('Bridging disabled')
        if self.controller_interface.get_hw_export():
            print('Hardware exported')
        else:
            print('Hardware not exported')
        if self.controller_interface.get_disable_port_uniqueness():
            print('Avoiding unique port names')
        else:
            print('Allowing unique port names')

    def controller_map_alsa_in_to_jack_playback(
            self,
            alsa_client_id,
            jack_port):
        print('--- map ALSA to JACK playback port')
        print('{}'.format(self.controller_interface.map_alsa_to_jack_port(
            alsa_client_id,
            jack_port,
            True)))

    def controller_map_alsa_out_to_jack_capture(
            self,
            alsa_client_id,
            jack_port):
        print('--- map ALSA to JACK capture port')
        print('{}'.format(self.controller_interface.map_alsa_to_jack_port(
            alsa_client_id,
            jack_port,
            False)))

    def controller_map_jack_port_to_alsa(self, jack_port):
        print('--- map JACK to ALSA port')
        out = self.controller_interface.map_jack_port_to_alsa(jack_port)
        print('{}:{} ({}:{})'.format(out[0], out[1], out[2], out[3]))

    def controller_get_jack_client_name(self):
        print('--- get jack client name')
        print(self.controller_interface.get_jack_client_name())

    def controller_export_hardware_ports(self, state):
        if state:
            print('--- enable export of hardware ports')
            self.controller_interface.set_hw_export(True)
        else:
            print('--- disable export of hardware ports')
            self.controller_interface.set_hw_export(False)

    def controller_set_port_name_uniqueness(self, state):
        if state:
            print('--- allow unique port names')
            self.controller_interface.set_disable_port_uniqueness(False)
        else:
            print('--- disallow unique port names')
            self.controller_interface.set_disable_port_uniqueness(True)

    def call_controller_function(self):
        if self.args.start:
            self.controller_start()
        elif self.args.stop:
            self.controller_stop()
        elif self.args.exit:
            self.controller_exit()
        elif self.args.status:
            self.controller_status()
        elif self.args.gjcn:
            self.controller_get_jack_client_name()
        elif self.args.ma2jp:
            self.controller_map_alsa_in_to_jack_playback(
                    self.args.ma2jp[0],
                    self.args.ma2jp[1])
        elif self.args.ma2jc:
            self.controller_map_alsa_in_to_jack_playback(
                    self.args.ma2jc[0],
                    self.args.ma2jc[1])
        elif self.args.mj2a:
            self.controller_map_jack_port_to_alsa(self.args.mj2a[0])
        elif self.args.ehw:
            self.controller_export_hardware_ports(True)
        elif self.args.dhw:
            self.controller_export_hardware_ports(False)
        elif self.args.dup:
            self.controller_set_port_name_uniqueness(False)
        elif self.args.aup:
            self.controller_set_port_name_uniqueness(True)
        else:
            self.parser.print_help()

    def __init__(self):
        self.initialize_dbus_controller_interface()
        self.add_arg_parser()
        self.call_controller_function()


if __name__ == '__main__':
    A2JControl()
