import appuifw, e32, camera, time, string
from camera import *
from key_codes import *
full_path_str = 'E:\\Images\\%s.jpg'
pic_name_str = ''
location_i = 1   # 0 for phone memory, 1 for memory card
print_date_i = 1 # print the date on the picture
sizes = image_sizes()
#------------- location_i -----------------
def save_on_c():
    global full_path_str, location_i
    full_path_str = 'C:\\Data\\Images\\%s.jpg'
    location_i = 0
def save_on_e():
    global full_path_str, location_i
    full_path_str = 'E:\\Images\\%s.jpg'
    location_i = 1
#--------------- white balance ----------
white_bal_str = 'auto'
def whbal_auto():
    global white_bal_str
    white_bal_str = 'auto'
def whbal_daylight():
    global white_bal_str
    white_bal_str = 'daylight'
def whbal_cloudy():
    global white_bal_str
    white_bal_str = 'cloudy'
def whbal_fluorescent():
    global white_bal_str
    white_bal_str = 'fluorescent'
def whbal_tungsten():
    global white_bal_str
    white_bal_str = 'tungsten'
#------------ picture size --------------
pic_size_tup = max(sizes)
def set_max():
    global pic_size_tup
    pic_size_tup = max(sizes)
def set_vga():
    global pic_size_tup
    pic_size_tup = (640,480)
#--------- date printing ---------------
def date_printing_on():
    global print_date_i
    print_date_i = 1 
def date_printing_off():
    global print_date_i
    print_date_i = 0 


class Keyboard(object):
    def __init__(self, onevent=lambda:None):
        self._keyboard_state = {}
        self._downs = {}
        self._onevent = onevent
 
    def handle_event(self, event):
        if event['type'] == appuifw.EEventKeyDown:
            code = event['scancode']
            if not self.is_down(code):
                self._downs[code] = self._downs.get(code, 0) + 1
            self._keyboard_state[code] = 1
        elif event['type'] == appuifw.EEventKeyUp:
            self._keyboard_state[event['scancode']] = 0
        self._onevent()
 
    def is_down(self, scancode):
        return self._keyboard_state.get(scancode, 0)
 
    def pressed(self, scancode):
        if self._downs.get(scancode, 0):
            self._downs[scancode] -= 1
            return True
        return False


class Camera(object, appuifw.Canvas):
 
    def __init__(self, aHandleEvent):
        self._iReady = False
        self._iTempImage = None
        self._iSaving = False
        self._iSaved = False
        self._iViewerActive = False
        appuifw.Canvas.__init__(self, self._redrawCallback, aHandleEvent)
        appuifw.app.body = self
        self._iReady = True
 
    def _redrawCallback(self, aRect=None):
        self.clear()
        if self._iTempImage:
            self.blit(self._iTempImage, target=(0, 0))

        if self._iReady:
            x = self.size[0]
            y = self.size[1]
            x_025 = x/4
            x_033 = x/3
            x_05  = x/2
            x_066 = x*2/3
            x_075 = x*3/4
            y1 = 20
            y2 = 40
            x1 = 10
            x2 = 110
            # background colour
            self.rectangle((0, 0, x, y), fill=0x000080)
            # outline rectangle
            self.rectangle((0, 0, x, y2+5), outline=0xC0FFFF)
            # notify user to wait
            self.text((x_05-60, y/2), u'Please wait...', 0xA0FFA0, u'SwissA')
            # status bar
            self.line((x2-5, 0, x2-5, y2+5),0xC0FFFF) # vertical delimiter
            # --------------- picture size status ----------------
            self.text((x1, y1), u'Size:', 0x50FFFF)
            offset = 50
            if pic_size_tup == (640,480):
                self.text((x1+offset,y1),u'VGA', 0x60FF60)
            else:
                self.text((x1+offset,y1),u'MAX', 0x60FF60)
            # ---------- print date on picture status ------------
            self.text((x1, y2), u'Date:', 0x50FFFF)
            if print_date_i == 1:
                self.text((x1+offset,y2), u'ON', 0x60FF60)
            else:
                self.text((x1+offset,y2), u'OFF', 0xFF3030)
            # -------------- white balance status -----------------
            self.text((x2, y1), u'Light:', 0x50FFFF)
            offset = 65
            if white_bal_str == 'auto':
                self.text((x2+offset,y1),u'AUTO', 0x60FF60)
            elif white_bal_str == 'cloudy':
                self.text((x2+offset,y1),u'CLOUDY', 0x60FF60)
            elif white_bal_str == 'daylight':
                self.text((x2+offset,y1),u'DAY', 0x60FF60)
            elif white_bal_str == 'fluorescent':
                self.text((x2+offset,y1),u'FLUORESCENT', 0x60FF60)
            elif white_bal_str == 'tungsten':
                self.text((x2+offset,y1),u'TUNGSTEN', 0x60FF60)
            # -------------- location status -----------------------
            self.text((x2,y2), u'Save on:',  0x50FFFF)
            offset = 80
            if location_i == 1:
                self.text((x2+offset,y2), u'memory card',  0x60FF60)
            else:
                self.text((x2+offset,y2), u'phone memory', 0x60FF60)
            # softkeys description
            self.rectangle((0, y-25, x,     y),  0xC0FFFF) # outline rectangle
            self.line((x_033,  y-25, x_033, y),  0xC0FFFF) # first vertical delimiter
            self.line((x_066,  y-25, x_066, y),  0xC0FFFF) # second vertical delimiter
            self.text((     20, y-5), u'Menu',   0x50FFFF) # left softkey
            self.text((x_05-35, y-5), u'Capture',0x50FFFF) # selection key
            self.text((   x-60, y-5), u'Exit',   0x50FFFF) # right softkey

    # show viewfinder on screen
    def _viewFinderRedrawCallback(self, aImage):
        self.blit(aImage, target=((self.size[0]-aImage.size[0])/2,
                                  (self.size[1]-aImage.size[1])/2 + 10))
        self._iTempImage = aImage

    def setActive(self):
        appuifw.app.body = self
        self._redrawCallback()
 
    def startViewFinder(self):
        self._iTempImage = None    # initialize image
        self.showCapture()
        camera.start_finder(self._viewFinderRedrawCallback,
                             size = (self.size[0] * 1.31, self.size[1]))
        self._iSaved = False       # nothing saved yet
        self._iViewerActive = True # viewfinder on
 
    def stopViewFinder(self):
        if self._iViewerActive:
            camera.stop_finder()
            self.showCapture()
            self._iViewerActive = False # viewfinder off
 
    def showCapture(self):
        self._redrawCallback()
 
    def capture(self):
        global pic_name_str, full_path_str
        try:
            self._iSaving = True
            self.stopViewFinder()
            e32.ao_yield()
            # read date and time
            ctime = time.localtime()
            # convert month from number to string
            if ctime[1] == 1:
                month = '-Jan-'
            elif ctime[1] == 2:
                month = '-Feb-'
            elif ctime[1] == 3:
                month = '-Mar-'
            elif ctime[1] == 4:
                month = '-Apr-'
            elif ctime[1] == 5:
                month = '-May-'
            elif ctime[1] == 6:
                month = '-Jun-'
            elif ctime[1] == 7:
                month = '-Jul-'
            elif ctime[1] == 8:
                month = '-Aug-'
            elif ctime[1] == 9:
                month = '-Sep-'
            elif ctime[1] == 10:
                month = '-Oct-'
            elif ctime[1] == 11:
                month = '-Nov-'
            elif ctime[1] == 12:
                month = '-Dec-'
            # picture name to save, something like "11-Jun-2007 12.45.32.jpg"
            pic_name_str = str(ctime[2]) + month + str(ctime[0]) + u' ' + str(ctime[3]) + u'-' + str(ctime[4]) + u'-' + str(ctime[5])
            # date as it appears on the picture 11-Jun-2007  12:45:32
            date  = str(ctime[2]) + month + str(ctime[0]) + u'   ' + str(ctime[3]) + u':' + str(ctime[4]) + u':' + str(ctime[5])
            # take the photo using the settings supplyed
            img = camera.take_photo('RGB',pic_size_tup,0,'none','auto',white_bal_str,0)
            # print date on image only if the size is the biggest and printing is on
            if (pic_size_tup == (1600, 1200)) and (print_date_i == 1):
                # black outline for date
                img.text((1201, 1001), date, 0x000000, u'Nokia Sans TitleSmBd S60')
                img.text((1200, 1001), date, 0x000000, u'Nokia Sans TitleSmBd S60')
                img.text((1199, 1001), date, 0x000000, u'Nokia Sans TitleSmBd S60')
                img.text((1201,  999), date, 0x000000, u'Nokia Sans TitleSmBd S60')
                img.text((1200,  999), date, 0x000000, u'Nokia Sans TitleSmBd S60')
                img.text((1199,  999), date, 0x000000, u'Nokia Sans TitleSmBd S60')
                # date, written in red
                img.text((1200, 1000), date, 0xFF0000, u'Nokia Sans TitleSmBd S60')
            # save the image in 100% quality JPEG
            img.save(full_path_str%pic_name_str, format='JPEG', quality=100, bpp=24, compression='none')
            # saving went fine
            self._iSaved = True
        except Exception, error:
            print error
            # saving failed
            self._iSaved = False
        self._iSaving = False
        self.showCapture()
 
    def isSaved(self):
        return self._iSaved
 
    def isViewerActive(self):
        return self._iViewerActive
 
    def __del__(self):
        if self._iViewerActive:
            camera.stop_finder()
 
# This class, where all the handlers are defined, uses both of the classes above.
class CameraView(object):
    def __init__(self):
        self._iKeyboard = Keyboard(self._keyObserver)
        self._iCamera = Camera(self._iKeyboard.handle_event)
 
    def setActive(self):
        self._iCamera.setActive()
        self._menuDimmer()

    def setViewOn(self):
        self._iCamera.startViewFinder()
        self._menuDimmer()
 
    def _keyObserver(self):
        # select key for capture    
        if self._iKeyboard.pressed(EScancodeSelect) or \
           self._iKeyboard.pressed(EScancodeYes):
            if self._iCamera.isViewerActive():
                self._handleCommands("CAPTURE")
            else:
                self._handleCommands("NEW")
 
        # 3 key for stoping the viewer
        elif self._iKeyboard.pressed(EScancode3):
            if self._iCamera.isViewerActive() and \
                            not self._iCamera.isSaved() :
                self._handleCommands("STOP")
 
 
    def _handleCommands(self, aCommand):
        if aCommand == "NEW":
            self._iCamera.startViewFinder()
            self._menuDimmer()
 
        elif aCommand == "STOP":
            self._iCamera.stopViewFinder()
            self._menuDimmer()
 
        elif aCommand == "CAPTURE":
            appuifw.note(u'Please wait until the picture is saved', 'info', 1)
            self._iCamera.capture()
            self._menuDimmer()
            if self._iCamera.isSaved():
                appuifw.note(u'Saved successfully', 'conf')
            else:
                appuifw.note(u'Failed to save', 'error')
            self._iCamera.startViewFinder()
            self._menuDimmer()
 
        elif aCommand == "EXIT":
            __exit__()
 
    def _menuDimmer(self):
        # create the menu
        menu = [(u'Image size',((u'Maximum', set_max),
                                (u'VGA (640x480)', set_vga)
                                ) 
                 ),
                (u'White balance',((u'Auto',       whbal_auto),
                                   (u'Daylight',   whbal_daylight),
                                   (u'Cloudy',     whbal_cloudy),
                                   (u'Neon',       whbal_fluorescent),
                                   (u'Tungsten',   whbal_tungsten)
                                   )
                 ),
                (u'Print date on image', ((u'On',  date_printing_on),
                                          (u'Off', date_printing_off)
                                          )
                 ),
                (u'Memory in use', ((u'Phone memory', save_on_c),
                                    (u'Memory card',  save_on_e)
                                    )
                 )
               ]
        # append commands
        if self._iCamera.isViewerActive():
            menu.append((u'Stop viewfinder', lambda:self._handleCommands("STOP")))
 
        else:
            menu.append((u'New picture', lambda:self._handleCommands("NEW")))
        menu.append((u'Exit', lambda:self._handleCommands("EXIT")))
 
        appuifw.app.menu = menu
 
    def __del__(self):
        # clean exit
        self._iCamera.__del__()
 
 
def __exit__():
    camView.__del__()
    APP_LOCK.signal()
 
if __name__ == '__main__':
    APP_LOCK = e32.Ao_lock()
    appuifw.app.screen = 'full'
    appuifw.app.exit_key_handler = __exit__
    camView = CameraView()
    camView.setViewOn()
    APP_LOCK.wait()
