#!/usr/bin/python

import sys
from getopt import getopt
import logging
from collections import deque

import cairo

USING_PYGTK = False
APP_NAME = "Axischart"
NUM_SAMPLES = 500
HMARGIN = 20
VMARGIN = 10
CHARTHEIGHT = 40


logger = logging.getLogger(APP_NAME)


class Tester (object):

    def __init__(self):
        super(Tester, self).__init__()
        w = gtk.Window()
        w.set_title(APP_NAME)
        w.connect("destroy", self._destroy_cb)
        d = gtk.DrawingArea()
        num_axes = int(gdk.AXIS_LAST)
        d.set_size_request(NUM_SAMPLES + 2*HMARGIN,
                           VMARGIN + ((CHARTHEIGHT+VMARGIN) * num_axes))
        if USING_PYGTK:
            d.connect("expose-event", self._pygtk_expose_cb)
        else:
            d.connect("draw", self._draw_cb)
        self._axis_ranges = {}  # {axis_num: [min_seen, max_seen]}
        self._axis_values = {}  # {axis_num: deque([val0, ..., valN])}

        e = gtk.EventBox()
        e.connect("button-press-event", self._motion_cb)
        e.connect("motion-notify-event", self._motion_cb)
        e.connect("proximity-in-event", self._motion_cb)
        e.connect("proximity-out-event", self._motion_cb)

        e.add(d)
        w.add(e)

        for a in [e, w, d]:
            a.add_events(gdk.POINTER_MOTION_MASK
                | gdk.PROXIMITY_OUT_MASK
                | gdk.PROXIMITY_IN_MASK
                | gdk.BUTTON_PRESS_MASK
                | gdk.BUTTON_RELEASE_MASK
                | gdk.BUTTON1_MOTION_MASK
                | gdk.ENTER_NOTIFY_MASK )

        if USING_PYGTK:
            logger.info("Enabling extension events for PyGTK")
            for a in [e, w, d]:
                a.set_extension_events(gdk.EXTENSION_EVENTS_CURSOR)

        self.win = w
        self._devices = set()

        #e.connect("realize", self._canvas_realized_cb)

    def run(self):
        self.win.show_all()
        gtk.main()

    def _canvas_realized_cb(self, e):
        print "REALIZED,", e
        if USING_PYGTK:
            e.add_events(gdk.POINTER_MOTION_MASK
                | gdk.PROXIMITY_OUT_MASK
                | gdk.PROXIMITY_IN_MASK
                | gdk.BUTTON_PRESS_MASK
                | gdk.BUTTON_RELEASE_MASK
                | gdk.ENTER_NOTIFY_MASK )
            e.set_extension_events(gdk.EXTENSION_EVENTS_ALL)
            win = e.get_window()

    def _destroy_cb(self, win):
        gtk.main_quit()

    def _pygtk_expose_cb(self, da, event):
        win = da.get_window()
        cr = win.cairo_create()
        self._draw_cb(da, cr)

    def _draw_cb(self, da, cr):
        cr.set_source_rgb(1, 1, 1)
        cr.paint()
        axis_ids = set(self._axis_ranges.keys())
        axis_ids.intersection_update(set(self._axis_values.keys()))
        for i in sorted(axis_ids):
            cr.set_source_rgb(0,0,0)
            cr.set_line_width(1)
            cr.set_line_cap(cairo.LINE_CAP_SQUARE)
            vmin, vmax = self._axis_ranges[i]
            assert vmax-vmin > 0
            values = self._axis_values[i]
            for x, v in enumerate(values):
                x += HMARGIN
                y0 = (i*(VMARGIN+CHARTHEIGHT)) + CHARTHEIGHT/2.0
                y = y0 + (CHARTHEIGHT*v) / (-2.0*(vmax-vmin))
                cr.move_to(x+0.5, y0+0.5)
                cr.line_to(x+0.5, y+0.5)
                cr.stroke()

    def _record_axis_value(self, i, value):
        vmin, vmax = self._axis_ranges.get(i, (0.0, 1.0))
        self._axis_ranges[i] = (min(vmin, value), max(vmax, value))
        values = self._axis_values.get(i, None)
        if values is None:
            values = deque(maxlen=NUM_SAMPLES)
            self._axis_values[i] = values
        values.append(value)

    def _motion_cb(self, widget, event):
        print event.type
        dev = event.device
        if dev not in self._devices:
            src = dev.get_source()
            #if dev.get_source() != gdk.SOURCE_MOUSE:
            #print dir(dev)
            #print dir(event)
            dev.set_mode(gdk.MODE_SCREEN)
            self._devices.add(dev)
            return

        d = event.device
        num_axes = int(gdk.AXIS_LAST)
        for i in xrange(num_axes):
            use = gdk.AxisUse(i)
            if use == gdk.AXIS_IGNORE:
                continue
            value = event.get_axis(use)
            if value is None or str(value) == 'nan':
                continue
            self._record_axis_value(i, value)
            if use == gdk.AxisUse.PRESSURE:
                print value
        widget.queue_draw()

if __name__ == '__main__':
    logging.basicConfig(level=logging.DEBUG)
    optnvals, args = getopt(sys.argv[1:], "p", ["pygtk"])
    optnvals = dict(optnvals)
    if not ("-p" in optnvals or "--pygtk" in optnvals):
        import pygtkcompat
        pygtkcompat.enable()
        pygtkcompat.enable_gtk(version='3.0')
        logger.info("Using GTK3 via pygtkcompat")
        USING_PYGTK = False
    else:
        logger.info("Using PyGTK directly")
        USING_PYGTK = True

    import gtk
    from gtk import gdk
    tester = Tester()
    tester.run()

