## Copyright 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/>.
##
from __future__ import with_statement

import sys
try:
    import json
except:
    import simplejson as json

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

class MessageType:
    def __init__(self, j):
        self.wire_selector = j['selector']
        self.selector = mlify(self.wire_selector)
        self.constructor = self.selector.capitalize()
        self.wire_argnames = j['args']
        self.argnames = map(mlify, 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:
    raw_spec = json.load(f)

copyright_stmt = '(* %s *)' % (raw_spec['copyright'])
license = '\n'.join((('(* %s *)' % (x,) if x else '') for x in raw_spec['license']))
spec = map(MessageType, raw_spec['definitions'])

def print_list(o, xs, sep, c):
    sys.stdout.write(o)
    needsep = False
    for x in xs:
        if needsep:
            sys.stdout.write(sep)
        else:
            needsep = True
        sys.stdout.write(x)
    sys.stdout.write(c)

def print_codec():
    print copyright_stmt
    print
    print license
    print
    print '(* WARNING: Autogenerated code. Do not edit by hand! *)'
    print
    print 'open Sexp'
    print
    print 'type t ='
    for t in spec:
        if t.argnames:
            print '  | %s of ' % (t.constructor),
            print_list('(', ['Sexp.t' for n in t.argnames], ' * ', ')\n')
        else:
            print '  | %s' % t.constructor
    print '  | UNKNOWN of Sexp.t'
    print
    print 'let sexp_of_message m = match m with'
    for t in spec:
        sys.stdout.write('  | %s' % t.constructor)
        if t.argnames:
            print_list(' (', [n for n in t.argnames], ', ', ')')
        print ' ->'
        sys.stdout.write('    Arr [Str "%s"' % t.wire_selector)
        if t.argnames:
            print_list('; ', t.argnames, '; ', '')
        print ']'
    print '  | UNKNOWN s -> s'
    print
    print 'let message_of_sexp s = match s with'
    for t in spec:
        sys.stdout.write('  | Arr [Str "%s"' % t.wire_selector)
        if t.argnames:
            print_list('; ', t.argnames, '; ', '')
        print '] ->'
        sys.stdout.write('    %s' % t.constructor)
        if t.argnames:
            print_list(' (', [n for n in t.argnames], ', ', ')')
        print
    print '  | _ -> UNKNOWN s'
    print
    for t in spec:
        sys.stdout.write('let %s' % t.selector)
        if t.argnames:
            print_list(' (', t.argnames, ', ', ')')
        sys.stdout.write(' = sexp_of_message (%s' % t.constructor)
        if t.argnames:
            print_list(' (', t.argnames, ', ', ')')
        sys.stdout.write(')\n')
    print

if __name__ == '__main__':
    print_codec()
