#!/usr/bin/python
# Originally written by Daofeng (/bar/dli/pyScript/trackDbParser.py)

import sys
sys.path.append('/apps/lib/python2.7/site-package')

# import MySQLdb

class dupKeyError(Exception):
    def __init__(self, key, line):
        self.key = key
        self.line = line
    def __str__(self):
        return repr(self.key) + ' from ' + repr(self.line)

tkColor = {
    'Input':'0,0,200',
    'MeDIPInput':'0,0,200', #0,0,200
    'H3K4me1':'0,133,66', # active 
    'H3K4me2':'0,82,41',
    'H3K4me3':'0,117,0',
    'H3K36me3':'33,97,11',
    'H3K9ac':'46,92,0',
    'H3K9me1':'150,0,0',
    'H3K9me3':'159,0,72', # repressive
    'H3K27me3':'180,0,0',
    'H3K27ac':'140,97,0',
    'p300':'158,84,0',
    'NR2F1':'51,102,190',
    'TFAP2A':'0,148,64',
    'H2AK5ac':'140,97,0',
    'H2AK9ac':'158,84,0',
    'H2A.Z':'51,102,190',
    'H2BK120ac':'0,148,64',
    'H2BK12ac':'0,0,175',
    'H2BK15ac':'180,0,0',
    'H2BK5ac':'0,120,110',
    'H2BK20ac':'40,100,20',
    'H3K14ac':'0,0,200',
    'H3K18ac':'150,0,0',
    'H3K23ac':'0,150,0',
    'H3K23me2':'0,110,120',
    'H3K27ac':'0,0,150',
    'H3K4ac':'113,113,0',
    'H3K56ac':'0,149,149',
    'H3K79me1':'185,0,185',
    'H3K79me2':'170,170,0',
    'H3T11ph':'0,185,134',
    'H4K20me1':'0,150,150',
    'H4K5ac':'150,0,150',
    'H4K8ac':'94,97,11',
    'H4K12ac':'123,0,102',
    'H4K91ac':'0,120,120',
    'Mre':'0,100,00',
    'MRE':'0,100,00',
    'mre':'0,100,00',
    'MRE-Seq':'0,100,00',
    'MRE':'0,100,00',
    'medip':'153,0,0',
    'MeDIP':'153,0,0',
    'MeDIP-Seq':'153,0,0',
    'mbd':'128,0,0',
    'ChromatinAccessibility':'0,77,0',
    'DNase hypersensitivity':'0,77,0',
    'DNase':'0,77,0',
    'BisulfiteSeq':'200,0,0',
    'Bisulfite-Seq':'200,0,0',
    'Bismark':'255,51,102',
    'BS':'200,0,0',
    'SBS':'200,0,0',
    'methylCRF':'172,0,230',
    'methylcrf':'172,0,230',
    'Cov':'200,0,0',
    'CAGE':'40,113,155',
    'mRNASeq':'40,113,155',
    'RNASeq':'40,113,155',
    'mRNA':'40,113,155',
    'RNA':'40,113,155',
    'mRNA-Seq':'40,113,155',
    'smRNASeq':'0,43,173',
    'smRNA':'0,43,173',
    'smRNA-Seq':'0,43,173',
    'ssRNA-Seq':'0,43,173',
    'ssRNA-seq':'0,43,173',
    'DGF':'0,0,255',
    'Digital_Genomic_Footprinting':'11,59,23',
    'Digital Genomic Footprinting':'11,59,23',
    'RRBS':'180,49,4',
    'STAT1':'102,0,153',
    'IgG':'77,121,255',
    '4074-1':'255,83,26',
    '4074-2':'255,83,26',
    '4074-3':'255,83,26',
    '4074-0':'209,157,0',
    'V5-1':'198,26,255',
    'V5-3':'198,26,255',
    'V5-4':'198,26,255',
    'infm':'204,51,255',
}

tkColor2 = {
    'SBS':'122,0,0',    
    'RRBS':'240,64,5',    
    'mCRF':'172,0,230',    
}

def trackGraColor(x, tot, fold):
    # x = assay
    alis = []
    try:
        col = tkColor[x]
    except KeyError:
        print >> sys.stderr, "ERROR: {0} not existed in assay list".format(x)
        sys.exit(1)
    blis = col.split(',')
    alis = blis
    clis = [int(i) for i in blis]
    if 0 in clis:
        aind = clis.index(0)
        step = 255/tot
        alis[aind] = str(step*fold)
    elif 255 in clis:
        aind = clis.index(255)
        step = 255/tot
        alis[aind] = str(255-step*fold)
    else:
        amax = max(clis)
        aind = clis.index(amax)
        step = amax/tot
        alis[aind] = str(amax-step*fold)
    return ','.join(alis)

class trackDb:
    '''trackDb parser'''
    def __init__(self,f):
        self.f = f

    def parse(self):
        with open(self.f, 'rU') as ff:
            lines = []
            for line in ff:
                if line.startswith('#'): continue
                aline = line.strip()
                if aline:
                    if aline.startswith('track'):
                        if lines:
                            yield track(lines)
                            lines = []
                    lines.append(aline)
            if lines: # the last track
                yield track(lines)
                lines = []

class track(object):
    '''a track record'''
    def __init__(self, lines):
        self.lines = lines
        self.info = {}
        self.parent = ''
        #self.children = []
        self.isSuper = False
        self.isComposite = False
        self.isContainer = False
        self.isCompsub = False
        self.isCompchild = False
        self.isNormal = True

        for i in self.lines:
            if i.startswith('#'): continue
            t = i.split()
            a = t[0]
            b = ' '.join(t[1:])
            if a not in self.info:
                self.info[a] = b
            else:
                raise dupKeyError(a, self.info['track'])
        
        if 'compositeTrack' in self.info:
            self.isComposite = True
            self.isNormal = False
            if 'parent' in self.info or 'superTrack' in self.info:
                self.isCompchild = True
                #self.isComposite = False
        if 'superTrack' in self.info and 'container' not in self.info:
            self.isSuper = True
            self.isNormal = False
        if 'container' in self.info:
            self.isContainer = True
            self.isNormal = False
        if 'view' in self.info:
            self.isCompsub = True
            self.isNormal = False

        #self.track = self.info['track'].replace('-', '_')
        self.track = self.info['track']
        self.shortLabel = self.info['shortLabel']
        if 'longLabel' in self.info:
            self.longLabel = self.info['longLabel']
        #self.metadata = self.info['metadata']
        if 'visibility' in self.info:
            self.visibility = self.info['visibility']
        
        if 'parent' in self.info:
            self.parent = self.info['parent']
        if 'superTrack' in self.info and not self.isSuper:
            self.parent = self.info['superTrack']
        if 'subTrack' in self.info:
            self.parent = self.info['subTrack']

        self.view = self.sampleType = self.cellType = self.assayType = self.donorID = ''
        if self.isNormal:
            if 'subGroups' in self.info:
                d = {}
                subGroups = self.info['subGroups']
                for i in subGroups.split():
                    j = i.split('=')
                    d[j[0]] = j[1]
                if 'view' in d:
                    self.view = d['view']
                if 'sampleType' in d:
                    self.sampleType = d['sampleType']
                if 'cellType' in d:
                    self.cellType = d['cellType']
                if 'assayType' in d:
                    self.assayType = d['assayType']
                if 'donorID' in d:
                    self.donorID = d['donorID']
                if 'dataType' in d:
                    self.dataType = d['dataType']
            else:
                t = self.shortLabel.split()
                self.assayType = t[1]
                self.sampleType = t[0]
            if self.shortLabel == 'UCSD H9 H3K18ac SK375':
                self.assayType = 'H3K18ac'
                self.sampleType = 'H9'
            if self.shortLabel == 'H22510 FB MRE 10':
                self.assayType = 'MRE'
                self.sampleType = 'FB'
            if self.shortLabel == 'H22510 FB MeDIP 10':
                self.assayType = 'MeDIP'
                self.sampleType = 'FB'
            if self.sampleType == '':
                t = self.shortLabel.split()
                self.sampleType = t[0]
            if self.assayType == '':
                t = self.shortLabel.split()
                self.assayType = t[1]
        
        if self.assayType == 'BS':
            self.assayType = 'Bisulfite-Seq'
        if self.assayType == 'MeDIP':
            self.assayType = 'MeDIP-Seq'
        if self.assayType == 'MRE':
            self.assayType = 'MRE-Seq'
        if self.assayType == 'mRNA':
            self.assayType = 'mRNA-Seq'
        if self.assayType == 'smRNA':
                self.assayType = 'smRNA-Seq'
        if self.assayType == 'DNase':
                self.assayType = 'ChromatinAccessibility'

        #if self.isContainer:
        #    self.assayType = self.track.replace('edacc6','').replace('ContainerRoadmap','')

        if self.isCompsub:
            self.view = self.info['view']

        if self.isComposite:
            if 'subGroup1' in self.info:
                self.viewList = self.subGroupParse(self.info['subGroup1'])
            if 'subGroup2' in self.info:
                self.sampleList = self.subGroupParse(self.info['subGroup2'])
            if 'subGroup3' in self.info:
                self.assayList = self.subGroupParse(self.info['subGroup3'])
            if 'subGroup4' in self.info:
                self.donorList = self.subGroupParse(self.info['subGroup4'])

        if 'bigDataUrl' in self.info:
            self.bigDataUrl = self.info['bigDataUrl']

    def __str__(self):
        outline = []
        #outline.append('\n')
        space = ''
        if self.isContainer or self.isCompsub:
            space = '    '
        if self.isNormal:
            space = '        '
        for i in self.lines:
            outline.append(space + i + '\n')
        outline.append('\n')
        return ''.join(outline)

    def __repr__(self):
        return self.__str__()

    def subGroupParse(self, line):
        d = {}
        for i in line.split():
            if '=' in i:
                j = i.split('=')
                if j[1] not in d:
                    d[j[1]] = j[0]
                #if j[0] not in d:
                #    d[j[0]] = j[1]
                #else:
                #    raise dupKeyError(j[1], line)
        return d
    
    def changeShow(self):
        x = 'off'
        if self.sampleType == 'H1' or self.isCompchild or self.isContainer or self.isCompsub:
            x = 'on'
        if self.isNormal:
            for i,j in enumerate(self.lines):
                if j.startswith('parent'):
                    self.lines[i] = "{} {}".format(j, x)
                if j.startswith('visibility'):
                    del self.lines[i]
        else:
            self.changevisibility('dense')
        if self.isNormal or self.isContainer:
            for i,j in enumerate(self.lines):
                if j.startswith('type'):
                    t = j.split()
                    if t[1] == 'bigWig':
                        if self.assayType == 'Bisulfite-Seq' or 'Bisulfite' in self.longLabel or 'RRBS' in self.longLabel:
                            self.lines[i] = 'type bigWig 0 1'
                            self.lines.append('viewLimits 0.0:1.0')
                        else:
                            self.lines[i] = 'type bigWig 0 30'
                            self.lines.append('viewLimits 0.0:30.0')


    def fixParent(self):
        '''change subTrack,superTrack to parent'''
        if self.isNormal or self.isCompsub:
            for i,j in enumerate(self.lines):
                if j.startswith('subTrack'):
                    self.lines[i] = j.replace('subTrack','parent')
        if self.isContainer or self.isComposite:
            for i,j in enumerate(self.lines):
                if j.startswith('superTrack'):
                    self.lines[i] = j.replace('superTrack','parent')
        if self.isCompchild or self.isComposite:
            for i,j in enumerate(self.lines):
                if j.startswith('dragAndDrop'):
                    self.lines[i] = 'dragAndDrop on'
            #self.lines.append('allButtonPair on') # caused problem that no grid selection for samples for composite tracks
    
    def changeParent(self, x):
        for i,j in enumerate(self.lines):
            if j.startswith('subTrack'):
                #self.lines[i] = "subTrack {0}".format(x)
                self.lines[i] = "parent {0}".format(x)
            elif j.startswith('parent'):
                self.lines[i] = "parent {0}".format(x)
    
    def changevisibility(self, x):
        nothave = True
        for i,j in enumerate(self.lines):
            if j.startswith('visibility'):
                self.lines[i] = "visibility {0}".format(x)
                nothave = False
        if nothave:
            self.lines.append("visibility {0}".format(x))

    def changelongLabel(self, x):
        for i,j in enumerate(self.lines):
            if j.startswith('longLabel'):
                self.lines[i] = "longLabel {0}".format(x)

    def changeshortLabel(self, x):
        for i,j in enumerate(self.lines):
            if j.startswith('shortLabel'):
                self.lines[i] = "shortLabel {0}".format(x)
    
    def changeColor(self, x):
        for i,j in enumerate(self.lines):
            if j.startswith('color'):
                self.lines[i] = "color {0}".format(x)
    
    def changePriority(self, x):
        if 'priority' in self.info:
            for i,j in enumerate(self.lines):
                if j.startswith('priority'):
                    self.lines[i] = "priority {0}".format(x)
        else:
            self.lines.insert(-1, "priority {0}".format(x))
    
    def changeBigDataUrl(self, x):
        if 'bigDataUrl' in self.info:
            for i,j in enumerate(self.lines):
                if j.startswith('bigDataUrl'):
                    self.lines[i] = "bigDataUrl {0}".format(x)
        else:
            self.lines.insert(1, "bigDataUrl {0}".format(x))
    
    def changesubGroups(self, d1, d2, d3):
        for i,j in enumerate(self.lines):
            if j.startswith('subGroups'):
                self.lines[i] = "subGroups view={0} sampleType={1} assayType={2} donorID={3}".format(self.view, d1[self.sampleType], d2[self.assayType], d3[self.donorID])
    
    def changesampleType(self, x):
        for i,j in enumerate(self.lines):
            if j.startswith('subGroups'):
                self.lines[i] = "subGroups view={0} sampleType={1} assayType={2} donorID={3}".format(self.view, x, self.assayType, self.donorID)
    
    def removesubGroupsSample(self):
        for i,j in enumerate(self.lines):
            if j.startswith('subGroups'):
                self.lines[i] = "subGroups view={0} assayType={1} donorID={2}".format('COV', self.assayType, self.donorID)

    def removesubGroupsAssay(self):
        for i,j in enumerate(self.lines):
            if j.startswith('subGroups'):
                self.lines[i] = "subGroups view={0} sampleType={1} donorID={2}".format('COV', self.sampleType, self.donorID)
    
    def addSample(self, x):
        x = x.strip()
        if x:
            if self.sampleList:
                self.sampleList[x] = x
            for i,j in enumerate(self.lines):
                if j.startswith('subGroup2'):
                    self.lines[i] += " {0}={0}".format(x)
    
    def addAssay(self, x):
        x = x.strip()
        if x:
            if self.assayList:
                self.assayList[x] = x
            for i,j in enumerate(self.lines):
                if j.startswith('subGroup3'):
                    self.lines[i] += " {0}={0}".format(x)
                    
    def addDonor(self, x):
        x = x.strip()
        if x:
            if self.donorList:
                self.donorList[x] = x
            for i,j in enumerate(self.lines):
                if j.startswith('subGroup4'):
                    self.lines[i] += " {0}={0}".format(x)

    def nameAletter(self, x):
        self.lines[0] = "track {0}{1}".format(x, self.track)
        #self.track = "{0}{1}".format(x, self.track)
            
    def replaceAletter(self, x):
        self.lines[0] = "track {0}{1}".format(x, self.track[1:])
        #self.track = "{0}{1}".format(x, self.track[1:])

    def changeTrackName(self, x):
        self.lines[0] = "track {0}".format(x)
        self.track = x

    def copyTrackinDB(self, db, aLetter):
        con = MySQLdb.connect('localhost','hguser','hguser',db)
        cur = con.cursor()
        #ntk = "{0}{1}".format(aLetter, self.track[1:])
        ntk = "{0}{1}".format(aLetter, self.track)
        try:
            cur.execute("drop table if exists {0}".format(ntk))
            #cur.execute("create table {0}{1} like {1}".format(aLetter, self.track))
            cur.execute("create table {0} (fileName varchar(255) not null)".format(ntk))
            cur.execute("insert {0} select * from {1}".format(ntk, self.track))
        except:
            print >> sys.stderr, "copy track {0} to {1} error".format(self.track, ntk)
            sys.exit(1)
        cur.close()
        con.close()
    
    def deleteTrackinDB(self, db):
        con = MySQLdb.connect('localhost','hguser','hguser',db)
        cur = con.cursor()
        try:
            cur.execute("drop table if exists {0}".format(self.track))
        except:
            print >> sys.stderr, "Error: delete track {0} error".format(self.track)
            #sys.exit(1)
        print >> sys.stderr, "delete track {0} success".format(self.track)
        cur.close()
        con.close()
    
    def getbbiTrackPath(self, db, tk):
        con = MySQLdb.connect('localhost','hguser','hguser',db)
        cur = con.cursor()
        row = 'None'
        try:
            cur.execute("select * from {}".format(tk))
            row = cur.fetchone()[0]
        except:
            print >> sys.stderr, "{} not existed".format(tk)
            #sys.exit(1)
        cur.close()
        con.close()
        return row

def lenAssay(tklis):
    alis = []
    for tk in tklis:
        alis.append(tk.assayType)
    alis = list(set(alis))
    return len(alis)

def lenSample(tklis):
    alis = []
    for tk in tklis:
        alis.append(tk.sampleType)
    alis = list(set(alis))
    return len(alis)

def main():
    tks = trackDb(sys.argv[1]).parse()
    for tk in tks:
        tk.fixParent()
        tk.changeShow()
        print tk

if __name__=="__main__":
    main()


