import cmq

'''
thunk

any rpc like this
{
'method' : 'thunk',
'params' : 'value'
}
become a function that return 'value'
the function use the id as name

it is called a thunk
it just return its value

should be stored somewhere
{
    'thunk':{
        '' : '',
        '' : ''
    }
}
'''

###############################################################################
#now thentergrated client and agent 
###############################################################################

def _agent_wipe(params):
    if isinstance(params,list):
        return [    _agent_wipe(param)
                    for param in params ]
    assert isinstance(params,dict), "expect dictionary parameter"
    if not 'url' in params:
        params['url'] = 'http://localhost:5984/'
    assert 'db' in params, "expect db in params"
    if not 'view' in params:
        params['view'] = '_all_docs'
    print('wipe database %s%s'%(params['url'],params['db']))
    server = couchdb.Server(params['url'])
    db = server[params['db']]
    keylst = [  key
                for key in db.view(params['view'])
                if not '_design/' in key.id         ]
    for key in keylst:
        print('delete %s' %key.id)
        db.delete({'_id':key.id,'_rev':key['value']['rev']})
    return keylst

def _agent_create(params):
    if isinstance(params,list):
        return [    _agent_create(param)
                    for param in params ]
    assert isinstance(params,dict)
    assert 'url' in params
    assert 'db' in params
    print('create database %s%s'%(params['url'],params['db']))
    server = couchdb.Server(params['url'])
    return server.create(params['db']) 

def _agent_emit(params):
    if isinstance(params,list):
        return [    _agent_create(param)
                    for param in params ]
    assert isinstance(params,dict)
    assert 'url' in params
    assert 'db' in params
    assert 'rpc' in params
    raise Exception("not implemented")
    return

_agentProcDir = {
    'wipe' : _agent_wipe,
    'create' : _agent_create
}

def cmqarg(procdir,addArgFn=None):
    import argparse

    parser = argparse.ArgumentParser(description='Couch Message Queue')
    parser.add_argument('--name',action='store',help='agent name')
    parser.add_argument('--db',action='store',help='database name')
    parser.add_argument('--url',action='store',default='http://localhost:5984/',help='database url')
    parser.add_argument('--process',action='store_true',help='query database and execute instruction')
    parser.add_argument('--view',action='store',default='_all_docs',help='couchdb view to use')
    parser.add_argument('--limit',action='store',default='0',help='limit quantity of instruction to run')
    parser.add_argument('--test',action='store_true',help="run unittest")
    if addArgFn:
        parser = addArgFn(parser)
    args = parser.parse_args()
    if args.test:
        import doctest
        doctest.testmod(optionflags=doctest.ELLIPSIS)#, verbose=True)
    if args.process:
        assert args.name
        assert args.db
        assert args.url
        assert args.view
        assert args.limit
        print('processing %s%s' % (args.url, args.db))
        c = connection(args.url,args.db,args.name)
        c.process(procdir,view=args.view, qty=args.limit)
    return args

if __name__ == '__main__':
    import json
    def addArgument(parser):
        parser.add_argument('--emit',nargs='+',help='method with json serialisable argument list')
        parser.add_argument('--report',action="store_true",help="return report from mq")
        parser.add_argument('--trace',action="store",help='return execution trace from mq with give id in it, even if in the middle of the trace')
        return parser

    args = cmq.cmqarg(_agentProcDir,addArgument)
    if args.emit:
        import json
        assert args.url
        assert args.db
        assert args.name
        print('emit %s to %s%s with %s'%(args.emit[0],args.url,args.db,args.emit[1:]))
        c = cmq.connection(args.url,args.db,args.name)
        method = args.emit[0]
        def tryJson(s):
            try:
                return json.loads(s)
            except:
                return str(s)
        params = [ tryJson(param) for param in args.emit[1:] if param ]
        call = caller().addCall(method,params).build()
        c.emit(call)
        #c.purge()    #deprecated
    if args.report:
        assert args.url
        assert args.db
        assert args.name
        print('building report')
        c = cmq.connection(args.url,args.db,args.name)
        print(c.report(view=args.view))
    if args.trace:
        assert args.url
        assert args.db
        assert args.name
        print('trace execution')
        c = cmq.connection(args.url,args.db,args.name)
        print(c.trace(args.trace,view=args.view))
    print('done')
