#!/usr/local/bin/python

import MySQLdb
import datetime
import time
import readline
import os
import re
import sys
import ConfigParser


#****************************************************************************
#
#  Get command line options
#
#  dirname   The directory containing the initialization file
#
#  database  The database to use: "prod" or "test"
#
#  subsys    The subsystem to use, e.g. ccs-refrig-subscale
#
#  ofile     The output file
#
#****************************************************************************

if len(sys.argv) < 5:
    print "Too few parameters"
    exit()

dir = sys.argv[1]
database = sys.argv[2]
subsys = sys.argv[3]
oFile = sys.argv[4]


#****************************************************************************
#
#  Get database parameters from initialization file
#
#****************************************************************************

cfg = ConfigParser.ConfigParser()
cfg.read(dir + "/refrigPlot.ini")
server = cfg.get(database, "server")
port = cfg.get(database, "port")
dbname = cfg.get(database, "dbname")
user = cfg.get(database, "user")
password = cfg.get(database, "password")


#****************************************************************************
#
#  Global variables initialization
#
#****************************************************************************

namel = []
idl = []
stateId = -1
start = None
end = None
cu = None


#****************************************************************************
#
#  Get console input
#
#  @param  prompt  The prompt to display
#
#  @return  The typed input, or None if EOF occurred (ctrl-D typed)
#
#****************************************************************************

def getInput(prompt):
    try:
        return raw_input(prompt)
    except:
        print
        return None


#****************************************************************************
#
#  Get the list of items to save, excluding "state"
#
#****************************************************************************

def getItems():
    global namel, idl, stateId
    count = cu.execute("select srcName,id from datadesc where srcSubsystem = '"
                       + subsys + "' order by id")
    data = cu.fetchall()
    for item in data:
        if item[0] != "state":
            namel = namel + [item[0]]
            idl = idl + [item[1]]
        else:
            stateId = item[1]
    return


#****************************************************************************
#
#  Display the list of items to save
#
#****************************************************************************

def showItems():
    print "Available items:"
    n = 0
    for name in namel:
        if (n % 4) == 0 and n != 0: print
        print "%4d: %-10s" % (n, name),
        n = n + 1
    print


#****************************************************************************
#
#  Get a start or end time from the console
#
#  @param  prompt  The prompt to display
#
#  @param  start   The base time to use for time increments, or 0 if the
#                  current time is to be used.
#
#  @return  The entered time, as milliseconds since midnight January 1st,
#           1970 UT, or None if EOF occurred
#
#****************************************************************************

def getTime(prompt, start):
    while True:
        #
        #  Get typed input
        #
        tim = getInput(prompt)
        if tim == None: return None

        #
        #  Get +/- sign value and remove it along with leading/trailing blanks
        #
        tmo = re.match("^ *([-+]?) *([^ ]+) *([^ ]*) *(.*)$", tim)
        if tmo == None: continue
        tm = tmo.group(1, 2, 3, 4)
        if tm[3] != "":
            print "Invalid time"
            continue
        pfx = 0
        if tm[0] != "":
            if tm[0] == "-": pfx = -1
            else: pfx = 1
        tim = tm[1]
        if tm[2] != "": tim = tim + " " + tm[2]

        #
        #  Process value with no sign ([YYYY-[MM-[DD ]]]HH:MM)
        #
        if pfx == 0:
            try:
                ts = time.strptime(tim, "%Y-%m-%d %H:%M")
            except:
                try:
                    ts = time.strptime(time.strftime("%Y-") + tim,
                                       "%Y-%m-%d %H:%M")
                except:
                    try:
                        ts = time.strptime(time.strftime("%Y-%m-") + tim,
                                           "%Y-%m-%d %H:%M")
                    except:
                        try:
                            ts = time.strptime(time.strftime("%Y-%m-%d ") + tim,
                                               "%Y-%m-%d %H:%M")
                        except:
                            print "Invalid time"
                            continue
            return 1000L * int(time.mktime(ts))

        #
        #  Process signed value
        #
        okay = (start != 0 or pfx == -1)
        tmo = re.match("^(\d+) (\d+):(\d+)$", tim)
        if tmo != None:
            td = tmo.group(1, 2, 3)
            tm = 60 * (int(td[2]) + 60 * (int(td[1]) + 24 * int(td[0])))
        else:
            tmo = re.match("^(\d+):(\d+)$", tim)
            if tmo != None:
                td = tmo.group(1, 2)
                tm = 60 * (int(td[1]) + 60 * (int(td[0])))
            else:
                tmo = re.match("^(\d+)$", tim)
                if tmo != None:
                    tm = 60 * int(tmo.group(1))
                else:
                    okay = False
        if okay:
            if pfx == -1: return 1000L * (int(time.time()) - tm)
            return start + 1000L * tm
        print "Invalid time"


#****************************************************************************
#
#  Get the start and end times of the interval of interest
#
#  @return  0: if information obtained
#          -1: if EOF occurred
#
#****************************************************************************

def getTimes():
    global start, end
    end = None
    while end == None:
        start = getTime("Start time ([YYYY-[MM-]DD ]]]HH:MM "
                        + "| -[DD [HH:]]MM): ", 0)
        if start == None: return -1
        end = getTime("End time ([YYYY-[MM-[DD ]]]HH:MM "
                      + "| {+|-}[DD [HH:]]MM): ", start)
    return 0


#****************************************************************************
#
#  Generate the data file for all quantities
#
#  @return  0: if file generated successfully
#           1: if no data found or file couldn't be opened
#
#****************************************************************************

def genData():
    count = cu.execute("select tstampmills,descr_id,doubleData from rawdata"
                       + " where tstampmills >= " + str(start)
                       + " and tstampmills <= " + str(end)
                       + " and descr_id != " + str(stateId)
                       + " order by tstampmills,descr_id")
    if count == 0:
        print "No matching data found"
        return 1
    data = cu.fetchall()
    print len(data) / len(idl), "values found"

    try:
        out = open(oFile, "w")
    except:
        print "Cannot open output data file"
        return 1

    out.write("Time")
    for name in namel:
        out.write("\t" + name)
    cTime = 0
    ix = len(idl)
    for item in data:
        time = item[0] / 1000
        if time != cTime:
            while ix < len(idl) - 1:
                out.write("\t")
                ix = ix + 1
            out.write("\n" + str(time) + "\t")
            cTime = time
            ix = 0
        id = item[1]
        while idl[ix] < id:
            out.write("\t")
            ix = ix + 1
        out.write(str(item[2]))
    out.write("\n")
    out.close()

    return 0


#****************************************************************************
#
#  Main code
#
#****************************************************************************

db = MySQLdb.connect(server, user, password, dbname, port=int(port))
cu = db.cursor()

getItems()
#showItems()
if getTimes() == 0:
    genData()

db.close()
