#!/usr/bin/env python2
# Copyright 2002 Jeremy Bornstein <jeremy@jeremy.org>
# Based on information and earlier program by Nelson Zink, from http://www.navaching.com/shaku/ergon.html

import md5
import time
import sys
import os
import string
import time
import cgi
import Cookie
import urllib


if os.environ.has_key ('SCRIPT_NAME'):
    myName = os.environ['SCRIPT_NAME']
else:
    myName = 'something' #figure out this later if necessary


def debugmsg (msg):
    timeStr = time.asctime ()
    sys.stderr.write ('%s: %s\n' % (timeStr, msg))


def getScriptURI ():
    if os.environ.has_key ('SCRIPT_URI'):
        scriptURI = os.environ['SCRIPT_URI']
    else:
        httpHost = os.environ['HTTP_HOST']
        requestURI = os.environ['REQUEST_URI']
        scriptURI = 'http://%s%s' % (httpHost, requestURI)
    return scriptURI

def getDefaultParameters ():
    params = {}
    params['fluteLength'] = 650
    params['holeDiameter'] = 10
    params['boreDiameter'] = 20.5
    params['wallThickness'] = 3 * 1.125
    params['ergonomicLimit'] = 60
    return params



def getParametersFromForm (form):
    params = {}

    fluteLength = form.getvalue ('fluteLength')
    if fluteLength == None:
        fluteLength = ''
    params['fluteLength'] = fluteLength

    holeDiameter = form.getvalue ('holeDiameter')
    if holeDiameter == None:
        holeDiameter = ''
    params['holeDiameter'] = holeDiameter

    boreDiameter = form.getvalue ('boreDiameter')
    if boreDiameter == None:
        boreDiameter = ''
    params['boreDiameter'] = boreDiameter

    wallThickness = form.getvalue ('wallThickness')
    if wallThickness == None:
        wallThickness = ''
    params['wallThickness'] = wallThickness

    ergonomicLimit = form.getvalue ('ergonomicLimit')
    if ergonomicLimit == None:
        ergonomicLimit = ''
    params['ergonomicLimit'] = ergonomicLimit

    return params


def getHTMLForErrors (errors):
    errorCount = len (errors)
    if errorCount == 0:
        return ''
    
    result = []
    result.append ('<table cellpadding=20 border=1 bordercolor="#FF0000">')
    result.append ('<tr><td>')

    if errorCount == 1:
        result.append ('Before proceeding, please correct the following error:')
    else:
        result.append ('Before proceeding, please correct the following errors:')
    result.append ('<ul>')
    result.append ('<font color=red>')

    for error in errors:
        result.append ('<li>')
        result.append (error)

    result.append ('</font>')
    result.append ('</ul>')
    result.append ('</td></tr>')
    result.append ('</table>')
    return string.join (result, '\n')


# we're already inside a <form> tag
def getHTMLForForm (params):
    result = []
    result.append ('<table>')
    result.append ('<tr><th align=right>Flute Length</th>')
    result.append ('<td><input type=text name=fluteLength value="%s"></td></tr>' % params['fluteLength'])
    result.append ('<tr><th align=right>Hole Diameter</th>')
    result.append ('<td><input type=text name=holeDiameter value="%s"></td></tr>' % params['holeDiameter'])
    result.append ('<tr><th align=right>Bore Diameter</th>')
    result.append ('<td><input type=text name=boreDiameter value="%s"></td></tr>' % params['boreDiameter'])
    result.append ('<tr><th align=right>Wall Thickness</th>')
    result.append ('<td><input type=text name=wallThickness value="%s"></td></tr>' % params['wallThickness'])
    result.append ('<tr><th align=right>Ergonomic Limit</th>')
    result.append ('<td><input type=text name=ergonomicLimit value="%s"></td></tr>' % params['ergonomicLimit'])
    result.append ('</table>')
    result.append ('<input type=submit name=calculate value="Calculate">')
    return string.join (result, '\n')
    

def getOutputFromInput (params):
    result = []

    TL = float(params['fluteLength'])
    Dh = float(params['holeDiameter'])
    BaseNote = 156521.0 / float(TL)
    Db = float(params['boreDiameter'])
    Wt = float(params['wallThickness'])
    Te = Wt + (0.75 * Dh)
    BigNum = 165674
    TubeLength = BigNum / BaseNote
    MEL = TubeLength - (0.3 * Db) - TL

    LastLength = TubeLength
    temp = 0
    HoleLocations = []
    Interval = [3, 2, 2, 3, 2]

    zz = 0
    for thisInterval in Interval:
        zz = zz + 1
        temp = temp + thisInterval
        Hz = BaseNote * pow(2,(temp/12.0))
        NewLength = BigNum / Hz
        S = (LastLength - NewLength) / 2.0
        CF = S*(  (     pow(((   (      (Te/S)*  pow(Db/Dh,2)     )   *2)+1),0.5)    )   -1)
        HoleLocation = round (NewLength-MEL-CF)
        #HoleLocation = NewLength-MEL-CF
        HoleLocations.append (HoleLocation)

        LastLength = NewLength + CF


    HoleLocations.reverse ()

    ErgoSpan = float(params['ergonomicLimit'])
    ThumbS = HoleLocations[1] - HoleLocations[0]
    TopS = HoleLocations[2] - HoleLocations[1]
    BottomS = HoleLocations[4] - HoleLocations[3]

    AlternateHoleLocations = [None, None, None, None, None]

    if ThumbS > (ErgoSpan * 2.0 / 3.0):
        AlternateHoleLocations[0] = HoleLocations[1] + (ErgoSpan * 2.0 / 3.0)
    if TopS > ErgoSpan:
        AlternateHoleLocations[2] = HoleLocations[1] + ErgoSpan
    if BottomS > ErgoSpan:
        AlternateHoleLocations[4] = HoleLocations[3] + ErgoSpan

    IInch = TL / 25.4
    AspectRatio = TL/Db


    result.append ('<table>')
    result.append ('<tr><th align=right>%s</th><td>%.2f Hz</td></tr>' %
                   ('Base Frequency', BaseNote))
    result.append ('<tr><th align=right>%s</th><td>%.2fmm</td></tr>' % ('Flute Length', TL))
    result.append ('<tr><th align=right>%s</th><td>%.2f</td></tr>' % ('Aspect Ratio', AspectRatio))
    result.append ('<tr><th align=right>%s</th><td>%.2fmm</td></tr>' % ('Hole diameter',Dh))

    for hole in range (0, len(HoleLocations)):
        if AlternateHoleLocations[hole] == None:
            result.append ('<tr><th align=right>Hole #%d</th><td>%dmm from top of flute</td></tr>' %
                           (5-hole,HoleLocations[hole]))
        else:
            result.append ('<tr><th align=right>Hole #%d</th><td>%dmm (%dmm) from top of flute</td></tr>' %
                           (5-hole,HoleLocations[hole],AlternateHoleLocations[hole]))


    result.append ('<tr><th align=right>%s</th><td>%dmm</td></tr>' % ('Span 5<->4',ThumbS))
    result.append ('<tr><th align=right>%s</th><td>%dmm</td></tr>' % ('Span 4<->3',TopS))
    result.append ('<tr><th align=right>%s</th><td>%dmm</td></tr>' % ('Span 2<->1',BottomS))
        
    result.append ('</table>')

    return string.join (result, '\n')



trulyStaticOpening = """
<html> 
<head>
<title>Shakuhachi Calculation</title>
</head> 
<body>
<p><strong>Attention!</strong> This version is obsolete. Please use the new version from now on: <a href="http://jeremy.org/music/shakutool.html">http://jeremy.org/music/shakutool.html</a></p>

"""


trulyStaticClosing = """
</body> 
</html>
"""

def getStaticOpening ():
    return trulyStaticOpening

def getStaticClosing ():
    return trulyStaticClosing


form = cgi.FieldStorage ()

isCalculate = form.getvalue ('calculate') != None

errors = []

staticOpening = getStaticOpening ()
staticClosing = getStaticClosing ()


if isCalculate and len(errors) == 0:
    params = getParametersFromForm (form)
    print "Content-Type: text/html"
    print ""
    print staticOpening
    print '<h1>results</h1>'
    print getOutputFromInput (params)
    print staticClosing
else:
    params = getDefaultParameters ()
    print "Content-Type: text/html"
    print ""
    print staticOpening
    print '<form action="%s" method=get>' % myName
    print getHTMLForForm (params)
    print '</form>'
    print staticClosing



