#!/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"


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"""
{B}threefive                    {U}

\tSCTE-35 inputs:{BLUE}mpegts, base64, hex, json, xml, and xmlbin{U} are auto-detected.
\tSCTE-35 outputs are {BLUE}base64, bytes, hex, int, json, xml, and xmlbin.{U}

         Input:{U}    Output:{U}
\t{U}{BLUE} mpegts {U}  {U}{BLUE} base64 {NORM} threefive https://example.com/video.ts {BLUE} base64 {U}
\t{U}{BLUE} xml    {U}  {U}{BLUE} bytes  {NORM} threefive {BLUE} bytes {U} < xml.xml
\t{U}{BLUE} base64 {U}  {U}{BLUE} hex    {NORM} threefive '/DAWAAAAAAAAAP/wBQb+AKmKxwAACzuu2Q==' {BLUE} hex {U}
\t{U}{BLUE} xmlbin {U}  {U}{BLUE} int    {NORM} threefive {BLUE} int {U} < xml.xml
\t{U}{BLUE} mpegts {U}  {U}{BLUE} json   {NORM} threefive video.ts
\t{U}{BLUE} json   {U}  {U}{BLUE} xml    {NORM} threefive  < json.json {BLUE} xml {U}
\t{U}{BLUE} hex    {U}  {U}{BLUE} xmlbin {NORM} threefive 0xfc301600000000000000fff00506fe00a98ac700000b3baed9 {BLUE} xmlbin {U}

{B}    hls      {U}{NORM} {BLUE}HLS decode SCTE-35:{NORM} threefive hls https://example.com/master.m3u8
\t\t\t\t  threefive hls help
              {BLUE}HLS encode SCTE-35:{U} threefive hls encode  -i https://example.com/master.m3u8 -s sidecar.txt -o output_dir
\t\t\t\t  threefive hls encode help

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

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

{U}{B}    proxy    {U}{NORM}{BLUE} Parse a https stream and write raw video to stdout:{NORM} threefive proxy video.ts

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

{U}{B}    sidecar  {U}{NORM}{BLUE} Parse a stream, write pts,write SCTE-35 Cues to sidecar.txt:{NORM} threefive sidecar video.ts

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

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

{U}{B}    version  {U}{NORM}{BLUE} Show version:{NORM} threefive version

{U}{B}    help     {U}{NORM} {BLUE}Help:{NORM} threefive help

"""


def read_buff():
    with reader(sys.stdin.buffer) as stuff:
        inbuff = stuff.read().decode()
        return inbuff


def mk_args(keys):
    """
    mk_args generates a list of args for inputs
    if no args are present,read from sys.stdin.buffer
    """
    args = [arg for arg in sys.argv[1:] if arg not in keys]
    if not args:
        args.append(read_buff())
    return args


# print_map functions


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


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():
    """
    print_version print the threefive version
    """
    print2(version)


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


print_map = {
    "hls": hls,
    "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()


# functions for mpegts_map


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)


mpegts_map = {
    "packets": packet_chk,
    "proxy": proxy_chk,
    "pts": pts_chk,
    "show": show_chk,
    "sidecar": sidecar_chk,
    "sixfix": sixfix,
}


def chk_mpegts_map():
    """
    chk_mpegts_map check sys.argv for mpegts_map keys
    """
    m_keys = list(mpegts_map.keys())
    args = mk_args(m_keys)
    for key in m_keys:
        if key in sys.argv:
            for arg in args:
                mpegts_map[key](arg)
            sys.exit()


# functions for funk_map


def base64_out(cue):
    """
    print SCTE-35 from mpegts as base64
    """
    print2(cue.encode())


def bytes_out(cue):
    """
    print SCTE-35 from mpegts as base64
    """
    print2(cue.bites)


def hex_out(cue):
    """
    print SCTE-35 from mpegts as hex
    """
    print2(cue.encode2hex())


def int_out(cue):
    """
    print SCTE-35 from mpegts as int
    """
    print2(cue.encode2int())


def json_out(cue):
    """
    print SCTE-35 from mpegts as json
    """
    cue.show()


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


def xmlbin_out(cue):
    """
    xml_out prints cue as xml
    """
    print2(cue.xml(binary=True))


funk_map = {
    "base64": base64_out,
    "bytes": bytes_out,
    "hex": hex_out,
    "int": int_out,
    "json": json_out,
    "xml": xml_out,
    "xmlbin": xmlbin_out,
}


def funk():
    """
    return a func
    if a key in out_map
    is also in sys.argv
    """
    func =json_out
    for k, v in funk_map.items():
        if k in sys.argv:
            func=v
    return func

def to_funk(this):
    """
    to_funk prints a cue in a variety of formats.
    """
    try:
        # mpegts streams handled here.
        strm = Stream(this)
        func = funk()
        strm.decode(func=func)
    except:  # try to load json or xml
        try:
            cue=Cue()
            cue.load(this)
        except:
            try:  # handle base64, bytes, and hex.
                cue = Cue(this)
                cue.decode()
            except:
                pass
        if cue:     
            cue.encode()
            func = funk()
            func(cue)
 

def chk_funk_map():
    """
    chk_func_map checks for func_map.keys() in sys.argv
    """
    funk_keys = list(funk_map.keys())
    args = mk_args(funk_keys)
    superfunk = decode
    if [fkey for fkey in funk_keys if fkey in sys.argv]:
        superfunk = to_funk
    else:
        superfunk = to_funk 
    [superfunk(arg) for arg in args]
    sys.exit()


if __name__ == "__main__":
    if len(sys.argv) < 2:
        sys.argv.append('json')
    chk_print_map()
    chk_mpegts_map()
    chk_funk_map()
# else:
#    decode(sys.stdin.buffer)
