# -*- coding: iso-8859-1 -*-

"""
 tguettler 2003-12-24
 Publisher for Quixote which uses ZEO.ClientStorage (ZODB)

 It includes a hook, to parse all html output with tidy.
 This hook displays all warnings from tidy in the logs. 

"""

# Python Imports
import os
import sys
import time
import random
import popen2
import tempfile

# Quixote Imports
from quixote import Publisher
from quixote.http_response import HTTPResponse

# ZODB Imports
import ZODB
from ZODB import DB
from ZEO.ClientStorage import ClientStorage
from ZODB.POSException import ConflictError

#My Imports
import WorkflowServer

def log(msg):
    timestamp = time.strftime("%Y-%m-%d %H:%M:%S",
                              time.localtime(time.time()))
    sys.stdout.write("[%s] %s\n" % (timestamp, msg))


def base_url():
    port=os.environ.get("SERVER_PORT")
    if port=="443":
        protocol="https"
    else:
        protocol="http"
    if port not in ["80", "443"]:
        port=":%s" % port
    else:
        port=""
    url="%s://%s%s%s/" % (
        protocol, os.environ["SERVER_NAME"], port,
        os.environ["SCRIPT_NAME"])
    return url

class ZEOClientPublisher(Publisher):
    def __init__(self):
        # $HOME/modarch/workflow/publisher.py:
        home=os.path.join(os.path.dirname(
             os.environ["MODARCH_HOME"]), "workflow")
        self.home=home

        socket_file=os.path.join(home, "var", "zeosocket")
        if not os.path.exists(socket_file):
            # Starte ZEO
            sys.stderr.write("Starting ZEO since there is no socket file\n")
            os.system(
                "cd '%s'; nohup ./start-zeo.sh >> var/log/zeo.log 2>&1 &" %
                home)
            
        self.storage=ClientStorage(socket_file)
        db=DB(self.storage)
        conn=db.open()
        dbroot=conn.root()
        
        create_new=0  # Set this to 1 for one request
                      # to create a new application
        if create_new:
            server=WorkflowServer.WorkflowServer(home)
            dbroot["server"]=server
        else:
            server=dbroot["server"]
            
        return Publisher.__init__(self, server)
        
    def start_request(self, request):
        self.root_namespace.base_url=base_url()
        username=os.environ.get("REMOTE_USER", "")
        self.root_namespace.users._username=username
        log("start_request: %s %s %s" % (
            username, os.environ.get("REMOTE_ADDR"),
            os.environ.get("PATH_INFO")))
        
    def try_publish(self, request, path):
        # Taken from Dulcinea/lib/ui/publish.py
        retries=8
        for i in range(retries):
            try:
                return Publisher.try_publish(self, request, path)
            except ConflictError, exc:
                print "ConflictError (%s): retrying request" % `exc.oid`
                get_transaction().abort()
                request.response = HTTPResponse() # reset response object
                time.sleep(random.random() * (i+1))
        else:
            raise RuntimeError("too many conflict errors")
        
    def finish_successful_request(self, request):
        #print "finish_sucessful_request"
        get_transaction().commit()

    def finish_interrupted_request(self, request, exc):
        get_transaction().abort()
        return Publisher.finish_interrupted_request(self, request, exc)

    def finish_failed_request(self, request):
        print "request failed, see error_log:", \
              request.environ.get("PATH_INFO")
        get_transaction().abort()
        return Publisher.finish_failed_request(self, request)
    
        
    def finish_output(self, output, request, path):
        c_type=request.response.headers.get("content-type")
        if not c_type or c_type=="text/html":
            self.html_tidy(output, path)
        return output
    
    def html_tidy(self, output, url):
        """
        Small hack to call html-tidy for every html
        page which is serverd by quixote.

        It is used for checking the html syntax only, the html
        output won't be changed.
        """
        prog="tidy"
        found=None
        path_list=os.environ.get("PATH", "").split(":")
        for path in path_list:
            path=path.strip()
            prog_abs=os.path.join(path, prog)
            if os.path.exists(prog_abs):
                found=prog_abs
                break
        if not found:
            return
        ignore=[
            'Warning: <table> lacks "summary" attribute',
            "Can't open",
            "Warning: <nobr> is not approved by W3C",
            "Warning: missing <!DOCTYPE> declaration",
            "Warning: trimming empty <pre>",
            "Warning: trimming empty <option>",
            "Warning: inserting missing 'title' element",
            "This document has errors that must be fixed before",
            "using HTML Tidy to generate a tidied up version",
            # The following lines are needed for old tidy versions:
            "The table summary attribute should be used to describe",
            "the table structure. It is very helpful for people using",
            "non-visual browsers. The scope and headers attributes for",
            "table cells are useful for specifying which headers apply",
            "to each table cell, enabling non-visual browsers to provide",
            "a meaningful context for each cell.",
            "For further advice on how to make your pages accessible",
            'see "http://www.w3.org/WAI/GL". You may also want to try',
            '"http://www.cast.org/bobby/" which is a free Web-based',
            "service for checking URLs for accessibility.",
            "You are recommended to use CSS to control line wrapping.",
            'Use "white-space: nowrap" to inhibit wrapping in place',
            "of inserting <NOBR>...</NOBR> into the markup.",
            "HTML & CSS specifications are available from http://www.w3.org/",
            "To learn more about Tidy see http://www.w3.org/People/Raggett/tidy/",
            "Please send bug reports to Dave Raggett care of <html-tidy@w3.org>",
            "Lobby your company to join W3C, see http://www.w3.org/Consortium"
            ]
        htmlfile=tempfile.mktemp()
        fd=open(htmlfile, "wt")
        fd.write(output)
        fd.close()
        stdout, stdin = popen2.popen4("tidy -q -errors %s" % htmlfile)
        out=stdout.readlines()
        os.unlink(htmlfile)
        for line in out:
            line=line.strip()
            if not line:
                continue
            cont=0
            for ign in ignore:
                if line.find(ign)!=-1:
                    cont=1
                    continue
            if cont:
                continue
            self.log("HTML-Tidy %s: %s" % (
                url, line))
        sys.stdout.flush()

        
    
