#!/usr/bin/env python
# -*- coding: utf-8 -*-

import argparse
import json
import socket
import struct
import os
import sys
import pkg_resources
import errno

WARN = "\033[93m" # yellow
NOTICE = "\033[94m" # green
ERROR = "\033[91m" # red
END = "\033[0m"

cli_version = pkg_resources.require("candy-board-cli")[0].version

# candy apn ls ... list all apns
# candy apn set <name> <user> <password> (<id>) ... add a given apn
# candy apn del <id> ... delete a given apn
# candy network show ... show phone network state and signal strength (RSSI in dBm)
# candy sim show ... show SIM status and info (MSISDN, IMSI)
# candy modem show ... show modem info (Model, Manufacturer, Revision, IMEI)
# candy service version ... return the board service software version
# candy version ... return this CLI version

if "SOCK_PATH" in os.environ:
    SOCK_PATH = os.environ["SOCK_PATH"]
else:
    SOCK_PATH = "/var/run/candy-board-service.sock"

def err(msg):
    print(ERROR + msg + END)

def warn(msg):
    print(WARN + msg + END)

def notice(msg):
    print(NOTICE + msg + END)

def main(args):
    if args.category == "version":
        print("CANDY Board Service CLI version: %s" % cli_version)
        if not os.path.exists(SOCK_PATH):
            notice("[NOTICE] CANDY Board Service isn't running")
        return 0

    if not os.path.exists(SOCK_PATH):
        err("[ERROR] CANDY Board Service isn't running")
        return 1

    sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
    try:
        sock.connect(SOCK_PATH)
    except socket.error, v:
        errorcode = v[0]
        if errorcode == errno.ECONNREFUSED:
            err("[ERROR] CANDY Board Service isn't running")
        elif errorcode == errno.EACCES:
            err("[ERROR] Permission denied. 'sudo' is required")
        else:
            err("[ERROR] I/O error, errno=%s" % errno.errorcode[errorcode])
        return errorcode

    code = 0

    if args.category in ("apn", "network", "sim", "modem", "service"):
        try:
            # request
            packer = struct.Struct("I")
            cmd_json = json.dumps(vars(args))
            size = len(cmd_json)
            packed_header = packer.pack(size)
            sock.sendall(packed_header)
            packer = struct.Struct("%is" % size)
            packed_json = packer.pack(cmd_json)
            sock.sendall(packed_json)

            # response
            packer = struct.Struct("I")
            packed_result = sock.recv(packer.size)
            result = packer.unpack(packed_result)

            # result
            if result != 0:
                packer = struct.Struct("%is" % result)
                packed_message = sock.recv(packer.size)
                message_json = packer.unpack(packed_message)
                message = json.loads(message_json[0])
                if message["status"] != "OK":
                    code = 2
                if message["result"]:
                    print(json.dumps(message["result"], indent=2))

        finally:
            sock.close()
            return code
    else:
        raise ValueError("Unsupported category")

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="CANDY Board Service CLI")
    categories = parser.add_subparsers(title="categories", dest="category")

    version_commands = categories.add_parser("version", help = "CLI Version")

    parser_apn = categories.add_parser("apn", help = "Manipulate APN settings")
    apn_commands = parser_apn.add_subparsers(title="APN actions", dest="action")

    parser_apn_ls = apn_commands.add_parser ("ls", help = "List all APNs")
    parser_apn_set = apn_commands.add_parser ("set", help = "Set a new APN")
    parser_apn_set.add_argument ("-n", "--name", type = str, required = True, help = "APN")
    parser_apn_set.add_argument ("-u", "--user-id", type = str, required = True, help = "User ID")
    parser_apn_set.add_argument ("-p", "--password", type = str, required = True, help = "User Password")
    parser_apn_set.add_argument ("-i", "--id", type = str, required = False, help = "APN ID (1 by default)")
    parser_apn_del = apn_commands.add_parser ("del", help = "Delete an exsiting APN")
    parser_apn_del.add_argument ("-i", "--id", type = str, required = False, help = "APN ID (1 by default)")

    parser_network = categories.add_parser("network", help = "Manage Phone Network")
    network_commands = parser_network.add_subparsers(title="Phone Network actions", dest="action")
    parser_network_show = network_commands.add_parser ("show", help = "Show Phone network state and Signal strength")

    parser_sim = categories.add_parser("sim", help = "Manage SIM")
    sim_commands = parser_sim.add_subparsers(title="SIM actions", dest="action")
    parser_sim_show = sim_commands.add_parser ("show", help = "Show SIM state and SIM information")

    parser_modem = categories.add_parser("modem", help = "Manage LTE/3G module modem")
    modem_commands = parser_modem.add_subparsers(title="Modem actions", dest="action")
    parser_modem_show = modem_commands.add_parser ("show", help = "Show Module information")
    parser_modem_reset = modem_commands.add_parser ("reset", help = "Reset modem")

    parser_service = categories.add_parser("service", help = "Manage CANDY Board Service")
    service_commands = parser_service.add_subparsers(title="CANDY Board Service actions", dest="action")
    parser_service_version = service_commands.add_parser ("version", help = "Show CANDY Board Service software version")

    args = parser.parse_args()
    sys.exit(main(args))
