"""
$URL: svn+ssh://svn.mems-exchange.org/repos/trunk/dulcinea/lib/util.py $
$Id: util.py 29786 2007-04-25 15:24:15Z rmasse $
"""
from datetime import datetime
from distutils.fancy_getopt import wrap_text
from formatter import AbstractFormatter, DumbWriter
from htmllib import HTMLParser
from os.path import isdir, dirname, abspath
from qpy import h8, stringify
from StringIO import StringIO
import re
import time


SAFE_TAGS = ['<p>', '</p>', '<b>', '</b>', '<i>', '</i>', '<ul>',
             '</ul>', '<li>', '</li>', '<br>', '<pre>', '</pre>',
             '<strong>', '</strong>']

def _htmlescape_except(text, safe_tags):
    """(text) -> h8

    Quotes 'text' for use in an HTML page, except for the tags
    listed in 'safe_tags' which are considered safe (e.g. <p>, <b>).
    Both upper and lower case versions of the tags will be applied
    """
    if text is None:
        return None
    text = stringify(h8.quote(text))
    for tag in safe_tags:
        tag_re = re.compile(stringify(h8.quote(tag)), re.IGNORECASE)
        text = tag_re.sub(tag, text)
    return h8(text)

# re to automatically hyperlink email addresses and URLs
_link_re = re.compile(r"""\b(
    # email address
      [\w.-]+ # local part
      @
      [\w.-]+\.[\w]{2,4} # domain
    |
    # URL
      (?:https?://|www\.) # must start with http or www
      [\w.-]+\.[\w]{2,4} # domain
      (?::\d+)? # optional port
      (?:/[\w#$%&+,-./:;=?@\[\]^_|~]*)? # optional path
   )""", re.VERBOSE)

def activate_links(text):
    """(text:str|None) -> h8|None
    Returns an h8.quoted version of text, with things that look like email
    addresses and URLs turned into hyperlinks.
    """
    def _link_replace(m):
        text = url = m.group(0)
        extra = ""
        if text.find("@") == -1:
            if text[-1] in ".,":
                # don't include as part of the URL (easier to handle here
                # than in the regex)
                extra = text[-1]
                text = text[:-1]
            if not text.startswith("http"):
                url = "http://" + text
        else:
            if not text.startswith("mailto"):
                url = "mailto:" + text
        return '<a href="%s">%s</a>%s' % (url, text, extra)

    if text is None:
        return None
    return h8(_link_re.sub(_link_replace, stringify(h8.quote(text))))


def format_text(text, safe_tags=SAFE_TAGS):
    """(text : string, safe_tags : [str]) -> h8

    Convert an ASCII string containing text into HTML.
    The resulting HTML has been reformatted in the following ways:
       * <, &, and > are escaped
       * Things that look like email addresses and URLs will be turned into
         hyperlinks.
       * If safe_tags is defined, it is expected to be a list of tags
         considered to be safe (e.g. <p>, <b>, etc).  These tags will
         not be escaped.
    """
    return activate_links(_htmlescape_except(text, safe_tags))

def sanitize_url(url):
    """(url:string) -> string
    Try to ensure a URL is well-formed, by adding http:// if it isn't present.
    """
    if url is None:
        return None
    if '@' in url and not url.startswith('mailto:'):
        # assume it's an e-mail address
        url = "mailto:" + url
    elif url.find(":") == -1:
        # assume http:// is missing
        url = "http://" + url
    return url

_paragraph_re = re.compile('\n\n+')

def split_paragraphs(text):
    return _paragraph_re.split(text)

def wrap_paragraphs(text):
    """(text) -> string
    Wrap a sequence of paragraphs for output as plain text.
    """
    if text is None:
        return ""
    return '\n\n'.join([wrap_paragraph(paragraph)
                        for paragraph in split_paragraphs(text)])

def wrap_paragraph(text):
    line_length = 70
    if isinstance(text, unicode):
        lines = [text.__class__(x, 'utf-8')
                 for x in wrap_text(text.encode('utf-8'), line_length)]
    else:
        lines = wrap_text(text, line_length)
    return '\n'.join(lines)

def insert_paragraph_tags(text):
    """(text:string|None) -> h8|None

    Prepare a text field for display as HTML.
    Currently this just HTML quotes the string and then inserts
    <p> tags at blank lines.  
    """
    if text is None:
        return None
    return h8(
        '<p>' +
        _paragraph_re.sub('</p><p>', stringify(h8.quote(text))) +
        '</p>')

def datetime_to_int(date_time):
    """(date_time:datetime) -> int
    Returns the number of seconds since the epoch.
    """
    return int(time.mktime(date_time.timetuple()))

def beginning_of_next_month(date_time):
    """(date_time:datetime) -> datetime
    Return a datetime for the exact beginning of the month
    following the given date_time.  
    """
    year = date_time.year
    month = date_time.month + 1
    if month == 13:
        year += 1
        month = 1
    return datetime(year=year, month=month, day=1, hour=0, minute=0,
                    second=0, microsecond=0)

def html2txt(text):
    """(any) -> str
    """
    sio = StringIO()
    parser = HTMLParser(AbstractFormatter(DumbWriter(sio)))
    parser.feed(stringify(text).encode('utf8'))
    result = sio.getvalue()
    return result.decode('latin1')

def is_new(persistent_object):
    """(persistent_object : durus.persistent.Persistent) -> boolean
    """
    return persistent_object._p_connection is None

def get_module_directory(module):
    result = abspath(module.__file__)
    if isdir(result):
        return result
    else:
        return dirname(result)
