#!/usr/bin/env python3

"""
fu command line SCTE35 decoder.

"""


import select
import sys
from new_reader import reader
from fu import Cue, Stream, print2,  version
from fu.hls import cli as hlscli
from fu.sixfix import sixfix
#from fu.injector import Injector
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)
        print2("")
        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"""
{BLUE}{B}                   futoo                              {U}

{B} Default    {U} {BLUE}The default action is to read a input and write a SCTE-35 output.{U}

  {BLUE}inputs {U} mpegts, base64, hex, json, xml, and xmlbin{U}.

  {BLUE}outputs{U} base64, bytes, hex, int, json, xml, and xmlbin.{U}

  {BLUE}fu can read from {U} strings, files, stdin, http(s), multicast, and Udp.

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

{B}  hls        {U}{NORM} {BLUE} SCTE-35 hls decode help:{U} fu hls help

  fu hls https://example.com/master.m3u8

{B}  hls encode {U} {BLUE} SCTE-35 hls encode help:{U}fu hls encode help

  fu hls encode  -i https://example.com/master.m3u8 -s sidecar.txt -o output_dir

{B}  inject     {U}{NORM}{BLUE} Inject an mpegts stream with a SCTE-35 sidecar file at pid:{NORM}

  fu inject video.ts with sidecar.txt at 333

{B}  packets    {U}{NORM}{BLUE} Print raw SCTE-35 packets from multicast mpegts video:{NORM}

  fu packets udp://@235.35.3.5:3535

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

  fu proxy video.ts

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

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

  fu sidecar video.ts

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

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

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

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

"""


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]
    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 fu version
    """
    print2(version)

"""
def inject():
    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 = Injector()
                supak.apply_args(args)
                supak.encode()
                return True
    print2("fu mpegts inject {infile} with {sidecar_file} at {pid}")
    return False
"""

print_map = {
    "hls": hls,
    "help": print_help,
    "version": print_version,
  #  "inject": fu,
}


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.base64())


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.hex())


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


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.xmlbin())


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.
    """
    if this in["",b""]:
        return
    try:
        # mpegts streams handled here.
        strm = Stream(this)
        strm.decode(func=funk()) # funk() works here
    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()
            funk()(cue) #   func works here too.


def chk_stdin(args):
    """
    chk_stdin autodetects input from stdin.

    """
    readable, _, _ = select.select([sys.stdin], [], [], 0)
    if sys.stdin in readable:  # check stdin for data
        one = reader(sys.stdin.buffer).read(1)
        if one not in [b'G']: # is this a packet?
            two = reader(sys.stdin.buffer).read()
            args.append((one + two).decode()) # no rewind on stdin
        else:
            reader(sys.stdin.buffer).read(187) # drop first packet
            Stream(sys.stdin.buffer).decode(func=funk())
            sys.exit()
    return args


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)
    args = chk_stdin(args)
   # superfunk = decode
    if [fkey for fkey in funk_keys if fkey in sys.argv]:
        superfunk = to_funk
    if args:
        [superfunk(arg) for arg in args] # multiple file input
    sys.exit()


if __name__ == "__main__":
    if len(sys.argv) < 2:
        sys.argv.append("json")
    chk_print_map()
    chk_mpegts_map()
    chk_funk_map()
