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

import _winreg
import os
import os.path

show_debug = True

try:
  from base.scicalc_debug import *
except:
  show_debug = False

#------------------------------------------------------------------------------
class Informations:
  """
  Analyse le système et renvoit des informations sur les versions de Python installées.
  Fournit également des informations sur d'autres librairies installées sur le système cible.

  La détection de python est basée sur la présence de l'entrée suivante dans la base de registre :
  HKEY_LOCAL_MACHINE\SOFTWARE\Python\PythonCore.

  Pour les différentes librairies, voir les fonctions qui vont bien (get_version_*) !!!
  Attention, toutefois, on ne cherche à récuperer le numéro de version que si le répertoire
  d'installation de la librairie concernée est présent.

  L'objectif étant de privilégier l'analyse de la base de registre ou des fichiers
  log d'installation tant que cela est possible.

  Comme ce fichier est également utilisé dans le setup (qui lui est compilé), toute utilisation
  d'import ne fera que faire grossir l'exécutable produit.

  Pour infos, la taille du fichier exécutable produit a diminué de plus de 35% !!!!
  """

  #----------------------------------------------
  def __init__(self):
    global show_debug

    # self.last_version = 2.3 par exemple si Python 2.3 est la version la plus recente detectee.
    # self.rep est le repertoire d'installation correspondant.
    # self.versions_multiple = True si plusieurs versions de Python detectees, False sinon.
    # self._versions = [2.2, 2.3] si Python 2.2 et Python 2.3 sont detectes.
    # self.python = {2.2: "C:\\python22", 2.3: "E:\\python23"} par exemple dans ce cas.
    # self.versions() renvoit alors "2.2, 2.3".

    # Python
    self.python = {}
    self.last_version = None
    self._versions = []
    try:
      key = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE,"SOFTWARE\\Python\\PythonCore")
      i = 0
      while 1:
        try:
          num = eval(_winreg.EnumKey(key, i))
          rep = _winreg.EnumValue(_winreg.OpenKey(key, str(num) + "\\InstallPath"), 0)[1]
          self._versions.append(num)
          if not self.python.has_key(num):
            self.python[num] = []
          self.python[num].append(rep)
          self.last_version = num
          i+=1
        except:
          break
    except:
      pass

    self.versions_multiples = len(self._versions) > 1

    if self.last_version <> None :
      self.rep = rep = self.python[self.last_version][0]
    else:
      self.rep = rep = ""
    self.python_version = self.get_version_python()
    if (show_debug == True) :
      debug(show_debug, "Python : %s" % str(self.python_version))

    # wxPython
    self.wxpython = os.path.exists(rep + "\\Lib\\site-packages\\wx.pth")
    self.wxpython_version = None
    if self.wxpython:
      try:
        self.wxpython_version = self.get_version_wxpython()
      except:
        pass
    if (show_debug == True) :
      debug(show_debug, "WxPython : %s, %s" % (str(self.wxpython), str(self.wxpython_version)))

    # Numeric
    self.Numeric = os.path.exists(rep + "\\Lib\\site-packages\\Numeric")
    self.numeric_version = None
    if self.Numeric:
      try:
        self.numeric_version = self.get_version_numeric()
      except:
        pass
    if (show_debug == True) :
      debug(show_debug, "Numeric : %s, %s" % (str(self.Numeric), str(self.numeric_version)))

    # numarray
    self.numarray = os.path.exists(rep + "\\Lib\\site-packages\\numarray")
    self.numarray_version = None
    if self.numarray:
      try:
        self.numarray_version = self.get_version_numarray()
      except:
        pass
    if (show_debug == True) :
      debug(show_debug, "numarray : %s, %s" % (str(self.numarray), str(self.numarray_version)))

    # matplotlib
    self.matplotlib = os.path.exists(rep + "\\Lib\\site-packages\\matplotlib")
    self.matplotlib_version = None
    if self.matplotlib:
      try:
        self.matplotlib_version = self.get_version_matplotlib()
      except:
        pass
    if (show_debug == True) :
      debug(show_debug, "matplotlib : %s, %s" % (str(self.matplotlib), str(self.matplotlib_version)))

    # scipy
    self.scipy = os.path.exists(rep + "\\Lib\\site-packages\\scipy")
    self.scipy_version = None
    if self.scipy:
      try:
        self.scipy_version = self.get_version_scipy()
      except:
        pass
    if (show_debug == True) :
      debug(show_debug, "SciPy core : %s, %s" % (str(self.scipy), str(self.scipy_version)))

    # pywin32
    self.pywin32 = os.path.exists(rep + "\\Lib\\site-packages\\pywin32_system32")
    self.pywin32_version = None
    if self.pywin32:
      try:
        self.pywin32_version = self.get_version_pywin32()
      except:
        pass
    if (show_debug == True) :
      debug(show_debug, "pywin32 : %s, %s" % (str(self.pywin32), str(self.pywin32_version)))

    # py2exe
    self.py2exe = os.path.exists(rep + "\\Lib\\site-packages\\py2exe")
    self.py2exe_version = None
    if self.py2exe:
      try:
        self.py2exe_version = self.get_version_py2exe()
      except:
        pass
    if (show_debug == True) :
      debug(show_debug, "py2exe : %s, %s" % (str(self.py2exe), str(self.py2exe_version)))

  #----------------------------------------------
  def _text_to_version(self, version):
    return tuple(map(int, str(version).split('.')))

  #----------------------------------------------
  def versions(self):
    return reduce(lambda x, y: x + ", " + y, self._versions)

  #----------------------------------------------
  def readLogFile(self, filename):
    """
    Lecture du fichier passé en paramètre. Ce fichier se trouve dans self.rep
    """
    f = open(self.rep + os.sep + filename, "r")
    txt = f.readlines()
    f.close()
    return txt

  #----------------------------------------------
  def getUninstallKey(self, txt):
    """
    Retourne la clé correspondant à la désinstallation du package dont le contenu du
    fichier log est passé en paramètre
    """
    for line in txt:
      if line.find('Reg DB Key:') != -1:
        key = line[line.find(']')+1:].strip('\n')
        break
    return key

  #----------------------------------------------
  def getUninstallDisplayName(self, lib):
    """
    Retourne la valeur de l'entrée DisplayName stockée dans la base de registre
    """
    import win32api, win32con

    try:
      key = win32api.RegOpenKey(win32con.HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\" + lib, 0, win32con.KEY_ALL_ACCESS)
      try:
        try:
          ver = win32api.RegQueryValueEx(key, "DisplayName")[0]
        except win32api.error:
          pass # no registry entry.
      finally:
        key.Close()
    except win32api.error:
        pass

    return ver

  #----------------------------------------------
  def Formate(self, txt):
    """
    Formatage du numéro de version pour l'affichage
    """
    arr = txt.split('-')
    ver = arr[1] + " (pour Python " + txt.split(' ')[1] + ")"
    return ver

  #----------------------------------------------
  def get_version_wxpython(self):
    """
    Retourne la version de wxpython installée sur le système cible

    Comment cela fonctionne ?
    On utilise le module wxversion qui fait plein de choses pour nous ;-)
    Si Python est installé sur C:\Python24,
    alors wxversion se trouve dans C:\Python24\Lib\site-packages
    Permet également de savoir si on a une version ansi ou unicode.
    """
    import wxversion
    installed = wxversion._find_installed()
    return [os.path.basename(p.pathname)[3:] for p in installed]

  #----------------------------------------------
  def getPackageVersion(self, logfile):
    """
    Retourne la version de numarray installée sur le système cible

    Comment cela fonctionne ?
    1/ On va chercher dans le répertoire d'installation de Python le fichier de désinstallation
    (numarray-wininst.log)
    2/ On récupère le nom de la clé dans Uninstall (ex : numarray-py2.4)
    3/ On récupère la clé de la base de registre pour la désinstallation de numarray
      Root Key : HKEY_LOCAL_MACHINE
      Reg DB Key : [Software\Microsoft\Windows\CurrentVersion\Uninstall]
      Reg DB Value : dans DisplayName
      Pour cela il faut parser le fichier de log ligne par ligne jusqu'à avoir les informations
      idoines. On pourrait également tout récupérer depuis le fichier log, mais bon, manipuler
      la base de registre permet de se familliariser avec certains modules de pywin32 ;-)
    4/ On reformate tout ça pour l'affichage
      ex : 24.2 (pour Python 2.4)
    """
    txt = self.readLogFile(logfile)
    lib = self.getUninstallKey(txt)
    ver = self.getUninstallDisplayName(lib)
    return self.Formate(ver)

  #----------------------------------------------
  def get_version_numarray(self):
    """
    Retourne la version de numarray installée sur le système cible
    """
    return self.getPackageVersion("numarray-wininst.log")

  #----------------------------------------------
  def get_version_numeric(self):
    """
    Retourne la version de numeric installée sur le système cible
    """
    return self.getPackageVersion("Numeric-wininst.log")

  #----------------------------------------------
  def get_version_matplotlib(self):
    """
    Retourne la version de matplotlib installée sur le système cible
    """
    return self.getPackageVersion("matplotlib-wininst.log")

  #----------------------------------------------
  def get_version_python(self):
    """
    Retourne la version de python installée sur le système cible
    """
    import sys
    return sys.version_info[0:3]

  #----------------------------------------------
  def get_version_scipy(self):
    """
    Retourne la version de scipy installée sur le système cible
    """
    return self.getPackageVersion("scipy_core-wininst.log")

  #----------------------------------------------
  def get_version_pywin32(self):
    """
    Retourne la version de pywin32 installée sur le système cible
    """
    return self.getPackageVersion("pywin32-wininst.log")

  #----------------------------------------------
  def get_version_py2exe(self):
    """
    Retourne la version de py2exe installée sur le système cible
    """
    return self.getPackageVersion("py2exe-wininst.log")
