import e32
import appuifw
import math

# 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
c=0
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 )]



H = ''
Tot = ''
Front = ''
Behind = ''
After = ''

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

  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]
        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
    elif code == "aperture":
        selected=fstops[index][1]
        result = calculate_DoF(selected)
        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"
        textEditor = appuifw.Text()
        textEditor.font = 'normal'
        textEditor.style = textEditor.style | appuifw.STYLE_BOLD | appuifw.HIGHLIGHT_SHADOW
        textEditor.add(u"Depth of Field\n\n")
        textEditor.style = 0
        textEditor.font = 'symbol'
        strlg = 12
        str = 'Near limit'
        textEditor.add(u"%s%s: %8s" % (str, (strlg-len(str))*'.', Dn + "\n"))
        str = 'Far limit'
        textEditor.add(u"%s%s: %8s" % (str, (1+strlg-len(str))*'.', Df + "\n"))
        str = 'Total'
        textEditor.add(u"%s%s: %8s" % (str, (3+strlg-len(str))*'.',Tot + "\n")) 
        str = 'In front'
        textEditor.add(u"%s%s: %8s" % (str, (1+strlg-len(str))*'.', Front + "\n"))
        str = 'Behind'
        textEditor.add(u"%s%s: %8s" % (str, (1+strlg-len(str))*'.', Behind + "\n\n"))
        textEditor.add(u"%21.21s %s" % ("Hyperfocal distance: ", round(result[0]/1000,2).__str__() + "m\n") + "%21.21s %s" % ("Circle of confusion: ", c.__str__() + "mm\n"))
        appuifw.app.body = textEditor 
		#appuifw.Text(u"Depth of Field\n" + "Near limit: " + round(result[1]/1000,2).__str__() + "m\n" + "Far limit: " + round(result[2]/1000,2).__str__() + "m\n" + "Total: " + round(result[3]/1000,2).__str__() + "m\n" + "In front: " + round(result[4]/1000,2).__str__() + "m\n" + "Behind: " + round(result[5]/1000,2).__str__() + "m\n\n" + "Hyperfocal distance: " + round(result[0]/1000,2).__str__() + "m\n" + "Circle of confusion: " + c.__str__() + "mm\n")
        appuifw.app.exit_key_handler = exit_key_handler
    else:
        appuifw.note(u"no valide code detected", 'error')
    lb.set_list(choices_labels)
 
def select_aperture():
    appuifw.app.body = lb

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


if __name__ == '__main__':

  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")

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

  appuifw.app.title = u"Conf. diam"
  choices = build_choices(cd,"cd_select") 
  choices_labels = [x[0] for x in choices]
  lb = appuifw.Listbox(choices_labels, handle_selection)
  
  appuifw.app.body = lb
  appuifw.app.menu = [(u"Choose aperture", select_aperture)]
  appuifw.app.exit_key_handler = exit_key_handler
   
  app_lock = e32.Ao_lock()
  app_lock.wait()
   
  appuifw.app.title = old_title
