#!/usr/bin/env python
# vim: sts=4 sw=4 et

import sys
from optparse import OptionParser

import _camunits, _camunitsgtk
import gtk, gobject, camunits, camunits.gtk

default_ui='/usr/share/camview-emc/camview-emc.ui'

parser = OptionParser()
parser.add_option('-C', '--chain', dest='chain', help='Load camunits chain from file')
parser.add_option('-w', '--window', dest='window', help='Embed into window')
parser.add_option('-p', '--plugin-path', dest='plugins',
                    help='Add the directories to the plugin search path',
                    action='append', default=[])
parser.add_option('-s', '--size', dest='size', help='Set size of widget WxH')
parser.add_option('-u', '--ui', dest='ui', help='UI File to load', default=default_ui)
parser.add_option('-x', '--crosshair', dest='crosshair',
                    help='Append crosshair unit', action='store_true', default=True)
parser.add_option('-X', '--no-crosshair', dest='crosshair',
                    help="Don't append crosshair unit", action='store_false')
parser.add_option('-v', '--video-size', dest='video_size', default='640x480',
                    help='Set video size of camera WxH')
parser.add_option('-g', '--gladevcp', dest='gladevcp', action='store',
                    help='Load GladeVCP panel from file')
parser.add_option('-c', '--component', dest='comp', help='Set component name to NAME')
parser.add_option('-H', '--hal', dest='hal', action='store', default=None,
                    help='Run HAL file after component is ready')

def reparent(window, parent):
    from Xlib import display
    from Xlib.xobject import drawable
    d = display.Display()
    w = drawable.Window(d.display, window.window.xid, 0)
    # Honor XEmbed spec
    atom = d.get_atom('_XEMBED_INFO')
    w.change_property(atom, atom, 32, [0, 1])
    w.reparent(parent, 0, 0)
    w.map()
    d.sync()

class EmcView:
    def __init__(self, options):
        m = camunits.Manager()
        for p in options.plugins:
            m.add_plugin_dir(p)

        if options.gladevcp:
            import gladevcp
        builder = gtk.Builder()
        builder.add_from_file(options.ui)
        window = builder.get_object('window1')

        self.builder = builder

        signals = {'on_button_save_clicked':self.save
                  ,'on_expander_control_activate':self.on_expander_control_activate
                  }
        builder.connect_signals(signals)

        xid = None
        if options.window:
            w = window
            xid = long(options.window, 0)
            plug = gtk.Plug(xid)
            for c in window.get_children():
                window.remove(c)
                plug.add(c)
            window = plug

        window.connect('destroy', gtk.main_quit)
        window.show_all()

        if options.window:
            reparent(window, xid)

        w = builder.get_object('chain_gl_widget')
        self.glwidget = w
        if options.chain:
            w.load_from_str(open(options.chain).read())
            self.chain_file = options.chain
        else:
            w.set_chain(self.create_chain(options))
            self.chain_file = None
        c = w.get_chain()
        c.attach_glib(1000, None)

        if options.size and 'x' in options.size:
            width, height = options.size.split('x', 1)
            w.set_size_request(int(width), int(height))

        self._units_cross = filter(lambda u: u.get_id() == 'emc.crosshair', c.get_units())
        self._units_halio = filter(lambda u: u.get_id() == 'emc.halio', c.get_units())

        self._units_color = self._units_cross + self._units_halio


        circle_e = builder.get_object('togglebutton_circle')
        circle_r = builder.get_object('hscale_circle')

        if self._units_cross:
            circle_r.connect('value-changed', lambda w: self.change_circle(w.get_value()))
            circle_e.connect('toggled', lambda w: self.change_circle_enable(w.get_active()))
            circle_e.connect('toggled', lambda w: circle_r.set_sensitive(w.get_active()))
            circle_r.set_value(100)
            circle_e.set_active(False)
        else:
            circle_e.set_sensitive(False)
            circle_r.set_sensitive(False)

        on = builder.get_object('togglebutton_enable')
        on.set_active(True)
        on.connect('toggled', lambda w: self.glwidget.set_active(w.get_active()))

        colorbutton = builder.get_object('colorbutton_crosshair')
        xorbutton   = builder.get_object('togglebutton_xor')
        if self._units_color:
            colorbutton.connect('color-set', lambda w: self.change_color(w.get_color()))
            xorbutton.connect('toggled', lambda w: self.change_xor(w.get_active()))
            xorbutton.set_active(True)
        else:
            colorbutton.set_sensitive(False)
            xorbutton.set_sensitive(False)

        spinbutton = builder.get_object('hscale_halio')
        spinbutton.set_value(20)
        if self._units_halio:
            spinbutton.connect('value-changed', lambda w: self.change_spacing(w.get_value()))
        else:
            spinbutton.set_sensitive(False)

        u = c.get_units()[0]
        combo = builder.get_object('combobox_format')
        model = combo.get_model()
        match = 0
        match_rgb = None
        for i,f in enumerate(u.get_output_formats()):
            s = "%sx%s" % (f.width, f.height)
            model.append((f.name, f))
            if 'UNRECOGNIZED' in f.name:
                continue
            if match_rgb is not None:
                continue
            if s == options.video_size:
                if 'RGB' in f.name:
                    match_rgb = i
                match = i

        combo.connect("changed", self.change_format)
        combo.set_active(match_rgb or match)

        notebook = builder.get_object('notebook1')
        ctrls = []
        for u in c.get_units():
            ctrl = camunits.gtk.ControlWidget()
            ctrl.set_unit(u)
            ctrl.set_expanded(True)
            notebook.append_page(ctrl, gtk.Label(u.get_id()))
            ctrls.append(ctrl)

        notebook.show_all()

        for ctrl in ctrls:
            ctrl.show_all()
            ctrl.set_expanded(False)
            ctrl.queue_draw()

        w.set_active(True)

        self.vcp_parent = self.builder.get_object('alignment_vcp')
        if options.gladevcp:
            import hal
            from gladevcp.makepins import GladePanel
            self.builder.add_from_file(options.gladevcp)
            #self.builder.add_objects_from_file(options.gladevcp, ['vcp1'])
            self.vcp_parent.add(self.builder.get_object('vcp1'))

            self.comp = hal.component(options.comp or 'camview')
            self.panel = GladePanel(self.comp, '', self.builder, None)
            self.comp.ready()
            if options.hal:
                import subprocess
                subprocess.call(['halcmd', '-f', options.hal])
            window.connect('destroy', lambda *a: self.comp.exit())
            expander = self.builder.get_object('expander_control')
        else:
            self.comp = None

    def on_expander_control_activate(self, widget):
        # XXX: Not working on hardy
        #self.vcp_parent.set_visible(widget.get_expanded())
        if widget.get_expanded():
            self.vcp_parent.show()
        else:
            self.vcp_parent.hide()

    def create_chain(self, options):
        m = camunits.Manager()
        c = camunits.Chain()
        for p in m.list_package('input', True):
            if p.get_unit_id() in ['input.example', 'input.log']:
                continue
            c.add_unit_by_id(p.get_unit_id())
            break
        else:
            print "No input plugins found"
            sys.exit(1)
        c.add_unit_by_id('convert.to_rgb8')
        c.add_unit_by_id('output.opengl')
        c.add_unit_by_id('emc.halio')
        if options.crosshair:
            c.add_unit_by_id('emc.crosshair')
        return c

    def change_format(self, w):
        f = w.get_model()[w.get_active()][1]
        if f is None:
            return
        u = self.glwidget.get_chain().get_units()[0]
        cf = u.get_output_format()
        if cf and cf.name == f.name:
            return
        self.glwidget.set_active(False)
        u.set_preferred_format(f.pixelformat, f.width, f.height, f.name)
        self.glwidget.set_active(True)

    def change_color(self, c):
        for u in self._units_color:
            u.set_control_float('color-r', c.red/65535.)
            u.set_control_float('color-g', c.green/65535.)
            u.set_control_float('color-b', c.blue/65535.)

    def change_xor(self, c):
        for u in self._units_color:
            u.set_control_boolean('gl-xor', c)

    def change_spacing(self, v):
        for u in self._units_color:
            u.set_control_int('spacing', int(v))

    def change_circle(self, v):
        for u in self._units_cross:
            u.set_control_int('circle-radius', int(v))

    def change_circle_enable(self, v):
        for u in self._units_cross:
            u.set_control_boolean('circle-enable', v)

    def save(self, w=None):
        buttons = (gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN,gtk.RESPONSE_OK)
        chooser = gtk.FileChooserDialog(title=None,action=gtk.FILE_CHOOSER_ACTION_SAVE,buttons=buttons)
        if self.chain_file:
            chooser.set_current_name(self.chain_file)
        chooser.set_do_overwrite_confirmation(True)

        response = chooser.run()
        if response == gtk.RESPONSE_OK:
            self.chain_file = chooser.get_filename()
            data = self.glwidget.get_chain().snapshot()
            fp = open(self.chain_file, 'w')
            fp.write(data)
            fp.close()
        elif response == gtk.RESPONSE_CANCEL:
            pass
        chooser.destroy()

options, args = parser.parse_args()

view = EmcView(options)
try:
    gtk.main()
finally:
    if view.comp:
        view.comp.exit()
