#!python

'''
Usage:
    eavesdroppr --config <configfile> channels
    eavesdroppr --config <configfile> -c <event_channel>
    eavesdroppr --config <configfile> -c <event_channel> -g (trigger | procedure)

Options:
    -g --generate    generate SQL LISTEN/NOTIFY code          
    -c --channel     target event channel
'''

'''
+mdoc+

eavesdroppr: command-line utility for "eavesdropping" on PostgreSQL databases.
This is a code generator and dependency injector for observing Postgres DB changes
(inserts or updates) via the PostgreSQL LISTEN/NOTIFY service. 

Event "channels" (a channel is a named context for listening to Postgres inserts/updates) are set up
in a YAML configuration file, using the following structure:


channels:
  <channel_name>:
          handler_function: <function_name>
          db_table_name: <table_under_observation>
          db_operation: (INSERT or UPDATE)
          pk_field_name: <name_of_primary_key_field>
          pk_field_type: <column type of primary key field>
          db_schema: <schema>
          db_proc_name: <procedure_name> ## optional; autogenerated if blank
          db_trigger_name: <trigger_name> ## optional; autogenerated if blank

          payload_fields:
            - <column_1>
            - <column_2>
            ...            

To use eavesdroppr, once you have created a YAML configuration:

1. Run eavesdroppr in generate mode (using the -g option) to generate the
   trigger and stored procedure DDL scripts necessary for setting up listen/notify on a given channel.

2. Execute the DDL scripts, using a database client of your choice. 

3. Run eavesdroppr in normal mode (using the -c option to specify the channel). 


eavesdroppr with start up and enter an infinite loop. The handler function in the configured channel 
will execute each time the database commits an INSERT or UPDATE against the designated table (as configured), 
and will continue to do so for as long as the eavesdroppr process is running.
  
+mdoc+
'''


import os, sys
import docopt
import yaml
import pgpubsub
import logging
from snap import snap, common
from mercury import edcore

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)


def main(args):

    yaml_config = None
    if args.get('--config'):
        yaml_config = common.read_config_file(args['<configfile>'])

    if args.get('channels'):
        print('\n'.join(yaml_config['channels'].keys()))
        return 0

    service_registry = common.ServiceObjectRegistry(snap.initialize_services(yaml_config))

    channel_id = args['<event_channel>']
    if not yaml_config['channels'].get(channel_id):
        raise edcore.NoSuchEventChannel(channel_id)

    channel_config = yaml_config['channels'][channel_id]

    project_dir = common.load_config_var(yaml_config['globals']['project_home'])
    sys.path.append(project_dir)

    handler_module_name = yaml_config['globals']['handler_module']
    handler_function_name = yaml_config['channels'][channel_id].get('handler_function') or 'default_handler'
    handler_function = common.load_class(handler_function_name, handler_module_name)
    connect_function_name = yaml_config['globals']['pubsub_connect_func']
    connect_function = common.load_class(connect_function_name, handler_module_name)

    if args['--generate']:
        edcore.generate_code(channel_id, channel_config, **args)
    else:
        edcore.listen(channel_id,
                      handler_function,
                      connect_function,
                      service_registry)


if __name__ == '__main__':
    args = docopt.docopt(__doc__)
    main(args)
