#!/usr/bin/python

# See below for name and description
# Copyright (C) 2010 Richard J. Edwards <software@cabbagesofdoom.co.uk>
#  
# This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
# 
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along with this program; if not, write to 
# the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
#
# Author contact: <software@cabbagesofdoom.co.uk> / School of Biological Sciences, University of Southampton, UK.
#
# To incorporate this module into your own programs, please see GNU Lesser General Public License disclaimer in rje.py

"""
Module:       RJE_HTML
Description:  Module for generating HTML 
Version:      0.0
Last Edit:    14/03/10
Copyright (C) 2010  Richard J. Edwards - See source code for GNU License Notice

Function:
    This module is primarily for general methods for making HTML pages for other modules. 

Commandline:
    stylesheets=LIST    : List of CSS files to use ['../example.css','../redwards.css']
    tabber=FILE         : Tabber javascript file location ['../javascript/tabber.js']
    border=X            : Border setting for tables [0]

See also rje.py generic commandline options.

Uses general modules: copy, glob, os, string, sys, time
Uses RJE modules: rje, rje_db, rje_slim, rje_uniprot, rje_zen
Other modules needed: None
"""
#########################################################################################################################
### SECTION I: GENERAL SETUP & PROGRAM DETAILS                                                                          #
#########################################################################################################################
import copy, glob, os, string, sys, time
sys.path.append(os.path.join(os.path.dirname(os.path.realpath(__file__)),'../libraries/'))
sys.path.append(os.path.join(os.path.dirname(os.path.realpath(__file__)),'../tools/'))
### User modules - remember to add *.__doc__ to cmdHelp() below ###
import rje, rje_zen
#########################################################################################################################
def history():  ### Program History - only a method for PythonWin collapsing! ###
    '''
    # 0.0 - Initial Compilation.
    '''
#########################################################################################################################
def todo():     ### Major Functionality to Add - only a method for PythonWin collapsing! ###
    '''
    # [ ] : List here
    '''
#########################################################################################################################
def makeInfo(): ### Makes Info object which stores program details, mainly for initial print to screen.
    '''Makes Info object which stores program details, mainly for initial print to screen.'''
    (program, version, last_edit, copyright) = ('RJE_HTML', '0.0', 'March 2010', '2010')
    description = 'RJE HTML Module'
    author = 'Dr Richard J. Edwards.'
    comments = ['This program is still in development and has not been published.',rje_zen.Zen().wisdom()]
    return rje.Info(program,version,last_edit,description,author,time.time(),copyright,comments)
#########################################################################################################################
def cmdHelp(info=None,out=None,cmd_list=[]):   ### Prints *.__doc__ and asks for more sys.argv commands
    '''Prints *.__doc__ and asks for more sys.argv commands.'''
    try:### ~ [1] ~ Setup ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ###
        if not info: info = makeInfo()
        if not out: out = rje.Out()
        ### ~ [2] ~ Look for help commands and print options if found ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ###
        help = cmd_list.count('help') + cmd_list.count('-help') + cmd_list.count('-h')
        if help > 0:
            print '\n\nHelp for %s %s: %s\n' % (info.program, info.version, time.asctime(time.localtime(info.start_time)))
            out.verbose(-1,4,text=__doc__)
            if rje.yesNo('Show general commandline options?'): out.verbose(-1,4,text=rje.__doc__)
            if rje.yesNo('Quit?'): sys.exit()           # Option to quit after help
            cmd_list += rje.inputCmds(out,cmd_list)     # Add extra commands interactively.
        elif out.stat['Interactive'] > 1: cmd_list += rje.inputCmds(out,cmd_list)    # Ask for more commands
        ### ~ [3] ~ Return commands ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ###
        return cmd_list
    except SystemExit: sys.exit()
    except KeyboardInterrupt: sys.exit()
    except: print 'Major Problem with cmdHelp()'
#########################################################################################################################
def setupProgram(): ### Basic Setup of Program when called from commandline.
    '''
    Basic Setup of Program when called from commandline:
    - Reads sys.argv and augments if appropriate
    - Makes Info, Out and Log objects
    - Returns [info,out,log,cmd_list]
    '''
    try:### ~ [1] ~ Initial Command Setup & Info ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ###
        info = makeInfo()                                   # Sets up Info object with program details
        cmd_list = rje.getCmdList(sys.argv[1:],info=info)   # Reads arguments and load defaults from program.ini
        out = rje.Out(cmd_list=cmd_list)                    # Sets up Out object for controlling output to screen
        out.verbose(2,2,cmd_list,1)                         # Prints full commandlist if verbosity >= 2 
        out.printIntro(info)                                # Prints intro text using details from Info object
        cmd_list = cmdHelp(info,out,cmd_list)               # Shows commands (help) and/or adds commands from user
        log = rje.setLog(info,out,cmd_list)                 # Sets up Log object for controlling log file output
        return (info,out,log,cmd_list)                      # Returns objects for use in program
    except SystemExit: sys.exit()
    except KeyboardInterrupt: sys.exit()
    except: print 'Problem during initial setup.'; raise
#########################################################################################################################
### END OF SECTION I                                                                                                    #
#########################################################################################################################

                                                    ### ~ ### ~ ###

#########################################################################################################################
### SECTION II: HTML Class                                                                                              #
#########################################################################################################################
class HTML(rje.RJE_Object):     
    '''
    HTML Class. Author: Rich Edwards (2010).

    Info:str
    - Tabber = Tabber javascript file location ['../javascript/tabber.js']
    
    Opt:boolean

    Stat:numeric
    - Border = Border setting for tables [0]

    List:list
    - StyleSheets = List of CSS files to use ['../example.css','../redwards.css']

    Dict:dictionary    

    Obj:RJE_Objects
    '''
#########################################################################################################################
    ### <1> ### Class Initiation etc.: sets attributes                                                                  #
#########################################################################################################################
    def _setAttributes(self):   ### Sets Attributes of Object
        '''Sets Attributes of Object.'''
        ### ~ Basics ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ###
        self.infolist = ['Tabber']
        self.optlist = []
        self.statlist = ['Border']
        self.listlist = ['StyleSheets']
        self.dictlist = []
        self.objlist = []
        ### ~ Defaults ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ###
        self._setDefaults(info='None',opt=False,stat=0.0,obj=None,setlist=True,setdict=True)
        self.HTMLdefaults()
    def HTMLdefaults(self):
        self.setInfo({'Tabber':'../javascript/tabber.js'})
        self.setStat({'Border':0})
        self.list['StyleSheets'] = ['../example.css','../slimhtml.css']
        ### ~ Other Attributes ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ###
#########################################################################################################################
    def _cmdList(self):  self.HTMLcmdList()    ### Sets Attributes from commandline
    def HTMLcmdList(self):     ### Sets Attributes from commandline
        '''
        Sets attributes according to commandline parameters:
        - see .__doc__ or run with 'help' option
        '''
        for cmd in self.cmd_list:
            try:
                self._generalCmd(cmd)   ### General Options ### 
                ### Class Options ### 
                self._cmdReadList(cmd,'info',['Tabber'])
                self._cmdReadList(cmd,'int',['Border'])
                self._cmdReadList(cmd,'list',['StyleSheets'])
            except: self.errorLog('Problem with cmd:%s' % cmd)
#########################################################################################################################
    ### <2> ### Main Class Backbone                                                                                     #
#########################################################################################################################
    def tabberHTML(self,id,tablist,level=0):     ### Returns text for Tabber HTML
        '''Returns text for Tabber HTML.'''
        try: return tabberHTML(id,tablist,level)
        except: self.errorLog('TabberHTML Error')
        return '!Error!'
#########################################################################################################################
### End of SECTION II: New Class                                                                                        #
#########################################################################################################################

                                                    ### ~ ### ~ ###

#########################################################################################################################
### SECTION III: MODULE METHODS                                                                                         #
#########################################################################################################################
def htmlHead(title,stylesheets=['../example.css','../redwards.css'],tabber=True,frontpage=False,nobots=True,keywords=[],javascript='../javascript/'):    ### Returns text for top of HTML file
    '''
    Returns text for top of HTML file.
    >> title:str = Title of webpage.
    >> stylesheets:list = List of stylesheets to use.
    >> tabber:bool [True] = whether page has tabber tabs
    >> frontpage:bool [False] = whether to replace all '../' links with './'
    >> nobots:bool [True] = whether to screen page from bot discovery
    >> keywords:list [] = List of keywords for header
    >> javascript:str ['../javascript/'] = Path to javascript files for tabber tabs
    '''
    html = ['<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">',
            '<html lang="en">','','<!-- ~~~~~~~~~~~~~~~ HTML head data ~~~~~~~~~~~~~~~~~ -->','<head>',
            '<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">', #!# Add additional metadata #!#
            '<title>%s</title>' % title,'']
    if keywords: html.insert(6,'<meta http-equiv="Keywords" name="Keywords" content="%s">' % string.join(keywords, ', '))
    if nobots: html.insert(6,'<meta name="robots" content="index,nofollow">')
    for stylesheet in stylesheets:
        if frontpage: html.append('<link rel="stylesheet" href="%s" TYPE="text/css" MEDIA="screen">' % string.replace(stylesheet,'../','./'))
        else: html.append('<link rel="stylesheet" href="%s" TYPE="text/css" MEDIA="screen">' % stylesheet)
    if tabber:
        html += ['','<!-- ~~~~~~~~~~~ Tabber Javascript ~~~~~~~~~~~ -->','<script type="text/javascript">',
                 'document.write(\'<style type="text/css">.tabber{display:none;}<\/style>\');',
                 'var tabberOptions = {',' /* Optional: start manually (run tabber) at end of file','*/',
                 '\'manualStartup\':true','};','</script>','<!-- Load the tabber code -->']
        if frontpage and javascript == '../javascript/': html += ['<script type="text/javascript" src="./javascript/tabber.js"></script>','']
        else: html += ['<script type="text/javascript" src="%stabber.js"></script>' % javascript,'']
    html += ['</head>','<!-- ~~~~~~~~~~~~~~~ End of HTML head data ~~~~~~~~~~~~~~~~~ -->','','<body>','']
    #print string.join(html,'\n')
    return string.join(html,'\n')
#########################################################################################################################
def htmlTail(copyright='RJ Edwards 2012',tabber=True):  ### Returns text for bottom of HTML
    '''
    Returns text for bottom of HTML.
    >> copyright:str = copyright text'
    >> tabber:bool = whether page has tabber tabs
    '''
    t = string.split(time.asctime(time.localtime(time.time())))
    datetime = '%s %s %s' % (t[2],t[1],t[-1])
    html = ['','<!-- ~~~~~~~~~~~~~~ HTML tail data ~~~~~~~~~~~~~~~~~ -->',
            '<HR><FONT COLOR=#979E45 SIZE=2>&copy; %s. Last modified %s.</FONT></P>' % (copyright,datetime),'']
    if tabber:
        html += ['<script type="text/javascript">','/* manualStartup=true so need to run it now */',
                 'tabberAutomatic(tabberOptions);','</script>','']
    html += ['</body>','</html>','<!-- ~~~~~~~~~~~~~~ End of HTML tail data ~~~~~~~~~~~~~~~~~ -->']
    #print string.join(html,'\n')
    return string.join(html,'\n')
#########################################################################################################################
def tabberHTML(id,tablist,level=0):     ### Returns text for Tabber HTML
    '''
    Returns text for Tabber HTML.
    >> id:str = Identifier for Tabber object
    >> tablist:list = List of (tab_title, tab_html_text) tuples
    >> level:int = Level of Tabber object (base = level)
    '''
    jointxt = '\n' + '    ' * level 
    html = ['<!-- ~~~~~~~~~~~~~~~ %s Tabber Div ~~~~~~~~~~~~~~~ -->' % id,'','<div class="tabber" id="%s">' % id,'']
    #print html
    for tab in tablist:
        #print tab
        #print tab[0],tab[1]
        #print tabberTabHTML(tab[0],tab[1])
        if len(tab) > 2: html += string.split(tabberTabHTML(tab[0],tab[1],tab[2]),'\n')
        else: html += string.split(tabberTabHTML(tab[0],tab[1]),'\n')
    html += ['</div>','<!-- ~~~~~~~~~~~~~~~ End of %s Tabber Div ~~~~~~~~~~~~~~~ -->' % id,]
    #print string.join(html,jointxt)
    return string.join(html,jointxt)
#########################################################################################################################
def tabberTabHTML(id,text,title=''):          ### Returns text for TabberTab HTML
    '''
    Returns text for TabberTab HTML.
    >> title:str = Text for title of TabberTab
    >> text:str = HTML text for TabberTab content
    '''
    if not title: title = id
    html = ['','<!-- ~~~ %s TabberTab div ~~~ -->' % id,'<div class="tabbertab" title="%s" id="%s">' % (title,id),'']
    html += string.split(text,'\n')
    html += ['','</div>','<!-- ~~~ %s TabberTab end ~~~ -->' % id]
    #print string.join(html,'\n  ')
    if string.join(html).upper().find('<PRE>') >= 0: return string.join(html,'\n')       
    else: return string.join(html,'\n  ')
#########################################################################################################################
def geneLink(gene,frontpage=False):     ### Returns gene link text
    '''Returns gene link text.'''
    if frontpage: return '<a href="./gene/%s.html">%s</a>' % (gene,gene)
    else: return '<a href="../gene/%s.html">%s</a>' % (gene,gene)
#########################################################################################################################
def domainLink(domain,frontpage=False):     ### Returns gene link text
    '''Returns domain link text.'''
    if frontpage: return '<a href="./domain/%s.html">%s</a>' % (domain,domain)
    else: return '<a href="../domain/%s.html">%s</a>' % (domain,domain)
#########################################################################################################################
def slimLink(pattern,frontpage=False):  ### Returns SLiM link text
    '''Returns gene link text.'''
    if frontpage: return '<a href="./slim/%s.html">%s</a>' % (rje_slim.slimFromPattern(pattern),pattern)
    else: return '<a href="../slim/%s.html">%s</a>' % (rje_slim.slimFromPattern(pattern),pattern)
#########################################################################################################################
def seqDetailsHTML(callobj,gene,dbxref):    #gene,seqid,dbxref,desc,godata):  ### Returns HTML text for seq details table
    '''
    Returns HTML text for seq details table.
    >> gene:str = Gene symbol
    >> seqid:str = Sequence Identifier
    >> dbxref:dict = Dictionary of {db:id} for GeneCards, EBI, EnsEMBL, HPRD, OMIM
    >> desc:str = Sequence description
    >> godata:dict = {CC/BP/MF:[(id,name)] list}
    '''
    try:### ~ [1] Setup ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ###
        seqid = '-'; desc = '<i>No sequence mapping.</i>'; godata = {}
        if dbxref:      #gene in callobj.data('DBXRef'):
            #dbxref = callobj.data('DBXRef')[gene]
            seqid = dbxref['EnsLoci']
            desc = dbxref['EnsDesc']
            ensg = dbxref['EnsEMBL']
            try: godata = callobj.dict['GO'][ensg]
            except: pass

        gfont = '<FONT SIZE=6 FACE="Verdana" COLOR=#014359>'
        ifont = '<FONT SIZE=5 FACE="Verdana" COLOR=#979E45>'
        dfont = '<FONT SIZE=4 COLOR=#014359>'
        html = ['','<!-- ~~~~ %s Gene Summary details table ~~~~ -->' % gene,'<table width="100%">',
                '<tr valign="top">'  #<td width="80%">', '<table>','<tr>',
                '<td width="30%%"><a href="../gene/%s.html">%s<b>%s</b></FONT></a></td>' % (gene,gfont,gene),
                '<td width="50%%">%s<b>%s</b></FONT></td>' % (ifont,seqid),
                '<td width="20%" align="right" rowspan="3">',
                '<a href="../index.htm"><img src="../resources/SBS_100.png" height="100" align="RIGHT" border="0" alt="Home"></a>',
                '</td></tr>']
        #x#if 'Gene' not in dbxref: dbxref['Gene'] = gene
        html += ['<tr><td colspan=2>']
        for db in ['Gene','UniProt','EnsEMBL','HPRD','OMIM']:
            if db not in dbxref: continue
            if db == 'Gene':
                href = 'http://www.genecards.org/cgi-bin/carddisp.pl?gene=%s' % dbxref[db]
                alt = 'GeneCards %s' % dbxref[db]
                src = '../resources/genecard.png'
            if db == 'UniProt':
                href = 'http://www.uniprot.org/uniprot/%s' % dbxref[db]
                alt = 'UniProt %s' % dbxref[db]
                src = '../resources/logo_ebi.png'
            if db == 'EnsEMBL':
                href = 'http://www.ensembl.org/Homo_sapiens/geneview?gene=%s' % dbxref[db]
                alt = 'EnsEMBL %s' % dbxref[db]
                src = '../resources/e-bang.gif'
            if db == 'HPRD':
                href = 'http://www.hprd.org/summary?protein=%s&isoform_id=%s_1&isoform_name=Isoform_1' % (dbxref[db],dbxref[db])
                alt = 'HPRD %s' % dbxref[db]
                src = '../resources/hprd.png'
            if db == 'OMIM':
                href = 'http://www.ncbi.nlm.nih.gov/entrez/dispomim.cgi?id=%s' % dbxref[db]
                alt = 'OMIM %s' % dbxref[db]
                src = '../resources/omim.png'
            html += ['<a href="%s"><img alt="%s" src="%s" align="BOTTOM" border="0" height="50"></a>' % (href,alt,src)] 
        html += ['</td></tr>','<tr><td colspan=2>%s<p>%s</p></FONT></td></tr>' % (dfont,desc)]
        html += ['</table>','<!-- ~~~~ End %s Gene Summary details table ~~~~ -->' % gene,'']
        gtab = []
        for gtype in ['CC','BP','MF']:
            if gtype in godata:
                gdict = {}
                for gotup in godata[gtype]:
                    if gotup[1] in ['cellular_component','biological_process','molecular_function']: continue
                    gdict[gotup[1]] = '<a href="http://amigo.geneontology.org/cgi-bin/amigo/go.cgi?view=details&search_constraint=terms&depth=0&query=GO:%s">%s</a>' % (gotup[0],gotup[1])
                if gdict:
                    ghtml = []
                    for g in rje.sortKeys(gdict): ghtml.append(gdict[g])
                    gtab.append(('GO_%s' % gtype,string.join(ghtml,' ~ ')))
        if gtab:
            html += ['','<!-- ~~~~ %s GO tabs ~~~~ -->' % gene,tabberHTML('GO',gtab),
                     '<!-- ~~~~ End %s GO tabs ~~~~ -->' % gene,'']
    except: callobj.errorLog('seqDetailsHTML Error')
    ### ~ [2] ~ Finish ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ###
    #print string.join(html,'\n')
    return string.join(html,'\n')
#########################################################################################################################
def checkHTML(hpage):   ### Checks for existence of complete HTML page
    '''Checks for existence of complete HTML page.'''
    if not os.path.exists(hpage): return False
    html = open(hpage,'r').read().upper()
    if html.find('<HTML') < 0 or html.find('</HTML>') < 0: return False
    return True
#########################################################################################################################
def stripTags(html,keeptags=[]):    ### Strips all HTML tag text from html code, except listed keeptags
    '''Strips all HTML tag text from html code, except listed keeptags.'''
    keeptags = string.split(string.join(keeptags).lower())
    tagsplit = string.split(html,'<')
    newhtml = tagsplit.pop(0)    
    while tagsplit:
        tagtxt = tagsplit.pop(0)
        tag = rje.matchExp('^\\\\?([A-Za-z0-9]+)',tagtxt)
        if tag and tag[0].lower() in keeptags: newhtml += '<%s' % tagtxt
        elif tagtxt.find('>') >= 0: newhtml += ' %s' % tagtxt[tagtxt.find('>')+1:]
    return string.replace(newhtml,'  ',' ')
#########################################################################################################################
### END OF SECTION III: MODULE METHODS                                                                                  #
#########################################################################################################################

                                                    ### ~ ### ~ ###

#########################################################################################################################
### SECTION IV: MAIN PROGRAM                                                                                            #
#########################################################################################################################
def runMain():
    ### ~ [1] ~ Basic Setup of Program  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ###
    try: (info,out,mainlog,cmd_list) = setupProgram()
    except SystemExit: return  
    except: print 'Unexpected error during program setup:', sys.exc_info()[0]; return
    
    ### ~ [2] ~ Rest of Functionality... ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ###
    try: #HTML(mainlog,cmd_list).run()
        print rje_zen.Zen().wisdom(), '\n\n *** No standalone functionality! *** \n\n'


    ### ~ [3] ~ End ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ###
    except SystemExit: return  # Fork exit etc.
    except KeyboardInterrupt: mainlog.errorLog('User terminated.')
    except: mainlog.errorLog('Fatal error in main %s run.' % info.program)
    mainlog.printLog('#LOG', '%s V:%s End: %s\n' % (info.program,info.version,time.asctime(time.localtime(time.time()))))
#########################################################################################################################
if __name__ == "__main__":      ### Call runMain 
    try: runMain()
    except: print 'Cataclysmic run error:', sys.exc_info()[0]
    sys.exit()
#########################################################################################################################
### END OF SECTION IV                                                                                                   #
#########################################################################################################################
