<?php

  /*

      reports.php

      Reports page.

      Changelog:
        2006-01-14 dave: Cleaned up code for v1.0 release
        2005-07-15 arne_sf: Added support for MS SQL database backend
        2005-07-09 arne_sf: Made the SQL code DBMS-specific, with support for PostgreSQL and MySQL
        2005-07-03 arne_sf: Replaced all instances of column name 'user' for table tbl_UserSites with 'userid'
          
      ## PAGE CONTAINS HANDYANDY MYSQL MODS ##
      ## Copyright (C) 2005 Andy Deakin (handya ndy.org.uk) ##

      ----

      Copyright (C) 2003  Central Manchester CLC
      Copyright (C) 2003  David Thorne (davethorne@gmail.com)

      This program is free software; you can redistribute it and/or
      modify it under the terms of the GNU General Public License
      as published by the Free Software Foundation version 2.

      This program is distributed in the hope that it will be useful,
      but WITHOUT ANY WARRANTY; without even the implied warranty of
      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      GNU General Public License for more details.

      You should have received a copy of the GNU General Public License
      along with this program; if not, write to the Free Software
      Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

  */

  // Start session and populate it with data
  session_start();

  // Page Security
  require_once 'system/security.php';
  if ($_SESSION['_usertype'] == '' || $_SESSION['_usertype'] == 'Client' ||
      $_SESSION['_usertype'] == 'Root') {
    ThrowOut();
  }

  // Includes
  require_once 'system/db.php';
  require_once 'system/lang.php';
  require_once 'system/functions.php';
  
  // Retrieve Get/Post variables
  $act = $_REQUEST['act'];
  $x = $_REQUEST['x'];
  $y = $_REQUEST['y'];
  $display = $_REQUEST['display'];
  $datefrom = $_REQUEST['datefrom'];
  $dateto = $_REQUEST['dateto'];
  $display2 = $_REQUEST['display'];

  if ($act == 'csv') {
    // Dont print any html stuff for csv output
    // Set the headers so the csv file can be saved
    require_once 'system/user_preferences.php';
    header("Content-Disposition: attachment; filename=summary.csv");
    header("Content-type: text/csv");
  } else {
    // Page Title
    $ptitle = "Summary";

    // Includes
    require 'header.php';
    require 'system/calendar.inc';
  }

  // Language selection
  set_text_domain("summary");

  // Data for the drop down selections
  // Possible comparisons
  $comparisons = array(
    'site'       => gettext('Site'),
    'assignedto' => gettext('User issues are assigned to'),
    'createdby'  => gettext('Users that created issues'),
    'reportedby' => gettext('Users that reported an issue'),
    //'associated' => 'Users associated with an issue',
    'priority'   => gettext('Issue Priority'),
    'status'     => gettext('Issue Status'),
    'level'      => gettext('Issue Level'),
    //'time10min'  => 'Time taken (in 10 minute increments)',
    //'time1hour'  => 'Time taken (in hourly increments)',
    //'dateday'    => 'Date (per day)',
    //'dateweek'   => 'Date (per week)',
    //'datemonth'  => 'Date (per month)'
  );

  // What information will be displayed
  $displaying = array(
    'amount'        => gettext('Number of issues'),
    'timetotal'     => gettext('Total time entered for issues by support agents'),
    'timeaverage'   => gettext('Average (mean) time entered per issue'),
    'lifetotal'     => gettext('Total time from issue creation to resolution (closed issues only)'),
    'lifeaverage'   => gettext('Average time from issue creation to resolution (closed issues only)')
  );

  function print_dropdown($name, $contents) {
    print "<select name=\"$name\">";
    foreach ($contents as $key => $desc) {
      print "<option value=\"$key\">$desc</option>";
    }
    print "</select>";
  }

  if ($act == '') {
?>
        <h1><?php echo gettext("Summary")?></h1>
        <h2><?php echo gettext("Please choose the categories to report on. To print a
            summary grouped by only one category, pick that category twice.")?></h2>
            
        <div class="block">
            <form name="mainform" method="get" action="">
                <input type="hidden" name="act" value="action" />
                <div align="center">
                    Compare
                    <?php print_dropdown('x', $comparisons); ?>
                    and
                    <?php print_dropdown('y', $comparisons); ?>
                    displaying
                    <?php print_dropdown('display', $displaying); ?>
                </div>
                    <p><?php echo gettext("Only consider issues created
                    between the following dates")?>:</p>
                <div class="labelfieldpair">
            <div class="name"><label><?php echo gettext("From")?></label></div>
                    <div class="field">
                        <input type="text" name="datefrom" id="datefrom" /> 
                        <a
                        href="javascript:showCalendar('caldatefrom','datefrom')"
                        >[ <?php echo gettext("calendar")?> ]</a>
                        <div id="caldatefrom" class="calendar"> </div>
                    </div>
                </div>
                <div class="labelfieldpair">
            <div class="name"><label><?php echo gettext("To")?></label></div>
                    <div class="field">
                        <input type="text" name="dateto" id="dateto" /> 
                        <a
                        href="javascript:showCalendar('caldateto','dateto')"
                        >[ <?php echo gettext("calendar")?> ]</a>
                        <div id="caldateto" class="calendar"> </div>
                    </div>
                </div>
                <div class="buttonpanel">
                    <input type="submit" value="<?php echo gettext("Run")?>" />
                </div>
            </form>
<?php
  }

  function to_time($data) {
    $days = floor($data / 86400);
    $data %= 86400;
    $hours = floor($data / 3600);
    $data %= 3600;
    $minutes = floor($data / 60);
    $seconds = $data % 60;
    if ($days > 1) return sprintf("%d days %02d:%02d", $days, $hours, $minutes);
    if ($days > 0) return sprintf("%d day %02d:%02d", $days, $hours, $minutes);
    return sprintf("%02d:%02d:%02d",$hours,$minutes,$seconds);
  }

  function run_query($fieldsx, $fieldsy, &$display) {
    global $aselects; global $afrom, $db;

    function maketimes($time) {
      if ($time && $time!='' && $time>=60) {
        $hours = floor($time/3600);
        $mins = substr("0" . floor(($time-($hours*3600))/60), -2);
        $time = "$hours:$mins";
        return $time;
      } else {
        return "-";
      }
    }
    
    global $datefrom;
    global $dateto;

    if ($db->phptype == "pgsql") {
      $axes = "vw_issues.{$fieldsx['id']}, vw_issues.{$fieldsy['id']}";
      $names = "vw_issues.{$fieldsx['name']}, vw_issues.{$fieldsy['name']}";
      $restrictions="tbl_Issues.domain = {$_SESSION['_domain']} AND vw_issues.id=tbl_Issues.id ";
    } else {
      $axes = "{$fieldsx['id']}, {$fieldsy['id']}";
      $names = "{$fieldsx['name']}, {$fieldsy['name']}";
      $restrictions="tbl_Issues.domain = {$_SESSION['_domain']} ";
    }

    // Restrict users to only the sites they are associated with
    $restrictions .= "AND tbl_UserSites.userid=$_SESSION[_id] AND
      tbl_Issues.site=tbl_UserSites.site";

    //
    // Add further restrictions on date
    //

    // Parse the dates given - if any
    $validdate = true;
    if ($datefrom != '') {
      $pieces = explode("/", $datefrom);
      if (count($pieces) == 1) {
        // Parse a date without slashes DDMMYYYY
        if (!is_numeric($pieces[0])) {
          $validdate = false;
        } elseif (strlen($pieces[0]) != 8) {
          $validdate = false;
        } else {
          $day = substr($pieces[0], 0,2);
          $month = substr($pieces[0], 2, 2);
          $year = substr($pieces[0], 4, 4);
          if (checkdate($month, $day, $year)) {
            $datefrom = mktime(0,0,0, $month, $day, $year);
          } else {
            $validdate = false;
          }
        }
      } elseif (count($pieces) == 3) {
        // Parse a date with slashes (DD/MM/YYYY)
        $day = intval($pieces[0]);
        $month = intval($pieces[1]);
        $year = intval($pieces[2]);
        if (!checkdate($month, $day, $year)) {
          // Invalid date
          $validdate = false;
        } else {
          $datefrom = mktime(0,0,0,$month, $day, $year);
        }
      } else {
        // Invalid date
        $validdate = false;
      }
    }
    if ($dateto != '') {
      $pieces = explode("/", $dateto);
      if (count($pieces) == 1) {
        // Parse a date without slashes DDMMYYYY
        if (!is_numeric($pieces[0])) {
          $validdate = false;
        } elseif (strlen($pieces[0]) != 8) {
          $validdate = false;
        } else {
          $day = substr($pieces[0], 0,2);
          $month = substr($pieces[0], 2, 2);
          $year = substr($pieces[0], 4, 4);
          if (checkdate($month, $day, $year)) {
            $dateto = mktime(23,59,59, $month, $day, $year);
          } else {
            $validdate = false;
          }
        }
      } elseif (count($pieces) == 3) {
        // Parse a date with slashes (DD/MM/YYYY)
        $day = intval($pieces[0]);
        $month = intval($pieces[1]);
        $year = intval($pieces[2]);
        if (!checkdate($month, $day, $year)) {
          // Invalid date
          $validdate = false;
        } else {
          $dateto = mktime(23,59,59,$month, $day, $year);
        }
      } else {
        // Invalid date
        $validdate = false;
      }
    }
    
    if (($datefrom != '' && $dateto == '') ||
        ($datefrom == '' && $dateto != '')) {
      $act = '';
      $message = gettext("CORRECTION: When restricting results by date, please enter both a 'from' date and a 'to' date.");
    } elseif ($datefrom >= $dateto && $datefrom != '') {
      $act = '';
      $message = gettext("CORRECTION: The 'to' date needs to be later than the 'from' date");
    } elseif (!$validdate) {
      $act = '';
      $message = gettext('CORRECTION: Invalid date entered - Dates must be entered in the form DD/MM/YYYY (with or without slashes) or selected from the popup calendar.');
    } else {
      // Date is okay - add the restriction (assuming a date was actually
      // entered)
      if ($datefrom != '' && $dateto != '') {
        $restrictions .= " AND tbl_Issues.createdon >= $datefrom AND
          tbl_Issues.createdon <= $dateto ";
      }

      //
      // Display method
      //

      // Did we ask for average or total?
      switch ($display) {
      case "timetotal":
      case "lifetotal":
        $oper = "SUM";
        break;
      case "timeaverage":
      case "lifeaverage":
        $oper = "AVG";
        break;
      case "amount":
        break;
      default:
        AccessDenied();
      }

      // Did we ask for time or lifecycle?
      switch ($display) {
      case "timetotal":
      case "timeaverage":
        $display = "time";
        break;
      case "lifetotal":
      case "lifeaverage":
        $display = "lifecycle";
        break;
      }

      // Now create the sql, separate versions for PostgreSQL and MySQL
      if ($display == 'amount') {
        $sql['pgsql'] = "SELECT COUNT(*) AS result, $axes, $names FROM vw_issues,
          tbl_usersites WHERE $restrictions GROUP BY $axes, $names";
        $sql['mysql'] = "SELECT COUNT(*) AS result, $aselects FROM $afrom
          WHERE $restrictions GROUP BY $axes, $names";
        $sql['mssql'] = $sql['mysql'];
      } elseif ($display == 'time') {
        $sql['pgsql'] = "SELECT $oper(time) AS result, $axes, $names FROM
          tbl_times, vw_issues, tbl_usersites WHERE tbl_times.issue =
          vw_Issues.id AND $restrictions GROUP BY $axes, $names";
        $sql['mysql'] = "SELECT $oper(time) AS result, $aselects FROM
          tbl_Times, $afrom WHERE tbl_Times.issue =
          tbl_Issues.id AND $restrictions GROUP BY $axes, $names";
        $sql['mssql'] = $sql['mysql'];
      } elseif ($display == 'lifecycle') {
        $closedstatus = get_closed_status($_SESSION['_domain']);
        $sql['pgsql'] = "SELECT $oper(closedon - createdon) AS result, $axes,
        $names FROM vw_issues, tbl_usersites WHERE status =
        $closedstatus AND $restrictions GROUP BY $axes, $names";
        $sql['mysql'] = "SELECT $oper(closedon - createdon) AS result, $aselects
          FROM $afrom WHERE tbl_Issues.status =
        $closedstatus AND $restrictions GROUP BY $axes, $names";
        $sql['mssql'] = $sql['mysql'];
      } else {
        // Shouldn't reach here unless user is doing something they shouldnt
        AccessDenied();
      }
            
      global $db;
      return db_recordset($sql[$db->phptype]);
    }
  }

  function get_fieldnames($field) {
  
    $fieldnames = array();
    switch ($field) {
    case 'site':
    case 'assignedto':
    case 'createdby':
    case 'reportedby':
    case 'priority':
    case 'status':
    case 'level':
      $fieldnames['id'] = $field;
      $fieldnames['name'] = "{$field}name";
      break;
    case 'associated':
    case 'time10min':
    case 'time1hour':
    case 'dateday':
    case 'dateweek':
    case 'datemonth':
    default:
      // This prevents sql injection from axes
      AccessDenied();
    }
    // Now for the header names
    switch ($field) {
    case 'site':
      $fieldnames['header'] = gettext('Site');
      break;
    case 'assignedto':
      $fieldnames['header'] = gettext('Assigned to');
      break;
    case 'createdby':
      $fieldnames['header'] = gettext('Created by');
      break;
    case 'reportedby':
      $fieldnames['header'] = gettext('Reported by');
      break;
    case 'priority':
      $fieldnames['header'] = gettext('Priority');
      break;
    case 'status':
      $fieldnames['header'] = gettext('Status');
      break;
    case 'level':
      $fieldnames['header'] = gettext('Level');
      break;
    case 'associated':
      $fieldnames['header'] = gettext('Associated users');
      break;
    case 'time10min':
      $fieldnames['header'] = gettext('Time spent');
      break;
    case 'time1hour':
      $fieldnames['header'] = gettext('Time spent');
      break;
    case 'dateday':
      $fieldnames['header'] = gettext('Date');
      break;
    case 'dateweek':
      $fieldnames['header'] = gettext('Date');
      break;
    case 'datemonth':
      $fieldnames['header'] = gettext('Date');
      break;
    }
    return ($fieldnames);
  }

  if ($act == 'action' || $act == 'csv') {
    // Validate x and y, and also get fieldnames for them
    // Fields are returned in an associative array
    $fieldsx = get_fieldnames($x);
    $x = $fieldsx['id'];
    $xname = $fieldsx['name'];

    $fieldsy = get_fieldnames($y);
    $y = $fieldsy['id'];
    $yname = $fieldsy['name'];

    // Get the display heading
    switch($display) {
    case 'amount':
      $displayheader = gettext("total number of issues");
      break;
    case 'timetotal':
      $displayheader = gettext("total time spent on issues");
      break;
    case 'timeaverage':
      $displayheader = gettext("average time spent on issues");
      break;
    case 'lifetotal':
      $displayheader = gettext("total time from issue creation to resolution");
      break;
    case 'lifeaverage':
      $displayheader = gettext("average time from issue creation to resolution");
      break;
    default:
      $displayheader = gettext("summary report");
    }

    // Now get a summary of all issues
    $results = run_query($fieldsx, $fieldsy, $display);
    $xhead = array();
    $yhead = array();
    foreach ($results as $result) {
      // Split the results into a two dimensional array addressed by the
      // header id's
      $data[$result[$x]][$result[$y]] = $result['result'];
      // Add the header data for the result
      $xhead[$result[$xname]] = $result[$x];
      $yhead[$result[$yname]] = $result[$y];
    }
    ksort($yhead);
    ksort($xhead);

    if ($act == 'csv') {
      // First check to see if we actually have 2 different comparisons
      // (otherwise only need 1 axis
      if ($x != $y) {
        // First line is the X axis headers
        // But first item should be blank (y axis headers column)
        // removing the need for a $flag style don't print the comma the
        // first time round.
        foreach ($xhead as $name => $id) {
          echo ",$name";
        }
        print "\n";

        // First column of each further line is the Y axis headers
        foreach ($yhead as $yfield => $yid) {
          echo preg_replace('/\* unassigned \*/',gettext('* unassigned *'),$yfield);
          foreach($xhead as $xfield => $xid) {
            $current = $data[$xid][$yid];
            $number = isset($current) ? $current:'0';
            if ($display == 'lifecycle' && $number != '0') {
              $number = to_time($number);
            } elseif ($display == 'time') {
              $number = maketimes($number);
              ##  $number = explode(".", $number);
              ## $number = $number[0];
            }
            echo ",$number";
          }
          print "\n";
        }
      } else {
        foreach($yhead as $yfield => $yid) {
          echo $yfield;
          $current = $data[$yid][$yid];
          $number = isset($current) ? $current:'0';
          if ($display == 'lifecycle' && $number != '0') {
            $number = to_time($number);
          } elseif ($display == 'time') {
            $number = maketimes($number);
            ##  $number = explode(".", $number);
            ## $number = $number[0];
          }
          echo gettext(",$number\n");
        }
      }
    } else {
?>
    <h1><?php echo gettext("Summary report")?></h1>
    <h2><?php echo gettext("Displaying the")?> <?php echo $displayheader?>. <a
      href="summary.php?act=csv&amp;x=<?php echo $x?>&amp;y=<?php echo $y?>&amp;display=<?php echo $display?>"><?php echo gettext("Export to csv")?>...</a></h2>
    
    <div class="block">
<?php
      // Start drawing the results
      if ($x == $y) {
        echo '<table border="0" align="center" cellpadding="1"' .
          'cellspacing="0" style="width: 90%;"' .
          'summary="'.gettext("Report table of the issue management system").'">';
        echo '<thead>';
        echo '<tr><th align="left" valign="bottom" class="issueheader">';
        echo "{$fieldsy['header']}</th>";
        echo '<th class="issueheader">&nbsp;</th>';
        echo '</tr>';
        echo '</thead>';
        echo '<tbody>';
        foreach ($yhead as $yfield => $yid) {
          echo '<tr><td align="left" class="issuecelldark">&nbsp;';
          echo "$yfield</td>";

          $current = $data[$yid][$yid];
          $number = isset($current) ? $current:'-';
          if ($display == 'lifecycle' && $number != '-') {
            $number = to_time($number);
          } elseif ($display == 'time') {
            $number = maketimes($number);
            ##  $number = explode(".", $number);
            ## $number = $number[0];
          }
          echo '<td align="center" class="issuecell">&nbsp;';
          echo "$number</td></tr>";
        }
        echo '</tbody>';
        echo '</table>';
      } else {
        // Split y headers into groups, so that the table will be split over
        // more than one line if it is too wide for the screen
        $maxwidth = 5;

        $xgroup = array_chunk($xhead, $maxwidth, true);
        
        foreach($xgroup as $xhead) {
          echo '<table border="0" align="center" cellpadding="1"' .
            'cellspacing="0" style="width: 90%;"' .
            'summary="'.gettext("Report table of the issue management system").'">';
          echo '<thead>';
          echo '<tr><th>&nbsp;</th><th align="center"
            colspan="' . count($xhead) . '">' . $fieldsx['header'] .
            '</th></tr>';
          echo '<tr><th align="left" valign="bottom" class="issueheader">';
          if ($xhead == $xgroup[0]) {
            echo "{$fieldsy['header']}";
          } else {
            echo "&nbsp;";
          }
          echo "</th>";

          foreach ($xhead as $name => $id) {
            echo '<th class="issueheader" valign="bottom">' .
              $name . "</th>\n";
          }
          echo '</tr>';
          echo '</thead>';
          echo '<tbody>';
          foreach ($yhead as $yfield => $yid) {
            echo '<tr><td align="left" class="issuecelldark">&nbsp;';
            echo preg_replace('/\* unassigned \*/',gettext('* unassigned *'),$yfield)."</td>";
            
            foreach($xhead as $xfield => $xid) {
              $current = $data[$xid][$yid];
              $number = isset($current) ? $current:'-';
              if ($display == 'lifecycle' && $number != '-') {
                $number = to_time($number);
              } elseif ($display == 'time') {
                $number = maketimes($number);
                ##  $number = explode(".", $number);
                ## $number = $number[0];
              }
              echo '<td align="center" class="issuecell">&nbsp;';
              echo "$number</td>";
            }

            echo '</tr>';
          }
          echo '</tbody>';
          echo "</table>";
        }
      }
?>
        
<?php
    }
  }
  
  if ($act != 'csv') {
    print "     </div>";
    
    // Include
    require 'footer.php';
  }
?>
