#!/usr/bin/env python3

# Copyright 2020-present Open Networking Foundation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License

import sys
import os
import json
import logging
import enum
import requests
import time
import serial
import subprocess
from collections import namedtuple

'''
Simple script that checks Aether network operational status periodically
by controlling the attached 4G/LTE modem with AT commands and
report the result to the central monitoring server.
'''


CONF = json.loads(
    open(os.getenv('CONFIG_FILE', "./config.json")).read(),
    object_hook=lambda d: namedtuple('X', d.keys())(*d.values())
)

logging.basicConfig(
    filename=CONF.log_file,
    format='%(asctime)s [%(levelname)s] %(message)s',
    level=logging.ERROR
)

report = {
    'name': CONF.edge_name,
    'status': {
        'control_plane': None,
        'user_plane': None
    },
    'speedtest': {
        'ping': {
            'dns': {
                'min': None,
                'avg': None,
                'max': None,
                'stddev': None
            }
        }
    }
}


class State(enum.Enum):
    error = "-1"
    disconnected = "0"
    connected = "1"

    @classmethod
    def has_value(cls, value):
        return value in cls._value2member_map_


class Modem():
    log = logging.getLogger('aether_edge_monitoring.Modem')

    read_timeout = 0.1

    def __init__(self, port, baudrate):
        self.port = port
        self.baudrate = baudrate
        self._response = None

    def connect(self):
        self.serial = serial.Serial(
            port=self.port,
            baudrate=self.baudrate,
            timeout=1)

    def _write(self, command):
        if self.serial.inWaiting() > 0:
            self.serial.flushInput()

        self._response = b""

        self.serial.write(bytearray(command + "\r", "ascii"))
        read = self.serial.inWaiting()
        while True:
            if read > 0:
                self._response += self.serial.read(read)
            else:
                time.sleep(self.read_timeout)
            read = self.serial.inWaiting()
            if read == 0:
                break
        return self._response.decode("ascii").replace('\r\n', ' ')

    def write(self, command, wait_resp=True):
        response = self._write(command)
        self.log.debug("%s: %s", command, response)

        if wait_resp and "ERROR" in response:
            return False, None
        return True, response

    def is_connected(self):
        success, result = self.write('AT+CGATT?')
        if not success or 'CGATT:' not in result:
            return State.error
        state = result.split('CGATT:')[1].split(' ')[0]
        return State(state)

    def close(self):
        self.serial.close()


def get_control_plane_state(modem):
    # Delete the existing session
    # "echo" works more stable than serial for this action
    # success, result = modem.write('AT+CFUN=0')
    logging.debug("echo 'AT+CFUN=0' > " + CONF.modem.port)
    success = os.system("echo 'AT+CFUN=0' > " + CONF.modem.port)
    logging.debug("result: %s", success)
    if success is not 0:
        msg = "Write 'AT+CFUN=0' failed"
        logging.error(msg)
        return State.error, msg

    # Wait until the modem is fully disconnected
    retry = 0
    state = None
    while retry < 5:
        state = modem.is_connected()
        if state is State.disconnected:
            break
        time.sleep(1)
        retry += 1

    # Consider the modem is not responding if disconnection failed
    if state is not State.disconnected:
        msg = "Failed to disconnect."
        logging.error(msg)
        return State.error, msg

    time.sleep(2)
    # Create a new session
    # "echo" works more stable than serial for this action
    # success, result = modem.write('AT+CGATT=1')
    logging.debug("echo 'AT+CFUN=1' > " + CONF.modem.port)
    success = os.system("echo 'AT+CFUN=1' > " + CONF.modem.port)
    logging.debug("result: %s", success)
    if success is not 0:
        msg = "Write 'AT+CFUN=1' failed"
        logging.error(msg)
        return State.error, msg

    # Give 10 sec for the modem to be fully connected
    retry = 0
    while retry < 30:
        state = modem.is_connected()
        if state is State.connected:
            break
        time.sleep(1)
        retry += 1
    # CGATT sometimes returns None
    if state is State.error:
        state = State.disconnected

    time.sleep(2)
    return state, None


def get_user_plane_state(modem):
    resp = os.system("ping -c 3 " + CONF.ping_to + ">/dev/null 2>&1")
    return State.connected if resp is 0 else State.disconnected, None


def run_ping_test(ip, count):
    '''
    Runs the ping test
    Input: IP to ping, # times to ping
    Returns: dict of the min/avg/max/stddev numbers from the ping command result
    '''
    result = {'min': None,
              'avg': None,
              'max': None,
              'stddev': None}
    try:
        pingResult = subprocess.check_output(
                "ping -c " + str(count) + " " + ip + \
                " | tail -1 | awk '{print $4}'",
                shell=True).decode("UTF-8").split("/")
        result = {'min': float(pingResult[0]),
                  'avg': float(pingResult[1]),
                  'max': float(pingResult[2]),
                  'stddev': float(pingResult[3])}
    except Exception as e:
        logging.error("Ping test failed for " + ip + ": %s", e)
    return result


def get_ping_test(modem):
    '''
    Each ping test result saves the min/avg/max/stddev to dict.
    1) Performs ping test to Google Public DNS for 10 iterations.
    2) # TODO: Performs ping to device on network.
    '''
    speedtest_ping = {}
    speedtest_ping['dns'] = run_ping_test("8.8.8.8", 10)
    return speedtest_ping


def report_status(cp_state, up_state, speedtest_ping):
    report['status']['control_plane'] = cp_state.name
    report['status']['user_plane'] = up_state.name
    report['speedtest']['ping'] = speedtest_ping

    logging.info("Sending report %s", report)
    try:
        result = requests.post(CONF.report_url, json=report)
    except requests.exceptions.ConnectionError:
        logging.error("Failed to report for %s", e)
        pass
    try:
        result.raise_for_status()
    except requests.exceptions.HTTPError as e:
        logging.error("Failed to report for %s", e)
        pass


def main():
    modem = Modem(CONF.modem.port, CONF.modem.baud)
    try:
        modem.connect()
    except serial.serialutil.SerialException as e:
        logging.error("Failed to connect the modem for %s", e)
        sys.exit(1)

    success = os.system("sudo ip route replace {}/32 via {}".format(
        CONF.ping_to, CONF.modem.ip_addr))
    if success is not 0:
        logging.error("Failed to add test routing.")
        sys.exit(1)

    while True:
        cp_state, cp_msg = get_control_plane_state(modem)
        up_state, up_msg = get_user_plane_state(modem)
        speedtest_ping = get_ping_test(modem)

        if cp_state is State.error:
            logging.error("Modem is in error state.")
            sys.exit(1)

        report_status(cp_state, up_state, speedtest_ping)
        time.sleep(CONF.report_interval)

    modem.close()


if __name__ == "__main__":
    main()
