function ProjectWalker($devID, $fileSave, $projID)
{
    global $sqlSess;
    global $repStartDate;
    global $numWeeks;
    global $startOfWeek;
    global $projTableAttr;
    global $projTable;
    global $showAsWeeks;
    global $showHoliday;
    global $byDeveloper;
    $h = new Holidays($repStartDate);
    $projRow = 3;
    $lastProj = 0;
    // The current week
    $repWeek = date("y", $startOfWeek) . date("W", $startOfWeek);
    $rowText = "";
    if ($sqlSess) {
        // Get all the relavant tasks
        // Note tcmax is the most recent task completion estimate - needed to ensure that jobs which are completed earlier
        // than estimate are not included in later reports
        $sql = "select t.taskid, tc.completionid, t.taskname, t.developerid, u.name, u.username, t.createddate t_createddate,\r\n          tc.statusid, tc.completiondate,tc.createddate tc_createddate, p.projectname, p.projectid, tc.commencedate\r\n          from taskcompletion tc, task t, users u, project p, taskcompletion tcmax\r\n          where tc.taskid=t.taskid and t.developerid = u.userid and p.projectid = t.projectid\r\n          and tc.taskid = tcmax.taskid and tcmax.completionid = (select max(completionid) from taskcompletion where taskid=tc.taskid)\r\n          and tc.completiondate >= '" . date("Y-m-d", $repStartDate) . "'\r\n          and tcmax.completiondate >= '" . date("Y-m-d", $repStartDate) . "'";
        if ($devID != "") {
            $sql = $sql . " and username = '******'";
        }
        if ($projID != "") {
            $sql = $sql . " and p.projectid = {$projID}";
        }
        if ($byDeveloper) {
            $sql = $sql . " order by u.name, p.projectid, t.createddate, tc.completionid";
        } else {
            $sql = $sql . " order by p.projectid, t.createddate, tc.completionid";
        }
        debug($sql);
        $taskRes = mysql_query($sql, $sqlSess);
        if ($taskRes) {
            $nextRow = mysql_fetch_array($taskRes);
            // Loop until all tasks are processed
            while ($nextRow) {
                // Create a header row for each project
                if ($nextRow['projectid'] != $lastProj) {
                    // Project header spans the whole table
                    $colSpan = $numWeeks * 2 + 2;
                    $projTableAttr[] = array("class='pr' colspan='{$colSpan}'");
                    if ($fileSave) {
                        $projTable[] = array($nextRow['projectname']);
                    } else {
                        // The project name + the edit and timesheet hyperlinks
                        $projTable[] = array(MakeURL("matrix", "proj=" . $nextRow['projectid'], $nextRow['projectname']) . " (" . MakeURL("proj", "proj=" . $nextRow['projectid'], "Edit project") . ") " . "(" . MakeURL("projecttime", "proj=" . $nextRow['projectid'], "Timesheet") . ")");
                    }
                    $lastProj = $nextRow['projectid'];
                    $projRow++;
                }
                // Alternate color stripes
                if ($projRow % 2 == 0) {
                    $pclass = "proj-e";
                    $lclass = "late-e";
                    $bclass = "block-e";
                    $sclass = "start-e";
                    $cclass = "comp-e";
                } else {
                    $pclass = "proj-o";
                    $lclass = "late-o";
                    $bclass = "block-o";
                    $sclass = "start-o";
                    $cclass = "comp-o";
                }
                // Initialise matrix row for current project. classes for first two cells
                $tdAttr = "class='ind',class='de'";
                if ($fileSave) {
                    $rowText = $nextRow['taskname'] . "," . $nextRow['name'];
                } else {
                    $rowText = "" . MakeURL("task", "task=" . $nextRow['taskid'], $nextRow['taskname']) . "," . MakeURL("matrix", "user="******"y", $repStartDate) . date("W", $repStartDate);
                // loop for each week in the report
                for ($i = 1; $i <= $numWeeks * 2; $i++) {
                    $chClass = "";
                    // Don't check the next row if at the end of the result set
                    if ($nextRow) {
                        $checkNextRow = True;
                    } else {
                        $checkNextRow = False;
                    }
                    // Check the next completion estimate to see if it is for the current project
                    // and was created during the current week in the report, If so loop until find
                    // the most up to date estimate in the current week.
                    // and check again. If not carry on using the currnet estimate.
                    while ($checkNextRow) {
                        if ($nextRow['taskid'] == $curRow['taskid'] and $cellWeek >= date("y", strtotime($nextRow['tc_createddate'])) . date("W", strtotime($nextRow['tc_createddate']))) {
                            $chClass = " change";
                            $curRow = $nextRow;
                            $nextRow = mysql_fetch_array($taskRes);
                            if (!$nextRow) {
                                $checkNextRow = false;
                            }
                        } else {
                            $checkNextRow = false;
                        }
                    }
                    // Get the started week, completed week and created week of the current completion estimate
                    $compWeek = date("y", strtotime($curRow['completiondate'])) . date("W", strtotime($curRow['completiondate']));
                    $createWeek = date("y", strtotime($curRow['tc_createddate'])) . date("W", strtotime($curRow['tc_createddate']));
                    $st = strtotime($curRow['commencedate']);
                    if ($st > 1) {
                        $startWeek = date("y", $st) . date("W", $st);
                    } else {
                        $startWeek = $createWeek;
                    }
                    // Is the task active (in prgress or completed, not on hold or blocked)
                    if ($curRow['statusid'] == 2 or $curRow['statusid'] == 5) {
                        $taskActive = true;
                    } else {
                        $taskActive = false;
                    }
                    // Get the cell value (week number or date of estimate depending on display mode)
                    // This will be used lower down to populate the cell if required
                    if ($showAsWeeks) {
                        $compStr = substr($compWeek, 2, 2);
                    } else {
                        $compStr = date("d", strtotime($curRow['completiondate'])) . "/" . date("m", strtotime($curRow['completiondate']));
                    }
                    // If options are to show out of office, and user is out of office mark as out
                    if ($showHoliday and $h->IsHoliday($curRow['developerid'], substr($cellWeek, 2, 2))) {
                        $rowText = $rowText . ",Out";
                        if ($projRow % 2 == 0) {
                            $tdAttr = $tdAttr . ",class='hol-e'";
                        } else {
                            $tdAttr = $tdAttr . ",class='hol-o'";
                        }
                    } else {
                        // If the completion estimate was created after the current week or the current
                        // week is in the future don't display a week number
                        if ($cellWeek < $createWeek or $cellWeek > $repWeek) {
                            $rowText = $rowText . ",";
                            // If the current week is in the future, but inside the scope of the completion
                            // estimate mark the cell as being in the project
                            if ($cellWeek > $createWeek and $cellWeek <= $compWeek and $taskActive or $cellWeek >= $startWeek and $cellWeek <= $compWeek and !$taskActive) {
                                if ($cellWeek > $createWeek) {
                                    $tdAttr = $tdAttr . ",class='{$pclass}'";
                                    $rowText = $rowText . "*";
                                } else {
                                    $tdAttr = $tdAttr . ",class='{$sclass}'";
                                }
                            } else {
                                // If the current week is in the past, but inside the scope of the task
                                // start date, mark the cell as being in the project
                                if ($cellWeek < $startWeek or $cellWeek > $repWeek) {
                                    $tdAttr = $tdAttr . ",";
                                } else {
                                    $tdAttr = $tdAttr . ",class='{$sclass}'";
                                }
                            }
                        } elseif ($cellWeek <= $compWeek) {
                            $rowText = $rowText . "," . $compStr;
                            switch ($curRow['statusid']) {
                                case 1:
                                    // Not Started
                                    if ($cellWeek >= $startWeek) {
                                        $cellClass = $sclass;
                                        $rowText = $rowText . "N";
                                    } else {
                                        $cellClass = "";
                                        $rowText = $rowText . "n";
                                    }
                                    break;
                                case 2:
                                    // In progress
                                    $cellClass = $pclass;
                                    break;
                                case 5:
                                    // completed
                                    $cellClass = $cclass;
                                    if ($cellWeek == $compWeek) {
                                        $rowText = $rowText . "c";
                                    }
                                    break;
                                case 4:
                                    // Blocked
                                    $cellClass = $bclass;
                                    $rowText = $rowText . "b";
                                    break;
                                default:
                                    $cellClass = "";
                            }
                            if ($cellWeek == $repWeek) {
                                $tdAttr = $tdAttr . ",class='{$cellClass} today{$chClass}'";
                            } else {
                                $tdAttr = $tdAttr . ",class='{$cellClass}{$chClass}'";
                            }
                        } elseif ($cellWeek > $compWeek && $cellWeek == $createWeek && $curRow['statusid'] == 5) {
                            $tdAttr = $tdAttr . ",class='{$cclass}'";
                            $rowText = $rowText . "," . $compStr . "c";
                        } else {
                            if ($curRow['statusid'] != 5) {
                                $rowText = $rowText . "," . $compStr;
                                if ($cellWeek == $repWeek) {
                                    $tdAttr = $tdAttr . ",class='{$lclass} today'";
                                } else {
                                    $tdAttr = $tdAttr . ",class='{$lclass}'";
                                }
                            } else {
                                $rowText = $rowText . ",";
                                if ($cellWeek == $repWeek) {
                                    $tdAttr = $tdAttr . ",class='today'";
                                } else {
                                    $tdAttr = $tdAttr . ",";
                                }
                            }
                        }
                    }
                    //$cellWeek++;
                    $nxtDate = strtotime("+{$i} weeks", $repStartDate);
                    $cellWeek = date("y", $nxtDate) . date("W", $nxtDate);
                }
                $projTableAttr[] = explode(",", $tdAttr);
                $projTable[] = explode(",", $rowText);
                $projRow++;
            }
        }
    }
    return $rowText;
}