'''
Pymodbus Web Frontend
=======================================

This is a simple web frontend using bottle as the web framework.
This can be hosted using any wsgi adapter.
'''
from bottle import route, request, Bottle
from bottle import jinja2_template as template
from pymodbus.device import ModbusAccessControl
from pymodbus.device import ModbusControlBlock

#---------------------------------------------------------------------------# 
# REST API
#---------------------------------------------------------------------------# 
class Response(object):
    '''
    A collection of common responses for the frontend api
    '''
    successful = { 'status' : 200 }
    failure    = { 'status' : 500 }

class ModbusApiWebApp(object):
    '''
    This is the web REST api interace into the pymodbus
    service.  It can be consumed by any utility that can
    make web requests (javascript).
    '''
    _namespace = '/api/v1'

    def __init__(self, server):
        ''' Initialize a new instance of the ModbusApi

        :param server: The current server instance
        '''
        self._server = server

    #---------------------------------------------------------------------#
    # Device API
    #---------------------------------------------------------------------#
    def get_device(self):
        return {
            'mode'        : self._server.control.Mode,
            'delimiter'   : self._server.control.Delimiter,
            'listen-only' : self._server.control.ListenOnly,
            'identity'    : self._server.control.Identity.summary(),
            'counters'    : dict(self._server.control.Counter),
            'diagnostic'  : self._server.control.getDiagnosticRegister(),
        }
    
    def get_device_identity(self):
        return {
            'identity' : dict(self._server.control.Identity)
        }
    
    def get_device_events(self):
        return {
            'events' : self._server.control.Events
        }
    
    def delete_device_events(self):
        self._server.control.clearEvents()
        return Response.successful
    
    def get_device_host(self):
        return {
            'hosts' : list(self._server.access)
        }
    
    def post_device_host(self):
        value = request.forms.get('host')
        if value:
            self._server.access.add(value)
        return Response.successful
    
    def delete_device_host(self):
        value = request.forms.get('host')
        if value:
            self._server.access.remove(value)
        return Response.successful
    
    def post_device_delimiter(self):
        value = request.forms.get('delimiter')
        if value:
            self._server.control.Delimiter = value
        return Response.successful
    
    def post_device_mode(self):
        value = request.forms.get('mode')
        if value:
            self._server.control.Mode = value
        return Response.successful
    
    def post_device_reset(self):
        self._server.control.reset()
        return Response.successful

    #---------------------------------------------------------------------#
    # Datastore API
    #---------------------------------------------------------------------#

#---------------------------------------------------------------------------# 
# Configurations
#---------------------------------------------------------------------------# 
def register_routes(application, register):
    ''' A helper method to register the routes of an application
    based on convention.

    :param application: The application instance to register
    :param register: The bottle instance to register the application with
    '''
    from bottle import route

    methods = dir(application)
    methods = filter(lambda n: not n.startswith('_'), methods)
    for method in methods:
        pieces = method.split('_')
        verb, path = pieces[0], pieces[1:]
        path.insert(0, application._namespace)
        path = '/'.join(path)
        func = getattr(application, method)
        register.route(path, method=verb, name=method)(func)

def build_application(server):
    ''' Helper method to create and initiailze a bottle application

    :param server: The modbus server to pull instance data from
    :returns: An initialied bottle application
    '''
    api = ModbusApiWebApp(server)
    register = Bottle()
    register_routes(api, register)
    return register

#---------------------------------------------------------------------------# 
# Start Methods
#---------------------------------------------------------------------------# 
def RunModbusFrontend(server, port=503):
    ''' Helper method to host bottle in twisted

    :param server: The modbus server to pull instance data from
    :param port: The port to host the service on
    '''
    from bottle import TwistedServer, run
    application = build_application(server)
    run(app=application, server=TwistedServer, port=port)

def RunDebugModbusFrontend(server, port=503):
    ''' Helper method to start the bottle server

    :param server: The modbus server to pull instance data from
    :param port: The port to host the service on
    '''
    from bottle import run

    application = build_application(server)
    run(app=application, port=port)

if __name__ == '__main__':
    from pymodbus.server.async import ModbusServerFactory

    RunDebugModbusFrontend(ModbusServerFactory)
