<?php
    function getStatesAsSelectOptions($selectedState, $name="state", $style='', $abbreviated=false){
        // Create the states array
        $states = array ('AK','AL','AR','AZ','CA','CO','CT','DC','DE','FL',
                         'GA','HI','IA','ID','IL','IN','KS','KY','LA','MA',
                         'MD','ME','MI','MN','MO','MS','MT','NC','ND','NE',
                         'NH','NJ','NM','NV','NY','OH','OK','OR','PA','RI',
                         'SC','SD','TN','TX','UT','VA','VT','WA','WI','WV',
                         'WY');

        $stateNames = array ('Alaska', 'Alabama', 'Arkansas', 'Arizona', 
                             'California', 'Colorado', 'Connecticut',  
                             'District Of Columbia', 'Delaware', 'Florida', 
                             'Georgia', 'Hawaii', 'Iowa', 'Idaho', 'Illinois', 
                             'Indiana', 'Kansas', 'Kentucky', 'Louisiana',  
                             'Massachusetts', 'Maryland', 'Maine', 'Michigan', 
                             'Minnesota', 'Missouri', 'Mississippi', 'Montana',
                             'North Carolina', 'North Dakota', 'Nebraska', 
                             'New Hampshire', 'New Jersey', 'New Mexico', 'Nevada', 
                             'New York', 'Ohio', 'Oklahoma', 'Oregon', 'Pennsylvania', 
                             'Rhode Island', 'South Carolina', 'South Dakota', 
                             'Tennessee', 'Texas', 'Utah', 'Virginia', 'Vermont', 
                             'Washington', 'Wisconsin', 'West Virginia', 'Wyoming');

        // Start the return with the beginning of the select
        $result='<select id="' . $name . '" name="' . $name . '" style="' . $style . '">';

        // Loop through the state array
        $currentStateNumber=0;
        foreach ($states as $currentState) {
            // Determine if this is one that is to be selected
            $selectedText='';
            if ($selectedState==$currentState) {
                // Create the selected html
                $selectedText='selected';
            }

            // Determine if they want abbreviated
            if ($abbreviated){
                // Add this option to the select
                $result = $result . '<option value="' . $currentState . '" ' . 
                          $selectedText . '>' . $currentState . '</option>';
            }
            else {
                // Add this option to the select
                $result = $result . '<option value="' . $currentState . '" ' . 
                          $selectedText . '>' . $currentState . '  (' . 
                          $stateNames[$currentStateNumber] . ')</option>';
            }

            // increment the loop number
            $currentStateNumber++;
        }

        // End the select
        $result=$result . '</select>';

        // Return the result
        return $result;
    }

    function getBlanksPerPageCombo($blanksPerPage=30, $showUserPreferences=true, $labelStyle='', $selectStyle='', $onChange='CreateAndGotoSearchOptions();'){
        // Initialize the return
        $result = '';

        try {
            // Determine if they do NOT want to show it
            $userPrefOption='    <option value="0" ' .  ($blanksPerPage == 0 ? 'selected' : '') . '>User Pref</option>';
            if (!$showUserPreferences){
                // Set it to nothing
                $userPrefOption='';
            }

            // Start the return with the beginning of the select
            $result=
                    '<label for="blanksPerPage" style="' . $labelStyle . '">Blanks/Page: </label>' . 
                    '<select style="' . $selectStyle . '" name="blanksPerPage" id="blanksPerPage"  onchange="' . $onChange . '">' .
                    $userPrefOption .
                    '    <option value="7" ' .  ($blanksPerPage == 7 ? 'selected' : '') . '>7</option>' .
                    '    <option value="15" ' .  ($blanksPerPage == 15 ? 'selected' : '') . '>15</option>' .
                    '    <option value="30" ' .  ($blanksPerPage == 30 ? 'selected' : '') . '>30</option>' .
                    '    <option value="50" ' .  ($blanksPerPage == 50 ? 'selected' : '') . '>50</option>' .
                    '    <option value="100" ' .  ($blanksPerPage == 100 ? 'selected' : '') . '>100</option>' .
                    '    <option value="250" ' .  ($blanksPerPage == 250 ? 'selected' : '') . '>250</option>' .
                    '</select>';
        } catch (Exception $ex) {
            // Assign the output string as to what happened
            return $result;
        }

        // Return whatever we got
        return $result;
    }
    
    function getTasksPerPageCombo($tasksPerPage=30, $showUserPreferences=true, $labelStyle='', $selectStyle='', $onChange='CreateAndGotoSearchOptions();'){
        // Initialize the return
        $result = '';

        try {
            // Determine if they do NOT want to show it
            $userPrefOption='    <option value="0" ' .  ($tasksPerPage == 0 ? 'selected' : '') . '>User Pref</option>';
            if (!$showUserPreferences){
                // Set it to nothing
                $userPrefOption='';
            }

            // Start the return with the beginning of the select
            $result=
                    '<label for="taskPerPage" style="' . $labelStyle . '">Tasks/Page: </label>' . 
                    '<select style="' . $selectStyle . '" name="tasksPerPage" id="tasksPerPage"  onchange="' . $onChange . '">' .
                    $userPrefOption .
                    '    <option value="7" ' .  ($tasksPerPage == 7 ? 'selected' : '') . '>7</option>' .
                    '    <option value="15" ' .  ($tasksPerPage == 15 ? 'selected' : '') . '>15</option>' .
                    '    <option value="30" ' .  ($tasksPerPage == 30 ? 'selected' : '') . '>30</option>' .
                    '    <option value="50" ' .  ($tasksPerPage == 50 ? 'selected' : '') . '>50</option>' .
                    '    <option value="100" ' .  ($tasksPerPage == 100 ? 'selected' : '') . '>100</option>' .
                    '    <option value="250" ' .  ($tasksPerPage == 250 ? 'selected' : '') . '>250</option>' .
                    '</select>';
        } catch (Exception $ex) {
            // Assign the output string as to what happened
            return $result;
        }

        // Return whatever we got
        return $result;
    }
    
    function getShowNoShowCombo($showWhatFinishedState, $showUserPreferences=true, $labelStyle='', $selectStyle=''){
        // Initialize the return
        $result = '';
        
        try {
            // Determine if they do NOT want to show it
            $userPrefOption='    <option value="0" ' .  ($showWhatFinishedState == 0 ? 'selected' : '') . '>User Pref</option>';
            if (!$showUserPreferences){
                // Set it to nothing
                $userPrefOption='';
            }

            // Start the return with the beginning of the select
            $result=
                    '<label for="showWhatFinishedState" style="' . $labelStyle . '">Show Completed: </label>' . 
                    '<select name="showWhatFinishedState" id="showWhatFinishedState"  onchange="CreateAndGotoSearchOptions()" style="' . $selectStyle . '">' .
                    $userPrefOption .
                    '    <option value="1" ' .  ($showWhatFinishedState == 1 ? 'selected' : '') . '>ALL</option>' .
                    '    <option value="2" ' .  ($showWhatFinishedState == 2 ? 'selected' : '') . '>NOT Closed OR Completed</option>' .
                    '    <option value="3" ' .  ($showWhatFinishedState == 3 ? 'selected' : '') . '>Completed Only</option>' .
                    '    <option value="4" ' .  ($showWhatFinishedState == 4 ? 'selected' : '') . '>Closed Only</option>' .
                    '    <option value="5" ' .  ($showWhatFinishedState == 5 ? 'selected' : '') . '>Closed or Completed</option>' .
                    '    <option value="6" ' .  ($showWhatFinishedState == 6 ? 'selected' : '') . '>Closed and Completed</option>' .
                    '</select>';
        } catch (Exception $ex) {
            // Assign the output string as to what happened
            return $result;
        }

        // Return whatever we got
        return $result;
    }
    
    function checkForToolsToRemove ($db, $userRow, $machineID){
        $result='';
        
        // Create a query to determine if any tools are requested to be removed on this machine
        $sql = 'SELECT at.*, t.Name ' . 
               'FROM assignedtools at ' . 
               'LEFT JOIN tools t ON at.CurrentToolID = t.ToolID ' .
               'WHERE RemoveAfterUse = 1 ' . 
               'AND MachineID = ' . $machineID . ';';

        // run the query to see if there are any rows
        $toolsToRemove = $db->queryDB($sql, $userRow, "global_functions php occurance 1");

        // Attempt to run the query and evaluate the response
        if (mysqli_num_rows($toolsToRemove)>=1){
            // Start a variable to return informing them of the tools to remove
            $result = 'INFO MESSAGE (global_functions)::Do not forget to remove the ' .
                             'tools that were asked to be removed in tool slot(s) ';

            // Start looping through to get the tool position
            while ($toolToRemove=mysqli_fetch_array($toolsToRemove)){
                // Add the tool position
                $result = $result . $toolToRemove["Position"] . ', ';
            }

            // Remove the last comma
            $result = (substr($result, 0, -2));

            // Add ending information
            $result = $result . '.';
        }
        
        // Return the result
        return $result;
    }
    
    function setTaskToolsAsSuggested($db, $userRow, $taskID, $machineID){
        $returnString='';
        
        try {
            // create a query to get the tools for this task
            $sql = 'SELECT * ' . 
                   'FROM tooltotasklinker ' .
                   'WHERE TaskID = ' . $taskID . ';';

            // run the query to get the tools in this task
            $toolsInTaskQuery = $db->queryDB($sql, null, "global_functions Form occurance 2");

            // Loop through the returned results
            while ($toolInTask=mysqli_fetch_array($toolsInTaskQuery)){
                // Create a query to determine if the this tool is not there
                $sql = 'SELECT * FROM assignedtools ' .
                       'WHERE (CurrentToolID <> ' . $toolInTask["ToolID"] . 
                          ' OR (ExposedLength <> ' . $toolInTask["ExposedLength"] . ' AND 0 <> ' . $toolInTask["ExposedLength"] . ') ' . 
                          ' OR (SuggestedUseNewTool <> ' . $toolInTask["UseNewTool"] . ' AND 0 <> ' . $toolInTask["UseNewTool"] . ')) ' . 
                       'AND MachineID = ' . $machineID . ' ' . 
                       'AND Position = ' . $toolInTask["ToolPosition"] . ';'; 

                // run the query to get the tool on the machine
                $toolInMachineQuery = $db->queryDB($sql, null, "global_functions Form occurance 3");

                // Determine if there is that tool in the machine
                $toolInMachineAssocRow=null;
                if (mysqli_num_rows($toolInMachineQuery)>0){
                    // Get the tool row on the machine
                    $toolInMachineAssocRow = $toolInMachineQuery->fetch_assoc();

                    // Create a query to update the suggested assigned tool with this tool
                    $sql = 'UPDATE assignedtools ' . 
                           'SET SuggestedChangeNewToolID = ' . $toolInTask["ToolID"] . ', ' .
                           '    SuggestedExposedLength = ' . $toolInTask["ExposedLength"] . ', ' .
                           '    SuggestedRemoveToolAfterUse = ' . $toolInTask["RemoveAfterUse"] . ', ' .
                           '    SuggestedUseNewTool = ' . $toolInTask["UseNewTool"] . ', ' .
                           '    SuggestedNote = "' . $toolInTask["Notes"] . '" ' .
                           'WHERE MachineID = ' . $machineID . ' ' . 
                           'AND Position = ' . $toolInTask["ToolPosition"] . ';'; 

                    // Run the update query
                    $db->queryDB($sql, $userRow, "global_functions Form occurance 4");
                }
            }
        } catch (Exception $exc) {
            $returnString = 'INFO MESSAGE (global_functions)::Tools were not moved to the new machine because of an error.';
        }
        
        // Return the return created or not
        return $returnString;
    }
    
    function modifyToolDetailsToMatchCurrent ($db, $userRow, $tid){
        // Assume that we are successful unless proven otherwise
        $errorString='';
        
        try {
            // Determine if the TID is one greater than 0
            if ($tid!=null && $tid>0){
                // Create a query to get the setups associated with this task
                $sql='SELECT ms.MachiningSetupID, ms.ToolDetails ' . 
                     'FROM machiningsetups ms ' .
                     'WHERE ms.TaskID=' . $tid . ';';
                
                // Run the query
                $currentSetups = $db->queryDB($sql, $userRow, "global_functions Form occurance 5");

                // Determine if there are any rows before attempting to loop through them
                if ($currentSetups != null && 
                    mysqli_num_rows($currentSetups)>0){
                    // Reset the amount of tools for the new setup
                    $toolNumber=0;
                    
                    // Create a multi-dimensional array that will hold the tools current position, old position and name
                    $toolsInGCode=array();

                    // Create a query to get the tools for the task
                    $sql='SELECT ttl.*, t.Name AS ToolName ' . 
                         'FROM tooltotasklinker ttl ' . 
                         'LEFT JOIN tools t ON ttl.ToolID = t.ToolID ' .
                         'WHERE ttl.TaskID=' . $tid . ' ' . 
                         'ORDER BY ttl.ToolPosition;';

                    // Run the query
                    $currentTools = $db->queryDB($sql, $userRow, "global_functions Form occurance 6");

                    // Determine if there are any rows before attempting to loop through them
                    if ($currentTools != null && 
                    mysqli_num_rows($currentTools)>0){
                        // Loop through the returned results
                        while ($currentTool=mysqli_fetch_array($currentTools)){
                            // Add this tool to the tools to check for while looping through code 
                            $toolsInGCode[$toolNumber]=array('CurrentPosition' => $currentTool["ToolPosition"],
                                                             'ToolName' => $currentTool["ToolName"]);
                            
                            // Increment the tool counting number
                            $toolNumber++;
                        }
                    }
                    
                    // Loop through the returned setups
                    while ($currentSetup=mysqli_fetch_array($currentSetups)){
                        // Hold onto a NEW details based on how the tools currently are
                        $newToolDetails="";
                        
                        // Split the string on end line characters
                        $tools = explode("\r", $currentSetup["ToolDetails"]);

                        // Loop through the file looking for end line characters
                        for ($i = 0; $i<count($tools); $i++) {
                            // Split the string on the tool name and number
                            $toolDetailsInfo = explode("-", $tools[$i], 2);
                            
                            // Ensure we get two values
                            if (count($toolDetailsInfo)==2){
                                // Loop through the tools found in order to replace key words
                                foreach ($toolsInGCode as $toolInfo) {
                                    // Determine if this is the same tool name
                                    if (trim($toolDetailsInfo[1]) == trim($toolInfo["ToolName"])) {
                                        // Replace any key words on this line for tools
                                        $newToolDetails = $newToolDetails . str_replace(trim($toolDetailsInfo[0]) . ' ', 'T' . $toolInfo['CurrentPosition'] . ' ', $tools[$i]);
                                        
                                        // Now that we found it, we can break out of this inner loop
                                        break;
                                    }                                
                                }                        
                            }
                        }
                        
                        // Make sure that I take into account quotes
                        $newToolDetails = $db->getDBConnection()->real_escape_string($newToolDetails);
                        
                        // Create a query to modify the setup table with the new tool details
                        $sql='UPDATE machiningsetups SET ModdedToolDetails = "' . $newToolDetails . '" ' . 
                             'WHERE MachiningSetupID='. $currentSetup["MachiningSetupID"] . ';'; 

                        // Attempt to run the update query
                        $db->queryDB($sql, $userRow, "global_functions Form occurance 7");
                    }
                }
            }
        } 
        catch (Exception $exc) {
            // Create the error string to return back to the caller
            return 'ABORT MODIFY (global_functions)::There an uncaught error modifying the Tool details to match new tool numbers.  The exception is: ' . $exc->getMessage() . '. Aborting...';
        }
        
        // Return what could be an error string
        return $errorString;
    }

    // Method that will remove everything under a directory including the directory
    function removeDirectory($directory) { 
        // Determine if we are currently being asked to remove a directory
        if (is_dir($directory)) { 
            // List any file in this directory
            $fileNames = scandir($directory);
            
            // Loop through the files
            foreach ($fileNames as $fileName) { 
                // Determine how relative it is to this directory
                if ($fileName != "." && $fileName != "..") { 
                    // Is it a directory
                    if (is_dir($directory. DIRECTORY_SEPARATOR .$fileName) && !is_link($directory . DIRECTORY_SEPARATOR . $fileName)){
                        // Call the recursion again on this directory inside of this directory
                        removeDirectory($directory. DIRECTORY_SEPARATOR .$fileName);
                    }
                    else{
                        // Remove what should be a file
                        unlink($directory. DIRECTORY_SEPARATOR .$fileName); 
                    }
                } 
            }
            
            // Remove the original passed in directory
            rmdir($directory); 
        } 
    }
    
    // Method to get which sandbox or real system that we are in.
    function getTMSHome(){
        // Just return the home created from checking out the directory of the file
        return explode('/', explode('/home/tmsadm/public_html/', dirname(__FILE__))[1])[0];
    }

    // Function to people to notify about stock levels
    function getStockNotificationEmails ($db, $userRow, $whichStock){
        // Create the return
        $returnEMails='';

        // Let's create and get the users to inform
        $sql='SELECT * 
              FROM users 
              WHERE CompanyID = 1
              AND UserTemplateOnly=0 
              AND ' . $whichStock . ' = 1;';
        $usersToNotify = $db->queryDB($sql, $userRow, "global_functions Form occurance 8");

        // Loop through the returned results
        while ($userToNofity=mysqli_fetch_array($usersToNotify)){
            // Add their e-mail to the return list
            $returnEMails .= $userToNofity["EMail"] . ',';
        }

        // Return the e-mails
        return $returnEMails;
    }
    
    function calculateForegroundHexColorFromBackgroundHexColor($hexBackgroundColorAsString){
        // Set the default value to be white as default
        $result = '#FFFFFF';
        
        // Create an offset to the numbers as zero at first
        $offset=0;
        
        // Create the RGB baluse to be black at first
        $red=0;
        $green=0;
        $blue=0;
        
        // Determine if they are including the pound sign in their string
        if (strlen($hexBackgroundColorAsString)==7 && substr($hexBackgroundColorAsString,0,1)=='#'){
            // Set the offset plus one
            $offset=1;
        }
        
        // Determine if There is anything in the string and it is the right size
        if (strlen($hexBackgroundColorAsString)==6 || 
            (strlen($hexBackgroundColorAsString)==7 && substr($hexBackgroundColorAsString,0,1)=='#')){
            // Attempt to convert hex to decimal for the RGB numbers
            $red=hexdec(substr($hexBackgroundColorAsString, $offset, 2));
            $green=hexdec(substr($hexBackgroundColorAsString, $offset+2, 2));
            $blue=hexdec(substr($hexBackgroundColorAsString, $offset+4, 2));

            // Create gamma factor of 2.2
            $gamma=2.2;
            
            // Make the formula now
            $colorResult = 0.2126 * pow($red/255, $gamma) +
                           0.7152 * pow($green/255, $gamma ) +
                           0.0722 * pow($blue/255, $gamma );
            
            // Now determine if the value created is greater than 50 percent
            if ($colorResult>.5){
                // Change the return text color to black
                $result='#000000';
            }
        }
        
        // return whatever we calculated or the default of white
        return $result;
    }

    function get_ip_address() {
        // check for shared internet/ISP IP
        if (!empty($_SERVER['HTTP_CLIENT_IP']) && validate_ip($_SERVER['HTTP_CLIENT_IP'])) {
            return $_SERVER['HTTP_CLIENT_IP'];
        }

        // check for IPs passing through proxies
        if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
            // check if multiple ips exist in var
            if (strpos($_SERVER['HTTP_X_FORWARDED_FOR'], ',') !== false) {
                $iplist = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
                foreach ($iplist as $ip) {
                    if (validate_ip($ip))
                        return $ip;
                }
            } else {
                if (validate_ip($_SERVER['HTTP_X_FORWARDED_FOR']))
                    return $_SERVER['HTTP_X_FORWARDED_FOR'];
            }
        }
        if (!empty($_SERVER['HTTP_X_FORWARDED']) && validate_ip($_SERVER['HTTP_X_FORWARDED']))
            return $_SERVER['HTTP_X_FORWARDED'];
        if (!empty($_SERVER['HTTP_X_CLUSTER_CLIENT_IP']) && validate_ip($_SERVER['HTTP_X_CLUSTER_CLIENT_IP']))
            return $_SERVER['HTTP_X_CLUSTER_CLIENT_IP'];
        if (!empty($_SERVER['HTTP_FORWARDED_FOR']) && validate_ip($_SERVER['HTTP_FORWARDED_FOR']))
            return $_SERVER['HTTP_FORWARDED_FOR'];
        if (!empty($_SERVER['HTTP_FORWARDED']) && validate_ip($_SERVER['HTTP_FORWARDED']))
            return $_SERVER['HTTP_FORWARDED'];

        // return unreliable ip since all else failed
        return $_SERVER['REMOTE_ADDR'];
    }

    /**
     * Ensures an ip address is both a valid IP and does not fall within
     * a private network range.
     */
    function validate_ip($ip) {
        if (strtolower($ip) === 'unknown')
            return false;

        // generate ipv4 network address
        $ip = ip2long($ip);

        // if the ip is set and not equivalent to 255.255.255.255
        if ($ip !== false && $ip !== -1) {
            // make sure to get unsigned long representation of ip
            // due to discrepancies between 32 and 64 bit OSes and
            // signed numbers (ints default to signed in PHP)
            $ip = sprintf('%u', $ip);
            // do private network range checking
            if ($ip >= 0 && $ip <= 50331647) return false;
            if ($ip >= 167772160 && $ip <= 184549375) return false;
            if ($ip >= 2130706432 && $ip <= 2147483647) return false;
            if ($ip >= 2851995648 && $ip <= 2852061183) return false;
            if ($ip >= 2886729728 && $ip <= 2887778303) return false;
            if ($ip >= 3221225984 && $ip <= 3221226239) return false;
            if ($ip >= 3232235520 && $ip <= 3232301055) return false;
            if ($ip >= 4294967040) return false;
        }
        return true;
    }

    /**
     * A PHP function that will generate a secure random password.
     * 
     * @param int $length The length that you want your random password to be.
     * @return string The random password.
     */
    function random_password($length){
        //A list of characters that can be used in our
        //random password.
        $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!-.[]?*()';
        //Create a blank string.
        $password = '';
        //Get the index of the last character in our $characters string.
        $characterListLength = mb_strlen($characters, '8bit') - 1;
        //Loop from 1 to the $length that was specified.
        foreach(range(1, $length) as $i){
            $password .= $characters[random_int(0, $characterListLength)];
        }
        return $password;

    }    
    
    function checkAndChangeStatusInfo($db, $userRow, $updateTaskID, $statusID){
        $sql='';
        try {
            // Get information about the current task before doing anything to it.
            $sql = 'SELECT t1.*, t2.StatusID AS ParentStatusID, t2.Title AS ParentTitle, ' . 
                          's2.Name AS ParentStatusNameBefore  ' . 
                   'FROM tasks t1 ' . 
                   'LEFT JOIN tasks t2 ON t1.ParentID = t2.TaskID ' .
                   'LEFT JOIN status s2 ON t2.StatusID = s2.StatusID ' .
                   'WHERE t1.TaskID = ' . $updateTaskID . ';';

            // Run the query to get the current task
            $currentTask = $db->queryDB($sql, $userRow, "global_functions occurance 1");

            // Ensure that the query came back well
            if (mysqli_num_rows($currentTask)==1){
                // Get the row as an array
                $currentAssocTaskRow = $currentTask->fetch_assoc();

                // Get some general information that we need.
                $oldStatusID=$currentAssocTaskRow["StatusID"];
                $companyID=$currentAssocTaskRow["CompanyID"];
                $parentStatusID=$currentAssocTaskRow["ParentStatusID"];
                $parentStatusNameBefore=$currentAssocTaskRow["ParentStatusNameBefore"];
                $parentTitle=$currentAssocTaskRow["ParentTitle"];
                $title=$currentAssocTaskRow["Title"];
                $parentTaskNumber=$currentAssocTaskRow["ParentID"];

                // Create the visualized task orientation as though this IS the parent
                $firstFour = str_pad($updateTaskID,4,"0",STR_PAD_LEFT);
                $lastFour = '0000';

                // Set the current status of the parent to one that we do not know.
                $parentStatusIDAfter = -1;

                // Determine if the status is changing
                if ($oldStatusID != $statusID){
                    // This is an update, so start making the update query
                    $sql='UPDATE taskstatus SET ';
                    $sql = $sql . 'EndDate=CURRENT_TIMESTAMP';
                    $sql = $sql . ', Comment="Change in status happening by ' . 
                           $userRow["FirstName"] . ' ' . $userRow["LastName"] . 
                           ' from myself."';
                    $sql = $sql . ', CompletingUserID=' . $userRow["UserID"];
                    $sql = $sql . ', Current=0';
                    $sql=$sql .' WHERE TaskID=' . $updateTaskID . ' ';
                    $sql=$sql .' AND ParentID=' . $parentTaskNumber . ' ';
                    $sql=$sql .' AND Current=1;';

                    // Attempt to run the query
                    $db->queryDB($sql, $userRow, "global_functions occurance 2");

                    // Determine if we are in delivered state. 10 is that state.
                    // TODO: I should have a flag in the DB for the finishing status
                    $endedDate = 'NULL';
                    If ($statusID==10){
                        // Since this is the delivered state, we end it immediately
                        $endedDate = 'CURRENT_TIMESTAMP';
                    }

                    // This is an insert, so start making the insert query
                    $sql='INSERT INTO taskstatus (TaskID, ParentID, StatusID, EndDate, Comment, StartingUserID, Current, AssignedToUserID) ' .  
                         'VALUES (' . $updateTaskID . ',' . $parentTaskNumber . ',' . $statusID . ',' . $endedDate . 
                                  ',"Change in status happening by ' . $userRow["FirstName"] . ' ' . $userRow["LastName"] . 
                                  ' from myself.",' . $userRow["UserID"] . ', 1, ' . $userRow["UserID"] . ');';

                    // Attempt to run the query
                    $db->queryDB($sql, $userRow, "global_functions occurance 3");

                    // Create a query to update the task to the status passed in
                    $sql='UPDATE tasks ' .
                         'SET StatusID=' . $statusID . ' ' .
                         'WHERE TaskID=' . $updateTaskID .';';

                    // Run the insert query
                    $db->queryDB($sql, $userRow, "global_functions occurance 12");
                    
                    // Determine if this is a parent or a child so we can make all of the status changes to the children as well.
                    if ($parentTaskNumber == 0){
                        // This is an update, so start making the update query
                        $sql='UPDATE taskstatus SET ';
                        $sql = $sql . 'EndDate=CURRENT_TIMESTAMP';
                        $sql = $sql . ', Comment="Change in status happening by ' . 
                               $userRow["FirstName"] . ' ' . $userRow["LastName"] . 
                               ' from my parent."';
                        $sql = $sql . ', CompletingUserID=' . $userRow["UserID"];
                        $sql = $sql . ', Current=0';
                        $sql=$sql .' WHERE ParentID=' . $updateTaskID . ' ';
                        $sql=$sql .' AND Current=1;';

                        // Attempt to run the query
                        $db->queryDB($sql, $userRow, "global_functions occurance 4");

                        // This is an insert, so start making the insert query
                        $sql='INSERT INTO taskstatus (TaskID, ParentID, StatusID, EndDate, Comment, StartingUserID, Current, AssignedToUserID) ' .  
                             'SELECT TaskID,' . $updateTaskID . ', ' . $statusID . ',' . $endedDate . ',"Change in status happening by ' . 
                                     $userRow["FirstName"] . ' ' . $userRow["LastName"] . ' from my parent.",' . 
                                     $userRow["UserID"] . ', 1, ' . $userRow["UserID"] . ' FROM tasks WHERE ParentID = ' . $updateTaskID . ';';

                        // Attempt to run the query
                        $db->queryDB($sql, $userRow, "global_functions occurance 5");
                    }
                    else {
                        // Create the visualized task orientation as though this IS the parent
                        $firstFour = str_pad($parentTaskNumber,4,"0",STR_PAD_LEFT);
                        $lastFour = str_pad($updateTaskID,4,"0",STR_PAD_LEFT);

                        // Create the query to get the correct the parent status
                        $sql =  'SELECT t.*, s.Name AS StatusName ' . 
                                '  FROM tasks t ' . 
                                '  JOIN status s on t.StatusID = s.StatusID ' . 
                                '  WHERE t.ParentID = ' . $parentTaskNumber . ' ' .
                                '  ORDER BY s.ProcessOrder ASC ' . 
                                '  LIMIT 1';

                        // Get the minimum status currently
                        $currentRollupRow = $db->queryDB($sql, $userRow, "global_functions occurance 6");

                        // Ensure that the query came back well
                        if (mysqli_num_rows($currentRollupRow)==1){
                            $currentAssocRollupRow = $currentRollupRow->fetch_assoc();
                            // Save the status that we are changing to to this
                            $parentStatusIDAfter = $currentAssocRollupRow["StatusID"];
                            $parentStatusNameAfter = $currentAssocRollupRow["StatusName"];

                            // Determine if the status is changing
                            if ($parentStatusID != $parentStatusIDAfter){
                                // This is updating the parent.  Put an entry into the parents table for statusinfo.
                                $sql='UPDATE taskstatus SET ';
                                $sql = $sql . 'EndDate=CURRENT_TIMESTAMP';
                                $sql = $sql . ', Comment="Change in status happening by ' . 
                                       $userRow["FirstName"] . ' ' . $userRow["LastName"] . 
                                       ' from child TaskID ' . $updateTaskID . 
                                       '. New status routing changed parent to first routing node."';
                                $sql = $sql . ', CompletingUserID=' . $userRow["UserID"];
                                $sql = $sql . ', Current=0';
                                $sql=$sql .' WHERE TaskID=' . $parentTaskNumber . ' ';
                                $sql=$sql .' AND Current=1;';

                                // Attempt to run the query
                                $db->queryDB($sql, $userRow, "global_functions occurance 4");

                                // This is an insert, so start making the insert query
                                $sql='INSERT INTO taskstatus (TaskID, ParentID, StatusID, EndDate, Comment, StartingUserID, Current, AssignedToUserID) ' .  
                                     'SELECT TaskID,' . $parentTaskNumber . ', ' . $parentStatusIDAfter . ',' . $endedDate . ',"Change in status happening by ' . 
                                             $userRow["FirstName"] . ' ' . $userRow["LastName"] . ' from my child TaskID ' . $updateTaskID . 
                                             '. New status routing changed parent to first routing node.",' . 
                                             $userRow["UserID"] . ', 1, ' . $userRow["UserID"] . ' FROM tasks WHERE TaskID = ' . $parentTaskNumber . ';';

                                // Attempt to run the query
                                $db->queryDB($sql, $userRow, "global_functions occurance 5");
                                
                                // Create the query to update the parent status
                                $sql =  'UPDATE tasks SET StatusID=' . $parentStatusIDAfter . 
                                        ' WHERE TaskID = ' . $parentTaskNumber . ';';

                                // Update the parent status and check that it changed
                                if ($db->queryDB($sql, $userRow, "global_functions occurance 7")){
                                    // Since successful, notify everyone who wants to know.
                                    // Let's create and get the users to inform.
                                    $sql='SELECT * 
                                          FROM users u
                                          LEFT JOIN (SELECT NotificationCategory, UserID FROM usertostatuslinker 
                                                     WHERE StatusID=' . $parentStatusIDAfter . ') usl ON u.UserID = usl.UserID
                                          WHERE u.UserID<>' . $userRow["UserID"] . '
                                          AND u.UserTemplateOnly=0 
                                          AND u.AccountStatus="Active"
                                          AND u.SilenceAllTaskNotifications<>1
                                          AND ((u.CompanyID = ' . $companyID . ') 
                                               OR (u.CompanyID = 1 AND u.SUEmployee=1) 
                                               OR (u.UserID = ' . $userRow["UserID"] . '));';

                                    // Make the query
                                    $usersToNotify = $db->queryDB($sql, $userRow, "global_functions occurance 8");

                                    // Loop through the returned results
                                    while ($userToNotify=mysqli_fetch_array($usersToNotify)){
                                        // Determine if this user is the same as the one adding it
                                        if ($userRow["UserID"]!=$userToNotify["UserID"]) {
                                            // Init the message
                                            $messageToSend='';

                                            // Determine if they care about status change or in packaging notifications. 
                                            //  Also if they are in the SU company and task is being 
                                            //  assigned to them.  The last is forced.)
                                            if (($userToNotify["NotificationCategory"]=="PARENT") || 
                                                ($userToNotify["NotificationCategory"]=="ALL") || 
                                                ($companyID==1 && $userToNotify["UserID"]==$userRow["UserID"])){
                                                // Create the message to add for this
                                                $messageToSend="<br>  ++ The Status has been changed from " .
                                                               $parentStatusNameBefore . 
                                                               " to " . $parentStatusNameAfter . ".  ";

                                                // Determine if this one is going into delivered
                                                if ($parentStatusNameAfter=='Delivered'){
                                                    // Inform that this completes the order
                                                    $messageToSend = $messageToSend . "This completes the FULL order.  It will be invoiced shortly.";
                                                }

                                                // add a carriage return
                                                $messageToSend = $messageToSend . "<br>";
                                            }

                                            // First determine if they care about any changes
                                            if ($messageToSend!="" && 
                                                preg_match("/^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,3})$/i", $userToNotify["EMail"])){

                                                // Set subscribed to as the default
                                                $messageToType = " that is under a category that you are currently monitoring.";
                                                $subjectToType = "EES Subscription Message: ";

                                                // Determine if this person is assigned to this task or not
                                                if ($userToNotify["UserID"]==$userRow["UserID"]){
                                                    // Change it to an assigned to message
                                                    $messageToType = " that you are ASSIGNED TO.";
                                                    $subjectToType = "EES ASSIGNED TO Message: ";
                                                }

                                                // Create the entire message
                                                $messageToSend= 'There have been changes made by ' . $userRow['FirstName'] . 
                                                        ' ' . $userRow['LastName'] . ' to a child task status ' . 
                                                        'that changed the parent task status' . $messageToType . 
                                                        '<br><br>COMPANY: "' . $currentAssocTaskRow['CompanyName'] . '"' .
                                                        '<br>Parent Task Title: "' . $parentTitle . '"' .
                                                        '<br>Parent TID: ' . $firstFour . '-0000<a href="https://www.eestms.com/' . 
                                                        getTMSHome() . '/updateTask.php?updateTaskID=' . $firstFour . 
                                                        '&parentTaskId=0">  (Click To View)</a>' .
                                                        '<br>Child Task Title: "' . $title . '"' .
                                                        '<br>Child TID: ' . $firstFour . '-' . $lastFour . '<a href="https://www.eestms.com/' .
                                                        getTMSHome() . '/updateTask.php?updateTaskID=' . $lastFour . 
                                                        '&parentTaskId=' . $firstFour . '">  (Click To View)</a>.' . '<br><br>Changes Made:' . 
                                                        $messageToSend;

                                                // Add a little more message to this notification
                                                $messageToSend = $messageToSend . '<br><br>If you need help with your user name or password, ' .
                                                        'you can reply to this e-mail or call us at (720)552-7997.<br><br>' .
                                                        'Regards, <br><br>Evolve Engineering and Software Support Team<br>' .
                                                        '(720)552-7997';

                                                // Decode the quotes to be shown as quotes.  Not weirdness
                                                $messageToSend = htmlspecialchars_decode ($messageToSend, ENT_COMPAT | ENT_HTML401);

                                                // Create the subject
                                                $subject = htmlspecialchars_decode ($subjectToType . "Status change Made to '" . 
                                                                                    $parentTitle . "' via changing " . 
                                                                                    "child task status for company '" . 
                                                                                    $currentAssocTaskRow["CompanyName"] . "'.");
                                                $headers = "From: EES Mail Admin"." <admin@eestms.com>\r\n"; 
                                                $headers .= "MIME-Version: 1.0\r\n";
                                                $headers .= "Content-type: text/html; charset=iso-8859-1\r\n";

                                                try {
                                                    // Attempt to mail it
                                                    mail($userToNotify["EMail"],$subject,$messageToSend,$headers);
                                                } 
                                                catch (Exception $e) {
                                                    return 'Notifications of status did not get sent. Check recipients e-mail addresses.';
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
            else {
                // Let the user know
                return 'Cannot get information about the current task in order to change the task status and notify appropriate people.';
            }
        } 
        catch (Exception $exc) {
            // Create the error string to return back to the caller
            return 'There was an uncaught error while trying to check or change status on task.  The exception is: ' . $exc->getMessage() . '. Aborting...';
        }
        
        // If we got here then assume success
        return "";
    }
    
 ?>