#!/usr/bin/env python3

#
# Development Order #5:
#
# This is the meat and bones of the tool, where the actual desired
# commands or operation will be run. The results are then recorded
# and added to the 'results' JSON data, which will then be sent
# back to the test. Both system and api are able to be used here.
#

import datetime
import subprocess
import json
import sys
import time
import os
import pscheduler
import tempfile

#error and diagnostic tracking
error = []
diags = []
authenticated = False
need_root = False

#declare local variables
interface = ''
path = ''
username = ''
password = ''
driver = ''
ssid = ''
bssid = ''
key_managment = ''


# from stdin
input = pscheduler.json_load(exit_on_error=True)

# Take input from test spec
try:
    interface = input['test']['spec']['interface']

except KeyError:
    pscheduler.fail('Missing the interface in input')

try:
    username = input['test']['spec']['username']
except KeyError:
    diags.append("Proceeding without a username")

try:
    password = input['test']['spec']['password']
except KeyError:
    diags.append("Proceeding without a password")

try:
    driver = input['test']['spec']['driver']
except KeyError:
    diags.append("Proceeding without a driver")

try:
    ssid = input['test']['spec']['ssid']
except KeyError:
    diags.append("Proceeding without a ssid")

try:
    bssid = input['test']['spec']['bssid']
except KeyError:
    diags.append("Proceeding without a bssid")

try:
    key_management = input['test']['spec']['key_management']
except KeyError:
    diags.append("Proceeding without key_management")


try:
    driver = input['test']['spec']['driver']
except KeyError:
    diags.append("proceeding with default driver")


timeout_iso = input['test']['spec'].get('timeout', 'PT10S')
timeout = pscheduler.timedelta_as_seconds( pscheduler.iso8601_as_timedelta(timeout_iso) )
succeeded = False

# create a temporary configuration file
temp = tempfile.TemporaryFile(mode = 'w+t')
path = temp.name
try:
    temp.writelines(['ctrl_interface=DIR=/var/run/wpa_supplicant\n', 'update_config=1\n', 'network={\n'])
    if ssid != '':
        temp.write('  ssid="' + ssid + '"' + '\n')
    if bssid != '':
        temp.write('  bssid="' + bssid + '"' + '\n')
    if password != '':
        temp.write('  psk="' + password + '"' + '\n')
    if key_management != '':
        temp.write('  key_mgmt=' + key_management + '\n')
    temp.write('}')
    #temp.seek(0)

#sleep until designated start time
try:
    pscheduler.sleep_until(input['schedule']['start'])
except KeyError:
    pscheduler.fail('Unable to find start time in input')

# check if the EUID is not the root
if os.geteuid() != 0:
    need_root = True

#remove the interface file if it exists
interface_path = '/var/run/wpa_supplicant' + interface
if os.path.exists(interface_path):
    need_root = True
    diags.append('Need root privilage to delete prior interface file')
    clear_interface = ['rm', interface_path]
    if need_root:
        clear_interface.insert(0, 'sudo') 
    # run the commands 
    status, stdout, stderr = pscheduler.run_program(clear_interface, timeout=timeout)
    if status != 0:
        succeeded = False
        fail_json = { 'succeeded': succeeded,
                      'error': 'failed to delete old interface file',
                      'diags':'\n'.join(diags)} }
        pscheduler.succeed_json(fail_json)
        error.append("(failed to delete old interface file) Error returned: \n%s" % stderr.strip('\n'))
    else:
        succeeded = True
        diags.append("Successfully deleted old interface file")

# reset the need root flag as root might not be needed next time
need_root = False

#kill all previous wpa_supplicants
kill_wpa = ['killall', 'wpa_supplicant']
if need_root: 
    diags.insert('Need root privelage to kill all wpa supplicant processes before starting a new one')
    kill_wpa.insert(0, 'sudo')
status, stdout, stderr = pscheduler.run_program(kill_wpa, timeout=timeout)

#run wpa to authenticate
start_time = datetime.datetime.now()
wpa_auth = ['wpa_supplicant', '-i', interface, '-c', path, '-d', driver, '-B']
if need_root: 
    wpa_auth.insert(0, 'sudo')
status, stdout, stderr = pscheduler.run_program(wpa_auth, timeout=timeout)

if status != 0:
    error.append('Error returned: \n%s' % stderr.strip('\n'))
    succeeded = False
    fail_json = { 'succeeded': succeeded,
              'error': 'failed to run wpa_supplicant',
              'diags':'\n'.join(diags)} }
        
    pscheduler.succeed_json(fail_json

else:
    diags.append(stdout)

#use wpa_cli to check if it was intiizlized correctly
wpa_status = ["wpa_cli", "status"]
if need_root:
    wpa_status.insert(0, 'sudo')

status, stdout, stderr = pscheduler.run_program(wpa_status, timeout=timeout)
    
if status != 0:
    error.append('Error returned: \n%s' % stderr.strip('\n'))
    succeeded = False
    fail_json = { 'succeeded': succeeded,
              'error': 'failed to run wpa_cli to validate the authentication',
              'diags':'\n'.join(diags)} }
    
    succeeded = False
else:
    authenticated = True
    succeeded = True

#get the end time for wpa_supplicant to be initialized
end_time = datetime.datetime.now()

# clean up the temporary file
temp.close()

# Organize results into json data
results = {
    'succeeded': succeeded,
    'result': {
        'schema': 1,
        'time': pscheduler.timedelta_as_iso8601( end_time - start_time),
        'succeeded': succeeded
        'authenticated': authenticated
    },
    'error': error,
    'diags': diags }

pscheduler.succeed_json(results)

