def update_message(status_msgs, data_location):
    """Simple execution of data update status-messages."""

    if status_msgs[0]:
        mh.send('Updated %s at %s.' %
                (data_location, bu.getcurrenttime()))
    else:
        mh.send('%s update failed at %s.' %
                (data_location, bu.getcurrenttime()))
    if len(status_msgs[1]) > 0:
        mh.send('Messages: %s.' % '; '.join(status_msgs[1]))

    return
def trip_message(status, trip_id, trip_notes=[]):
    """Simple execution of trip analysis state messages."""

    if status:
        mh.send('Trip %i matched at %s.' % (trip_id, bu.getcurrenttime()))
    else:
        mh.send('Trip %i match failed at %s.' % (trip_id, bu.getcurrenttime()))
    if len(trip_notes) > 0:
        note_row = '%s.' % '; '.join(trip_notes)
        mh.send(note_row)
    else:
        note_row = ''
    mh.sendlog('%s,%s,%s' % (trip_id, status, note_row))

    return
def main():
    """Controls the procedural order of the script when run by itself."""

    # Loading data.

    loaded_network = load_link_network_from_arcgis(NETWORK_LOAD_INFO)
    mh.send('Link network loaded version %s at %s.' % (NET_VERSION,
                                                       bu.getcurrenttime()))

    if loaded_network:

        trips_so_far = 0
        while trips_so_far < SCRIPT_TRIP_LIMIT:

            loaded_trips = load_gps_trips_from_mysql(
                data_dictionary = TRIPS_LOAD_INFO,
                # Specific trips only for testing.
                trip_ids = None,
                logfile_path = LOGFILE_PATH,
                trip_limit = CHUNK_TRIP_LIMIT
                )

            # Add these trips to the script count.
            trips_so_far += len(loaded_trips)


            # Ensures logfile lines will start on new row.
            mh.sendlog('')
            mh.send('%i GPS trips loaded from database at %s.' %
                    (len(loaded_trips), bu.getcurrenttime()))

            # Have some trips: Analyze each.
            if loaded_trips:

                for trip in loaded_trips:

                    trip_messages = []
                    is_good = True

                    while is_good:

                        # PRE-VET: Must be within the envelope of the area of
                        # study. Doesn't currently work: Need to work on
                        # envelope logic.
                        ##trackpoints_out = trip.find_trackpoints_outside_area(
                        ##    easting_range = AREA_ENVELOPE[0],
                        ##    northing_range = AREA_ENVELOPE[1]
                        ##    )
                        ##number_out = len(trackpoints_out)
                        ##if number_out > 0:
                        ##    trip_messages.append('PREFAIL-OUT')
                        ##    trip_messages.append('%i out-of-area: %s' %
                        ##                         (number_out,
                        ##                          str(trackpoints_out)))
                        ##    is_good = False
                        ##    break

                        # PRE-VET: Must be longer than the distance threshold.
                        tdistance, ttime = trip.find_absolute_trip_length()
                        if tdistance < DISTANCE_THRESHOLD:
                            trip_messages.append('PREFAIL-SHORT')
                            trip_messages.append(
                                'Total length of %0g feet in %i seconds' %
                                (tdistance, ttime)
                                )
                            is_good = False
                            break

                        # PRE-VET: Must not have gaps larger than the distance
                        # threshold.
                        gdistance, gtime = trip.find_largest_trackpoint_gap()
                        if gdistance > DISTANCE_THRESHOLD:
                            trip_messages.append('PREFAIL-GAP')
                            trip_messages.append(
                                'Gap of %2g feet over %i seconds' %
                                (gdistance, gtime)
                                )
                            is_good = False
                            break

                        # Set route & fix backtrack issues.
                        trip.set_entire_route(link_network = loaded_network,
                                              avoid_problems = True,
                                              cursor_size = CURSOR_SIZE)
                        is_good, messages = trip.fix_routelink_backtracks(
                            link_network = loaded_network
                            )
                        trip_messages.extend(messages)

                        break

                    trip_message(is_good, trip.trip_id, trip_messages)

                    if LOG_TRIPS_DEBUGGING:
                        with open(os.path.join(VERSION_PATH,'DebugTrip%i.txt' %
                                               trip.trip_id), 'wb') as dfile:
                            for trip_note in trip.all_notes:
                                dfile.write('%s\n' % trip_note)

                # Write output data (updates).

                # Trackpoints (ArcGIS).
                status_msgs = update_trackpoints_in_arcgis(
                    gps_trips = loaded_trips,
                    output_dictionary = TRACKPOINTS_UPDATE_INFO
                    )
                update_message(status_msgs, TRACKPOINTS_PATH)

                # Routes (ArcGIS).
                status_msgs = update_routes_in_arcgis(
                    gps_trips = loaded_trips,
                    link_network = loaded_network,
                    output_dictionary = ROUTES_UPDATE_INFO
                    )
                update_message(status_msgs, ROUTES_PATH)

                # Routepoints (ArcGIS).
                status_msgs = update_routepoints_in_arcgis(
                    gps_trips = loaded_trips,
                    output_dictionary = ROUTEPOINTS_UPDATE_INFO
                    )
                update_message(status_msgs, ROUTEPOINTS_PATH)

                # O&D nodes (ArcGIS).
                status_msgs = update_od_nodes_in_arcgis(
                    gps_trips = loaded_trips,
                    link_network = loaded_network,
                    output_dictionary = OD_UPDATE_INFO
                    )
                update_message(status_msgs, OD_PATH)

                # Layer files (ArcGIS).
                # Use the idlist below to only (re)create these trips' layers.
                idlist = [trip.trip_id for trip in loaded_trips]
                # Use the idlist below to (re)create all trips' layers.
                ##idlist = get_all_trip_ids(TRACKPOINTS_PATH, 'trip_id')
                status_msgs = create_output_layers_for_arcgis(
                    trip_ids = idlist,
                    output_dictionary = LAYERS_CREATE_INFO
                    )
                update_message(status_msgs, LAYER_PATH)

                # Need to close & open log so next chunk can read updated rows.
                mh.closelog()
                mh.filehandle = open(LOGFILE_PATH, 'a')

            # Have no more trips loaded: Break out of loop.
            else:
                break

        # Logfile cleanup.

        mh.closelog()
        mh.send('All output located at: %s' % VERSION_PATH)
        sort_logfile(LOGFILE_PATH)
        mh.send('Logfile: %s' % os.path.basename(LOGFILE_PATH))

        # Write output data (whole rewrites).

        # O&D nodes (CSV).
        status_msgs = create_csv_od_from_arcgis(
            source_path = OD_PATH,
            data_dictionary = OD_CSV_UPDATE_INFO
            )
        update_message(status_msgs, OD_CSV_PATH)

        # Routes (CSV).
        status_msgs = create_csv_routes_from_arcgis(
            source_path = ROUTES_PATH,
            data_dictionary = ROUTES_CSV_UPDATE_INFO
            )
        update_message(status_msgs, ROUTES_CSV_PATH)
        mh = bu.messagehandler(log = True,
                               filename = LOGFILE_PATH,
                               append = True)
        # Console message setting.
        mh.echo = True
        # Mail message settings.
        mh.mail = False
        ##mh.sender = '*****@*****.**'
        ##mh.recipient = '*****@*****.**'
        ##mh.subject = '%s Log for %s' % (bu.program, bu.gettoday())

        # Logfile only for recording the individual trip messages.
        # Turn off auto-write using this, use sendlog(message) for logfile.
        mh.logfile = False

        mh.send('%s started at %s.' % (bu.program, bu.getcurrenttime()))

        main()

        status = 0

    except:
        # Handle errors by setting the exit status (so if a batch file wraps
        # this script can use it). A utility function formats the messages from
        # the geoprocessor.
        status = 1
        bu.handleexception(arcpy, mh)

    finally:
        # Cleanup actions include sending a mail message to the administrator
        # to indicate program success or failure, closing the logfile, and