#! /usr/bin/env python
#
# Severly hacked version of ht2html.py originally written by Guido van Rossum
# My version allows eleven different color 'motifs': red, brown, pink,
# orange, purple,  black, olive, bluepurple, blue, green, and sienna
# These are specified via the 'pagecolor' metadata tag.
#
# During the parsing of the links.h file (which contains the anchors
# for the navigation bar, the program now also tries to determine the
# color 'motif' for the page by opening its .ht file and looking for
# the pagecolor tag.  If it exists, it sets the background in the
# nav bar for that row to be the lightcolor corresponding to the
# color motif specified for that page.
#
# I also allow for a 'split_content' metadata tag which when defined
# parses the contents into two parts 'shared' and 'not-shared'.  The
# shared part is to the left of the 'navigational-links'.  The
# 'not-shared' part is fully below the nav-links.  This is so long
# pages doe not waste so much space being occupied with en empty nav
# bar toward the middle and bottom of the page.  The catch is you need
# to add: <!--SHARED PART ENDS HERE--> in your page where you want
# the split to occur.
#
# You may use this script freely.  While the authors have tryed to make the
# results of using this script predictable, we are not liable for
# any damages that may result from the use of this software.
#
# Roger E. Masse

import os
import sys
import errno
import re
import rfc822
import string
import getopt
import whrandom

# ROOTDIR must be set to the name of the web pages root directory,
# and specifically, the dir which contains the script dir.
ROOTDIR = "www.python.org"

def fixpath():
    """Add the directory containing the script to the front of sys.path.

    Do not do this if we're being imported as a module, or if it is
    absent or if it is the current directory, or if it is already there.

    """
    if __name__ != '__main__':
        return
    scriptname = sys.argv[0]
    dirname = os.path.dirname(scriptname)
    if not dirname or dirname == os.curdir:
        return dirname
    if dirname not in sys.path:
        sys.path.insert(0, dirname)
    return dirname

SCRIPTDIR = fixpath()

from FileWrapper import FileWrapper

def main():
    backup = ""
    verbose = ""
    relative = ""
    compare = "C"
    rootdir = ROOTDIR
    root = None
    cornerbanner = None
    try:
        opts, args = getopt.getopt(sys.argv[1:], "vbfrR:t:s:c:")
    except getopt.error, msg:
        usage(msg)
    if not args:
        usage("no files specified")
    for o, a in opts:
        if o == '-v': verbose = "V"
        if o == '-b': backup = "B"
        if o == '-f': compare = ""
        if o == '-r': relative = "R"
        if o == '-R': relative = "R"; rootdir = a
        if o == '-s': root = a
        if o == '-t': loadtemplate(a)
        if o == '-c': cornerbanner = a
    mode = "w" + backup + compare + verbose + relative
    if relative:
        # - interpret args as being wrt current directory,
        # - and translate them to be wrt www.python.org web pages root
        #   (named according to value of 'rootdir' variable)
        # - and then cd to the web pages root, so we work with respect to it.
        reldir, updir = below(os.getcwd(), rootdir)
        for i in range(len(args)):
            args[i] = os.path.normpath(os.path.join(reldir, args[i]))
        os.chdir(updir)
    dolist(args, mode, root, cornerbanner)

def dosubdir(dir, mode, root):
    print "Checking subdirectory", dir, "..."
    files = []
    try:
        names = os.listdir(dir)
    except os.error, msg:
        print "Can't list", dir, ":", msg
        return
    for name in names:
        if name[-5:] == 'html' or name[0] == '.': continue
        file = os.path.join(dir, name)
        if file[-3:] == '.ht' or (name != 'RCS' and name != 'CVS' and
                                   os.path.isdir(file) and
                                   not os.path.islink(file)):
            files.append(file)
    files.sort()
    dolist(files, mode, root)

def dolist(args, mode, root=None, cornerbanner=None):
    for file in args:
        if os.path.isdir(file):
            dosubdir(file, mode, root)
            continue
        name, ext = os.path.splitext(file)
        if ext == '.html':
            print "Won't overwrite", file
            continue
        htmlfile = name + '.html'
        try:
            fi = open(file, "r")
        except IOError, msg:
            print "Can't open", file, ":", msg
            continue
        try:
            fo = FileWrapper(htmlfile, mode)
        except (os.error, IOError), msg:
            print "Can't create", htmlfile, ":", msg
        else:
            try:
                process(fi, fo, name, file, root, cornerbanner)
                fo.close()
                try:
                    os.chmod(htmlfile, 0664)
                except os.error, e:
                    # TBD: should we really discriminate?
                    code, msg = e
                    if code == errno.EPERM:
                        sys.stderr.write(
                            'WARNING: Could not change permission on file: ' +
                            htmlfile +
                            ', %s (errcode: %d)\n' % (msg, code))
                    else:
                        raise e
            finally:
                fo.close("abort")
        fi.close()

def usage(msg=None):
    sys.stdout = sys.stderr
    if msg:
        print msg
    print "usage:", sys.argv[0], "[-v] [-b] [-f] file.ht ..."
    print "-v: verbose (report files written/moved/removed)"
    print "-b: make backup of old html file if overwritten"
    print "-f: force writing html file (even if no change)"
    print "-r: relative mode (ask Ken)"
    print "-R rootdir: set rootdir for relative mode; implies -r"
    print "-s url: set URL used for root; must end in /"
    print "-t file: use the template defined in file"
    print "-c <imagefile>: specify the cornerbanner for the page"
    
    sys.exit(2)

def loadtemplate(name):
    if not name: return
    rootpath = os.path.normpath(os.path.join(SCRIPTDIR, os.pardir))
    filename = os.path.join(rootpath, name)
    try:
        execfile(filename, globals())
    except (IOError, SyntaxError), msg:
        print "%: Couldn't load template: %s" % (`filename`, str(msg))

SITELINKS = [
    ("./", "Home"),
    ("About.html", "About"),  
    ("Help.html", "Help"),
    ("People.html", "Community"),
    ]

HEAD = """\
<HTML>
<!-- THIS PAGE IS AUTOMATICALLY GENERATED.  DO NOT EDIT. -->

<!--User-specified headers:
Title: %(title)s
Wide-page: %(widepage)s
Meta: %(meta)s
Banner: %(rawbanner)s
Banner-alt: %(banneralt)s
Author: %(author)s
-->

<HEAD>
  <TITLE>%(title)s</TITLE>%(meta)s
</HEAD>

<BODY BGCOLOR="%(bgcolor)s" BACKGROUND="back.jpg" TEXT="%(fgcolor)s"
      LINK="%(linkcolor)s" VLINK="%(vlinkcolor)s" ALINK="%(alinkcolor)s">
<!--<BODY BGCOLOR="%(bgcolor)s" TEXT="%(fgcolor)s"
      LINK="%(linkcolor)s" VLINK="%(vlinkcolor)s" ALINK="%(alinkcolor)s">-->
<A NAME="top"></A>
<TABLE WIDTH="100%%" BORDER=0 CELLSPACING=0 CELLPADDING=0>

  <TR>
    <TD WIDTH=150 VALIGN=CENTER BGCOLOR="%(lightshade)s">
    <CENTER><A HREF="http://www.cs.umd.edu">
      <IMG BORDER=0 SRC="%(cornerbanner)s"></A></CENTER>
    </TD>

    <TD WIDTH=15 BGCOLOR="%(lightshade)s">&nbsp;&nbsp;</TD><!--spacer-->

    <TD WIDTH="90%%" BGCOLOR="%(lightshade)s">

      <TABLE WIDTH="100%%" BORDER=0 CELLSPACING=0 CELLPADDING=0
             COLS=4 ROWS=2 BGCOLOR="%(lightshade)s">

             %(sitelinks)s
            
      </TABLE>

    </TD>

  </TR>
"""

SIDEBAR = """
  <TR>

    <TD WIDTH=150 VALIGN=TOP BGCOLOR="%(lightshade)s">

      <TABLE WIDTH="100%%" BORDER=0 CELLSPACING=0 CELLPADDING=0
             BGCOLOR="%(lightshade)s">

        <!--User insert Other-links starts here-->
        %(otherlinks)s
        <!--User insert Other-links ends here-->

        <TR>
          <TD BGCOLOR="%(darkshade)s">
            <FONT COLOR="%(bgcolor)s"><b>Email us</b></FONT>
          </TD>
        </TR>

        <TR>
          <TD BGCOLOR="%(lightshade)s">
            <A HREF="mailto:%(fixed_author)s">%(author)s</A>
            <P>
            <CENTER>
            <A HREF="http://www.python.org/"
            ><IMG SRC="PythonPoweredSmall.gif"
                      WIDTH=55 HEIGHT=22 BORDER=0></A>
            </CENTER>
          </TD>
        </TR>

      </TABLE>

    </TD>

    <TD WIDTH=15>&nbsp;&nbsp;</TD><!--spacer-->

    <TD VALIGN=TOP WIDTH="90%%">
    <BR>
    <!--User part of page starts here-->

"""

TAIL = """
    <!--User part of page ends here-->
    </TD>
  </TR>
</TABLE>
</BODY>
</HTML>
"""
TAILTOP = """
    <!--User part of the side-by-side-with-nav-bar content ends here-->
    </TD>
  </TR>
</TABLE>
<P>
<!--User part of the normal content starts here -->
"""
WIDEHEAD = """
</TABLE>
<BR>
<!--User part of page starts here-->
"""

WIDETAIL = """
<!--User part of page ends here-->
</BODY>
</HTML>
"""
SPLITMARKER = """<!--SHARED PART ENDS HERE-->"""

DARKBGCOLORMARKER = 'BGCOLOR="#003366"'     # these should be set to the dark and
LIGHTBGCOLORMARKER = 'BGCOLOR="#99CCFF"'    # light colors of your 'template' file
                                            # that is the style file that acts as
                                            # a template for all the content.

def process(fi, fo, name, file, root=None, cornerbanner=None):
    print "Processing", file, "..."
    name = os.path.normpath(name)
    comps = string.split(name, os.sep)
    depth = len(comps) - 1
    root = root or "../" * depth

    bgcolor = "#FFFFFF"
    fgcolor = "#000000"

    linkcolor = "#0000BB"
    vlinkcolor = "#551A8B"
    alinkcolor = "#FF0000"

    msg = rfc822.Message(fi)
    widepage = msg.getheader('wide-page') or ""
    title = msg.getheader('title') or comps[-1]
    meta = msg.getheader('meta') or ""
    if meta: meta = "\n" + meta
    author = msg.getheader('author') or 'webmaster@python.org'
    split_content = msg.getheader('split_content') or ""
    fixed_author = re.sub("(?i)<br>", "", author)
    rawbanner = msg.getheader('banner') or ""
    banner = root + "pics/" + (rawbanner or "pythonHi.gif")
    banneralt = msg.getheader('banner-alt') or "Python"
    ol1 = load_other_links(file, msg.getheader('links'))
    ol2 = msg.getheader('other-links') or ""
    pagecolor = msg.getheader('pagecolor')

    darkshade, mediumshade, lightshade = getpagecolor(pagecolor)

    ##     lampshade = None

    sitelinks = make_sitelinks(name, root) % vars()
    otherlinks = fix_otherlinks(name, ol1 + ol2) % vars()

    # the command line arguement overrides the 'autoselect' mechanism
    if cornerbanner is None:
        if not pagecolor:
            cornerbanner = pick_cornerbanner()
        else:
            cornerbanner = "mswe613_%s.gif" % pagecolor

    fo.write(HEAD % vars())
    if widepage:
        fo.write(WIDEHEAD % vars())
    else:
        fo.write(SIDEBAR % vars())

    # process user page
    if split_content or pagecolor:
        while 1:
            line = fi.readline()
            if not line:
                split_content = 0
                break
            if string.find(line, SPLITMARKER) <> -1:
                fo.write(line)
                fo.write(TAILTOP)
                continue
            i = string.find(string.upper(line), DARKBGCOLORMARKER)
            if i <> -1:
                newline = replacecolor(line , i, DARKBGCOLORMARKER, darkshade)
                fo.write(newline)
                continue            
            i = string.find(string.upper(line), LIGHTBGCOLORMARKER)
            if i <> -1:
                newline = replacecolor(line , i,
                                       LIGHTBGCOLORMARKER, lightshade)
                fo.write(newline)
                continue
            
            fo.write(line)
    else:
        fo.writelines(fi.readlines())
        
    if widepage or split_content:
        fo.write(WIDETAIL % vars())
    else:
        fo.write(TAIL % vars())

def getpagecolor(pagecolor):
    
    if pagecolor == 'green':
        lightshade = "#99FFCC"
        mediumshade = "#33FF99"
        darkshade = "#006633"
    elif pagecolor == 'sienna':
        lightshade = "#FFCC99"
        mediumshade = "#CC9966"
        darkshade = "#A1690C"
    elif pagecolor == 'blue':
        lightshade = "#99CCFF"
        mediumshade = "#3399FF"
        darkshade = "#003366"
    elif pagecolor == 'brown':
        lightshade = "#CA957A"
        mediumshade = "#AD5B32"
        darkshade = "#993300"
    elif pagecolor == 'shockingpink':
        lightshade = "#F28ACF"
        mediumshade = "#E93EB0"
        darkshade = "#E10096"
    elif pagecolor == 'pink':
        lightshade = "#F6A7DC"
        mediumshade = "#EE6CC3"
        darkshade = "#E661A2"
    elif pagecolor == 'orange':
        lightshade = "#FFA892"
        mediumshade = "#FF6842"
        darkshade = "#E8690C"
    elif pagecolor == 'purple':
        lightshade = "#C59BD0"
        mediumshade = "#9247A7"
        darkshade = "#680085"
    elif pagecolor == 'black':
        lightshade = "#9B9B9B"
        mediumshade = "#3C3C3C"
        darkshade = "#000000"
    elif pagecolor == 'olive':
        lightshade = "#AAAB8D"
        mediumshade = "#727342"
        darkshade = "#424301"
    elif pagecolor == 'bluepurple':
        lightshade = "#A59EBA"
        mediumshade = "#52467B"
        darkshade = "#110048"
    else: # pagecolor == 'red':
        lightshade = "#D3828A"
        mediumshade = "#B93845"
        darkshade = "#A60212"

    return darkshade, mediumshade, lightshade

def replacecolor(line, i, oldmarker, newshade):
    """Replace the color specified by oldmarker with the
       one specified in newshade"""
    
    first = line[:i]
    middle = line[i:i+len(oldmarker)]
    last = line[i+len(oldmarker):]
    colorparts = string.split(middle, '"')
    middle = colorparts[0] + '"' + newshade + '"'
    newline = first + middle + last
    #print "replacing: ", line
    #print "with: ", newline
    return newline

def make_sitelinks(name, root):
    """Massage the site navigation panel into submission."""
    name = name + ".html"
    list = []
    for (link, label) in SITELINKS:
        s = label
        if samedir(link, name):
            # Don't make an anchor if links.h refers to us
            s2 = "<B>%s</B>" % s
            s = "<B><FONT SIZE=+1>%s</FONT></B>" % s
        if not samefile(link, name):
            s = '<A HREF="%s%s">%s</A>' % (root, link, s2)
        s = '  <TD WIDTH="25%%" BGCOLOR="%(lightshade)s">' + s + '</TD>'
        list.append(s)
    list = ["<TR>"] + list[:4] + ["</TR>", "<TR>"] + list[4:] + ["</TR>"]
    return string.join(list, "\n          ")

def pick_cornerbanner():
    # XXX Should really do a list of the pics directory...
    NBANNERS = 6
    i = whrandom.randint(0, NBANNERS-1)
    s = "mswe613_%01d.gif" % i
    print "banner:", s
    return s

def fix_otherlinks(name, otherlinks):
    """Apply various bits of magic to the otherlinks specs."""
    # Assume the base text consists of a bunch of <LI> items,
    # with <H3>...</H3> items in between.
    # Change each of these into a table cell.

    s = otherlinks

    p = re.compile('<h3>(.*?)</h3>', re.I | re.S)
    x = '<TR><TD BGCOLOR="%(lightshade)s">&nbsp;\n'
    s = p.sub(x + 
              '<TR><TD BGCOLOR="%(darkshade)s"><B><FONT COLOR="%(bgcolor)s">'
              r'\1'
              '</FONT></B></TD></TR>', s)

    n = len(x)
    if s[:n] == x:
        s = s[n:]

    p = re.compile('<li>', re.I)
    s = p.sub('<TR><TD BGCOLOR="%(lightshade)s">', s)
    
    head, name = os.path.split(name)
    name = name + ".html"
    p = re.compile('<a href="?([^<>"]*)"?>([^<>]*)</a>', re.S | re.I)
    res = []
    i = 0
    m = p.search(s)
    while m:
        j = m.start()
        href, text = m.group(1, 2)
        if href == name or (href in ("", "./") and name == "index.html"):
            all = "<FONT SIZE=+1><b>%s</b></FONT>" % text
        else:
            all = '<A HREF="%s">%s</A>' % (href, text)

        # see if the corresponding .ht file exists and if it has a pagecolor
        # attribute.  if so use the lightcolor aspect of that pagecolor
        if href in ("", "./"):
            htfile = "index.ht"
        else:
            htfile = href[:-2]
        try:
            f = open(htfile, 'r')
        except IOError:
            res.append(s[i:j]) # Table row specifier
        else:
             msg = rfc822.Message(f)
             pc = msg.getheader('pagecolor')
             if pc:
                 ds, ms, ls = getpagecolor(pc)
                 colorow = '<TR><TD BGCOLOR="%s">' % ls
                 res.append(colorow) # Table row specifier with color
             else:
                 res.append(s[i:j]) # Table row specifier
             f.close()    
        
        res.append(all)    # Anchor specifier
        i = m.end()
        m = p.search(s, i)
    res.append(s[i:])
    if filter(None, res):
        res.append('\n<TR><TD BGCOLOR="%(lightshade)s">&nbsp;')
   
    return string.join(res, "")

def load_other_links(file, names=None):
    head, tail = os.path.split(file)
    if names:
        files = []
        for name in string.split(names):
            files.append(os.path.join(head, name))
    else:
        file = os.path.join(head, "links.h")
        if os.path.exists(file):
            files = [file]
        else:
            files = []
    texts = []
    for file in files:
        f = open(file)
        text = f.read()
        f.close()
        texts.append(text)
    return string.join(texts, "\n")

def samedir(a, b):
    aa = splitit(a)
    bb = splitit(b)
    return aa[:-1] == bb[:-1]

def samefile(a, b):
    if a == b:
        return 1
    aa = splitit(a)
    bb = splitit(b)
    if aa[:-1] != bb[:-1]:
        return 0
    a = aa[-1] or "index.html"
    b = bb[-1] or "index.html"
    return a == b
    
def splitit(a):
    aa = string.split(a, '/')
    while '.' in aa:
        aa.remove('.')
    return aa

def below(path, dir):
    "Return all of path below last match of dir, and path to get up there."
    try:
        start = string.rindex(path, dir)
    except ValueError:
        raise RuntimeError, ("Can only process files in web hierarchy"
                             " below %s dir" % `dir`)
    if start == -1:
        return path
    else:
        if start + len(dir) == len(path):
            return ".", "."
        else:
            reldir = path[start + len(dir) + 1:]
            updir = len(string.split(reldir, '/')) * "../"
            return reldir, updir

if __name__ == '__main__':
    try:
        main()
    except KeyboardInterrupt:
        print "[Interrupted]"
        sys.exit(1)
