#!/usr/bin/python
#####################################################################
# csv2table converts a shiftx2 csv format to a tabular format
# using object oriented python
# author: Yifeng Liu
# date: July 26th, 2010
#####################################################################
import sys

tablerows = {} # a hash table for all rows in the table, mapping from residue number to table entry object

class TableEntry(object):
    ''' an object oriented modelling of a table row '''
    
    def __init__(self):
        ''' initialize all the table entries into empty entries '''
        ''' ('Num', 'I', 'CA', 'CB', 'CO', 'N', 'H', 'HA') ''' # backbone atoms
        ''' ('Num', 'I', 'CD',  'CD1', 'CD2', 'CG', 'CG1', 'CG2')''' # sidechain C atoms
        ''' ('Num', 'I', 'HB', 'HB2', 'HB3', 'HD1', 'HD2', 'HD21', 'HD22', 'HD3', 'HE', 'HE1', 'HE2', 'HE21', 'HE22', 'HE3', 'HG', 'HG1', 'HG12', 'HG13', 'HG2', 'HG3', 'HZ') ''' # sidechain H atoms

        # major table 
        # String bbheader = "NUM  RES  HA     H      N        CA      CB      C\n";
        # String sideCs_header = "NUM  RES   CD     CD1    CD2    CG     CG1   CG2\n";  
        # String sideHs_header = "NUM  RES  HB   HB2  HB3  HD1  HD2  HD21 HD22 HD3  HE   HE1  HE2  HE21 HE22 HE3  HG   HG1  HG12 HG13 HG2  HG3  HZ\n";

        self.H = self.HA = self.CA = self.CB = self.CO = self.N = '****'
        self.CD = self.CD1 = self.CD2 = self.CG = self.CG1 = self.CG2 = '****'
        self.HB = self.HB2 = self.HB3 = \
            self.HD1 = self.HD2 = self.HD21 = self.HD22 = self.HD3 = \
            self.HE = self.HE1 = self.HE2 = self.HE21 = self.HE22 = self.HE3 = \
            self.HG = self.HG1 = self.HG12 = self.HG13 = self.HG2 = self.HG3 = \
            self.HZ = '****'
        
        self.restype = ""
        self.resnum = None

        '''
        self.field_hash = {
            "restype" : self.restype, 
            "resnum"  : self.resnum, 
            "CA" : self.CA, "CB" : self.CB, "CO" : self.CO,
            "C"  : self.CO, "N"  : self.N,  "H"  : self.H,
            "HN" : self.H, "HA" : self.HA, "CD" : self.CD,
            "CD1": self.CD1, "CD2": self.CD2, "CG" : self.CG,
            "CG1": self.CG1, "CG2": self.CG2, "HB" : self.HB,
            "HB2": self.HB2, "HB3": self.HB3, "HD1": self.HD1,
            "HD2": self.HD2, "HD21": self.HD21, "HD22": self.HD22,
            "HD3" : self.HD3, "HE"  : self.HE, "HE1" : self.HE1,
            "HE2" : self.HE2, "HE21": self.HE21, "HE22": self.HE22,
            "HE3" : self.HE3, "HG"  : self.HG, "HG1" : self.HG1, 
            "HG12": self.HG12, "HG13": self.HG13, "HG2" : self.HG2,
            "HG3" : self.HG3, "HZ" : self.HZ
            }
           '''

    def setfield(self, fname, value):
        ''' set the given field with the given value '''
        if fname == "restype":
            self.restype = value
        elif fname == "resnum":
            self.resnum = value
        elif fname == "CA":
            self.CA = value
        elif fname == "CB":
            self.CB = value
        elif fname == "CO" or fname == "C":
            self.CO = value
        elif fname == "N":
            self.N = value
        elif fname == "H" or fname == "HN":
            self.H = value
        elif fname == "HA":
            self.HA = value
            
        elif fname == "CD":
            self.CD = value
        elif fname == "CD1":
            self.CD1 = value
        elif fname == "CD2":
            self.CD2 = value
        elif fname == "CG":
            self.CG = value
        elif fname == "CG1":
            self.CG1 = value 
        elif fname == "CG2":
            self.CG2 = value

        elif fname == "HB":
            self.HB = value
        elif fname == "HB2":
            self.HB2 = value
        elif fname == "HB3":
            self.HB3 = value
        elif fname == "HD1":
            self.HD1 = value
        elif fname == "HD2":
            self.HD2 = value
        elif fname == "HD21":
            self.HD21 = value
        elif fname == "HD22":
            self.HD22 = value
        elif fname == "HD3":
            self.HD3 = value
        elif fname == "HE":
            self.HE = value
        elif fname == "HE1":
            self.HE1 = value
        elif fname == "HE2":
            self.HE2 = value 
        elif fname == "HE21":
            self.HE21 = value
        elif fname == "HE22":
            self.HE22 = value
        elif fname == "HE3":
            self.HE3 = value
        elif fname == "HG":
            self.HG = value
        elif fname == "HG1":
            self.HG1 = value 
        elif fname == "HG12":
            self.HG12 = value
        elif fname == "HG13":
            self.HG13 = value
        elif fname == "HG2":
            self.HG2 = value
        elif fname == "HG3":
            self.HG3 = value
        elif fname == "HZ":
            self.HZ = value
        else:
            print "the specified field", fname, "is not supported."

    def backbone_str(self):
        values = [self.CA, self.CB, self.CO, self.N, self.H, self.HA] #, self.HB2, self.HB3, self.HG2, self.HG3, self.HD2, self.HD3, self.HE2, self.HE3]
        header = [str(self.resnum), self.restype]
        return  "%3s %s %6s %6s %6s %6s %6s %6s" % tuple(header + values) 

    def sidec_str(self):
        values =  [self.CD, self.CD1, self.CD2, self.CG, self.CG1, self.CG2]
        header = [str(self.resnum), self.restype]
        return  "%3s %s %6s %6s %6s %6s %6s %6s" % tuple(header + values) 

    def sideh_str(self):
        values = [self.HB, self.HB2, self.HB3, self.HD1, self.HD2, self.HD21, self.HD22, self.HD3, \
                     self.HE, self.HE1, self.HE2, self.HE21, self.HE22, self.HE3, self.HG, self.HG1, self.HG12, self.HG13, self.HG2, self.HG3, self.HZ]
        header = [str(self.resnum), self.restype]
        return  "%3s %s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s" % tuple(header + values) 


def convert_table(lines):
    ''' convert the given list of comma separated strings into a tabular output '''

    outstrs = []
    for line in lines:
        line = line.strip()
        if line != "":
            tmplist = line.split(',')
            resnum = int(tmplist[0])
            restype = tmplist[1]
            atomtype = tmplist[2]
            cs = "%.2f" % float(tmplist[3])

            if resnum not in tablerows:
                row = TableEntry()
                row.setfield("resnum", resnum)
                row.setfield("restype", restype)
                row.setfield(atomtype, cs)
                tablerows[resnum] = row        
            else:
                row = tablerows[resnum]
                row.setfield("resnum", resnum)
                row.setfield("restype", restype)
                row.setfield(atomtype, cs)
                tablerows[resnum] = row

    resnums = tablerows.keys()
    resnums.sort()

    # print out backbone table
    outstr = "%3s %s %6s %6s %6s %6s %6s %6s" % ('Num', 'I', 'CA', 'CB', 'CO', 'N', 'H', 'HA')
    outstrs.append(outstr)

    for row in resnums:
        outstrs.append(tablerows[row].backbone_str())
    outstrs.append("\n")

    # print out sidechain C table
    outstr = "%3s %s %6s %6s %6s %6s %6s %6s" % ('Num', 'I', 'CD',  'CD1', 'CD2', 'CG', 'CG1', 'CG2')
    for row in resnums: 
        outstrs.append(tablerows[row].sidec_str())
    outstrs.append("\n")

    # print out sidechain H table
    outstr = "%3s %s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s" % ('Num', 'I', 'HB', 'HB2', 'HB3', 'HD1', 'HD2', 'HD21', 'HD22', 'HD3', 'HE', 'HE1', 'HE2', 'HE21', 'HE22', 'HE3', 'HG', 'HG1', 'HG12', 'HG13', 'HG2', 'HG3', 'HZ')
    for row in resnums: 
        outstrs.append(tablerows[row].sideh_str())
    outstrs.append("\n")
    
    outstr = "\n".join(outstrs)
    return outstr
    
if __name__ == '__main__':
    if len(sys.argv)<3:
        print "Usage: python csv2table.py [input.csv] [output.table]"
        sys.exit(-1)

    csvfile = sys.argv[1]
    tablefile = sys.argv[2]

    input = open(csvfile, 'r')
    output = open(tablefile, 'w')

    for line in input:
        line = line.strip()
        if line != "":
            tmplist = line.split(',')
            resnum = int(tmplist[0])
            restype = tmplist[1]
            atomtype = tmplist[2]
            cs = "%.2f" % float(tmplist[3])

            if resnum not in tablerows:
                row = TableEntry()
                row.setfield("resnum", resnum)
                row.setfield("restype", restype)
                row.setfield(atomtype, cs)
                tablerows[resnum] = row        
            else:
                row = tablerows[resnum]
                row.setfield("resnum", resnum)
                row.setfield("restype", restype)
                row.setfield(atomtype, cs)
                tablerows[resnum] = row

    resnums = tablerows.keys()
    resnums.sort()

    # print out backbone table
    print >> output, "%3s %s %6s %6s %6s %6s %6s %6s" % ('Num', 'I', 'CA', 'CB', 'CO', 'N', 'H', 'HA')
    for row in resnums:
        print >> output, tablerows[row].backbone_str()
    print >> output, "\n"

    # print out sidechain C table
    print >> output, "%3s %s %6s %6s %6s %6s %6s %6s" % ('Num', 'I', 'CD',  'CD1', 'CD2', 'CG', 'CG1', 'CG2')
    for row in resnums: 
        print >> output, tablerows[row].sidec_str()
    print >> output, "\n"

    # print out sidechain H table
    print >> output, "%3s %s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s" % ('Num', 'I', 'HB', 'HB2', 'HB3', 'HD1', 'HD2', 'HD21', 'HD22', 'HD3', 'HE', 'HE1', 'HE2', 'HE21', 'HE22', 'HE3', 'HG', 'HG1', 'HG12', 'HG13', 'HG2', 'HG3', 'HZ')
    for row in resnums: 
        print >> output, tablerows[row].sideh_str()
    print >> output, "\n"
    
    
