source: tmcsimulator/branches/LCSv2/controllers/default.py @ 641

Revision 641, 24.0 KB checked in by jdalbey, 5 years ago (diff)

LCSv2.default.py modified for #254. Changed studentnames file reading.

Line 
1# added comments for testing
2# Constants
3kLogfile = "LCSlogfile.txt"
4kSimtimefile = "sim_elapsedtime.json"  #"../webapps/dynamicdata/sim_elapsed_time.json"
5hwys = ['','1','5', '22', '55', '57', '73', '74', '91', '133', '142', '241', '261', '405', '605']
6hwyDirections = ['','NB', 'SB', 'NB/SB','EB','WB','EB/WB']
7# Names to appear in the username dropdown box
8users = []
9users.append('')
10# Show the login page
11def index():
12    userfile = open('student_names.txt','r')
13    # read the file into a buffer
14    buffer = [line.strip() for line in userfile.readlines()]
15    # Append each name in the buffer to the users list, skipping blank lines
16    for item in buffer:
17        if len(item) > 0:
18            users.append(item)
19    # build the form
20    form = FORM(LABEL('User:',_for='username', _class="label username-label"),
21                #INPUT(_name='username', _size='15', _style="font-size: 18px;"), BR(),
22                SELECT(users,_name='username',requires=IS_LENGTH(minsize=1,error_message='Must select a user from the list.')),BR(),
23                INPUT(_type='submit',_value="Log in", _class=" btn btn-primary", _style="margin-top: 3%;"))
24    if form.process().accepted:
25        # Put the username entry into the session variable
26        session.username = reverseNameFields(form.vars.username)
27        redirect(URL('home'))
28    return dict(form=form)
29def home():
30    return dict(name=session.username)
31def help():
32    return dict()
33# List all the current records in the database - remove in final application
34def list():
35    highways = db().select(db.closures.ALL, orderby=db.closures.closureid)
36    return dict(highways = highways)
37# Show details of a single record - remove in final application
38def show():
39    # Retrieve the requested log entry from the database
40    # Assumes the requested entry exists in the db (no error handling yet)
41    hwy = db(db.closures.lognum == request.args(0)).select().first()
42    return dict(hwy=hwy)
43# Display a search form
44def search():
45    form = FORM(LABEL('ClosureID/Log:',_for='closureid', _class="label"), 
46                INPUT(_name='closureid',_size='7', _style="margin-right: 5px;"),
47                INPUT(_name='lognum',_size='3'),
48                XML('   '), 
49                LABEL('Route: ',_for='route', _class="label"), 
50                SELECT(hwys,_name='route'), XML('   '), 
51                LABEL('Direction: ',_for='direction', _class="label"),
52                SELECT(hwyDirections,_name='direction'), BR(),BR(), 
53                LABEL('Dates:',_for='startdate', _class="label"), 
54                INPUT(_name='startdate',_class='date'), 
55                XML('   '), 
56                LABEL('  to:',_for='enddate', _class="label"), 
57                INPUT(_name='enddate',_class='date'),BR(),
58                INPUT(_value="Search", _type='submit', _class="btn btn-primary btn-default", _style="margin:  7% 45% 2% 40%;"))
59    if form.process(onvalidation=special_validation).accepted:
60        # Put the form fields into the session variables
61        session.closureid = form.vars.closureid.strip().upper()
62        session.lognum = form.vars.lognum.strip()
63        session.startdate = form.vars.startdate.strip()
64        session.enddate = form.vars.enddate.strip()
65        session.route = form.vars.route
66        session.direction = form.vars.direction
67        redirect(URL('results'))
68    return dict(form=form)
69# Search Form: Special validation check to reject lognum without closureID
70def special_validation(form):
71    # Error if a lognum was given and no closure id
72    if (len(form.vars.lognum) > 0 and len(form.vars.closureid) == 0):
73       form.errors.lognum = 'Must provide a closureID when specifying a log number'
74# Show the item that was found in the search
75def results():
76    # query object is equivalent to the where clause in query
77    query = True
78    msg = ""
79    if (len(session.closureid) != 0):
80        query = (db.closures.closureid == session.closureid)
81        msg += " Closure ID = " + session.closureid   
82    if (len(session.lognum) != 0):
83        query = query & (db.closures.lognum == session.lognum)
84        msg += " Log number = " + session.lognum   
85    if (len(session.route) != 0):
86        query = query & (db.closures.route == session.route)
87        msg += " Route = " + session.route
88    if (len(session.direction) != 0):
89        query = query & (db.closures.direction == session.direction)
90        msg += " Route = " + session.route
91    if (len(session.startdate) != 0):
92        query = query & (db.closures.startdate >= session.startdate)
93        msg += "Start date = " + session.startdate
94    if (len(session.enddate) != 0):
95        query = query & (db.closures.enddate <= session.enddate)
96        msg += "End date = " + session.enddate
97   
98    # if no restrictions entered then get all entries
99    if query == True :
100        hwy = db().select(db.closures.ALL)
101        msg = "ALL"
102    else:
103        # get entries with the matching requirements
104        hwy = db(query).select()
105
106    count = len(hwy)
107    # Show the results in table format.  Get the radio call number from supervisor name lookup
108    header = THEAD(TR(TH(''), TH('DTM',BR(),'Area'), TH('Closure ID/',BR(),'Log No.'),TH('Route & Dir/',BR(),'Type of Closure'),TH('Start Date/',BR(),'End Date/',BR(),'Est. Delay'),TH('Facility/Lanes'),TH('Limits'),TH('Work'), TH('TMP:',BR(),'Cozeep/',BR(),'Detour'),TH('Requestor/',BR(),'Radio Call No.')))
109    multiform = []
110    # Iterates over all search results
111    for row in hwy:
112        statusfields = row.closureid +','+ row.lognum + ',1097,' + str(row.s1097user) +','+ str(row.startdate) + ',' + formatTime(row.starttime) +','+str(row.s1097date)+','+ formatTime(row.s1097time) + ',1098,' + str(row.s1098user) +','+ str(row.s1098date)+','+ formatTime(row.s1098time)+ ',1022,' + str(row.s1022user) +','+ str(row.s1022date)+','+ formatTime(row.s1022time)
113        # Each row contains a form with two buttons and columns with fields from database
114        multiform.append(TR(TD(
115                    XML("<button class='submit-button' onclick=\"showPopup(\'"),statusfields,XML("\')\">View History</button>"),BR(),
116                    FORM(
117                          INPUT(_type='submit',_name='btn2',_value='Show Status Form',_class="submit-button" ),
118                          INPUT(_type='hidden',_name='row',_value=row.closureid))),
119                          TD(row.closureid[0]),TD(row.closureid,HR(),row.lognum), TD(row.route,' ',row.direction,HR(),row.closuretype), TD(row.startdate,' ',formatTime(row.starttime),HR(),row.enddate,' ',formatTime(row.endtime),HR(),row.estdelay), TD(row.facility,HR(),row.closedlanes),
120TD(row.startlocation,HR(),row.endlocation), TD(row.worktype), TD(row.tmpcozeep,BR(),row.tmpdetour), TD(row.supervisor,HR(),db(db.supervisors.name == row.supervisor).select().first().radiocallnum) )) 
121
122    session.chosenid = request.vars.row #Pass the hidden field containing the closure ID
123    if request.vars.btn2:
124        redirect(URL('statuslist'))
125    return dict(msg=msg, count=count, highways=hwy, table=header, multiform=multiform)
126
127# Show a selected closure with a status update form
128def statuslist():
129    closedItems = []
130    if (session.chosenid):
131        if (type(session.chosenid) is str):
132            retrieved = db(db.closures.closureid == session.chosenid).select().first()
133            closedItems.append(retrieved) 
134        else:
135            # This logic is available to show multiple results, for possible future use.
136            for item in session.chosenid:
137                retrieved = db(db.closures.closureid == item).select().first()
138                closedItems.append(retrieved) 
139        # Build the table rows       
140        tblrows = TR()       
141        for row in closedItems:
142            # Construct the status radio buttons; disable if date already in database
143            statusflags = "disabled" if row.s1097date == "" else "" 
144            if row.s1097date == "":
145                btn = LABEL('1097'), INPUT(_type='radio', _name='statustype', _value='1097'+row.closureid)
146            else:
147                btn = LABEL('1097 ○',_class='labelgray'),
148            btngroup = btn
149            if row.s1098date == "":
150                btn = LABEL('1098'), INPUT(_type='radio', _name='statustype', _value='1098'+row.closureid)
151            else:
152                btn = LABEL('1098 ○',_class='labelgray'),
153            btngroup += btn
154            if row.s1022date == "":
155                btn = LABEL('1022'), INPUT(_type='radio', _name='statustype', _value='1022'+row.closureid)
156            else:
157                btn = LABEL('1022 ○',_class='labelgray'),
158            btngroup += btn
159
160            if row.s1097date != "" and row.s1098date != "" and row.s1022date != "":
161                btngroup += BR(),LABEL('Statuser:', _class='labelgray')
162            else:   
163                btngroup += BR(),LABEL('Statuser:'),INPUT(_name='statuser',_size='9'),BR(),BR(),INPUT(_type='submit',_value="submit status update",_class="submit-button")
164#            LABEL('1097 ○',_class='colorgray'), INPUT(_type='radio', _name='statustype', _value='1097'+row.closureid),LABEL('1098'), INPUT(_type='radio', _name='statustype', _value='1098'+row.closureid),LABEL('1022'), INPUT(_type='radio', _name='statustype', _value='1022'+row.closureid),BR(), LABEL('Statuser:'),INPUT(_name='statuser',_size='9')
165            tblrows += TR(TD(row.closureid,HR(),row.lognum),TD(row.route,' ',row.direction,HR(),row.closuretype),TD(row.startdate,HR(),row.enddate,HR(),row.estdelay),TD(row.supervisor,BR(),db(db.supervisors.name == row.supervisor).select().first().radiocallnum),TD(btngroup))
166        form = FORM(BR(), 
167                TABLE(THEAD(TR(TH('Closure ID/',BR(),'Log No.'), TH('Route & Dir',BR(),'Type of Closure'),TH('Start Date/',BR(),'End Date/',BR(),'Est. Delay'),TH('Requestor/',BR(),'Radio Call No.'),TH('Status'))),
168                    tblrows,
169                     
170                    _border='1', _cellpadding='5', _width="70%"))
171       
172    else:
173        msg = "No items were selected.  Use the checkbox in the lefthand column."
174        form = ""
175        return dict(msg=msg,form=form)
176   
177    if form.process().accepted:
178        #session.flash = 'Status submit acknowledgement appears here.'
179        session.statustype = form.vars.statustype
180        session.statuser = form.vars.statuser
181        redirect(URL('statusAck'))
182    return dict(form=form)
183
184# show status update acknowledgement - and update database
185def statusAck():
186    if (session.statustype):
187        if (type(session.statustype) is str):
188            msg = "You submitted a status update for " + session.statustype[4:] + ": " + session.statustype[0:4] 
189#           Perform the update on the database
190            # Construct the name of the field to update
191            fieldname = "s"+session.statustype[0:4]+"user"
192            db(db.closures.closureid == session.statustype[4:]).update(**{fieldname:session.statuser})
193            import datetime 
194            now = datetime.datetime.today()
195            fieldname = "s"+session.statustype[0:4]+"date"
196            db(db.closures.closureid == session.statustype[4:]).update(**{fieldname:now.strftime("%Y-%m-%d")})
197            fieldname = "s"+session.statustype[0:4]+"time"
198            db(db.closures.closureid == session.statustype[4:]).update(**{fieldname:now.strftime("%H%M")})
199            # Log the update to external file
200            logmessage = getSimTime() + ", LCS status update: " + session.username + ", " + session.statustype[4:] + ", " + session.statustype[0:4] + ", " + session.statuser + " " + "\n"
201            text_file = open(kLogfile, "a")
202            text_file.write(logmessage)
203            text_file.close()
204        else:
205            msg = "error because only checking one box is allowed."
206    else:
207        msg = "Error no statustype checkbox was checked"
208       
209    return dict(msg=msg)
210# Utility functions for formatting
211def formatTime(msg):
212    if (msg):
213        return msg[0:2]+':'+msg[2:4]
214    else:
215        return ""
216
217# Fetch simulation time and format it into a timestamp
218def getSimTime():
219    import json,datetime
220    try:
221        jsontime = json.load(open(kSimtimefile,'r'))
222        currentSimTime = jsontime["elapsedtime"]
223        timestamp = str(datetime.timedelta(seconds = int(currentSimTime)))
224        return '0'+timestamp  # assume simtime is < 10 and prefix a zero
225    except:
226        # Fallback if missing file, use current time
227        now = datetime.datetime.today()
228        return now.strftime("%H:%M:%S")
229
230# Create a new record
231def submit():
232    # Don't name this function 'request' because it creates a name conflict with http.request
233    hournames = ['','00', '01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21', '22', '23']
234    closuretypes = ['', 'Lane', 'Full', 'Moving', 'One-Way Traffic', 'Alternating Lanes', 'Traffic Break']
235    facilities = ['', 'Connector', 'Conventional_Hwy', 'Mainline', 'Off Ramp', 'On Ramp', 'Rest Area', 'Surface Street']
236    worktypes = ['','AC Paving', 'Accident Investigation', 'Attenuator Repair', 'Blasting', 'Bridge Inspection', 'Bridge Work', 'Brush Fire', 'Chip Seal Operation', 'Concrete Pour', 'Core Drilling', 'Crack Seal Operation', 'Curb/Gutter/Sidewalk Work', 'Drainage Cleaning', 'Drainage Inspection', 'Drainage Work', 'Electrical Work', 'Emergency Work', 'Falsework Installation', 'Falsework Removal', 'Fence Work', 'Filming Activity', 'Fog Seal Operation', 'Graffiti Removal', 'Grinding and Paving', 'Grinding Operation', 'Guardrail Repair', 'Guardrail Work', 'Highway Construction', 'K-rail Installation', 'K-rail Removal', 'Landscape Work', 'Litter Removal', 'Maintenance Operation', 'Median Barrier Work', 'Miscellaneous Work', 'Pavement Marker Replacement', 'Pavement Repair', 'Pavement Work', 'Paving Operation', 'Pile Driving', 'Police Investigation', 'Roadway Excavation', 'Roadway Flooding', 'Sewer Work', 'Shoulder Work', 'Sign Work', 'Slab Replacement', 'Slide Removal', 'Slope Clearing', 'Soundwall Work', 'Special Event', 'Spray Operation', 'Striping Operation', 'Survey Work', 'Sweeping Operation', 'Traffic Signal Work', 'Tree Work', 'Utility Work', 'Vegetation Spraying']
237    supervisors = ['']  # List of names for the dropdown box
238    # Obtain all the supervisor names from the database
239    for row in db().select(db.supervisors.ALL):
240        supervisors.append(row.radiocallnum + ' ' + row.name)
241    crew = ['']  # List of names for the dropdown box
242    crewlookup = []
243    # Obtain all the crew names from the database
244    for row in db().select(db.crew.ALL):
245        crew.append(row.radiocallnum + ' ' + row.name)
246        crewlookup.append(row.radiocallnum + ' ' + row.name)
247    # Build the list of street locations and a hidden cross street lookup table
248    streets = ['']
249    streetlookup = []
250    for row in db().select(db.streets.ALL, orderby=db.streets.street):
251        streets.append(row.street)
252        streetlookup.append(row.route + ',' + row.street)
253    # Build the list of existing closures   
254    existingclosures = []
255    existingclosures.append("")
256    for row in db().select(db.closures.ALL, orderby=db.closures.closureid):
257        # Omit duplicate ID's (with different lognumbers)
258        if row.closureid not in existingclosures:
259            existingclosures.append(row.closureid)
260       
261    form = FORM(
262                LABEL('*Route',_for='route'), SELECT(hwys,_name='route', _id='routecombo', _onchange='routechanged()', requires=IS_LENGTH(minsize=1,error_message='route cannot be empty')), XML('&nbsp;&nbsp;&nbsp;'), 
263           LABEL('*Direction',_for='direction'), SELECT(hwyDirections,_name='direction', requires=IS_LENGTH(minsize=1,error_message='direction cannot be empty')), XML('&nbsp;&nbsp;&nbsp;'), 
264           LABEL('*Facility',_for='facility'), SELECT(facilities,_name='facility', _id='facilitycombo', requires=IS_LENGTH(minsize=1,error_message='facility cannot be empty')), BR(),BR(), 
265           TABLE(TR(TD(),TD(LABEL('*County')),TD(LABEL('*Location'))),
266                TR(TD(LABEL('BEGIN=')),TD(SELECT('ORA',_name='startcounty')),
267                TD(SELECT(streets,_name='startlocation',_id='startlocation')),
268           TR(TD(LABEL('END=')),TD(SELECT('ORA',_name='endcounty')),TD(SELECT(streets,_name='endlocation',_id='endlocation'))))),BR(),
269           LABEL('Date Range:'),BR(),
270           LABEL('From',_for='startdate'),INPUT(_name='startdate',_size='8',_class='date'), XML('&nbsp;&nbsp;&nbsp;'), 
271           LABEL('to:',_for='enddate'), INPUT(_name='enddate',_size='8',_class='date'),XML('&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'), 
272           LABEL('Times',_for='starttime'),SELECT(hournames,_name='starttime'), 
273           LABEL(':',_for='starttimemin'),SELECT('','00','15','30','45','59',_name='starttimemin'), XML('&nbsp;&nbsp;'), 
274           LABEL('to:',_for='endtime'),SELECT(hournames,_name='endtime'), 
275           LABEL(':',_for='endtimemin'),SELECT('','00','15','30','45','59',_name='endtimemin'), BR(),BR(), 
276           TABLE(TR(TD(LABEL('*Type of Closure') ),
277                    TD(LABEL('*Type of Work')),
278                    TD(LABEL('Estimated Delay')),
279                    TD(LABEL('TMP Details'))), 
280                 TR(TD(SELECT(closuretypes,_name='closuretype',_id='closuretype', _onchange='closuretypechanged()',requires=IS_LENGTH(minsize=1,error_message='type of closure cannot be empty'))), 
281                    TD(SELECT(worktypes,_name='worktype', requires=IS_LENGTH(minsize=1,error_message='type of work cannot be empty'))), 
282                    TD(INPUT(_name='estdelay',_size='4'),'minutes'), 
283                    TD(INPUT(_type='checkbox',_name='cozeep'),'CoZeep MaZeep/CHP',BR(), 
284                       INPUT(_type='checkbox', _name='detour'),'Detour Available')),
285                 TR(TD(DIV(LABEL("Lanes closed"),DIV(INPUT(_type='checkbox', _name='lanes', _id='lanes', _value=' '), _id='boxes'),_id='lanechooser',_style='display:none')),
286                    TD(INPUT(_type='hidden', _name='lanecount', _id='lanecount', _value='4')),
287                    TD(),
288                    TD()),
289                 _width='100%' ),
290    TABLE(TR(TD(LABEL('*Supervisor')),
291            TD(LABEL('Field Rep'))
292            ), 
293          TR(TD(SELECT(supervisors,_name='supervisor', _id='supervisorcombo', _onchange='supervisorchanged()', requires=IS_LENGTH(minsize=1,error_message='supervisor cannot be empty'))),
294             TD(SELECT(crew,_name='fieldrep',_id='fieldrep')),
295             TD(XML("&nbsp;&nbsp;&nbsp;&nbsp;")),
296             TD('Is this an existing incident?',
297                INPUT(_type='radio',_name='existing',_value='No',_onclick='radioclicked()'),
298                'No',
299                INPUT(_type='radio',_name='existing',_value='Yes',value='Yes',_onclick='radioclicked()'),
300                'Yes'
301               )
302             ),
303          TR(TD(),TD(),TD(), TD('    Select closure ID:',SELECT(existingclosures,_name='existingid'),_id='closureselect'))),
304    TABLE(TR(TD( LABEL('Meeting Place/CHP Contact')),
305            TD(LABEL('Reason for Closure')),
306            TD(LABEL('Additional Remarks / Detour '))), 
307                  TR(TD(INPUT(_name='meeting', _size='25')),TD(INPUT(_name='reason',_size='25')),TD(INPUT(_name='remarks',_size='25'))) ), BR(), 
308            INPUT(_type='submit',_value='Submit Closure', _class="btn btn-primary btn-default", _style="margin:  2% 45% 2% 40%;"),
309            XML('\n'),SELECT(streetlookup,_name='stlookup', _id='stlookup', _class='hideme'), 
310SELECT(crewlookup,_name='crewlookup', _id='crewlookup', _class='hideme')) 
311
312    if form.process(onvalidation=validate_existing_id).accepted:
313        newLognum = calcNextLogNum(form.vars.existingid)
314        if newLognum == '1':
315            newID = calcNextClosureID(form.vars.route)
316        else:
317            newID = form.vars.existingid
318        supervisor_name = form.vars.supervisor[3:]
319        fieldrep_name = form.vars.fieldrep[5:]
320        selectedlanes = buildLanesClosedString(form.vars.lanes,form.vars.lanecount)
321        # Insert the record into the database
322        newrec = db.closures.insert(closureid=newID, lognum=newLognum, route=form.vars.route, direction=form.vars.direction, facility=form.vars.facility, startcounty=form.vars.startcounty, endcounty=form.vars.endcounty, startlocation=form.vars.startlocation, endlocation=form.vars.endlocation, startdate=form.vars.startdate, enddate=form.vars.enddate, starttime=form.vars.starttime+form.vars.starttimemin, endtime=form.vars.endtime+form.vars.endtimemin, closuretype=form.vars.closuretype, closedlanes=selectedlanes, worktype=form.vars.worktype, estdelay=form.vars.estdelay, tmpcozeep=getCheckbox(form.vars.cozeep), tmpdetour=getCheckbox(form.vars.detour), supervisor=supervisor_name, fieldrep=fieldrep_name, s1097date='', s1098date='', s1022date='' )
323        session.flash = 'New lane closure added: ' + newID + ' ' + newLognum + ': ' + selectedlanes
324        # Log the new closure to external file. Username, closureID, route, dir, type of closure, type of work
325        logmessage = getSimTime() + ", LCS new closure: " + session.username + ", " + newID + '.' + newLognum + ', ' + form.vars.route + form.vars.direction + ', ' + form.vars.closuretype + ', ' + form.vars.worktype + "\n"
326        text_file = open(kLogfile, "a")
327        text_file.write(logmessage)
328        text_file.close()
329        redirect(URL('search.html'))
330    return dict(form=form)
331
332# An unlinked page to allow admin to reset the database to simulation start state
333def resetdb():
334    form = FORM("Press this button to reset the closure database to its original state at the start of a simulation.",BR(),
335                "Warning: this will delete all the current closures.",BR(),
336                "Import filename is 'db_closures_start.csv'.",BR(),
337                INPUT(_value="Reset Database", _type='submit', _class="btn btn-primary btn-default"))
338    if form.process().accepted:
339        db(db.closures.id > 0).delete()   # remove all current records
340        with open('db_closures_start.csv', 'rb') as dumpfile:
341            db.closures.import_from_csv_file(dumpfile)  # import from starting state
342        session.flash = 'Closure database has been reset'
343        redirect(URL('search.html'))
344    return dict(form=form)
345
346# Validation for existing closure button
347# If user selected Yes (it's existing incident) then they must select a closure ID
348def validate_existing_id(form):
349    if form.vars.existing == 'Yes' and form.vars.existingid == '':
350        form.errors.existingid = "Existing incidents require selecting an existing closure ID"
351
352# Calculate the closure id to assign to the new closure
353def calcNextClosureID(routeNum):
354    # Retrieve the last existing closure on this route
355    #item = db(db.closures.closureid.startswith('T'+routeNum)).select().last() # defective
356    item = db(db.closures.route == routeNum).select().last() 
357    if (item != None):
358        currID = item.closureid
359        lastchar = currID[-1:]  # Get last character of ID
360        lastchar = chr(ord(lastchar) + 1) # increment it to next character (need bounds check)
361        newID = currID[:-1] + lastchar  # append char to ID
362        return newID
363    else:
364        return 'T'+routeNum+'AA'  # For a non-existing route
365   
366# If existing incident closure ID is provided, increment the log number by 1
367def calcNextLogNum(existingid):
368    if existingid != '':
369        item = db(db.closures.closureid.startswith(existingid)).select().last()
370        prevLog = int(item.lognum)
371        nextLog = prevLog + 1
372        return str(nextLog)
373    else:
374        return '1'
375
376
377# Convert checkbox value to YES/NO
378def getCheckbox(ckBox):
379    if (ckBox == "on"):
380        return "YES"
381    else:
382        return "NO"
383
384# Swap the fields in a name, changing lastname first to firstname first.
385def reverseNameFields(formattedname):
386    # Divide the name into last and first names
387    x = formattedname.split(',')
388    # If there isn't a comma, return the entire name
389    if len(x) == 1:
390        return x[0].strip()
391    else:  # return the swapped fields
392        return x[1].strip() + ' ' + x[0]
393
394# Convert the lanes closed checkboxes into a human readable string
395# E.g.  #1 #3 of 4
396# Note: ckBoxGroup parameter contains only checked items
397def buildLanesClosedString(ckBoxGroup,lanecount):
398    result = ""
399    if ckBoxGroup is not None:
400        # Append each checked value to a string
401        for item in ckBoxGroup:
402            result = result + "#"+item + " "
403        result = result + "of " + lanecount
404    return result
Note: See TracBrowser for help on using the repository browser.