#! @PYTHON3@

import ovs.db.error
import ovs.db.schema
import getopt
import sys

argv0 = sys.argv[0]


def printEdge(tableName, type, baseType, label):
    if baseType.ref_table_name:
        if type.n_min == 0:
            if type.n_max == 1:
                arity = "?"
            elif type.n_max == sys.maxsize:
                arity = "*"
            else:
                arity = "{,%d}" % type.n_max
        elif type.n_min == 1:
            if type.n_max == 1:
                arity = ""
            elif type.n_max == sys.maxsize:
                arity = "+"
            else:
                arity = "{1,%d}" % type.n_max

        options = {}
        options['label'] = '"%s%s"' % (label, arity)
        if baseType.ref_type == 'weak':
            options['style'] = 'dotted'
        print("\t%s -> %s [%s];" % (
            tableName,
            baseType.ref_table_name,
            ', '.join(['%s=%s' % (k, v) for k, v in options.items()])))


def schemaToDot(schemaFile, arrows):
    schema = ovs.db.schema.DbSchema.from_json(ovs.json.from_file(schemaFile))

    print("digraph %s {" % schema.name)
    print('\trankdir=LR;')
    print('\tsize="6.5,4";')
    print('\tmargin="0";')
    print("\tnode [shape=box];")
    if not arrows:
        print("\tedge [dir=none, arrowhead=none, arrowtail=none];")
    for tableName, table in schema.tables.items():
        options = {}
        if table.is_root:
            options['style'] = 'bold'
        print("\t%s [%s];" % (
            tableName,
            ', '.join(['%s=%s' % (k, v) for k, v in options.items()])))
        for columnName, column in table.columns.items():
            if column.type.value:
                printEdge(tableName, column.type, column.type.key,
                          "%s key" % columnName)
                printEdge(tableName, column.type, column.type.value,
                          "%s value" % columnName)
            else:
                printEdge(tableName, column.type, column.type.key, columnName)
    print("}")


def usage():
    print("""\
%(argv0)s: compiles ovsdb schemas to graphviz format
Prints a .dot file that "dot" can render to an entity-relationship diagram
usage: %(argv0)s [OPTIONS] SCHEMA
where SCHEMA is an OVSDB schema in JSON format

The following options are also available:
  --no-arrows                 omit arrows from diagram
  -h, --help                  display this help message
  -V, --version               display version information\
""" % {'argv0': argv0})
    sys.exit(0)


if __name__ == "__main__":
    try:
        try:
            options, args = getopt.gnu_getopt(sys.argv[1:], 'hV',
                                              ['no-arrows',
                                               'help', 'version'])
        except getopt.GetoptError as geo:
            sys.stderr.write("%s: %s\n" % (argv0, geo.msg))
            sys.exit(1)

        arrows = True
        for key, value in options:
            if key == '--no-arrows':
                arrows = False
            elif key in ['-h', '--help']:
                usage()
            elif key in ['-V', '--version']:
                print("ovsdb-dot (Open vSwitch) @VERSION@")
            else:
                sys.exit(0)

        if len(args) != 1:
            sys.stderr.write("%s: exactly 1 non-option argument required "
                             "(use --help for help)\n" % argv0)
            sys.exit(1)

        schemaToDot(args[0], arrows)

    except ovs.db.error.Error as e:
        sys.stderr.write("%s: %s\n" % (argv0, e.msg))
        sys.exit(1)

# Local variables:
# mode: python
# End:
