# Copyright (c) Qualcomm Technologies, Inc.
# All Rights Reserved.
# Confidential and Proprietary - Qualcomm Technologies, Inc.

import os
import sys
import SCons

def exists(env):
  return True

def generate(env):
  verbose = int(env.GetOption("verbose"))
  if sys.platform.startswith("linux"):
    platform = "linux"
    ending = ""
  elif sys.platform.startswith("win"):
    platform = "win"
    ending = ".exe"
  bin_path = os.path.dirname(os.path.realpath(__file__))
  marking_path =  os.path.join(bin_path, 'bin')
  bin_path = os.path.join(bin_path, 'bin', platform)

  minkidl_builder = env.Builder(generator = minkidl_generator,
                                src_suffix = '.idl',
                                suffix = '.h',
                                emitter = minkidl_emitter)

  env['MINKIDL']          = '{}/minkidl{}'.format(bin_path,ending)
  env['MINKIDLCOM']       = '$MINKIDL --no-typed-objects --allow-undefined-behavior --marking {}/marking.txt -o $TARGET $SOURCE '.format(marking_path)
  if verbose not in (2, 3):
    env['MINKIDLCOMSTR']    = 'minkidl ${TARGET.basename}.h'

  env.Replace(IDLINCPATH=[])
  env.Append(BUILDERS={'MINKIDL' : minkidl_builder})

  env.AddMethod(run_minkidl,'RunMinkidl')
  ignore_builder = env.Builder(action=ignore_file_builder)
  env.Append(BUILDERS={'IgnoreFileBuilder':ignore_builder})
  if env.StandaloneSdk():
    env.Append(IDLINCPATH='${SDK_ROOT}/inc/idl')
  else:
    env.Append(IDLINCPATH=
               '${BUILD_ROOT}/ssg/securemsm/trustzone/qsee/idl/public')
  try:
    root_env = env['ROOT_GLOBAL_ENV']
    if not root_env.get('MINKIDL_HAS_RUN'):
      env.RunMinkidl()
      root_env['MINKIDL_HAS_RUN'] = True
  except:
    env.RunMinkidl()


def ignore_file_builder(env,target,source):
  with open(str(target[0]),'w+') as f:
    f.write('*.o\n')
    f.write('*.lib\n')
    f.write('*~\n')
    f.write('*.pp\n')
    f.write('*.pyc\n')
    f.write('*.elf\n')
    f.write('*.map\n')
    f.write('*.scl\n')
    f.write('*.mbn\n')
    f.write('*.so\n')
    f.write('*.elf\n')
    f.write('*.pbn\n')
    f.write('*.hash\n')
    f.write('*.dat\n')
    f.write('*.enc\n')
    f.write('*.bin\n')
    f.write('*.efi\n')
    f.write('*.log\n')
    f.write('*.fv\n')
    f.write('*.obj\n')
    f.write('*.tempsym\n')
    f.write('*.i\n')
    f.write('*.scl\n')
    f.write('*.tempscl\n')
    f.write('scorpion/\n')
    f.write('A53_64/\n')
    f.write(env.subst('${BUILD_ID}/') + '\n')
    for idl in sorted(source, key=lambda x: x.get_abspath()):
      rel_path = str(idl).split('trustzone_images')[1]
      if rel_path.startswith('/ssg'):
        rel_path = rel_path.replace('/ssg/','')
        f.write(rel_path + '\n')


def minkidl_generator(env, target, source, for_signature):
  verbose = int(env.GetOption("verbose"))
  cmds = []
  for t in target:
    cmd = env.subst('$MINKIDLCOM ', target=t, source=source[0])
    incpaths = env.get('IDLINCPATH')
    if incpaths:
      incpaths = [env.RealPath(x) for x in env.Flatten(incpaths)]
      incpathstr = ' -I ' + ' -I '.join(incpaths)
      cmd += incpathstr
    if str(t).endswith('_invoke.h'):
      cmd += ' --skel '
    if str(t).endswith('_invoke.hpp'):
      cmd += ' --skel '
    if str(t).endswith('.hpp'):
      cmd += ' --cpp '
    comstr = 'minkidl ' + str(t)
    if verbose in (2, 3):
        comstr = cmd
    cmds.append(env.Action(cmd, comstr))
  return cmds

def minkidl_emitter(env, target, source):
    base, ext = os.path.splitext(str(target[0]))
    incl = base + '.h'
    t = [incl]
    incl = base + '.hpp'
    t.append(incl)
    if os.path.basename(str(source[0])).startswith('I'):
      skeleton = base + '_invoke.h'
      t.append(skeleton)
      skeleton = base + '_invoke.hpp'
      t.append(skeleton)
    env.Alias('minkidl_headers',t)
    return (t,source)

def run_minkidl(env,paths=None):
  if paths is None:
    paths = list()
  all_idls = list()

  paths += ['$BUILD_ROOT']
  skips = ['${BUILD_ROOT}/build']

  if not env.StandaloneSdk():
    env = env.Clone()
    env.Tool('deploy_sdk', toolpath=['$BUILD_ROOT/ssg/bsp/build/scripts'])
    # idl files that live under
    # ssg/securemsm/trustzone/qsee/idl/(public/private) are
    # special cases so we skip them
    skips.append(os.path.join('ssg','securemsm','trustzone','qsee','idl'))
  else:
    paths += ['${SDK_ROOT}/inc/idl', '${SDK_ROOT}/samples']

    # Because we do not make TA developers specify what IDL files they
    # depend on and where those IDL files should be compiled out to, we
    # must tell scons how to build all IDL files that TAs may
    # potentially depend on.  This is a headache for a couple reasons:
    # 1) Different construction environments may want to build IDL files
    # with different versions of the IDL compiler.  2) When in the TA SI
    # build system, the BUILD_ROOT folder may have multiple SDK versions
    # underneath it.  So, we will have special behavior for when we are
    # in the TA SI build system to avoid compiling every SDK version's
    # IDL files.
    skips.append('${BUILD_ROOT}/sdk')

  # some binary test app files are version-controlled with specific header
  # versions that should not be regenerated automatically
  skips.append('${BUILD_ROOT}/ssg/securemsm/trustzone/qsapps/bintestapp_501')

  if env.get("QCBUILDDEBUG"):
    print("(idlcompiler.py) Compiling IDL files recursively from here:")
    for p in paths:
      print(("                 " + format(env.RealPath(p))))
    print(("(idlcompiler.py) Skipping any path found during recursion " +
          "ending with:"))
    for s in skips:
      print(("                 " + format(env.RealPath(s))))

  for p in paths:
    for dir, subdirs, files in os.walk(env.RealPath(p), topdown=True):
      for skip in skips:
        for subdir in subdirs:
          if (os.path.abspath(os.path.join(dir, subdir)) ==
              os.path.abspath(env.subst(skip))):
            subdirs.remove(subdir)
      for file in files:
        if file.endswith('.idl'):
          if env.StandaloneSdk() and SCons.Script.ARGUMENTS.get('sdk_version') and SCons.Script.ARGUMENTS.get('sdk_version') not in ["TZ.XF.5.0", "latest"] and p != '${SDK_ROOT}/samples':
            # TODO: To check which service files are not compiled which are present in env['MINKIDL'].
            # remove ".idl" from back, ("C" or "I") from start of "file"
            search_file=file[1:-4]
            if ('C'+search_file+'_UID') in env['MINKIDL']:
              all_idls.extend(env.MINKIDL(os.path.join(dir,file)))
          else:
            all_idls.extend(env.MINKIDL(os.path.join(dir,file)))



  # Here is the special case handling for IDL files under
  # ssg/securemsm/trustzone/qsee/idl/(public|private).  We want the
  # output for these IDLs should go to
  # ssg/securemsm/trustzone/qsee/include.  This behavior is specific
  # to internal QC builds.
  if not env.StandaloneSdk():
    qsee_path = '${BUILD_ROOT}/ssg/securemsm/trustzone/qsee'
    target_dir = os.path.join(qsee_path, 'include')

    idl_files  = env.Glob(qsee_path + '/idl/public/*.idl')
    for idl_file in idl_files:
      idltoh = os.path.basename(os.path.splitext(str(idl_file))[0] + '.h')
      target = os.path.join(target_dir, idltoh)
      all_idls.extend(env.MINKIDL(target=target, source=idl_file))

    idl_files = env.Glob(qsee_path + '/idl/private/*.idl')
    for idl_file in idl_files:
      idltoh = os.path.basename(os.path.splitext(str(idl_file))[0] + '.h')
      target = os.path.join(target_dir, idltoh)
      all_idls.extend(env.MINKIDL(target=target, source=idl_file))

  all_idls = list(set(all_idls))
  env.Alias("idlcomplete", all_idls)

  if not env.StandaloneSdk():
    ret = env.IgnoreFileBuilder(target='$BUILD_ROOT/ssg/.p4ignore',
                                source=all_idls)
    env.Alias('P4IgnoreFile',ret)
