import os
import argparse
from shell_runner import ShellRunner
import time
import string
parser=argparse.ArgumentParser()

parser.add_argument('-w','--work_dir', help='Working directory', required=True)
parser.add_argument('-d','--dmg', help='Working directory', required=True)
parser.add_argument('-p','--python', help='Python version. For example 3.8', required=False)

args=parser.parse_args()
work_dir = args.work_dir
in_dmg = args.dmg
print("Working directory: " + work_dir)
print("Dmg: " + in_dmg)
dmg = in_dmg.split("/")[-1]
print("Filename: " + dmg)

username = os.environ['ALTOOL_USER']
password = os.environ['ALTOOL_PASSWORD']
sig = os.environ['SIGN_SIG']

mydir = os.path.dirname(os.path.realpath(__file__))
ent = mydir + "/ent.plist"
print("ent.plist: " + ent)

python_version = "3.6"
if args.python is not None:
    python_version = args.python

shell = ShellRunner()

# This is a loosey-goosey check. Do not attempt to re-use as is.
# References:
# https://stackoverflow.com/questions/1446549/how-to-identify-binary-and-text-files-using-python
# http://code.activestate.com/recipes/173220/
def istext(filename):
    try:
        s=open(filename).read(512)
        text_characters = "".join(map(chr, range(32, 127))) + "\n\r\t\b"
        if not s:
            # Empty files are considered text
            return True
        if "\0" in s:
            # Files with null bytes are likely binary
            return False
        # Get the non-text characters (maps a character to itself then
        # use the 'remove' option to get rid of the text characters.)
        t = s.translate(str.maketrans("", "",text_characters))
        # If more than 30% non-text characters, then
        # this is considered a binary file
        if float(len(t))/float(len(s)) > 0.30:
            return False
        return True
    # Ignore broken symlinks
    except FileNotFoundError:
        print("FileNotFoundError" + filename)
        raise FileNotFoundError
    # Treat as binary if UnicodeDecode fails
    except UnicodeDecodeError:
        print("UnicodeDecodeError: " + filename )
        return False


def copy_app():

    print("Attaching " + in_dmg)
    cmd = ("hdiutil attach " + in_dmg).split()
    shell.runshell(cmd, work_dir)

    print("Copying /Volumes/" + dmg + " to " + work_dir)
    cmd = ("cp -pR /Volumes/" + dmg + "/CASA.app" + " " + work_dir + "/").split()
    shell.runshell(cmd, work_dir)

    print("Detaching volume /Volumes/" + dmg )
    cmd = ("hdiutil detach /Volumes/" + dmg).split()
    shell.runshell(cmd, work_dir)

def sign_app():
    print("Sign binaries")
    binaries = []
    for root, dirs, files in os.walk(work_dir + "/CASA.app"):
        for file in files:
            print("root " + root)
            print("dirs " + str(dirs))
            print("file " + file)
            file_with_path=os.path.join(root, file)
            print("file " + file_with_path)
            if not ("casa-data" in file_with_path \
                    or "casadata" in file_with_path
                    or "CASA.app/Contents/Resources/" in file_with_path\
                    or file.endswith(".pyc") \
                    or file.endswith(".txt")) \
                    and (file.startswith("protoc") \
                    or file.startswith("grpc")\
                    or file.endswith(".dylib") \
                    or file.endswith(".so") \
                    or file.endswith(".app")\
                    or not istext(file_with_path)):
                print(file_with_path)
                binaries.append(file_with_path)
    for f in binaries:
        cmd = ("codesign --timestamp --options=runtime -f --signature-size 10240 --entitlements " + ent +
           " -s " + sig + " " + f)
        print("cmd")
        shell.runshell(cmd.split(), work_dir + "/CASA.app")

    print("Sign casaviewer executable")
    cmd = ("codesign --timestamp --options=runtime -f --signature-size 10240  --entitlements " + ent +
           " -s " + sig + " Contents/Frameworks/Python.framework/Versions/" + python_version + "/lib/python" + python_version + "/site-packages/casaviewer/__bin__/casaviewer.app/Contents/MacOS/casaviewer")
    print("Signing casaviewer ")
    print("cmd")
    shell.runshell(cmd.split(), work_dir + "/CASA.app")
    

    print("Sign casaplotms")
    cmd = ("codesign --timestamp --options=runtime -f --signature-size 10240 --entitlements " + ent +
        " -s " + sig + " Contents/Frameworks/Python.framework/Versions/" + python_version + "/lib/python" + python_version + "/site-packages/casaplotms/__bin__/casaplotms.app/Contents/MacOS/casaplotms")
    print("Signing casaplotms ")
    print("cmd")
    shell.runshell(cmd.split(), work_dir + "/CASA.app")

    print("Sign casaplotserver")
    cmd = ("codesign --timestamp --options=runtime -f --signature-size 10240 --entitlements " + ent +
           " -s " + sig + " Contents/Frameworks/Python.framework/Versions/" + python_version + "/lib/python" + python_version + "/site-packages/casaplotserver/__bin__/casaplotserver.app/Contents/MacOS/casaplotserver")
    print("Signing casaplotserver ")
    print("cmd")
    shell.runshell(cmd.split(), work_dir + "/CASA.app")

    print("Sign applet")
    cmd = ("codesign --timestamp --options=runtime -f --signature-size 10240 --entitlements " + ent +
           " -s " + sig + " Contents/MacOS/applet")
    print("Signing applet ")
    print("cmd")
    shell.runshell(cmd.split(), work_dir + "/CASA.app")

    print("Sign breakpad")
    cmd = ("codesign --timestamp --options=runtime -f --signature-size 10240 --entitlements " + ent +
           " -s " + sig + " Contents/Frameworks/Breakpad.framework/Versions/A/Breakpad")
    print("Signing breakpad")
    print("cmd")
    shell.runshell(cmd.split(), work_dir + "/CASA.app")

    print("Sign python")
    cmd = ("codesign --timestamp --options=runtime -f --signature-size 10240 --entitlements " + ent +
           " -s " + sig + " Contents/Frameworks/Python.framework/Versions/" + python_version + "/Python")
    print("Signing python")
    print("cmd")
    shell.runshell(cmd.split(), work_dir + "/CASA.app")

    print("Sign CASA.app (again)")
    cmd = ("codesign --timestamp --options=runtime -f --signature-size 10240 --entitlements " + ent +
           " -s " + sig + " CASA.app")
    print("cmd")
    shell.runshell(cmd.split(), work_dir)

def zip_app():
    print("Create zip")
    cmd = ("ditto -ck --sequesterRsrc --keepParent CASA.app CASA.zip")
    shell.runshell(cmd.split(), work_dir)

def init_shell_state():
    class State:
        uuid = ""
        request_status=""
    shell.state = State()

def process_submit_output(x):
    message = x.decode('utf-8').rstrip("\n\r")
    print("%s" % message)
    data = []
    if "RequestUUID" in message:
        uuid = message.split()
        print("Found request uuid: " + message.split(" = ")[1].strip())
        shell.state.uuid = message.split(" = ")[1].strip()
    return data

def process_status(x):
    message = x.decode('utf-8').rstrip("\n\r")
    print(">>>>%s" % message)
    data = []
    if "Status:" in message:
        status = message.split(": ")[1].strip()
        print("Found status: " + status)
        shell.state.request_status = status
    return data


def submit_app():
    print("Submit app")
    print(work_dir)
    cmd = ('xcrun altool --notarize-app --primary-bundle-id edu.nrao.casa -u ' + username+' -p ' + password + ' --file CASA.zip')
    shell.runshell(cmd.split(), work_dir, False,process_stdout=process_submit_output)

def sim_submit_app():
    print("Submit app")
    print(work_dir)
    cmd = (os.path.dirname(os.path.realpath(__file__))+"/notarization_simulator.sh")
    shell.runshell(cmd.split(), work_dir, True,process_stderr=process_submit_stderr)

def read_results():
    print("Waiting for results")
    print(work_dir)
    cmd = ("xcrun altool --notarization-info " + shell.state.uuid + " -u " + username + " -p " + password)
    shell.runshell(cmd.split(), work_dir, False, process_stdout=process_status)

def staple():
    print("Stapling")
    print(work_dir)
    cmd = ("xcrun stapler staple CASA.app")
    shell.runshell(cmd.split(), work_dir, False)

def create_dmg():
    print("Creating .dmg")
    print(work_dir)
    cmd = (mydir+"/make-dmg " + work_dir +"/CASA.app " + dmg)
    shell.runshell(cmd.split(), work_dir, False)



copy_app()
sign_app()
zip_app()
init_shell_state()
submit_app()
#sim_submit_app()
print("uuid: " + str(shell.state.uuid))
time.sleep(300)
read_results()
print(">>" + shell.state.request_status)
while (shell.state.request_status =="in progress"):
    time.sleep(300)
    read_results()
    print(shell.state.request_status)

status =  shell.state.request_status
print("Final status: " + shell.state.request_status)
if status == "success":
    staple()
    create_dmg()
    exit(0)
else:
    exit(1)