#!/usr/bin/python3
import argparse
import fathomcamera.fathomexpress_timing as fx

import gi
gi.require_version('Gst', '1.0')
gi.require_version('Gdk', '3.0')
gi.require_version('Gtk', '3.0')
gi.require_version('GLib','2.0')
gi.require_version('GstVideo', '1.0')

from gi.repository import Gdk
from gi.repository import Gst
from gi.repository import Gtk
from gi.repository import GstVideo
from gi.repository import GLib

import signal
signal.signal(signal.SIGINT, signal.SIG_DFL)

from fathomcamera.video_source import *
from fathomcamera.alex_small_network import *
from fathomcamera.fathom_video_sink import *
from fathomcamera.gtk_output import *
from fathomcamera.fathom_thread_model import *

def window_closed (widget, event, pipeline):
  print("window closed")
  widget.hide()
  pipeline.set_state(Gst.State.NULL)
  Gtk.main_quit ()

if __name__=="__main__":
  Gdk.init([])
  Gtk.init([])
  Gst.init([])

  fx.SetGlobalOption(fx.GlobalOption.LOGLEVEL, 2)

  parser = argparse.ArgumentParser()
  # VideoSource subclasses as choices for source
  parser.add_argument('--src',
                      choices=[cls.__name__ for cls in vars()['VideoSource'].__subclasses__()],
                      default="TestSource")
  # Fathom devices as choices for destination
  fathom_names = fx.EnumerateDevices()
  parser.add_argument('--dest',
                      choices=fathom_names,
                      default=fathom_names[0] if fathom_names else "default")
  parser.add_argument('--stop-at',
                      help="stop execution after number of frames processed",
                      type=int)
  args = parser.parse_args()

  # construct objects representing the parts of the pipeline

  source = vars()[args.src]()
  network = AlexSmallNetwork()
  viewsink = GtkPreviewSink("view")
  appsink = FathomAppsink(network,"app")

  # build Gstreamer launch string

  source2tee = "%s ! tee name=t" % source.get_launch()
  tee2view   = "t. ! %s" % viewsink.get_launch()
  tee2app    = "t. ! %s" % appsink.get_launch()
  launch     = "%s %s %s" % (source2tee, tee2view, tee2app)

  print(launch)
  pipeline = Gst.parse_launch( launch )

  # update objects with the created pipeline

  viewsink.set_pipeline(pipeline)
  appsink.set_pipeline(pipeline)

  # build GUI

  window = Gtk.Window()
  window.connect("delete-event", window_closed, pipeline)
  window.set_default_size (640, 480)
  window.set_title ("Hello Fathom!")

  box = Gtk.Box()
  box.set_spacing(5)
  box.set_orientation(Gtk.Orientation.VERTICAL)
  window.add(box)

  box.pack_start(viewsink, True, True, 0)
  if args.stop_at is None:
    output = OutputWidget()
  else:
    output = CountingOutputWidget(args.stop_at)
  box.pack_start(output, False, True, 0)

  window.show_all()
  window.realize()
  viewsink.realize()

  # Initialize Fathom device

  dev = fx.Device(args.dest)
  dev.OpenDevice()
  graph = dev.AllocateGraph(network.get_graph_binary())

  # Initialize input and output threads for Fathom

  worker = GlibFathomWorker(fx, graph, appsink, output.put_output)
  worker.start()

  if pipeline.set_state(Gst.State.PLAYING) == Gst.StateChangeReturn.FAILURE:
      pipeline.set_state(Gst.State.NULL)
  else:
      Gst.debug_bin_to_dot_file (pipeline,Gst.DebugGraphDetails.ALL,'playing-pipeline')    # export GST_DEBUG_DUMP_DOT_DIR=/tmp/
      Gtk.main()
      Gst.debug_bin_to_dot_file (pipeline,Gst.DebugGraphDetails.ALL,'shutting-down-pipeline')
      pipeline.set_state(Gst.State.NULL)
      print("exiting main loop")
      graph.DeallocateGraph()
      dev.CloseDevice()
      print("fathom closed")
      worker.stop()
