# -*- coding: utf-8 -*-
#
# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

# Import guard for OpenCV.
try:
    import cv
    import cv2
except ImportError:
    # We can't raise error because it will fail the interpreter.
    pass

import gtk
import glib
import pango
import numpy

from autotest_lib.client.cros import factory_setup_modules
from cros.factory.test import factory
from cros.factory.test import ui as ful

# OpenCV will automatically search for a working camera device if we use the
# index -1.
DEFAULT_DEVICE_INDEX = -1

DEFAULT_WIDTH = 640
DEFAULT_HEIGHT = 480

PREFERRED_FPS = 30
PREFERRED_INTERVAL = int(round(1000.0 / PREFERRED_FPS))

GDK_PIXBUF_BIT_PER_SAMPLE = 8

LABEL_FONT = pango.FontDescription('courier new condensed 16')

class CameraPreview(object):
    '''Camera preview class.'''

    def __init__(
        self,
        msg,
        key_action_mapping,
        device_index=DEFAULT_DEVICE_INDEX,
        width=DEFAULT_WIDTH,
        height=DEFAULT_HEIGHT):
        '''Initializes and creates a preview widget.

        @param key_action_mapping: a dictionary to indicate function to invoke.
        @param device_index: an integer passed to OpenCV to detect video
                             capture device.
        @param width: the width of the preview image.
        @param height: the height of the preview image.
        @param msg: message to display on the preview widget.
        '''

        self.gio_tag = None
        self.key_action_mapping = key_action_mapping
        self.device_index = device_index

        # Blank images to fill the pixbuf when no device is detected.
        self.blankImg = numpy.zeros((height, width, 3), dtype=numpy.uint8)

        self.label = label = gtk.Label(msg)
        label.modify_font(LABEL_FONT)
        label.modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse('light green'))

        self.widget = gtk.VBox()
        self.widget.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse('black'))
        self.widget.add(label)

        # Initialize the canvas.
        self.width = width
        self.height = height
        self.pixbuf = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, False, 8,
            self.width, self.height)
        self.img = gtk.image_new_from_pixbuf(self.pixbuf)
        self.widget.add(self.img)
        self.img.show()

        self.widget.key_callback = self.key_release_callback

    def key_release_callback(self, widget, event):
        factory.log('key_release_callback %s(%s)' %
                    (event.keyval, gtk.gdk.keyval_name(event.keyval)))
        if event.keyval in self.key_action_mapping:
            if self.key_action_mapping[event.keyval] is not None:
                self.key_action_mapping[event.keyval]()
                return True

    def init_device(self, device_index=None, start_capture=True):
        '''Initializes the camera.

        Args:
            device_index: Device index for OpenCV. Default to use the
                          index assigned in the constructor.
            start_capture: True to capture images immediately. False
                           to leave caller decides the timing.
        '''
        if device_index is None:
            device_index = self.device_index
        factory.log('Calling init_device with [%s]' % device_index)
        # Initialize the camera with OpenCV.
        self.dev = dev = cv2.VideoCapture(device_index)
        self.gio_tag = None
        if not dev.isOpened():
            self.dev.release()
            raise IOError(
                'Device #%s does not support video capture interface' %
                device_index)
        dev.set(cv.CV_CAP_PROP_FRAME_WIDTH, self.width)
        dev.set(cv.CV_CAP_PROP_FRAME_HEIGHT, self.height)
        if start_capture:
            self.capture_start()

    def capture_core(self):
        '''Captures an image and displays it.

        The FPS is determined by the camera hardware limit, the gtk display
        overhead and the amount of memory copy operations. This subroutine
        involves 3 copy operations of image data which usually takes less than
        10 ms on an average machine.
        '''
        # Read image from camera.
        ret, cvImg = self.capture_single()

        # Convert from BGR to RGB in-place.
        cv2.cvtColor(cvImg, cv.CV_BGR2RGB, cvImg)

        # Convert to gdk pixbuf format.
        pbuf = gtk.gdk.pixbuf_new_from_data(cvImg.data,
            gtk.gdk.COLORSPACE_RGB, False, GDK_PIXBUF_BIT_PER_SAMPLE,
            cvImg.shape[1], cvImg.shape[0], cvImg.strides[0])

        # Copy to the display buffer.
        pbuf.copy_area(0, 0, pbuf.get_width(), pbuf.get_height(), self.pixbuf,
                       0, 0)

        # Queue for refreshing.
        self.img.queue_draw()

        return True

    def capture_single(self, filename=None):
        # Read image from camera.
        ret, cvImg = self.dev.read()
        if not ret:
            raise IOError('Error while capturing. Camera disconnected?')
        if filename:
            logging.info('Save to file %s' % filename)
            cv2.imwrite(filename, cvImg)
        return (ret, cvImg)

    def capture_start(self):
        # Register the image capturing subroutine using glib.
        # It will be called every PREFERRED_INTERVAL time.
        self.gio_tag = glib.timeout_add(PREFERRED_INTERVAL,
            lambda *x:self.capture_core(),
            priority=glib.PRIORITY_LOW)

    def capture_stop(self):
        self.dev.release()
        # Unregister the image capturing subroutine.
        if self.gio_tag:
            glib.source_remove(self.gio_tag)
            # reset pbuf to blank screen.
            pbuf = gtk.gdk.pixbuf_new_from_data(self.blankImg.data,
                gtk.gdk.COLORSPACE_RGB, False, GDK_PIXBUF_BIT_PER_SAMPLE,
                self.blankImg.shape[1],
                self.blankImg.shape[0],
                self.blankImg.strides[0])
            # Copy to the display buffer.
            pbuf.copy_area(0, 0, pbuf.get_width(), pbuf.get_height(),
                           self.pixbuf, 0, 0)
            # Queue for refreshing.
            self.img.queue_draw()
