#!/usr/bin/ardipython

import argparse
import platform
import shutil
import sys
#import pycurl
import os
import requests
from subprocess import call
#from StringIO import StringIO
import traceback
import xmltodict

def SetNSSM(nssmpath,drivername,property,value):
    cmd = "\"" + nssmpath + "\" set \"" + drivername + "\" " + property + " " + value
    call(cmd, shell=True)
    #print cmd

def WindowsInstaller(driver,mode,portno,url):
    print("Installing Driver for Windows...")

    #Get Python Location
    pathtopython = "c:\\python38\\python.exe"
    try:
        pathtopython = os.getenv('ARDIPythonPath')        
    except:
        pass

    #Get Logging Path
    loggingpath = "c:\\windows\\temp"
    try:
        loggingpath = os.getenv('ARDILogPath')        
    except:
        pass

    if loggingpath is None:
        loggingpath = "c:\\windows\\temp"
    
    is64 = False
    if platform.machine().endswith('64'):
        is64 = True

    basepath = os.path.dirname(os.path.realpath(__file__))
    nssmpath = basepath
    if is64:
        nssmpath = nssmpath + "\\nssm\\win64"
    else:
        nssmpath = nssmpath + "\\nssm\\win32"

    nssmpath = nssmpath + "/nssm.exe"    
    print("Creating NSS Service...")

    exedriver = False
    exepath = basepath + "\\" + mode + "\\" + driver + "\\" + driver + ".exe"
    if os.path.isfile(exepath):
        exedriver = True
        print("Detected Windows-Based Executable Driver @ " + exepath)

    drivername = "ARDI " + driver.upper() + " Driver (" + str(port) + ")"

    #Installing the base service...
    if exedriver == True:
        cmd = "\"" + nssmpath + "\" install \"" + drivername + "\" \"" + exepath + "\" " + str(portno) + " " + url
    else:
        cmd = "\"" + nssmpath + "\" install \"" + drivername + "\" \"" + pathtopython + "\" \"\"\"" + basepath + "\\" + mode + "\\" + driver + "\\" + driver + ".py " + "\"\"\" " + str(portno) + " " + url
    call(cmd, shell=True)
    #print "Running - " + cmd    

    #Redirection of I/O...
    SetNSSM(nssmpath,drivername,"AppStderr",loggingpath + "\\ardi-" + driver + "-" + str(port) + "_error.log")
    SetNSSM(nssmpath,drivername,"AppStderrCreationDisposition","2")
    SetNSSM(nssmpath,drivername,"AppStdout",loggingpath + "\\ardi-" + driver + "-" + str(port) + "_nssm.log")
    SetNSSM(nssmpath,drivername,"AppStdoutCreationDisposition","2")    
    SetNSSM(nssmpath,drivername,"AppRotateFiles","1")
    SetNSSM(nssmpath,drivername,"AppRotateBytes","1048576")
    SetNSSM(nssmpath,drivername,"AppDirectory",basepath + "\\" + mode + "\\" + driver)

    #Prevent Windows Event-Style Terminations (Useless on Python apps)
    SetNSSM(nssmpath,drivername,"AppStopMethodSkip","6")

    activepath = os.path.dirname(os.path.abspath(__file__)) + "\\nssm.conf"
    if os.path.exists(activepath):
        print("Found additional NSSM service config details at " + activepath)
        with open(activepath) as f:
            lines = f.readlines()
            for l in lines:
                l = l.strip()
                ps = l.find(' ')
                a = l[0:ps]
                b = l[ps+1:]

                SetNSSM(nssmpath,drivername,a,b)
                
    activepath = os.path.dirname(os.path.abspath(__file__)) + "\\nssm" + str(portno) + ".conf"
    if os.path.exists(activepath):
        print("Found additional NSSM service config details at " + activepath)
        with open(activepath) as f:
            lines = f.readlines()
            for l in lines:
                l = l.strip()
                ps = l.find(' ')
                a = l[0:ps]
                b = l[ps+1:]

                SetNSSM(nssmpath,drivername,a,b)
    
    print("Starting NSS Service...")
    
    cmd = "\"" + nssmpath + "\" start \"" + drivername + "\""
    call(cmd, shell=True)
    #print "Running - " + cmd    
    
def LinuxInstaller(driver,mode, portno, url):
    
    print("Installing Driver for Linux...")
    
    basepath = os.path.dirname(os.path.realpath(__file__))
    lxpath = basepath + "/linux"
    
    dtype = "live"
    if (mode == "hist"):
        dtype = "hist"

    finalpath = "/etc/systemd/system/ardi-" + str(portno)+".service"
    logpath = "/var/log/ardi/driver-" + str(portno) + ".log"
    driverpath = os.path.dirname(os.path.abspath(__file__)) + "/" + dtype + "/" + driver + "/" + driver + ".py"

    #Get Python Location
    try:
        pathtopython = os.getenv('ARDIPythonPath')
    except:
        pass
    if pathtopython is None:
        pathtopython = "python3"    
    
    print("Creating Daemon Script...")
    file = open(lxpath + '/systemd.service','r')
    fl = file.read()
    file.close()
    st = str(fl)
    st = st.replace("$DRIVER$",driver)
    st = st.replace("$DRIVERTYPE$",dtype)
    st = st.replace("$PORT$",str(portno))
    st = st.replace("$SERVER$",url)    
    st = st.replace("$SERVICENAME$","ardi-" + str(portno))
    st = st.replace("$FULLPATH$",finalpath)
    st = st.replace("$DRIVERPATH$",driverpath)
    st = st.replace("$LOGPATH$",logpath)
    st = st.replace("$PYTHON$",pathtopython)
    #finalpath = basepath + "/" + mode + "/" + driver + "/" + str(portno)    
    file = open(finalpath,'w')
    file.write(st)
    file.flush()
    file.close()    
    #print("Marking File as Executable...")
    #call("chmod gu+x " + finalpath, shell=True)
    
    #finalpath = finalpath + " " + str(portno)
    
    call("chmod gu+r " + finalpath,shell=True)
        
    cmd = "systemctl daemon-reload"
    call(cmd, shell=True)
    
    print("Creating Log Files...")
    
    call("touch " + logpath, shell=True)    
    call("chmod a+r " + logpath, shell=True)
        
    print("Starting Service...")

    call("systemctl start ardi-" + str(portno) , shell=True)
    call("systemctl enable ardi-" + str(portno) , shell=True)
    
def GetDriverDetails(remotehost,portno):    
    try:
        #buf = StringIO()
        
        url = 'http://' + remotehost + '/api/driverdetails?driver=' + str(portno)
        
        web = requests.get(url,timeout=5)
        s = web.text

        result = xmltodict.parse(s)

        #print result
        try:
            print("Driver Name: " + result['driverinfo']['name'])
            print("Driver Type: " + result['driverinfo']['driver'])
            print("Driver Mode: " + result['driverinfo']['mode'])

            if (result['driverinfo']['mode'] == 'Live'):
                s = 'L'
            else:
                if (result['driverinfo']['mode'] == 'Event'):
                    s = 'E'
                else:
                    s = 'H'
            s = s + result['driverinfo']['driver']
        except:
            return ""
                            
        return s
    except:
        return ""

parser = argparse.ArgumentParser(description="Manage ARDI Drivers")
parser.add_argument('port', help='The driver ID from the ARDI web page')
parser.add_argument('server', help='The URL of the ARDI site')
parser.add_argument('--ifdriver',help='Only perform the action if the driver is of the matching type')
    
args = parser.parse_args()
    
#Override
remotehost="localhost"
if args.server != None:
    remotehost = args.server

server = remotehost

ifdriver = ""
if args.ifdriver is not None:
    ifdriver = args.ifdriver

is_admin = False

import ctypes, os
try:
    is_admin = os.geteuid() == 0
except AttributeError:
    is_admin = ctypes.windll.shell32.IsUserAnAdmin() != 0
    
  
if is_admin == False:
    print("Error: This must be run as root/an Administrator")
    sys.exit(0)        

#Install driver as a service...
port = int(args.port)
driver = GetDriverDetails(remotehost,port)

if driver == "":
    print("Driver Not Found On Specified ARDI Instance")
    sys.exit()

mode = "live"
if (driver[0] == 'H'):
    mode = "hist"
if (driver[0] == 'E'):
    mode = "event"

driver = driver[1:]

if ifdriver != "":
    if driver != ifdriver:
        print("Driver does not match given filter")
        sys.exit(0)

print("Installing " + driver + " Driver Service")

if platform.system() == "Windows":
    WindowsInstaller(driver,mode,port,server)
    pass
else:
    LinuxInstaller(driver,mode,port,server)
    pass

#Install SupervisorD script (for Containerised Linux versions)
try:
    sitename = "default"
    n = server.rfind('/')
    if n > 0:
        sitename = server[n+1:]

    basepath = os.path.dirname(os.path.abspath(__file__)) + "\\"
    if basepath == "\\":
        basepath = ""

    svpath = "/opt/ardi/supervisor.d/driver_" + sitename + "_" + str(port) + ".conf"
    if platform.system() == "Windows":
        svpath = os.path.abspath(basepath + "supervisor.d\\driver_" + sitename + "_" + str(port) + ".conf")

    print("Saving Supervisor File @ " + svpath)
        
    cmd = "[program:driver_" + str(port) + "]\n";
    cmd += "command=python3 /opt/ardi/drivers/"
    if mode == 0:
        cmd += "live/"
    else:
        cmd += "hist/"
    cmd += driver + "/" + driver + ".py " + str(port) + " " + server + "\n"
    cmd += "priority=20\n"
    cmd += "autostart=true\n"
    cmd += "startsecs=10\n"
    cmd += "autorestart=true\n"
    cmd += "redirect_stderr=true\n"

    file = open(svpath, "w")
    file.write(cmd)
    file.close()    
except:
    pass

print("ARDI Driver Service Added!")
