"""mems.instrument.hardware.pxc_200

Driver for the Polaroid DMC camera.
"""

__revision__ = "$Id: dmc.py,v 1.8 2002/03/29 17:03:22 akuchlin Exp $"

import fcntl, os, struct, sys, tempfile, time
import sane

from PIL import Image
from mems.instrument import protocols
from mems.instrument.server import util
from mems.instrument.server.configuration import get_configuration

# Debugging flag to print timing messages
__timing__ = 0

# Global variable holding the camera object
camera = None

# Global variable holding the name of a temporary file that will be used
# for the life of this process.
image_path = tempfile.mktemp(suffix='.jpg')

# Global: desired image size
x_requested, y_requested = (320,240)

class DMC:
    """Class for controlling the Polaroid DMC.

    Methods:
    get_image            Return a PIL Image object containing the current image
    get_hires_image      Return a high-resolution image as an Image object
    close                Put the camera to bed
    
    Attributes:
    image_size           Size of image to return
    """
    
    def __init__ (self):
	"Open serial port connections and initialize instance variables."

        self.image_size = (320,240)
	self.__camera = None
	self.open()


    def open (self):
        # Open the camera device, and set its parameters to 
        # reasonable values. 
	self.close()        
        self.__camera = sane.open('dmc:/dev/camera')
        self._set_imagemode()
        self.__camera.shutterspeed = 100


    def _set_imagemode (self):
        """_set_imagemode() : select an appropriate DMC mode depending on 
        the selected image size.
        """
        image_size = self.image_size
	if image_size == (80,60): mode = 'Thumbnail'
	elif image_size == (270,201): mode = 'Viewfinder'
	elif image_size == (320,240): mode = 'Full frame'
	elif image_size == (801,600): mode = 'Full frame'
	elif image_size == (1599,1200): mode = 'Super-Resolution'
	else:
    	    raise ValueError, ('Unsupported image size %s for DMC' 
	                       % (image_size,))

	self.__camera.imagemode = mode

    def set(self, **kw):
        params_used = []

        if kw.has_key('ASA'):
            params_used.append( 'ASA' )
            value = kw['ASA']
            self.__camera.asa = value
            
        if kw.has_key('shutterspeed'):
            params_used.append( 'shutterspeed' )
            value = kw['shutterspeed']
            self.__camera.shutterspeed = value

        if kw.has_key('white_balance'):
            params_used.append( 'white_balance' )
            value = kw['white_balance']
            self.__camera.whitebalance = value
            
        # Change the selected image size
        if kw.has_key('image_size'):
            params_used.append('image_size')
            image_size = kw['image_size']

            # Only set the camera's mode if the size actually changed
            if image_size != self.image_size:
                self.image_size = image_size
		self._set_imagemode()
                
        return params_used
    
    def get_image(self):
        "Grab an image from the camera & return it"
        t1 = time.time()
        self.__camera.start()

        t2 = time.time()
        image = self.__camera.snap()
        
        t3 = time.time()

        if __timing__:
            print "Start, snap: ", t2-t1, t3-t2
            print '*** Low-level get_image time:', t3 - t1

        return image

    def get_hires_image(self):
        "Grab a high-resolution image from the camera & return it"

        t1 = time.time()
        old_image_size = self.image_size
        self.set(image_size = (801,600))

        self.__camera.start()
        t2 = time.time()
        image = self.__camera.snap()

        self.set(image_size = old_image_size)
        
        t3 = time.time()
        if __timing__:
            print "Start, snap: ", t2-t1, t3-t2
            print '*** Low-level get_image time:', t3 - t1

        return image

    def close(self):
        "Put the camera to bed when shutting down"
	if self.__camera is not None:
	    self.__camera.close()
            self.__camera = None
        

def do_snapshot ():
    image = camera.get_image()
    image = image.resize( (x_requested, y_requested) )
    
    # Write the image data to a temporary file
    path = tempfile.mktemp(suffix='.jpg')
    image.save(path)

    # Atomically move the temporary file to the final filename.
    os.rename(path, image_path)
    
    util.send_message("network_server",
                       "image path=%s hires=no" % image_path)


def do_hires ():
    image = camera.get_hires_image()
    # Write the image data to a temporary file
    path = tempfile.mktemp(suffix='.jpg')
    image.save(path)

    # Atomically move the temporary file to the final filename.
    os.rename(path, image_path)
    
    util.send_message("network_server",
                       "image path=%s hires=yes" % image_path)


def do_size (x, y):
    # Select the size made available by the camera that's required to
    # support the requested image size.
    global x_requested, y_requested
    x_requested, y_requested = x,y
    
    if x <= 270 and y <= 201:
        camera.set(image_size = (270,201))
    elif x <= 320 and y <= 240:
        camera.set(image_size = (320,240))
    else:
        camera.set(image_size = (801,600))

    camera.open()
        


def loop ():
    "Main loop for the camera process"
    
    config = get_configuration()
    while 1:
        if util.has_input_waiting(sys.stdin):
            line = sys.stdin.readline()
            cmd, args = protocols.parse_message_line(line)
            if config.get_debug():
                print '%s: Received command %s %r' % (__name__, cmd, args)
                
            if cmd == 'quit':
                if config.get_debug():
                    print '%s: exiting' % __name__
                break

            elif cmd == "snapshot":
                do_snapshot(**args)
            elif cmd == "hires":
                do_hires(**args)
            elif cmd == "size":
                do_size(**args)
            else:
                raise RuntimeError, ("Unknown command %r args=%r" % (cmd, args))

    
def main ():
    global camera
    camera = DMC()
    
    # Run main loop, and be sure to delete the temporary file
    # (XXX this may be a bit too much tidiness; after a 'quit' is sent
    # to the camera process, the network server can then crash because
    # the image file is no longer there.)
    try:
        loop()
    finally:
        try:
            os.unlink(image_path)
        except os.error:
            pass
        
    return 

