#!/usr/bin/env python

""" [CODEV-NIC #149] Converts the tickets in the RT database into a
'.dot' (Graphviz, http://www.graphviz.org/) graph.

Author:

Stephane Bortzmeyer <bortzmeyer@nic.fr>

Licence:

What you want

"""

import psycopg
import sys
import string
import time
import getopt
import re

# Default values
DSN="dbname=rt3"
include_closed = False # TODO: implement it!
printing = False
dependency_color = "black"
reference_color = "green"

def usage():
    sys.stderr.write("Usage: %s [options]\n" % sys.argv[0])
    sys.stderr.write("""
    Possible options:
      --include-closed (-c): Include closed or stalled tickets
      --DSN (-d): a PostgreSQL DSN (like 'dbname=rt') to indicate the database to connect to
      """)

def error(message):
    sys.stderr.write("ERROR: %s\n" % message)
    sys.exit(1)

def sanitize(phrase):
    result = re.sub("\"", "'", phrase)
    return result

try:
    optlist, args = getopt.getopt (sys.argv[1:], "cd:",
                                   ["include-closed", "DSN="])
    for option, value in optlist:
        if option == "--help" or option == "-h":
            usage()
            sys.exit(0)
        elif option == "--DSN" or option == "-d":
            DSN = value
        elif option == "--include-closed" or option == "-c":
            include_closed = True
        else:
            error ("Unknown option " + option)
except getopt.error, reason:
    error ("Usage: " + sys.argv[0] + ": " + reason)

if len(args) != 0:
    usage()
    error("No argument allowed")

connection = psycopg.connect(DSN)
cursor = connection.cursor()
tickets = {}
priorities = {}
dependencies = {}
references = {}

# Find the tickets
# TODO: due dates
cursor.execute("""
   SELECT id,subject,priority,due FROM Tickets WHERE status='new' OR status='open';
   """)
for tuple in cursor.fetchall():
    id = int(tuple[0])
    tickets[id] = sanitize(tuple[1]) # TODO: also convert from UTF-8?
    priorities[id] = int(tuple[2])
    
# Find the relationships between tickets (links)
# TODO: other types (parent / child)
cursor.execute("""
   SELECT localbase,localtarget,type FROM Links WHERE 
      ((SELECT status FROM Tickets WHERE id = localtarget) = 'new' OR
      (SELECT status FROM Tickets WHERE id = localtarget) = 'open') AND
      ((SELECT status FROM Tickets WHERE id = localbase) = 'new' OR
      (SELECT status FROM Tickets WHERE id = localbase) = 'open')
   """)
for tuple in cursor.fetchall():
    type = str(tuple[2])
    if type == 'DependsOn':
        dependencies["%i-%i" % (int(tuple[0]), int(tuple[1]))] = True
    elif type == 'RefersTo':
        references["%i-%i" % (int(tuple[0]), int(tuple[1]))] = True
connection.close()

#output = open("RT-%s.dot" % time.strftime ("%Y-%B-%d:%H:%M",
#                                           time.localtime(time.time())),
#              "w")
output = open("RT.dot", 
              "w")
if printing:
    presentation = """
         // Size in inches
         page="8.5,11.6";
         ratio = fill;
    """
else:
    presentation = """
         // Size in inches
         size="8.5,11.6";
         ratio = auto;
    """
output.write("""digraph RT {
         label = "RT tickets on %s. %i tickets.";
         fontsize = 24;
         overlap = scale;
         %s
""" % (time.strftime("%A %d %B %Y %H:%M UT", time.gmtime(time.time())),
       len(tickets),
       presentation))
output.write("""// Tickets
    """)
for ticket in tickets.keys():
    # TODO: flag overdue tickets
    output.write("node [shape=octagon, fontsize=%i, width=%i];\n" %
                 (14 + priorities[ticket]*6, priorities[ticket] + 1))
    output.write("\"#%i\" [label=\"#%i %s\"];\n" % (int(ticket), int(ticket),
                                                tickets[ticket]))
for dependency in dependencies.keys():
    (local, remote) = string.split(dependency, "-")
    output.write("\"#%s\" -> \"#%s\" [color=%s, weigth=20];\n" %
                 (local, remote,
                  dependency_color))
for reference in references.keys():
    (local, remote) = string.split(reference, "-")
    output.write("\"#%s\" -> \"#%s\" [color=%s, weigth=10];\n" %
                 (local, remote,
                  reference_color))
output.write("}\n")
output.close()

