#!/usr/bin/python -tt

#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
# Author    : Nizar Swidan, nizars@mellanox.com
# Version    : 1.0.4
# Release Date    : 22-Nov-2015
#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

import sys
import shutil
from optparse           import OptionParser
import signal
import os
import re

###########################################################
#        Global Variables

version = "1.0.4"
out_path = "/tmp/"
is_generated = False
out_xml = "/tmp/ibdiagnet2_db.xml"
in_db_csv = ""

###########################################################

def clear_partial_output():
    print ("Cleaning partial output")
    if is_generated:
        shutil.rmtree(out_path)
    elif os.path.isfile(out_xml):
        os.remove(out_xml)

###########################################################
#   SIGINT-2-Interrupt from keyboard; Handlers (Ctrl+C)

def signal_handler(signal, frame):
    clear_partial_output()
    print ("\nRunning ibdiagnet_csv2xml was halted! No out directories/files.")
    sys.exit(0)

signal.signal(signal.SIGINT, signal_handler)

###########################################################
#         Perform Conversion

delimiter = "," # "\t" "|" # delimiter used in the CSV file(s)
start = "START_"
end = "END_"

def get_item_name(table_name):
    switcher = {
        "NODES" : "NODE",
        "LINKS" : "LINK",
        "PORTS" : "PORT",
        "ERRORS_LINKS_CHECK" : "ERROR_LINKS",
        "SM_INFO" : "SINGLE_SM_INFO",
        "ERRORS_SUBNET_MANAGER_CHECK" : "ERROR_SUBNET_MANAGER",
        "ERRORS_PORTS_COUNTERS_VALUE_CHECK" : "ERROR_PORTS_COUNTERS_VALUE",
        "PM_INFO" : "SINGLE_PM_INFO",
        "NODES_INFO" : "NODE_INFO",
        "PKEY" : "SINGLE_PKEY",
        "AGUID" : "SINGLE_AGUID",
    }
    return switcher.get(table_name, "ITEM")

#----------------------------------------------------------

def write_records_to_xml(xfile, table_name, attributes, records):
    item_name = get_item_name(table_name)
    for record in records:
        record = record.split(delimiter)
        if len(attributes) == len(record):
            xfile.write("\t\t<" + item_name + ">\n")
            for i in range(0, len(record)):
                xfile.write("\t\t\t<" + attributes[i] + ">" + record[i].strip() + "</" + attributes[i] + ">\n")
            xfile.write("\t\t</" + item_name + ">\n")

#----------------------------------------------------------

def convert():
    open_files_count = 0
    try:
        rfile = open(in_db_csv, 'r')
        open_files_count += 1
        xfile = open(out_xml, 'w')
        open_files_count += 1

        # Read db_csv
        csv_content = rfile.read()
        csv_tables = re.findall ("%s(.*?)%s" % (start, end), csv_content, re.DOTALL)
        xfile.write("<?xml version=" + '"' + "1.0" + '"' + " encoding=" + '"' + "UTF-8" + '"' + " standalone=" + '"' + "yes" + '"' + " ?>\n")
        xfile.write("<IBDIAGNET>\n")
        for csv_table in csv_tables:
            csv_table = csv_table.splitlines()
            if len(csv_table) > 1:
                #write table tag
                xfile.write("\t<" + csv_table[0] + ">\n")
                attributes = csv_table[1].split(delimiter)
                attributes = map(str.strip, attributes)
                write_records_to_xml(xfile, csv_table[0], attributes, csv_table[2:])
                xfile.write("\t</" + csv_table[0] + ">\n")
        xfile.write("</IBDIAGNET>")
        rfile.close()
        xfile.close()
    except Exception, e:
        print e
        if open_files_count>0:
            rfile.close()
        if open_files_count>1:
            xfile.close()
        clear_partial_output()
        sys.exit(1)
    

###########################################################
#     Main flow helper functions

def ensure_out_dir_existence():
    global out_path
    if not out_path.endswith("/"):
        out_path = out_path + "/"
    if not os.path.isdir(out_path):
        os.makedirs(out_path)
        global is_generated
        is_generated = True
    
def decide():
    print ("The provided out file '" + args[1] + "' already exists")
    sys.stdout.write("Overwrite '" + args[1] + "'? ")
    decision_ch = sys.stdin.read(1).lower()
    if (decision_ch == 'y'):
        return
    else:
        if (decision_ch != 'n'):
            print ("Invalid char")
        print("Halting ibdiagnet_csv2xml conversion")
        sys.exit(0)

def add_options (parser):
    """ Add options to parser
    """
    parser.add_option("-v", "--version", help = "print tool version and exit [default False]", action = "store_true",  default = False) 

def main():
    global args
    usage = "usage: %prog [options] [in.db_csv] <out.xml>"
    usage += "\n\t%prog tool converts the <in>.db_csv file to an <out>.xml file"
    usage += "\n\tThe tool must recieve <in>.db_csv file"
    usage += "\n\tThe tool may recieve <out>.xml file, by default it is set to '/tmp/ibdiagnet2_db.xml'"
    usage += "\n\nExample: ./%prog /var/tmp/ibdiagnet2/ibdiagnet2.db_csv /tmp/ibdiagnet2_db.xml"
    parser = OptionParser(usage=usage)
    add_options(parser)
    (options, args) = parser.parse_args() 
    
    if options.version:
        print ("Version: " + version)
        sys.exit(0)
    
    global in_db_csv
    if len(args) == 1:
        if os.path.isfile(args[0]):
            in_db_csv = args[0]
            if not in_db_csv.lower().endswith(".db_csv"):
                print "Error: No .db_csv input file was provided. (input file must end with '.db_csv')"
                sys.exit(1)
            ensure_out_dir_existence()
        else:
            print ("Error: " + args[0] + " is not an existing file")
            sys.exit(1)
    elif len(args) == 2:
        if os.path.isfile(args[0]):
            if os.path.isfile(args[1]):
                decide()
                os.remove(args[1])
            in_db_csv = args[0]
            if not in_db_csv.lower().endswith(".db_csv"):
                print "Error: No .db_csv input file was provided. (input file must end with '.db_csv')"
                sys.exit(1)
            global out_xml 
            out_xml = args[1]
            if not out_xml.lower().endswith(".xml"):
                print "Error: Out file name must end with '.xml')"
                sys.exit(1)
            global out_path
            out_path = os.path.dirname(args[1])
            ensure_out_dir_existence()
        else:
            print ("Error: " + args[0] + " is not an existing file")
            sys.exit(1)
    else:
        print ("Error: Invalid number of provided arguments")
        parser.print_help()
        sys.exit(1)
        
    convert()
    print ("Conversion has finished successfully!")
    print ("Out XML file:\n" + out_xml)
    sys.exit(0)

if __name__=='__main__':
    main()

