from __future__ import with_statement

## Copyright 2010, 2011, 2012 Tony Garnock-Jones <tonygarnockjones@gmail.com>.
##
## This file is part of Hop.
##
## Hop is free software: you can redistribute it and/or modify it
## under the terms of the GNU General Public License as published by
## the Free Software Foundation, either version 3 of the License, or
## (at your option) any later version.
##
## Hop is distributed in the hope that it will be useful, but WITHOUT
## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
## or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
## License for more details.
##
## You should have received a copy of the GNU General Public License
## along with Hop.  If not, see <http://www.gnu.org/licenses/>.

copyright_stmt = \
'''/* Copyright 2010, 2011, 2012 Tony Garnock-Jones <tonygarnockjones@gmail.com>.
 *
 * This file is part of Hop.
 *
 * Hop is free software: you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Hop is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
 * License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Hop.  If not, see <http://www.gnu.org/licenses/>.
 */
'''

import sys
import json

def cify(s):
    s = s.replace('-', '_')
    s = s.replace(' ', '_')
    return s

class MessageType:
    def __init__(self, j):
        self.wire_selector = j['selector']
        self.selector = cify(self.wire_selector)
        self.wire_argnames = j['args']
        self.argnames = map(cify, self.wire_argnames)

    def format_args(self, template, separator = ', '):
        return separator.join([template % (x,) for x in self.argnames])

with file("../../protocol/messages.json") as f:
    spec = map(MessageType, json.load(f)['definitions'])

def entrypoint_header():
    print copyright_stmt
    print
    print '#ifndef cmsg_messages_h'
    print '#define cmsg_messages_h'
    print
    print 'extern void init_messages(void);'
    print
    for t in spec:
        print 'extern sexp_t *selector_%s;' % (t.selector,)
    print
    for t in spec:
        print 'extern sexp_t *message_%s(%s);' % (t.selector, t.format_args('sexp_t *%s'))
    print
    print 'typedef union parsed_message_t_ {'
    for t in spec:
        if t.argnames:
            print '  struct { sexp_t %s; } %s;' % (t.format_args('*%s'), t.selector)
    print '} parsed_message_t;'
    for t in spec:
        print
        print 'static inline int parse_%s(sexp_t *message, parsed_message_t *out) {' % \
            (t.selector,)
        print '  if (!sexp_pairp(message)) return 0;'
        print '  if (sexp_cmp(sexp_head(message), selector_%s) != 0) return 0;' % (t.selector,)
        for n in t.argnames:
            print '  if (!sexp_pseudo_pop(&message)) return 0;'
            print '  out->%s.%s = sexp_head(message);' % (t.selector, n)
        print '  return sexp_tail(message) == NULL;'
        print '}'
    print
    print '#endif'

def entrypoint_body():
    print copyright_stmt
    print
    print '#include <stdlib.h>'
    print '#include <string.h>'
    print '#include <stdio.h>'
    print '#include <signal.h>'
    print
    print '#include <assert.h>'
    print
    print '#include "cmsg_private.h"'
    print '#include "ref.h"'
    print '#include "sexp.h"'
    print '#include "messages.h"'
    print
    for t in spec:
        print 'sexp_t *selector_%s = NULL;' % (t.selector,)
    print
    print 'void init_messages(void) {'
    for t in spec:
        print '  selector_%s = sexp_cstring("%s");' % (t.selector, t.wire_selector)
    for t in spec:
        print '  INCREF(selector_%s);' % (t.selector,)
    print '}'
    for t in spec:
        print
        print 'sexp_t *message_%s(%s) {' % (t.selector, t.format_args('sexp_t *%s'))
        print '  sexp_t *m = NULL;'
        for n in reversed(t.argnames):
            print '  m = sexp_cons(%s, m);' % (n,)
        print '  return sexp_cons(selector_%s, m);' % (t.selector,)
        print '}'

if __name__ == '__main__':
    drivername = sys.argv[1]
    globals()['entrypoint_' + drivername]()
