import e32
import appuifw
import math
import graphics

# list of f-stops and N values
fstops=[('f1', 0.0), ('f1.2', 1.18946), ('f1.4', 1.0), ('f1.6', 1.3333), ('f1.7', 1.5), ('f1.8', 1.6666), ('f2.0', 2.0), ('f2.2', 2.333), ('f2.4', 2.5), ('f2.5', 2.6666), ('f2.8', 3.0), ('f3.2', 3.333) , ('f3.4', 3.5), ('f3.6', 3.666), ('f4.0', 4.0), ('f4.5', 4.333), ('f4.8', 4.5) , ('f5.0', 4.666 ), ('f5.6', 5.0), ('f6.4', 5.333), ('f6.7', 5.5), ('f7.1', 5.666) , ('f8.0', 6.0), ('f9.0', 6.333), ('f9.5', 6.5) , ('f10', 6.666), ('f11', 7.0), ('f12.7', 7.333), ('f13.5', 7.5 ), ('f14.3', 7.666), ('f16', 8.0), ('f18', 8.333 ), ('f19', 8.5 ), ('f20', 8.6666 ) , ('f22', 9.0 ), ('f25', 9.333 ), ('f27', 9.5 ), ('f28', 9.666 ), ('f32', 10.0 ), ('f45', 11.0 ), ('f64', 12.0 ) ]

# confusion diameter (for oly E-510 c == 0.015)
#c=0.015
cd=[ ('35mm', 0.03), ('1.3x DSLR', 0.023), ('1.5x DSLR', 0.02), ('1.6x DSLR', 0.01875), ('2x DSLR', 0.015), ('6x5', 0.05), ('6x6', 0.06), ('6x7', 0.065), ('6x9', 0.075), ('4x5', 0.150) , ('5x7', 0.2 ), ('8x10', 0.3 )]


# global vars
c = ''
H = ''
Tot = ''
Front = ''
Behind = ''

#########################################################################################
def calculate_DoF(fstop):
  global H, Tot, Behind, Front, c

  N=math.pow(2.0,(fstop/2.0))

  # Hyperfocal distance
  H=(f*f)/(N*c)+f

  #Near distance of acceptable sharpness:
  Dn=s*1000.0*(H-f)/(H+(s*1000.0)-2.0*f)
  
  #Far distance of acceptable sharpness:
  Df=s*1000.0*((H)-f)/((H)-(s*1000.0))

  #Total
  Tot=Df-Dn

  # behind subject
  Behind=Df-s*1000.0
  
  # in front of the subject
  Front=s*1000.0-Dn

  return [H, Dn, Df, Tot, Front, Behind]

#########################################################################################
def build_choices(elements,action):
	ch = []
	for element in elements:
		ch.append((u""+element[0]+"",action))
  
	return ch

######################################################################################### 
def handle_selection():
    global lb, choices, choices_labels, c

    index = lb.current()
    code = choices[index][1]
    lb.set_list([u"Please wait..."])

    if code == "cd_select":
        c = cd[index][1]
        # now we have to select the aperture
        choose_aperture()
    elif code == "aperture":
        selected=fstops[index][1]
        result = calculate_DoF(selected)
        display_result(fstops, f, s, c, result, index)
    else:
        appuifw.note(u"no valide code detected", 'error')
    #lb.set_list(choices_labels)

#########################################################################################
def callback(event):
    print event

#########################################################################################
def draw_state():
    appuifw.app.body = canvas

#########################################################################################
def select_aperture():
    appuifw.app.body = lb

#########################################################################################
def exit_key_handler():
    appuifw.app.title = old_title
    appuifw.app.body = None
    app_lock.signal()

#########################################################################################
def choose_conf_diam():
  global lb, choices, choices_labels
  choices = build_choices(cd,"cd_select") 
  choices_labels = [x[0] for x in choices]
  lb = appuifw.Listbox(choices_labels, handle_selection)
  appuifw.app.title = u"Conf. diam"
  appuifw.app.body = lb

#########################################################################################
def choose_aperture():
  global lb, choices, choices_labels
  choices = build_choices(fstops,"aperture")
  choices_labels = [x[0] for x in choices]
  lb = appuifw.Listbox(choices_labels, handle_selection)
  appuifw.app.title = u"Sel. aperture" 
  appuifw.app.body = lb

#########################################################################################
def display_result(fstops, f, s, c, result, index):
  Df = result[2]
  if Df < 0:
    Df = 'Inf'
  else:
    Df = round(Df/1000,2).__str__() + "m"
  Dn = result[1]
  if Dn < 0:
    Dn = 'Inf'
  else:
    Dn = round(Dn/1000,2).__str__() + "m"
  Tot = result[3]
  if Tot < 0:
    Tot = 'Inf'
  else:
    Tot = round(Tot/1000,2).__str__() + "m"
  Behind = result[5]
  if Behind < 0:
    Behind = 'Inf'
  else:
    Behind = round(Behind/1000,2).__str__() + "m"
  Front = result[4]
  if Front < 0:
    Front = 'Inf'
  else:
    Front = round(Front/1000,2).__str__() + "m"
  
  appuifw.app.title = u"DoF "+fstops[index][0].__str__() + "@" + f.__str__() + "mm ->" + s.__str__() + "m"
  appuifw.app.body = canvas
  canvas.clear()
  canvas.text( (10,25), u"Depth of Field", font= ('title',26, graphics.FONT_BOLD | graphics.FONT_ITALIC))
  canvas.text( (10,50), u"Near limit", font='normal')
  canvas.text( (120,50), u":%-9.9s" % Dn, font='normal')
  canvas.text( (10,70), u"Far limit", font='normal')
  canvas.text( (120,70), u":%-9.9s" % Df, font='normal')
  canvas.text( (10,90), u"Total", font='normal')
  canvas.text( (120,90), u":%-9.9s" % Tot, font='normal')
  canvas.text( (10,110), u"In front", font='normal')
  canvas.text( (120,110), u":%-9.9s" % Front, font='normal')
  canvas.text( (10,130), u"Behind", font='normal')
  canvas.text( (120,130), u":%-9.9s" % Behind, font='normal')
  canvas.text( (10,150), u"%-21.21s %s" % ("Hyperfocal distance: ", round(result[0]/1000,2).__str__() + "m"), font='legend')
  canvas.text( (10,170), u"%-21.21s %s" % ("Circle of confusion: ", c.__str__() + "mm"), font='legend')

def run_select():
  # select the confusion diameter
  choose_conf_diam()

  #appuifw.app.body = canvas
  appuifw.app.menu = [(u"Choose aperture", choose_aperture)]

#########################################################################################
if __name__ == '__main__':

  appuifw.app.exit_key_handler = exit_key_handler

  old_title = appuifw.app.title
 
  # s = lenght from subject in meters
  #s = 10.0
  s = appuifw.query(u"Enter the distance to the subject (m)", "number", 10)

  # lens focal length
  f = appuifw.query(u"Enter the lense focal length (mm)", "number", 55)

  # global vars
  lb = ''
  choices = ''
  choices_labels = ''
  canvas = appuifw.Canvas() #event_callback=callback, redraw_callback=lambda rect:draw_state())
  #screen_width,screen_height = canvas.size
  appuifw.app.body = canvas
  
  app_lock = e32.Ao_lock()

  run_select()

app_lock.wait()
   
appuifw.app.title = old_title
