import os
import sys
import platform
import subprocess
import json
from distutils.spawn import find_executable

currentDir = os.path.dirname(sys.executable if getattr(sys, 'frozen', False)
  else __file__)

def onWindows():
  return sys.platform == "win32"

# windows platform specific import
if onWindows():
  try:
    import _winreg as winreg
  except ModuleNotFoundError:
    import winreg

  # Pass Installation registry KEY NAME along with VALUE NAME
  def getRegValue(keyName, valueName):
    reg = winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE)
    key = winreg.OpenKey(reg, keyName)
    value = winreg.QueryValueEx(key, valueName)
    winreg.CloseKey(key)
    return value[0]

def cygpath(path):
  result = path
  # try to find in PATH
  if not os.path.exists(result):
    result = find_executable(result)
    if not result:
      result = path
  # try to find as cygwin path
  if onWindows() and not os.path.exists(result):
    try:
      p = subprocess.Popen( ["cygpath", "-w", "-a", result], \
        stdout=subprocess.PIPE, stderr=subprocess.PIPE)
      (stdoutdata, stderrdata) = p.communicate()
      found = False
      for line in stdoutdata.splitlines():
        if not isinstance(line, str):
          line = line.decode()
        if not found:
          p = line.strip()
          if os.path.exists(p):
            result = p
            found = True
    except IOError:
      pass 
    except OSError:
      pass 
  return result

# found on https://wiki.python.org/moin/PythonDecoratorLibrary#Memoize
class memoize(dict):
    def __init__(self, func):
        self.func = func

    def __call__(self, *args):
        return self[args]

    def __missing__(self, key):
        result = self[key] = self.func(*key)
        return result

def get_qacli_from_user_config(version):
  path = None
  max = None
  for file in (
    os.path.join(
      os.path.expanduser("~"), ".config", "PRQA", "installed_packages"
    ),
    os.path.join(
      os.path.expanduser("~"), ".config", "Perforce", "installed_packages"
    ),
    os.path.join(os.sep, "etc", "prqa.d", "installed_packages"),
    os.path.join(os.sep, "etc", "Perforce.d", "installed_packages")
  ):
    if os.path.exists(file):
      for line in open(file):
        if not isinstance(line, str):
          line = line.decode()
        # Why does this file look like json, but in fact is not?...
        data = json.loads(line.replace("'", '"'))
        if "product" in data:
          if (
             data["product"].endswith("qa-framework") or
             data["product"] == "Helix-QAC"
          ):
            v = data["version"]
            if not max or v > max:
              if not version or (version and v == version):
                max = v
                path = data["location"]
  if path:
    path = os.path.join(path, "common", "lib", "qacli")
  return path

def get_qacli_from_registry(version):
  path = None
  version_found = None
  for hk in winreg.HKEY_CURRENT_USER, winreg.HKEY_LOCAL_MACHINE:
    if not path or not(version_found == version):
      reg = winreg.ConnectRegistry(None, hk)
      max = None
      for product in (
        "Perforce\\Helix-QAC", "PRQA\\prqa-framework", "PRQA\\qa-framework"
      ):
        try:
          key = winreg.OpenKey(reg, "Software\\" + product)
          i = 0
          while True:
            verskey = winreg.EnumKey(key, i)
            if not max or verskey > max:
              if not version or (version and verskey == version):
                max = verskey
                vkey = winreg.OpenKey(key, verskey)
                path = winreg.QueryValueEx(vkey, "Path")[0]
                winreg.CloseKey(vkey)
            i += 1
          winreg.CloseKey(key)
        except WindowsError:
          # Crazy API: the intended way to end the above loop is to overflow i.
          pass
  if path:
    path = os.path.join(path, "common", "lib", "qacli.exe")
  return path

def test_qacli(path):
  version = None
  exit_code = None
  if path:
    try:
      p = subprocess.Popen( [path, "-v"], \
        stdout=subprocess.PIPE, stderr=subprocess.PIPE)
      (stdoutdata, stderrdata) = p.communicate()
      for line in stdoutdata.splitlines():
        if not isinstance(line, str):
          line = line.decode()
        if line.startswith("PRQA Framework"):
          version = "".join(c for c in line if c.isdigit() or c == '.')
          version = version[:version.rfind(".") ]
        if line.startswith("Helix"):
          version = "".join(c for c in line if c.isdigit() or c == '.')
      exit_code = p.wait()
    except OSError as ex:
      exit_code = ex.errno
  return exit_code, version

@memoize
def qacli(version):
  path = "qacli"
  (exitCode, version_found) = test_qacli(path)
  if exitCode != 0 or (version and not(version == version_found)):
    if onWindows():
      path = get_qacli_from_registry(version)
    else:
      path = get_qacli_from_user_config(version)
    (exitCode, version_found) = test_qacli(path)
  return path, version_found

def get_CCT_path(args):
  result = args.outputpath
  if not result:
    result = get_user_CCT_path(args.qacversion)
  return result
 
@memoize
def get_user_CCT_path(version):
  result = None
  path = None
  (qaclip, version) = qacli(version)
  if qaclip:
    p = subprocess.Popen(
      [qaclip, "admin", "--get-user-data-location"],
      stdout=subprocess.PIPE, stderr=subprocess.PIPE
  )
    (stdoutdata, stderrdata) = p.communicate()
    for line in stdoutdata.splitlines():
      if not isinstance(line, str):
        line = line.decode()
      if os.path.exists(line):
        path = line
      elif line.startswith("User Data Location ="):
        path = line[line.find("=") + 1:].strip()
  if path:
    for candidate in (
      "Helix-QAC-", "PRQA-Framework-", "prqa-framework-",
      "QA-Framework-", "qa-framework-"
    ):
      if not result:
        result = os.path.join(path, candidate + version, "config", "cct")
        if not os.path.exists(result):
          result = None
  return result

