# (Be in -*- python -*- mode.)
#
# ====================================================================
# Copyright (c) 2007-2010 CollabNet.  All rights reserved.
#
# This software is licensed as described in the file COPYING, which
# you should have received as part of this distribution.  The terms
# are also available at http://subversion.tigris.org/license-1.html.
# If newer versions of this license are posted there, you may use a
# newer version instead, at your option.
#
# This software consists of voluntary contributions made by many
# individuals.  For exact contribution history, see the revision
# history and logs, available at http://cvs2svn.tigris.org/.
# ====================================================================

"""Expand RCS/CVS keywords."""


import re
import time

from cvs2svn_lib.context import Ctx


class _KeywordExpander:
  """A class whose instances provide substitutions for CVS keywords.

  This class is used via its __call__() method, which should be called
  with a match object representing a match for a CVS keyword string.
  The method returns the replacement for the matched text.

  The __call__() method works by calling the method with the same name
  as that of the CVS keyword (converted to lower case).

  Instances of this class can be passed as the REPL argument to
  re.sub()."""

  date_fmt_old = "%Y/%m/%d %H:%M:%S"    # CVS 1.11, rcs
  date_fmt_new = "%Y-%m-%d %H:%M:%S"    # CVS 1.12

  date_fmt = date_fmt_new

  @classmethod
  def use_old_date_format(klass):
      """Class method to ensure exact compatibility with CVS 1.11
      output.  Use this if you want to verify your conversion and you're
      using CVS 1.11."""
      klass.date_fmt = klass.date_fmt_old

  def __init__(self, cvs_rev):
    self.cvs_rev = cvs_rev

  def __call__(self, match):
    return '$%s: %s $' % (
        match.group(1), getattr(self, match.group(1).lower())(),
        )

  def author(self):
    return Ctx()._metadata_db[self.cvs_rev.metadata_id].original_author

  def date(self):
    return time.strftime(self.date_fmt, time.gmtime(self.cvs_rev.timestamp))

  def header(self):
    return '%s %s %s %s Exp' % (
        self.source(), self.cvs_rev.rev, self.date(), self.author(),
        )

  def id(self):
    return '%s %s %s %s Exp' % (
        self.rcsfile(), self.cvs_rev.rev, self.date(), self.author(),
        )

  def locker(self):
    # Handle kvl like kv, as a converted repo is supposed to have no
    # locks.
    return ''

  def log(self):
    # Would need some special handling.
    return 'not supported by cvs2svn'

  def mdocdate(self):
    return '%s %d %s' % (
        time.strftime("%B", time.gmtime(self.cvs_rev.timestamp)),
        time.gmtime(self.cvs_rev.timestamp).tm_mday,
        time.strftime("%Y", time.gmtime(self.cvs_rev.timestamp))
        )

  def name(self):
    # Cannot work, as just creating a new symbol does not check out
    # the revision again.
    return 'not supported by cvs2svn'

  def openbsd(self):
    self.use_old_date_format()
    return '%s %s %s %s Exp' % (
        self.rcsfile(), self.cvs_rev.rev, self.date(), self.author(),
        )

  def rcsfile(self):
    return self.cvs_rev.cvs_file.rcs_basename + ",v"

  def revision(self):
    return self.cvs_rev.rev

  def source(self):
    project = self.cvs_rev.cvs_file.project
    return '%s/%s%s' % (
        project.cvs_repository_root,
        project.cvs_module,
        '/'.join(self.cvs_rev.cvs_file.get_path_components(rcs=True)),
        )

  def state(self):
    # We check out only live revisions.
    return 'Exp'


_kws = 'Author|Date|Header|Id|Locker|Log|Mdocdate|Name|OpenBSD|RCSfile|Revision|Source|State'
_kw_re = re.compile(r'\$(' + _kws + r'):[^$\n]*\$')
_kwo_re = re.compile(r'\$(' + _kws + r')(:[^$\n]*)?\$')


def expand_keywords(text, cvs_rev):
  """Return TEXT with keywords expanded for CVS_REV.

  E.g., '$Author$' -> '$Author: jrandom $'."""

  return _kwo_re.sub(_KeywordExpander(cvs_rev), text)


def collapse_keywords(text):
  """Return TEXT with keywords collapsed.

  E.g., '$Author: jrandom $' -> '$Author$'."""

  return _kw_re.sub(r'$\1$', text)


