#!/usr/bin/env python3

import os
import argparse
import re
import shutil
import subprocess
import copy
import macBundleCreation as mbc

parser = argparse.ArgumentParser()

# Set apart a dictionary that we will need throughout all work, to store the
# various directories needed.
dirDic = {};

# Start by documenting the current directory if we are actually 
# at the right place, that is the binary top directory.
workingDir = os.getcwd()
print("working directory:" + workingDir + "\n");

if not os.path.exists("CMakeCache.txt"):
    print('''No CMakeCache.txt file found. Please change directory to the
    CMAKE_BINARY_DIRECTORY''')
    exit(1);

dirDic["workingDir"] = workingDir

configFilePath = workingDir + "/../../development/CMakeLists.txt"
print("configFilePath: " + configFilePath)
if not os.path.exists(configFilePath):
    print('''No source CMakeLists.txt file found. Please change directory to the
    CMAKE_BINARY_DIRECTORY''')
    exit(1);

dirDic["configFilePath"] = configFilePath

version = mbc.getProgramVersionFromCMakeLists(dirDic)
print("Program version: " + version)

# The bundle is in src/ and is named
# src/XtpCpp.app

bundleDirRelPath = "src/XtpCpp.app"

# Immediately set the development directory, that will be needed later.

devDirName = "/Users/rusconi/devel/xtpcpp/development";
dirDic["devDirName"] = devDirName;

# We need to craft the name of the program that we'll have to copy in the
# bundleDir/Contents/MacOS directory.

if not os.path.isabs(bundleDirRelPath):
    bundleDirAbsPathName = workingDir + "/" + bundleDirRelPath;

    if not os.path.exists(bundleDirAbsPathName):
        print('''Failed to craft an absolute path name for bundle directory.
        Exiting\n''');

        exit(1);

    bundleDir = os.path.basename(bundleDirAbsPathName);

else:
    bundleDirAbsPathName = bundleDirRelPath;
    bundleDir = os.path.basename(bundleDirAbsPathName);

dirDic["bundleDirAbsPathName"] = bundleDirAbsPathName;
dirDic["bundleDirRelPath"] = bundleDirRelPath;
dirDic["bundleDir"] = bundleDir;

print("bundleDirAbsPathName: " + bundleDirAbsPathName + "\n");
print("bundleDir: " + bundleDir + "\n");

pluginsSubDirList = [ "iconengines", "imageformats", "platforms", "platformthemes",
    "sqldrivers", "styles" ]

dirDic["pluginsSubDirList"] = pluginsSubDirList

dirDic["pluginsFileList"] = []

# Craft all the subdirectories in the bundle directory.
# The dictionary will be filled-in with the various directory
# names and paths.
mbc.createBundleSubDirs(dirDic);

# Craft the filename of the program that needs to be located in the
# Contents/MacOS directory. The program binary image is copied there by the
# CMake build system.

programName = os.path.basename(bundleDir);
programName = re.sub('\.app$', '', programName);
dirDic["programName"] = programName;
print("The program name is: " + dirDic["programName"] + "\n");

programPath = dirDic["macosDir"] + "/" + dirDic["programName"];
dirDic["programPath"] = programPath;

if not os.path.exists(dirDic["programPath"]):
    print("Failed to find the binary " + dirDic["programName"] + "in the " +
            dirDic["macosDir"] + " directory.\n"
            "Please, rerun the build system to craft the bundle file system.");

    print("The program path is: " + dirDic["programPath"] + "\n");

# Create the qt.conf file that will tell Qt where to find the 
# various resources, in the bundle file system.
print("Creating the qt.conf file in " + dirDic["resourcesDir"] + "\n");
qtConfFileContents = "[Paths]\nPlugins = Plugins\n";
with open(dirDic["resourcesDir"] + "/qt.conf", "w") as f:
    f.write(qtConfFileContents)

# There is the platforms library dependency that does not show up 
# when making the "otool -L" invocation. So we need to copy that library in the
# frameworksDir and also add it to the deps list.

shutil.copy2("/opt/local/libexec/qt5/plugins/platforms/libqcocoa.dylib",
        dirDic["platformsDir"]);


####################### Library dependencies ######################
###################################################################

# Now recursively check for the dependency libraries starting from the program, 
# and recursively go down all the libraries to check their own dependencies
# (QtScript will depend on QtCore, # for example).

fullLibDepList = [ ]

# Initialize the process with the program binary itself and then all platforms library.
libDeps = [ dirDic["programPath"],
        "/opt/local/libexec/qt5/plugins/platforms/libqcocoa.dylib" ];

while len(libDeps):
    for object in libDeps:

        print("Checking the dependencies of object: " + object);

        # Get a list of the dependencies of the current object
        # (be that object the program itself or a lib dependency).
        newLibDepList = mbc.nonSystemDepLibs(object);

        # print("This round dependencies (for " + object + ":\n" +
        #         "\n".join(newLibDepList) + "\n")

        for iterLib in newLibDepList:
            # If that library was not already found, then append it to the list
            # of the final list of dependencies. Also, make sure it will be
            # processed in turn by appending it to the libDeps list being
            # processed.
            if not iterLib in fullLibDepList:
                fullLibDepList.append(iterLib);
                libDeps.append(iterLib);

        # Now that we have iterated into all the lib deps of object, we can
        # remove the object from the libDeps.
        libDeps.remove(object);

print("Now copy all these dependencies to the bundle:\n" +
        "\n".join(fullLibDepList) + "\n");

mbc.copyLibsToBundle(fullLibDepList, dirDic["frameworksDir"], True);

libList = os.listdir(dirDic["frameworksDir"]);

print("Final list of dependency libraries actually in the Frameworks directory:\n" +
        "\n".join(libList) + "\n\n");

# Now that we have all the dependency libraries, we can iterate in each one and
# make sure we change the "install_name_tool -i" such that the binary program
# can find them all.
for lib in libList:
    mbc.doInstallNameDashI(dirDic["frameworksDir"] + "/" + lib);

# At this point we need to do the "install_name_tool -change" stuff.
for lib in libList:
    mbc.doInstallNameDashChange(dirDic["frameworksDir"] + "/" + lib);

for plugin_lib in dirDic["pluginsFileList"]:
    mbc.doInstallNameDashI(plugin_lib);

# At this point we need to do the "install_name_tool -change" stuff.
for plugin_lib in dirDic["pluginsFileList"]:
    mbc.doInstallNameDashChange(plugin_lib);



# Finally we have to run the change function for the program itself.
mbc.doInstallNameDashChange(dirDic["macosDir"] + "/" + dirDic["programName"]);

print("Finished generic processing " + dirDic["programName"] + "\n");

print("Now starting the specific processing for " + dirDic["programName"] + "\n");

input("Done working on " + dirDic["bundleDir"] + " Continue with documentation? (Return | Ctrl-C)\n");

# Now copy the user manual and license file to the proper bundle directory.

mbc.doProgramSpecific(dirDic);

# Finally, copy the app bundle to the Desktop
mbc.moveBundleToDesktop(dirDic);



answer = input('''Backup all the libraries ? (yY | nN)\n''');

if answer == 'y' or answer == 'Y':
    scriptPath = os.path.dirname(os.path.abspath( __file__ ));
    scriptPath += "/backupLibs.py";

    completedProcess = subprocess.run(["sudo", scriptPath, 
        "--backup", " ".join(fullLibDepList)], stdout=subprocess.PIPE)

    completedProcess.check_returncode();

    output = completedProcess.stdout.decode("utf-8");
    print(output);

# At this point we can prepare the library-renaming script.
mbc.renameLibraries(fullLibDepList, dirDic);

# At this point we can prepare the library-reinstating script.
mbc.reinstateLibraries(fullLibDepList, dirDic);


