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

# ==============================================================================
# COPYRIGHT (C) 1991 - 2003  EDF R&D                  WWW.CODE-ASTER.ORG
# THIS PROGRAM IS FREE SOFTWARE; YOU CAN REDISTRIBUTE IT AND/OR MODIFY
# IT UNDER THE TERMS OF THE GNU GENERAL PUBLIC LICENSE AS PUBLISHED BY
# THE FREE SOFTWARE FOUNDATION; EITHER VERSION 2 OF THE LICENSE, OR
# (AT YOUR OPTION) ANY LATER VERSION.
#
# THIS PROGRAM IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, BUT
# WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED WARRANTY OF
# MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. SEE THE GNU
# GENERAL PUBLIC LICENSE FOR MORE DETAILS.
#
# YOU SHOULD HAVE RECEIVED A COPY OF THE GNU GENERAL PUBLIC LICENSE
# ALONG WITH THIS PROGRAM; IF NOT, WRITE TO EDF R&D CODE_ASTER,
#    1 AVENUE DU GENERAL DE GAULLE, 92141 CLAMART CEDEX, FRANCE.
# ==============================================================================

"""
   Some utilities
"""

__revision__ = "$Id: utils.py 2579 2006-12-11 08:47:28Z courtois $"

__all__ = ['get_absolute_path', 'get_absolute_dirname',
           'search_cmd', 'change_text_file', 'IterVersion']

# ----- differ messages translation
def _(mesg):
   return mesg

import os
import re

#-------------------------------------------------------------------------------
def get_absolute_path(path):
   """Retourne le chemin absolu en suivant les liens éventuels.
   """
   if os.path.islink(path):
      path = os.path.realpath(path)
   res = os.path.normpath(os.path.abspath(path))
   return res

def get_absolute_dirname(path):
   """Retourne le chemin absolu en suivant les liens éventuels.
   """
   res = os.path.normpath(os.path.join(get_absolute_path(path), os.pardir))
   return res

#-------------------------------------------------------------------------------
def search_cmd(pattern, fich, delimiter=' ;='):
   """Retourne la commande contenant `pattern` dans `fich`.
   """
   cmd = None
   content = open(fich, 'r').read()
   sep = '[%s]*' % re.escape(delimiter)
   expr = re.compile('%(sep)s(.*?%(pattern)s.*?)%(sep)s' % {
      'pattern' : pattern,
      'sep'     : sep,
   }, re.MULTILINE)
   mat = expr.search(content)
   if mat != None:
      cmd = mat.group(1)
      for char in delimiter:
         lsplit = cmd.split(char)
         cmd = ' '.join([s for s in lsplit if re.search(pattern, s)])
   return cmd

#-------------------------------------------------------------------------------
def _chgline(line, dtrans, delimiter):
   """Change all strings by their new value provided by 'dtrans' dictionnary
   in the string 'line'.
   """
   delim = re.escape(delimiter)
   for old, new in dtrans.items():
      line = re.sub(delim + old + delim, str(new), line)
   return line

def change_text_file(filename, dtrans, delimiter, keep=False, ext='.orig'):
   """Change all strings by their new value provided by 'dtrans' dictionnary
   in the existing file 'filename'.
   """
   iret=0
   fold = filename + ext
   try:
      os.rename(filename, fold)
   except OSError:
      return 4
   fsrc=open(fold, 'r')
   fnew=open(filename, 'w')
   for line in fsrc:
      fnew.write(_chgline(line, dtrans, delimiter))
   fnew.close()
   fsrc.close()
   if not keep:
      os.remove(fold)
   return iret

#-------------------------------------------------------------------------------
class IterVersionError:
   pass

class IterVersion:
   """Classe pour itérer sur les sous-versions d'un produit.
   """
   def __init__(self, vini, *delta):
      """Version de la forme n1.n2.n3, et on va jusqu'à l'indice
          "n1+delta1"."n2+delta2"."n3+delta3".
      """
      self.l_vini = self.v2l(vini)
      self.l_vcur = self.l_vini[:]
      self.delta  = delta[:]
      self.imax   = len(self.delta) - 1
      if len(self.l_vini) != len(self.delta):
         raise IterVersionError, 'number of delta does not match version'

   def v2l(self, vers):
      """'1.4.7' => [1, 4, 7]
      """
      try:
         liste = [int(ind) for ind in vers.split('.')]
      except Exception, msg:
         raise IterVersionError, msg
      return liste

   def l2v(self, liste):
      """[1, 4, 7] => '1.4.7'
      """
      return '.'.join(['%s' % val for val in liste])

   def possible(self):
      """Listes des valeurs suivantes possibles
      """
      self.l_poss = [range(self.l_vcur[i] + 1, self.l_vini[i] + self.delta[i] + 1) \
               for i in range(self.imax + 1)]

   def next(self):
      """Retourne la version suivant la version courante selon 'stage'.
      """
      ok = False
      i = self.imax
      self.possible()
      i = self.imax
      while i >= 0 and not ok:
         if len(self.l_poss[i]) > 0:
            self.l_vcur[i] = self.l_poss[i].pop(0)
            ok = True
         else:
            self.possible()
            self.l_vcur[i] = 0
            self.l_vini[i] = 0
            i -= 1
      if not ok:
         raise StopIteration
      return self.l2v(self.l_vcur)

   def jump(self):
      """Saute à la sous-version suivante.
      """
      self.l_vini[self.imax] = -9999
      
   def __iter__(self):
      """Returns the iterator itself.
      """
      return self

#-------------------------------------------------------------------------------
if __name__ == '__main__':
   itv = IterVersion('1.4.7', 1, 4, 5)
   for i, vers in enumerate(itv):
      if i > 6:
         itv.jump()
      print i, vers

