# -*- coding: utf-8 -*-
"""
PyBlosxom plugin to override timestamps of blog entries.

If there is a file named TIMESTAMPS in your data directory, use ISO 8601
timestamps form that file to override file mtimes.

Example TIMESTAMPS file:

  2004-10-02T02:29:03+0300 unicode-emails-in-python.txt
  2004-12-30T00:16:09+0200 python/profiling.txt

You can get these timestamps with ls --full-time and then some massaging.

Installation: just drop this file into your PyBlosxom plugin directory.

After I've written this plugin, I discovered HardCodeDates by Nathan Kent
Bullock: http://pyblosxom.sourceforge.net/blog/registry/date/HardCodeDates

It is remarkably similair to mine, except it doesn't support explicit
time zones in TIMESTAMPS file.  I prefer mine for stylistic issues (such as
docstrings and more Pythonic idioms).

A related plugin is rememberdates by Richard Chamberlain:
http://pyblosxom.sourceforge.net/blog/registry/date/rememberdates
"""

__author__ = 'Marius Gedminas'
__version__ = '$Date: 2005-12-31 03:48:41 +0200 (Sat, 31 Dec 2005) $'
__url__ = 'http://mg.pov.lt/timestamps.py'
__description__ = "Reads entry timestamps from a plain-text file."


import os
import time


def parse_iso8601(timestamp):
    """Parse ISO 8601 timestamp and return a time_t value.

        >>> parse_iso8601('2005-01-16T17:49:19+0200')
        1105890559
        >>> parse_iso8601('2005-01-16T15:49:19+0000')
        1105890559

    """
    datetime, timezone = timestamp[:19], timestamp[19:]
    timetuple = time.strptime(datetime, '%Y-%m-%dT%H:%M:%S')
    # XXX this is deep magic and should have more unit tests
    #     sadly, changing time.timezone in a unit test is tricky
    utcoffset = (int(timezone) // 100 * 60 + int(timezone) % 100) * 60
    return int(time.mktime(timetuple[:-1] + (0, ))) - time.timezone - utcoffset


class Timestamps:
    """Timestamp cache."""

    def __init__(self, filename, basedir=''):
        self._filename = filename
        self._mtime = None
        self._basedir = basedir
        self._timestamps = {}

    def _reload(self):
        """Reload TIMESTAMPS."""
        self._timestamps = {}
        try:
            f = open(self._filename)
            self._mtime = os.fstat(f.fileno()).st_mtime
            for line in f:
                try:
                    timestamp, filename = line.strip().split(None, 1)
                    mtime = parse_iso8601(timestamp)
                    fullfilename = os.path.join(self._basedir, filename)
                    self._timestamps[fullfilename] = mtime
                except ValueError, TypeError:
                    pass
            f.close()
        except IOError:
            self._mtime = None

    def get(self, filename):
        """Return timestamp override for filename or None."""
        try:
            mtime = os.stat(self._filename).st_mtime
        except IOError:
            mtime = None
        if mtime != self._mtime:
            self._reload()
        return self._timestamps.get(filename)


def cb_start(args):
    """Initialize."""
    global timestamps
    datadir = args['request'].getConfiguration()['datadir']
    timestamps = Timestamps(os.path.join(datadir, 'TIMESTAMPS'), datadir)


def cb_filestat(args):
    """Callback for file status.

    `args` is a dict with the following keys:
    - "filename" - name of the entry
    - "mtime" - tuple as returned by os.stat

    Returns the (possibly modified) args dict.
    """
    mtime = timestamps.get(args['filename'])
    if mtime:
        args['mtime'] = args['mtime'][:8] + (mtime, ) + args['mtime'][9:]
    return args


if __name__ == '__main__':
    import doctest
    doctest.testmod()

