import sys
import os
import time
import threading
import time
import argparse
import traceback

from ..net import sink_netserver
from ..net import sink_encoder
from ..net import sink_passthrough
from ..net import sink_bin2dash
from ._scriptsupport import *

def main():
    SetupStackDumper()
    parser = ArgumentParser(description="Forward pointcloud streams", formatter_class=argparse.RawDescriptionHelpFormatter)
    parser.add_argument("--noforward", action="store_true", help="Don't forward pointclouds, only prints statistics at the end")
    
    output_selection_args = parser.add_argument_group("output selection").add_mutually_exclusive_group()
    output_selection_args.add_argument("--port", action="store", default=4303, type=int, metavar="PORT", help="Port to serve compressed pointclouds on (default: 4303)")
    output_selection_args.add_argument("--bin2dash", action="store", metavar="URL", help="Send compressed data to bin2dash URL in stead of serving. Example URL:  https://vrt-evanescent.viaccess-orca.com/pctest/")
    
    output_args = parser.add_argument_group("output arguments")
    output_args.add_argument("--seg_dur", action="store", type=int, metavar="MS", help="Bin2dash segment duration (milliseconds, default 10000)")
    output_args.add_argument("--timeshift_buffer", action="store", type=int, metavar="MS", help="Bin2dash timeshift buffer depth (milliseconds, default 30000)")
    output_args.add_argument("--noencode", action="store_true", help="Send uncompressed pointclouds (default: use cwipc_codec encoder)")
    output_args.add_argument("--octree_bits", action="append", type=int, metavar="N", help="Override/append encoder parameter (depth of octree)")
    output_args.add_argument("--jpeg_quality", action="append", type=int, metavar="N", help="Override/append encoder parameter (jpeg quality)")
    output_args.add_argument("--tiled", action="store_true", help="Encode and transmit streams for every tile (bin2dash only)")
    output_args.add_argument("--tile", action="append", type=int, help="Encode and transmit stream for specific tile (bin2dash only), can be specified more than once.")
    args = parser.parse_args()
    beginOfRun(args)
    #
    # Create source
    #
    sourceFactory, source_name = cwipc_genericsource_factory(args)
    source = sourceFactory()
    if args.noencode:
        encoder_factory = sink_passthrough.cwipc_sink_passthrough
    else:
        encoder_factory = sink_encoder.cwipc_sink_encoder
    if args.noforward:
        forwarder = None
    elif args.bin2dash:
        forwarder = encoder_factory(
            sink_bin2dash.cwipc_sink_bin2dash(
                args.bin2dash,
                seg_dur_in_ms=args.seg_dur,
                timeshift_buffer_depth_in_ms=args.timeshift_buffer, 
                verbose=(args.verbose > 1),
                nodrop=args.nodrop
            ),
            verbose=(args.verbose > 1),
            nodrop=args.nodrop
        )
    else:
        forwarder = encoder_factory(
            sink_netserver.cwipc_sink_netserver(
                args.port, 
                verbose=(args.verbose > 1),
                nodrop=args.nodrop
            ),
            verbose=(args.verbose > 1),
            nodrop=args.nodrop
        )
    if args.octree_bits or args.jpeg_quality or args.tiled:
        if args.tiled:
            tilecount = source.maxtile()
            td = [source.get_tileinfo_dict(i) for i in range(tilecount)]
            tiledescriptions = filter(lambda e: e['cameraMask'] != 0, td)
            tiledescriptions = list(tiledescriptions)
            if len(tiledescriptions) < len(td):
                if args.verbose:
                    print(f'cwipc_forward: ignoring full tile', file=sys.stderr)
        elif args.tile:
            tiledescriptions = [source.get_tileinfo_dict(i) for i in args.tile]
        else:
            tiledescriptions = None
        forwarder.set_encoder_params(octree_bits=args.octree_bits, jpeg_quality=args.jpeg_quality, tiles=tiledescriptions)

    sourceServer = SourceServer(source, forwarder, args, source_name=source_name)
    sourceThread = threading.Thread(target=sourceServer.run, args=(), name="cwipc_forward.SourceServer")
    if forwarder:
        forwarder.set_producer(sourceThread)

    #
    # Run everything
    #
    try:
        sourceThread.start()

        if forwarder and hasattr(forwarder, 'start'):
            forwarder.start()
            
        sourceThread.join()
    except KeyboardInterrupt:
        print("Interrupted.")
        sourceServer.stop()
    except:
        traceback.print_exc()
    
    #
    # It is safe to call join (or stop) multiple times, so we ensure to cleanup
    #
    sourceServer.stop()
    sourceThread.join()
    if forwarder and hasattr(forwarder, 'stop'):
        forwarder.stop()
    if forwarder and hasattr(forwarder, 'statistics'):
        forwarder.statistics()
    sourceServer.statistics()
    del forwarder
    del sourceServer
    endOfRun(args)
    
if __name__ == '__main__':
    main()
    
    
    

import sys
import os
import time
import threading
import time
import argparse
import traceback

from ..net import sink_netserver
from ..net import sink_encoder
from ..net import sink_passthrough
from ..net import sink_bin2dash
from ._scriptsupport import *

def main():
    SetupStackDumper()
    parser = ArgumentParser(description="Forward pointcloud streams", formatter_class=argparse.RawDescriptionHelpFormatter)
    parser.add_argument("--noforward", action="store_true", help="Don't forward pointclouds, only prints statistics at the end")
    
    output_selection_args = parser.add_argument_group("output selection").add_mutually_exclusive_group()
    output_selection_args.add_argument("--port", action="store", default=4303, type=int, metavar="PORT", help="Port to serve compressed pointclouds on (default: 4303)")
    output_selection_args.add_argument("--bin2dash", action="store", metavar="URL", help="Send compressed data to bin2dash URL in stead of serving. Example URL:  https://vrt-evanescent.viaccess-orca.com/pctest/")
    
    output_args = parser.add_argument_group("output arguments")
    output_args.add_argument("--seg_dur", action="store", type=int, metavar="MS", help="Bin2dash segment duration (milliseconds, default 10000)")
    output_args.add_argument("--timeshift_buffer", action="store", type=int, metavar="MS", help="Bin2dash timeshift buffer depth (milliseconds, default 30000)")
    output_args.add_argument("--noencode", action="store_true", help="Send uncompressed pointclouds (default: use cwipc_codec encoder)")
    output_args.add_argument("--octree_bits", action="append", type=int, metavar="N", help="Override/append encoder parameter (depth of octree)")
    output_args.add_argument("--jpeg_quality", action="append", type=int, metavar="N", help="Override/append encoder parameter (jpeg quality)")
    output_args.add_argument("--tiled", action="store_true", help="Encode and transmit streams for every tile (bin2dash only)")
    output_args.add_argument("--tile", action="append", type=int, help="Encode and transmit stream for specific tile (bin2dash only), can be specified more than once.")
    args = parser.parse_args()
    beginOfRun(args)
    #
    # Create source
    #
    sourceFactory, source_name = cwipc_genericsource_factory(args)
    source = sourceFactory()
    if args.noencode:
        encoder_factory = sink_passthrough.cwipc_sink_passthrough
    else:
        encoder_factory = sink_encoder.cwipc_sink_encoder
    if args.noforward:
        forwarder = None
    elif args.bin2dash:
        forwarder = encoder_factory(
            sink_bin2dash.cwipc_sink_bin2dash(
                args.bin2dash,
                seg_dur_in_ms=args.seg_dur,
                timeshift_buffer_depth_in_ms=args.timeshift_buffer, 
                verbose=(args.verbose > 1),
                nodrop=args.nodrop
            ),
            verbose=(args.verbose > 1),
            nodrop=args.nodrop
        )
    else:
        forwarder = encoder_factory(
            sink_netserver.cwipc_sink_netserver(
                args.port, 
                verbose=(args.verbose > 1),
                nodrop=args.nodrop
            ),
            verbose=(args.verbose > 1),
            nodrop=args.nodrop
        )
    if args.octree_bits or args.jpeg_quality or args.tiled:
        if args.tiled:
            tilecount = source.maxtile()
            td = [source.get_tileinfo_dict(i) for i in range(tilecount)]
            tiledescriptions = filter(lambda e: e['cameraMask'] != 0, td)
            tiledescriptions = list(tiledescriptions)
            if len(tiledescriptions) < len(td):
                if args.verbose:
                    print(f'cwipc_forward: ignoring full tile', file=sys.stderr)
        elif args.tile:
            tiledescriptions = [source.get_tileinfo_dict(i) for i in args.tile]
        else:
            tiledescriptions = None
        forwarder.set_encoder_params(octree_bits=args.octree_bits, jpeg_quality=args.jpeg_quality, tiles=tiledescriptions)

    sourceServer = SourceServer(source, forwarder, args, source_name=source_name)
    sourceThread = threading.Thread(target=sourceServer.run, args=(), name="cwipc_forward.SourceServer")
    if forwarder:
        forwarder.set_producer(sourceThread)

    #
    # Run everything
    #
    try:
        sourceThread.start()

        if forwarder and hasattr(forwarder, 'start'):
            forwarder.start()
            
        sourceThread.join()
    except KeyboardInterrupt:
        print("Interrupted.")
        sourceServer.stop()
    except:
        traceback.print_exc()
    
    #
    # It is safe to call join (or stop) multiple times, so we ensure to cleanup
    #
    sourceServer.stop()
    sourceThread.join()
    if forwarder and hasattr(forwarder, 'stop'):
        forwarder.stop()
    if forwarder and hasattr(forwarder, 'statistics'):
        forwarder.statistics()
    sourceServer.statistics()
    del forwarder
    del sourceServer
    endOfRun(args)
    
if __name__ == '__main__':
    main()
    
    
    

# # Create source # # # Run everything # # # It is safe to call join (or stop) multiple times, so we ensure to cleanup #