""" NetworkMonitor.py

Monitors the network connection to a test server """

# Append path
import sys
sys.path.append("./src")

# Imports
import argparse
import KeyboardThread
import PingThread
import platform
import re
import RollingLogFile
import ScpThread
import signal
import subprocess
import threading
import time
import TracerouteThread

PLATFORM_LINUX = "Linux"
PLATFORM_MACOS = "Darwin"
PLATFORM_WINDOWS = "Windows"

# Global variables
connectionMonitor = None

class ConnectionMonitor():
    def __init__(self):
        """Constructor"""
        # Initialize variables
        self.exitFlag = False
        self.variableLock = threading.Lock()
        self.logFile = RollingLogFile.RollingLogFile("monitor", "a")
        self.pingOutputFile = RollingLogFile.RollingLogFile("ping", "a")
        self.tracerouteOutputFile = RollingLogFile.RollingLogFile("traceroute", "a")
        self.scpOutputFile = RollingLogFile.RollingLogFile("scp", "a")
        
        # Detect OS
        self.platform = platform.uname()[0]
        if (self.platform != PLATFORM_LINUX) and (self.platform != PLATFORM_MACOS) and (self.platform != PLATFORM_WINDOWS):
            raise Exception("Platform type not recognized: " + self.platform)

    def Run(self, args):
        """Main connection monitor function"""
        # Kick off threads
        self.logFile.Write("Connection monitor starting")
        print("Starting connection monitor, press 'q' exit")
        exit = False
        keyboardThread = KeyboardThread.KeyboardThread(self.platform, self.logFile)
        keyboardThread.start()
        pingThread = None
        if args.ping:
            pingThread = PingThread.PingThread(self.platform, args.target, args.ping_interval, self.logFile, self.pingOutputFile)
            pingThread.start()
        scpThread = None
        if args.scp:
            scpThread = ScpThread.ScpThread(self.platform, args.target, args.scp_interval, args.scp_payload, args.scp_options, self.logFile, self.scpOutputFile)
            scpThread.start()
        tracerouteThread = None
        if args.traceroute:
            tracerouteThread = TracerouteThread.TracerouteThread(self.platform, args.target, args.traceroute_interval, self.logFile, self.tracerouteOutputFile)
            tracerouteThread.start()
        
        # Run loop
        while not exit:
            if keyboardThread.CheckForExitKeyPressed():
                self.logFile.Write("Connection monitor detected exit request")
                exit = True
            if keyboardThread.CheckForError() != "":
                self.logFile.Write("Connection monitor detected error in keyboard thread: " + keyboardThread.CheckForError())
                exit = True
            if (pingThread is not None) and (pingThread.CheckForError() != ""):
                self.logFile.Write("Connection monitor detected error in ping thread: " + pingThread.CheckForError())
                exit = True
            if (scpThread is not None) and (scpThread.CheckForError() != ""):
                self.logFile.Write("Connection monitor detected error in SCP thread: " + scpThread.CheckForError())
                exit = True
            if (tracerouteThread is not None) and (tracerouteThread.CheckForError() != ""):
                self.logFile.Write("Connection monitor detected error in traceroute thread: " + tracerouteThread.CheckForError())
                exit = True
            if not exit:
                time.sleep(1.0)
        
        # Wait for threads to complete
        if pingThread is not None:
            pingThread.SignalExit()
        if scpThread is not None:
            scpThread.SignalExit()
        if tracerouteThread is not None:
            tracerouteThread.SignalExit()
        if pingThread is not None:
            pingThread.join()
        if scpThread is not None:
            scpThread.join()
        if tracerouteThread is not None:
            tracerouteThread.join()
        self.logFile.Write("Connection monitor exiting")

# Main function
if __name__ == "__main__":
    # Parse the command-line arguments
    parser = argparse.ArgumentParser(description='Profile network connectivity to a remote server')
    parser.add_argument("-t", "--target",
        required=True,
        type=str,
        help="name of the target server")
    parser.add_argument("-p", "--ping",
        required=False,
        default=1,
        type=int,
        choices=[0, 1],
        help="enable ping (default 1)")
    parser.add_argument("-P", "--ping_interval",
        required=False,
        default=15,
        type=int,
        help="ping interval in seconds (default 15)")
    parser.add_argument("-r", "--traceroute",
        required=False,
        default=1,
        type=int,
        choices=[0, 1],
        help="enable traceroute (default 1)")
    parser.add_argument("-R", "--traceroute_interval",
        required=False,
        default=300,
        type=int,
        help="traceroute interval in seconds (default 300)")
    parser.add_argument("-s", "--scp",
        required=False,
        default=0,
        type=int,
        choices=[0, 1],
        help="enable scp (default 0)")
    parser.add_argument("-S", "--scp_interval",
        required=False, 
        default=180,
        type=int,
        help="scp interval in seconds (default 180)")
    parser.add_argument("-d", "--scp_payload",
        required=False,
        default="payload.dat",
        type=str,
        help="name of scp payload file (default payload.dat)")
    parser.add_argument("-o", "--scp_options",
        required=False,
        default="",
        type=str,
        help="additional options to pass to the scp command")
    args = parser.parse_args()

    # Create and run the connection monitor
    connectionMonitor = ConnectionMonitor()
    connectionMonitor.Run(args)
