#!/usr/bin/python
################################################################################
# Copyright 2025 ModalAI Inc.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice,
#    this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright notice,
#    this list of conditions and the following disclaimer in the documentation
#    and/or other materials provided with the distribution.
#
# 3. Neither the name of the copyright holder nor the names of its contributors
#    may be used to endorse or promote products derived from this software
#    without specific prior written permission.
#
# 4. The Software is used solely in conjunction with devices provided by
#    ModalAI Inc.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
################################################################################

from __future__ import print_function

import getopt
import json
import os
import subprocess
import sys
import time


CONFIG_FILE = "/etc/modalai/voxl-modem.conf"
QRB_PLATFORMS = set(["qrb5165", "qrb5165-rb5", "m0104", "m0054", "m0052"])


def platform_name():
    return os.uname()[1]


def require_supported_platform():
    platform = platform_name()

    if platform not in QRB_PLATFORMS:
        print("[ERROR] Unsupported platform: %s" % platform)
        sys.exit(404)

    print("[INFO] qrb5165 based platform detected: %s" % platform)


def load_config():
    print("[INFO] Opening config file...")

    with open(CONFIG_FILE, "r") as config_file:
        print("[INFO] Converting to json...")
        return json.load(config_file)


def command_output(args):
    output = subprocess.check_output(args)

    if not isinstance(output, str):
        output = output.decode("utf-8", "replace")

    return output


def get_dmesg_output():
    return command_output(["dmesg"])


def wait_for_dmesg_interface(interface):
    dmesg_output = get_dmesg_output()

    while interface not in dmesg_output:
        time.sleep(1)

        try:
            dmesg_output = get_dmesg_output()
        except subprocess.CalledProcessError:
            print("waiting for %s..." % interface)

    print("[INFO] %s detected" % interface)


def wait_for_interface_ip_prefix(interface, prefix):
    while True:
        print("Waiting for '%s' to have the correct IP address..." % interface)

        try:
            result = command_output(["ifconfig", interface])
            print(result)

            if prefix in result:
                return

        except Exception:
            print("IP not yet set")

        time.sleep(1)


def dtc_configure():
    require_supported_platform()
    time.sleep(5)

    config_dict = load_config()
    dtc_ip = config_dict["dtc_ip"]
    dmesg_output = get_dmesg_output()

    if "eth0" in dmesg_output:
        print("[INFO] Using eth0 for DTC")
        subprocess.call(["ip", "link", "set", "dev", "eth0", "up"])
        subprocess.call(["ip", "addr", "flush", "dev", "eth0"])
        time.sleep(1)
        print("[INFO] Setting IP to: %s" % dtc_ip)
        subprocess.call(["ip", "addr", "add", dtc_ip + "/255.255.255.0", "dev", "eth0"])
        time.sleep(1)
        return

    print("[INFO] Using usb0 for DTC")
    wait_for_dmesg_interface("usb0")
    print("[INFO] Waiting for usb0 interface to be available")

    while "usb0" not in command_output(["ifconfig"]):
        time.sleep(1)

    print("[INFO] Setting IP to: %s" % dtc_ip)
    subprocess.call(["ifconfig", "usb0", dtc_ip])


def microhard_configure():
    require_supported_platform()
    time.sleep(5)

    config_dict = load_config()
    microhard_ip = config_dict["microhard_ip"]
    dmesg_output = get_dmesg_output()

    if "eth0" in dmesg_output:
        print("[INFO] Using eth0 for Microhard")
        wait_for_interface_ip_prefix("eth0", "inet 192.168.168.")
        print("[INFO] Setting IP to: %s" % microhard_ip)
        subprocess.call(["ifconfig", "eth0", microhard_ip])
        return

    print("[INFO] Using usb0 for Microhard")
    wait_for_dmesg_interface("usb0")
    wait_for_interface_ip_prefix("usb0", "inet 192.168.168.")
    print("[INFO] Setting IP to: %s" % microhard_ip)
    subprocess.call(["ifconfig", "usb0", microhard_ip])


def print_help():
    print("Usage: voxl-modem [options]")
    print("")
    print("    --microhard_configure        Configures network to bring up Microhard modem.")
    print("                                     Usage: voxl-modem --microhard_configure")
    print("")
    print("    --dtc_configure              Configures network to bring up DTC modem.")
    print("                                     Usage: voxl-modem --dtc_configure")
    print("")


def main(argv):
    try:
        opts, args = getopt.getopt(argv, "h", ["help", "microhard_configure", "dtc_configure"])
    except getopt.GetoptError as err:
        print("Error: %s" % err)
        print_help()
        return 2

    if args or len(opts) == 0:
        print_help()
        return 0

    for opt, _arg in opts:
        if opt in ("-h", "--help"):
            print_help()
            return 0

        if opt == "--microhard_configure":
            microhard_configure()
            return 0

        if opt == "--dtc_configure":
            dtc_configure()
            return 0

    print_help()
    return 2


if __name__ == "__main__":
    sys.exit(main(sys.argv[1:]))
