#!/usr/bin/env python3

import fnmatch
import os
import re
import ntpath
import sys
import argparse

import ctypes

#from http://stackoverflow.com/a/3429034
#Get required functions, strcpy..
strcpy = ctypes.cdll.msvcrt.strcpy
ocb = ctypes.windll.user32.OpenClipboard    #Basic Clipboard functions
ecb = ctypes.windll.user32.EmptyClipboard
gcd = ctypes.windll.user32.GetClipboardData
scd = ctypes.windll.user32.SetClipboardData
ccb = ctypes.windll.user32.CloseClipboard
ga = ctypes.windll.kernel32.GlobalAlloc    # Global Memory allocation
gl = ctypes.windll.kernel32.GlobalLock     # Global Memory Locking
gul = ctypes.windll.kernel32.GlobalUnlock
GMEM_DDESHARE = 0x2000

def Get( ):
  ocb(None) # Open Clip, Default task
  pcontents = gcd(1) # 1 means CF_TEXT.. too lazy to get the token thingy ...
  data = ctypes.c_char_p(pcontents).value
  #gul(pcontents) ?
  ccb()
  return data

def Paste( data ):
  ocb(None) # Open Clip, Default task
  ecb()
  hCd = ga( GMEM_DDESHARE, len( bytes(data,"ascii") )+1 )
  pchData = gl(hCd)
  strcpy(ctypes.c_char_p(pchData),bytes(data,"ascii"))
  gul(hCd)
  scd(1,hCd)
  ccb()


def getFunctions(filepath):
    selfmodule = (re.search('addons[\W]*([_a-zA-Z0-9]*)', filepath)).group(1)
    # print("Checking {0} from {1}".format(filepath,selfmodule))

    with open(filepath, 'r') as file:
        content = file.read()

        srch = re.compile('[^E]FUNC\(([_a-zA-Z0-9]*)\)')
        modfuncs = srch.findall(content)
        modfuncs = sorted(set(modfuncs))

        srch = re.compile('EFUNC\(([_a-zA-Z0-9]*),([_a-zA-Z0-9]*)\)')
        exfuncs = srch.findall(content)
        exfuncs = sorted(set(exfuncs))

    fileFuncs = []
    for func in modfuncs:
        fileFuncs.append("ace_{0}_fnc_{1}".format(selfmodule,func))

    for exModule,func in exfuncs:
        fileFuncs.append("ace_{0}_fnc_{1}".format(exModule, func))

    return fileFuncs


def getStrings(filepath):
    selfmodule = (re.search('addons[\W]*([_a-zA-Z0-9]*)', filepath)).group(1)
    # print("Checking {0} from {1}".format(filepath,selfmodule))

    with open(filepath, 'r') as file:
        content = file.read()

        srch = re.compile('[^E][CL]STRING\(([_a-zA-Z0-9]*)\)')
        modStrings = srch.findall(content)
        modStrings = sorted(set(modStrings))

        srch = re.compile('E[CL]STRING\(([_a-zA-Z0-9]*),([_a-zA-Z0-9]*)\)')
        exStrings = srch.findall(content)
        exStrings = sorted(set(exStrings))

    fileStrings = []
    for localString in modStrings:
        fileStrings.append("STR_ACE_{0}_{1}".format(selfmodule, localString))

    for (exModule, exString) in exStrings:
        fileStrings.append("STR_ACE_{0}_{1}".format(exModule, exString))

    return fileStrings

def main():

    print("#########################")
    print("# All Functions  #")
    print("#########################")

    sqf_list = []

    allFunctions = []
    allStrings = []

    parser = argparse.ArgumentParser()
    parser.add_argument('-m','--module', help='only search specified module addon folder', required=False, default=".")
    args = parser.parse_args()

    for root, dirnames, filenames in os.walk('../addons' + '/' + args.module):
      for filename in fnmatch.filter(filenames, '*.sqf'):
        sqf_list.append(os.path.join(root, filename))
      for filename in fnmatch.filter(filenames, '*.cpp'):
        sqf_list.append(os.path.join(root, filename))
      for filename in fnmatch.filter(filenames, '*.hpp'):
        sqf_list.append(os.path.join(root, filename))

    for filename in sqf_list:
        allFunctions = allFunctions + getFunctions(filename)
    for filename in sqf_list:
        allStrings = allStrings + getStrings(filename)


    codeHeader = "diag_log text '*********** Scaning for nil functions [funcs {0} / strings {1}]';".format(len(set(allFunctions)), len(set(allStrings)))
    codeFuncCheck = "{ if (isNil _x) then {systemChat format ['%1 is nil', _x]; diag_log text format ['%1 is nil', _x];}} forEach allFunctions;"
    codeStringCheck = "{ if (!isLocalized _x) then {systemChat format ['%1 is not in stringtable', _x]; diag_log text format ['%1 is not in stringtable', _x];}} forEach allStrings;"

    outputCode = "{0} allFunctions = {1}; allStrings = {2}; {3} {4}".format(codeHeader, list(set(allFunctions)), list(set(allStrings)), codeFuncCheck, codeStringCheck)

    print(outputCode)
    Paste(outputCode);

    print ("")
    print ("Copied to clipboard, [funcs {0} / strings {1}]'".format(len(set(allFunctions)), len(set(allStrings))))

if __name__ == "__main__":
    main()