#!/usr/bin/env python3

"""
threefive command line SCTE35 decoder.

"""


import sys
from new_reader import reader
from threefive import Cue, Stream, print2, decode, version
from threefive.sixfix import sixfix
from threefive.superkabuki import SuperKabuki
from threefive.showcues import cli as hlscli
from sideways import cli as sidecli

REV = "\033[7;1m"
NORM = "\033[27m\033[0m"
NORM = "\033[0m"
BLUE = "\033[36;1;51m"

B = "\033[7;1m"
U = "\033[m"
mapped = {
    "base64": "encode",
    "bytes": "get_bytes",
    "hex": "encode2hex",
    "json": "get_json",
    "int": "encode2int",
    "xml": "xml",
}


def xml_out(cue):
    """
    xml_out prints cue as xml
    """
    print2(cue.xml())


class SupaStream(Stream):
    """
    SupaStream is subclass of Stream used
    to print raw SCTE-35 packets.
    """

    def _parse_scte35(self, pkt, pid):
        print2(pkt)
        super()._parse_scte35(pkt, pid)


def mk_sidecar(cue):
    """
    mk_sidecar generates a sidecar file with the SCTE-35 Cues
    """
    pts = 0.0
    with open("sidecar.txt", "a") as sidecar:
        cue.show()
        if cue.packet_data.pts:
            pts = cue.packet_data.pts
        data = f"{pts},{cue.encode()}\n"
        sidecar.write(data)


HELP = f"""
threefive                    {U}

{U}{B}    decode    {U}{BLUE}  base64:     {NORM}threefive '/DAWAAAAAAAAAP/wBQb+AKmKxwAACzuu2Q=='

                {BLUE}hex: {NORM}       threefive 0xfc301600000000000000fff00506fe00a98ac700000b3baed9

                {BLUE}files:     {NORM} threefive myvideo.ts

                {BLUE}stdin:     {NORM} cat myvideo.ts | threefive

                {BLUE}http(s):   {NORM} threefive https://futzu.com/xaa.ts

                {BLUE}udp:       {NORM} threefive udp://127.0.0.1:3535

                {BLUE}multicast: {NORM} threefive udp://@235.35.3.5:3535

                {BLUE}hls:       {NORM} threefive hls https://example.com/master.m3u8

{U}{B}    encode   {U}{BLUE}\tLoad JSON, XML, Base64 or Hex and encode to
                JSON, XML, Base64, Hex, Int or Bytes:{NORM} threefive encode help

{U}{B}    hls      {U}{NORM}{BLUE}\tHLS decode SCTE-35:{NORM} threefive hls help

                {BLUE}HLS encode SCTE-35:{U} threefive hls encode help{U}

{U}{B}    inject   {U}{NORM}{BLUE}\tInject an mpegts stream with a SCTE-35 sidecar file
                at pid:{NORM} threefive inject video.ts with sidecar.txt at 333

{U}{B}    mpegts   {U}{NORM}{BLUE}\tFunctions for MPEGTS (packet, proxy,
                pts, sidecar, sixfix show, xml):{NORM} threefive mpegts help

{U}{B}    version  {U}{NORM}{BLUE}\tShow version:{NORM} threefive version

{U}{B}    help     {U}{NORM} {BLUE}\tHelp:{NORM} threefive help
"""


def print_help():
    """
    print_help checks sys.argv for the word help
    and displays the help if found
    """
    print2(HELP)
    sys.exit()


def print_version():
    """
    version_chk checks for the version keyword.

    """
    print2(f"{version}")
    sys.exit()


def encode_help():
    print(
        f"""

        {BLUE}Base64 to bytes:{NORM}threefive  encode  bytes {U}  '/DAlAAAAAAAAAP/wFAUAAAAOf+/+FOvVwP4ApMuAAA4AAAAAzBon0A=='

        {BLUE}Base64 to hex:{NORM}\tthreefive  encode hex {U}  '/DBCAAGRZOeYAP/wBQb/ijB9aAAsAipDVUVJAAAAAX//AABSfTABFG1zbmJjX0VQMDE3MTc0MzEyNzg2NgEBAABDk4yN'

        {BLUE}Base64 to xml:{NORM}\tthreefive  encode xml {U}  '/DAxAAGRZOeYAP/wFAUAAAAMf+//kCYroP4AUmXAAAAAAAAMAQpDVUVJUJ8xMjEq9sE7YA=='

        {BLUE}Hex to int:{NORM}   \tthreefive  encode  int {U} 0xfc302500000000000000fff014050000000e7feffe14ebd5c0fe00a4cb80000e00000000cc1a27d0

        {BLUE}JSON to base64:{NORM}\tthreefive  encode {U} < json.json

        {BLUE}JSON to xml:{NORM}\tthreefive  encode  xml {U} < json.json

        {BLUE}xml to hex:{NORM}   \tcat xml.xml | threefive  encode hex {U}
    """
    )


def json_load():
    """
    json_load is used by encode
    """
    cmdlist = list(mapped.keys()) + ["encode"]
    if "help" in sys.argv:
        encode_help()
        sys.exit()
    json = False
    arglist = [arg for arg in sys.argv[1:] if arg not in cmdlist]
    if not arglist:
        with reader(sys.stdin.buffer) as stuff:
            json = stuff.read().decode()
            arglist.append(json)
    for that in arglist:
        try:
            cue = Cue()
            cue.load(that)
        except:
            try:
                cue = Cue(that)
                cue.decode()
            except:
                print2("threefive accepts json, xml, base64, or hex as input")
                return False
        cue.encode()
        for k, v in mapped.items():
            if k in sys.argv:
                method = getattr(cue, v)
                print2(method())
                sys.exit()

    print2(cue.encode())
    sys.exit()


def superkabuki():
    args = {}
    if "inject" in sys.argv:
        args["input"] = sys.argv[sys.argv.index("inject") + 1]
        if "with" in sys.argv:
            args["sidecar"] = sys.argv[sys.argv.index("with") + 1]
            if "at" in sys.argv:
                args["scte35_pid"] = sys.argv[sys.argv.index("at") + 1]
                supak = SuperKabuki()
                supak.apply_args(args)
                supak.encode()
                return True
    print2("threefive mpegts inject {infile} with {sidecar_file} at {pid}")
    return False


def hls():
    if "encode" in sys.argv:
        sidecli()
    else:
        hlscli()


def no_op(cue):
    """
    no_op is just a dummy func to pass to Stream.decode()
    to suppress output.
    """
    return cue


def packet_chk(this):
    """
    packet_chk checks for the packet keyword
    and displays SCTE-35 packets if present.
    """
    supa = SupaStream(this)
    supa.decode()


def proxy_chk(this):
    """
    proxy_chk checks for the proxy keyword
    and proxies the stream to stdout if present.
    proxy_chk also writes pts,cue pairs to sidecar.txt
    """
    strm = Stream(this)
    strm.proxy(func=mk_sidecar)


def pts_chk(this):
    """
    pts_chk is used to display PTS.
    """
    strm = Stream(this)
    strm.show_pts()


def show_chk(this):
    """
    show_chk checks for the show keyword
    and displays the streams if present.
    """
    strm = Stream(this)
    strm.show()


def sidecar_chk(this):
    """
    sidecar_chk checks for the sidecar keyword and
    generates a sidecar file if present.
    """
    strm = Stream(this)
    strm.decode(func=mk_sidecar)


def to_xml(this):
    """
    to_xml prints cues as xml instead of json.
    """
    try:
        # Mpegts Video
        strm = Stream(this)
        strm.decode(func=xml_out)
        return True

    except:
        try:
            cue = Cue(this)
            cue.decode()
            print2(cue.xml())
            return True
        except:
            return False


func_map = {
    "xml": to_xml,
}


def mhelp():
    print(
        f"""

    {U}    packets  {U}{NORM}{BLUE}\tPrint raw SCTE-35 packets from multicast mpegts video:{NORM}  threefive {B} mpegts {U} {B} packets {U} udp://@235.35.3.5:3535

    {U}    proxy    {U}{NORM}{BLUE}\tParse a https stream and write raw video to stdout:{NORM}  threefive {B} mpegts {U} {B} proxy {U} https://example.com/video.ts

    {U}    pts      {U}{NORM}{BLUE}\tPrint PTS from mpegts video:{NORM}  threefive {B} mpegts {U} {B} pts {U} video.ts

    {U}    sidecar  {U}{NORM}{BLUE}\tParse a stream, write pts,write SCTE-35 Cues to sidecar.txt:{NORM}  threefive {B} mpegts {U} {B} sidecar {U} https://example.com/video.ts

    {U}    sixfix   {U}{NORM}{BLUE}\tFix SCTE-35 data mangled by ffmpeg:{NORM}  threefive {B} mpegts {U} {B} sixfix {U} video.ts

    {U}    show     {U}{NORM}{BLUE}\tProbe mpegts video:{NORM}  threefive {B} mpegts {U} {B} show {U} video.ts

    {U}    xml      {U}{NORM}{BLUE}\tParse an mpegts stream and output xml: {NORM} threefive {B} mpegts {U} {B} xml {U} video.ts

"""
    )


def mpegts():
    mpegts_map = {
        "help": mhelp,
        "pts": pts_chk,
        "show": show_chk,
        "sixfix": sixfix,
        "packets": packet_chk,
        "proxy": proxy_chk,
        "sidecar": sidecar_chk,
        "xml": to_xml,
    }

    sys.argv.remove("mpegts")
    for k, v in mpegts_map.items():
        if k in sys.argv:
            if k in ["help"]:
                mhelp()
            else:
                args = [arg for arg in sys.argv[1:] if arg not in mpegts_map]
                for mo in args:
                    v(mo)
            sys.exit()


print_map = {
    "hls": hls,
    "encode": json_load,
    "mpegts": mpegts,
    "help": print_help,
    "version": print_version,
    "inject": superkabuki,
}


def chk_print_map():
    """
    chk_print_map checks for print_map.keys() in sys.argv
    """
    for k, v in print_map.items():
        if k in sys.argv:
            v()
            sys.exit()


def chk_func_map():
    """
    chk_func_map checks for func_map.keys() in sys.argv
    """
    for k, v in func_map.items():
        if k in sys.argv:
            args = [arg for arg in sys.argv[1:] if arg not in func_map]
            for mo in args:
                v(mo)
            sys.exit()


if __name__ == "__main__":
    if len(sys.argv) > 1:
        chk_print_map()
        chk_func_map()
        for arg in sys.argv[1:]:
            decode(arg)
    else:
        decode(sys.stdin.buffer)
