from __future__ import print_function

import paramiko
import time

class MiniAMD:
    def __init__(self,username='auger',hostname='192.168.2.2',port=22):
        """ Module to control the MiniAMD Odroid remotely through ssh

        Keyword arguments:
        username    -- username for the remote login
        hostname    -- ip-address/name of the remote hostname
        port        -- port to connect to (22 for ssh connection)
        """
        self.username = username
        self.hostname = hostname
        self.port = port
        self.client = paramiko.SSHClient()
        self.client.load_system_host_keys()
        self.client.set_missing_host_key_policy(paramiko.WarningPolicy)

    def __del__(self):
        self.client.close()

    def connect(self):
        """ Opens the connection to the MiniAMD Odroid """
        self.client.connect(self.hostname,port=self.port,username=self.username)

    def exec_command(self,command):
        """ Executes a command on the MiniAMD Odroid

        Keyword arguments:
        command     -- command to be executed on remote host
        """
        return self.client.exec_command(command)

    def shutdown(self):
        """ Shuts down the MiniAMD Odroid """
        return self.client.exec_command('sudo shutdown -h now')

    def reboot(self):
        """ Reboots the MiniAMD Odroid """
        return self.client.exec_command('sudo shutdown -r now')

    def SwitchSiPMVoltageOff(self):
        """ Switches the SiPM Voltages of MiniAMD off and checks that it successfully worked

        Returns:
        fail        -- 1 if an error occured, 0 if voltage was switched off successfully
        """
        print('Switching SiPM voltage off. This can take a while...')
        stdin,stdout,stderr = self.client.exec_command("lukas/easiroc/vext_control 0")
        output = str(stdout.read())
        if output.find('leaving voltage disabled')>0:
            print('Voltage already disabled. Leaving voltage disabled.')
            return 0
        elif output.find('voltage was set to')>0 and output.find('.stable')>0:
            print('Voltage successfully ramped down.')
            return 0
        else:
            print('ERROR: Voltage could not be ramped down!')
            return 1

    def IsTriggerRunning(self):
        """ Checks if the program for the MiniAMD trigger is running on the Odroid.

        Returns:
        running     -- 1 if trigger is running, 0 if it is not running
        """
        stdin,stdout,stderr = self.client.exec_command('ps aux | grep shelf')
        output = str(stdout.read())
        if output.find('./shelf')>=0:
            return 1
        else:
            return 0

    def StartTrigger(self,flags = ['--nostore','--count-all','--maxtime=14400','--trigger-threshold=720','--nomulti','--stack-trigger','--rampdown']):
        """ Will start the MiniAMD trigger. Before starting, it checks if a trigger is already running.
        After sending the command to MiniAMD it will wait for 10 seconds for the trigger to start and check if the process is running.

        Returns:
        fail        -- 1 if trigger was already running, 0 if command could be sent successfully.
        """

        if self.IsTriggerRunning():
            print("MiniAMD trigger is already running. Doing nothing.")
            return 0
        command = 'cd lukas/easiroc/;./shelf -o miniamd.conf'
        for flag in flags:
            command += " " + flag
        #return self.client.exec_command('ls -l')
        stdin,stdout,stderr =  self.client.exec_command(command)
        time.sleep(50)
        if self.IsTriggerRunning():
            return 0
        return 1

    def StopTrigger(self,timeout=90):
        """ Stops the MiniAMD Odroid trigger.
        Searches for all processes that have the name of the trigger program and sends them a SIGINT
        Then waits for the trigger to stop by checking if the process is still running.

        Keyword arguments:
        timeout     -- Time to wait for the trigger to stop in seconds (defaul=120)

        Returns:
        fail        -- 0 if trigger stopped successfully, else 1
        """
        stdin,stdout,stderr = self.client.exec_command('ps aux | grep shelf')
        output = str(stdout.read())
        out = output.split('\n')
        if len(out)==1:
            output = output.split('\\n')
        else:
            output = out
        shelfs = []
        for out in output:
            if out.find('./shelf')>=0:
                shelfs.append(out)
        pids = []
        for shelf in shelfs:
            pids.append(shelf.split()[1])
        print(pids)
        if len(pids)==0:
            print('ERROR: MiniAMD trigger is not running.')
            return 1
        pids = sorted(pids,reverse=True)
        for pid in pids:
            self.client.exec_command('kill -SIGINT ' + pid)

        print('Waiting for trigger to stop...',end='')
        starttime = time.time()
        while self.IsTriggerRunning() and time.time()-starttime<timeout:
            time.sleep(1)
            print('.',end='')
        if time.time()-starttime>timeout:
            print('Trigger could not be stopped after {:d} seconds.'.format(timeout))
            return 1
        print('\nTrigger successfully stopped.')
        return 0

        def KillTrigger(self):
            """ Will kill the MiniAMD trigger process.
            This should only be done if the process does not stop otherwise.
            """
            stdin,stdout,stderr = self.client.exec_command('ps aux | grep shelf')
            output = str(stdout.read())
            out = output.split('\n')
            if len(out)==1:
                output = output.split('\\n')
            else:
                output = out
            shelfs = []
            for out in output:
                if out.find('./shelf')>=0:
                    shelfs.append(out)
            pids = []
            for shelf in shelfs:
                pids.append(shelf.split()[1])
            print(pids)
            if len(pids)==0:
                print('ERROR: MiniAMD trigger is not running.')
                return 1
            for pid in pids:
                self.client.exec_command('kill ' + pid)