function commit_genie()
{
    // Load genie details into the form memory
    $_SESSION['form_memory']['genie'][0] = mydb::cxn()->real_escape_string($_POST['id']);
    $_SESSION['form_memory']['genie'][1] = mydb::cxn()->real_escape_string($_POST['genie_num1']) . "-" . mydb::cxn()->real_escape_string($_POST['genie_num2']);
    $_SESSION['form_memory']['genie'][2] = mydb::cxn()->real_escape_string($_POST['crew_affiliation_id']);
    $_SESSION['form_memory']['genie'][3] = mydb::cxn()->real_escape_string($_POST['crew_affiliation_name']);
    $_SESSION['form_memory']['genie'][4] = mydb::cxn()->real_escape_string($_POST['in_service_date']);
    $_SESSION['form_memory']['genie'][5] = mydb::cxn()->real_escape_string($_POST['retired_date']);
    $_SESSION['form_memory']['genie'][6] = mydb::cxn()->real_escape_string($_POST['retired_reason']);
    $_SESSION['form_memory']['genie'][7] = mydb::cxn()->real_escape_string($_POST['retired_category']);
    $_SESSION['form_memory']['genie'][8] = mydb::cxn()->real_escape_string($_POST['status']);
    // This function is called within a try/catch block - let any exceptions thrown by the genie class return to the caller
    $eq = new genie();
    $eq->load($_SESSION['form_memory']['genie'][0]);
    $eq->set('serial_num', $_SESSION['form_memory']['genie'][1]);
    $eq->set('crew_affiliation_id', $_SESSION['form_memory']['genie'][2]);
    $eq->set('in_service_date', $_SESSION['form_memory']['genie'][4]);
    $eq->set('retired_date', $_SESSION['form_memory']['genie'][5]);
    $eq->set('retired_reason', $_SESSION['form_memory']['genie'][6]);
    $eq->set('retired_category', $_SESSION['form_memory']['genie'][7]);
    $eq->set('status', $_SESSION['form_memory']['genie'][8]);
    $eq->save();
    return true;
    // Success
}
function check_add_rappel_form_data()
{
    global $which_form;
    //Make sure info for each HRAP is either complete or non-existant (no partial info, all or nothing)
    $incomplete_sections = NULL;
    $id_mismatch_fields = NULL;
    $duplicate_operations = array();
    $sticks = array(1, 2, 3);
    $doors = array('left', 'right');
    //print_r($_POST);
    foreach ($sticks as $stick) {
        foreach ($doors as $door) {
            $position = 'stick' . $stick . '_' . $door;
            $name_id_field = 'name_' . $position . '_id';
            $name_text_field = 'name_' . $position . '_text';
            $genie_id_field = 'genie_' . $position . '_id';
            $genie_text_field = 'genie_' . $position . '_text';
            $rope_id_field = 'rope_' . $position . '_id';
            $rope_text_field = 'rope_' . $position . '_text';
            $rope_end_field = 'rope_' . $position . '_end';
            if (array_key_exists($name_id_field, $_POST)) {
                $null_so_far = true;
                $partial = false;
                if ($_POST[$name_id_field] != '') {
                    $null_so_far = false;
                }
                if ((!isset($_POST[$genie_text_field]) || $_POST[$genie_text_field] == '') != $null_so_far) {
                    $partial = true;
                }
                // Use the text field to identify rope & genie (instead of the dB ID number). This allows a
                if ((!isset($_POST[$rope_text_field]) || $_POST[$rope_text_field] == '') != $null_so_far) {
                    $partial = true;
                }
                // rope to be entered in this field that does not exist in the dB.  It will be added implicitly.
                if (!isset($_POST[$rope_end_field]) && !$null_so_far) {
                    $partial = true;
                }
                // It's OK if ONLY the rope_end is selected, since there's no way to unselect a radio button
                //****************************************************************************************
                //***** ALLOW MISSING ROPE AND GENIE INFO ************************************************
                //***** A 'rappel' can be entered without rope and genie info (Just rappeller name) *****
                //****************************************************************************************
                /*
                if($partial) {
                					  if(strlen($incomplete_sections) > 1) $incomplete_sections .= ", ";
                					  $incomplete_sections .= "Stick ".$stick.":".$door;
                }
                */
                if (!$partial && !$null_so_far) {
                    // Check each rope and genie serial_num to see if they exist in the database.
                    // If an item is NOT found in the database, create one
                    $genie_query = "SELECT items.serial_num as genie\n\t\t\t\t\t\t\t\t\t  FROM items\n\t\t\t\t\t\t\t\t\t  WHERE LOWER(items.serial_num) = '" . strtolower(mydb::cxn()->real_escape_string($_POST[$genie_text_field])) . "' and item_type = 'genie'";
                    $result = mydb::cxn()->query($genie_query);
                    if (mydb::cxn()->affected_rows < 1) {
                        // The genie does not exist in the database.  Create it.
                        $new_genie = new genie();
                        $new_genie->set('serial_num', $_POST[$genie_text_field]);
                        $new_genie->save();
                        echo "NEW GENIE CREATED (" . $new_genie->get('serial_num') . ")";
                    }
                    $rope_query = "SELECT items.serial_num as rope\n\t\t\t\t\t\t\t\t\t  FROM items\n\t\t\t\t\t\t\t\t\t  WHERE LOWER(items.serial_num) = '" . strtolower(mydb::cxn()->real_escape_string($_POST[$rope_text_field])) . "' and item_type = 'rope'";
                    $result = mydb::cxn()->query($rope_query);
                    if (mydb::cxn()->affected_rows < 1) {
                        // The rope does not exist in the database.  Create it.
                        $new_rope = new rope();
                        $new_rope->set('serial_num', $_POST[$rope_text_field]);
                        $new_rope->save();
                    }
                    // Ensure that each hrap has matching _text and _id fields.
                    // For example: name_stick1_left_text and name_stick1_left_id should describe the same HRAP.  However, if a user types an HRAP name
                    // in the name_stick1_left_text field but that HRAP does not exist, the name_stick1_left_id field will never be populated since the ID
                    // field is only populated when the user clicks on an entry in the context menu.
                    //
                    // This section will check each _text/_id field pair for agreement.  If a discrepancy is found, return to the form and allow user
                    // to manually correct the issue.
                    $hrap_query = "SELECT CONCAT(hraps.firstname,' ',hraps.lastname) as name\n\t\t\t\t\t\t\t\t\t FROM hraps\n\t\t\t\t\t\t\t\t\t WHERE hraps.id = '" . $_POST[$name_id_field] . "'";
                    $hrap_db = NULL;
                    $result = mydb::cxn()->query($hrap_query);
                    if (mydb::cxn()->affected_rows > 0) {
                        $row = $result->fetch_assoc();
                        $hrap_db = $row['name'];
                    }
                    if (!isset($_POST[$name_text_field])) {
                        $_POST[$name_text_field] = NULL;
                    }
                    if (strtolower($_POST[$name_text_field]) != strtolower($hrap_db)) {
                        if (strlen($id_mismatch_fields) > 1) {
                            $id_mismatch_fields .= "<br>\n";
                        }
                        $id_mismatch_fields .= "Stick " . $stick . ":" . $door . " Name";
                    }
                }
                // End: if(!$partial && !null_so_far)
            }
            // End: if(array_key_exists($name_id_field,$_POST))
            // Check for duplicate entries already in the databse. Build an array of rappels
            // in the db that match the rappels for each stick/door POST'ed.
            if (isset($_POST[$name_id_field]) && $_POST[$name_id_field] != '') {
                $query = "SELECT rappels.operation_id " . "FROM rappels INNER JOIN operations on rappels.operation_id = operations.id " . "WHERE " . "DATE_FORMAT(operations.date,'%c/%d/%Y') = '" . $_POST['date'] . "'" . " && rappels.hrap_id = '" . $_POST[$name_id_field] . "'";
                if (isset($_POST[$rope_id_field]) && $_POST[$rope_id_field] != '') {
                    $query .= " && rappels.rope_id = " . $_POST[$rope_id_field];
                }
                if (isset($_POST[$rope_end_field]) && $_POST[$rope_end_field] != '') {
                    $query .= " && rappels.rope_end = '" . $_POST[$rope_end_field] . "'";
                }
                if (isset($_POST[$genie_id_field]) && $_POST[$genie_id_field] != '') {
                    $query .= " && rappels.genie_id = " . $_POST[$genie_id_field];
                }
                if (isset($_GET['op']) && $_GET['op'] != '') {
                    $query .= " && (rappels.operation_id != " . $_GET['op'] . ")";
                }
                $result = mydb::cxn()->query($query);
                while ($row = $result->fetch_assoc()) {
                    array_push($duplicate_operations, $row['operation_id']);
                }
            }
            // End: if(isset($_POST[$name_id_field]) && $_POST[$name_id_field] != '')
        }
        // End: foreach($doors AS $door)
    }
    // End: foreach($sticks AS $stick)
    // Check for spotter id mismatch (like above)
    // Allow blank Spotter field (because not all spotters have profiles in the RapRec program).
    if (isset($_POST['name_spotter_id']) && $_POST['name_spotter_id'] != '') {
        $spotter_query = "\tSELECT CONCAT(hraps.firstname,' ',hraps.lastname) as name\n\t\t\t\t\t\t\t\t\t  FROM hraps\n\t\t\t\t\t\t\t\t\t  WHERE hraps.id = '" . $_POST['name_spotter_id'] . "'";
        $spotter_db = '';
        $result = mydb::cxn()->query($spotter_query);
        if (mydb::cxn()->affected_rows > 0) {
            $row = $result->fetch_assoc();
            $spotter_db = $row['name'];
        }
        if (strtolower($_POST['name_spotter_text']) != strtolower($spotter_db)) {
            if (strlen($id_mismatch_fields) > 1) {
                $id_mismatch_fields .= "<br>\n";
            }
            $id_mismatch_fields .= "Spotter Name";
        }
    }
    // END if( !isset($_POST['name_spotter_id'])...
    // Throw the appropriate exceptions, if necessary
    if (strlen($incomplete_sections) > 1) {
        throw new Exception('Partial entries are not allowed.<br>Please complete or clear the following sections:<br><br>' . $incomplete_sections);
        return 0;
    }
    if (strlen($id_mismatch_fields) > 1) {
        throw new Exception('You must make your selection by choosing an item off the popup menu.<br>The following fields were not properly selected:<br><br>' . $id_mismatch_fields);
        return 0;
    }
    // Check for a duplicate entry already in the database
    // Oprations with the same date, rappellers, ropes and genies will be considered duplicates
    if (count($duplicate_operations) > 0) {
        $duplicate_operations = array_unique($duplicate_operations);
        $message = "You may be entering a duplicate record. Review the following rappels before saving this entry:<br />\n";
        foreach ($duplicate_operations as $d) {
            $message .= "<a href=\"view_rappels.php?op=" . $d . "\">Operation #" . $d . "</a><br />\n";
        }
        $message .= "</ul>\n";
        throw new Exception($message);
        return 0;
    }
}