<?php

/**
 * File containing timetable class.
 *
 * @package    mod_timetable
 * @copyright  2020 Raphael Dannecker <raphael.dannecker@steinbeisschule-reutlingen.de>
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 */

namespace mod_timetable;

require_once('lesson.php');

defined('MOODLE_INTERNAL') || die();

const FLAG_Entfall       = 0b0000000000000001;
const FLAG_Betreuung     = 0b0000000000000010;
const FLAG_Sondereinsatz = 0b0000000000000100;
const FLAG_Wegverlegung  = 0b0000000000001000;
const FLAG_Freisetzung   = 0b0000000000010000;
const FLAG_PlusVertreter = 0b0000000000100000;
const FLAG_Teilverlegung = 0b0000000001000000;
const FLAG_Hinverlegung  = 0b0000000010000000;

function lesson_in_lessons($obj, $array) {
  for($n=0;$n<count($array);$n++) {
    if ($obj->lessonid== $array[$n]->lessonid &&
      $obj->teacher == $array[$n]->teacher &&
      $obj->subject == $array[$n]->subject &&
      $obj->class   == $array[$n]->class &&
      $obj->room    == $array[$n]->room &&
      $obj->type    == $array[$n]->type) return true;
  }
  return false;
}

function collapse_lessons($array) {
  $result = array();
  foreach ($array as $lesson) {
    $integrated = false;
    foreach ($result as $rlesson) {
      if ($rlesson->integrate($lesson)) $integrated = true;
    }
    if (!$integrated) $result[] = $lesson;
  }
  return $result;
}

/**
 * Class timetable
 *
 * @package    mod_timetable
 * @copyright  2020 Raphael Dannecker <raphael.dannecker@steinbeisschule-reutlingen.de>
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 */
class timetable {

  /** @var array the data of timetable */
  public $data;
  //public $lessons;
  //public $lessons_canceled;

  /**
   * Class constructor
   *
   * @param string $type The type of the timetable [class, room, teacher]
   * @param string $name Name of class or room or teacher
   */
  public function __construct($type, $name) {
    $this->type = $type;
    $this->name = $name;
    $this->periodmax=0;
    $this->clear_data();
  }

  public function clear_data() {
    $this->data = array();
    $this->lessons = array();
    $this->lessons_canceled = array();
    $this->lessons_event = array();
    for ($i=1; $i<=6; $i++) {
      $this->data[$i] = array();
      $this->lessons[$i] = array();
      $this->lessons_canceled[$i] = array();
      $this->lessons_event[$i] = array();
      for ($j=1; $j<=15; $j++) {
        $this->lessons[$i][$j] = array();
        $this->lessons_canceled[$i][$j] = array();
        $this->lessons_event[$i][$j] = array();
      }
    }
  }


  /**
   *
   * @param int $week The week of timetable
   */
  public function read_db($week) {
    global $USER, $DB, $CFG;

    $this->clear_data();
    $this->numdayweek = 5 + get_config('timetable', 'saturday');
    $this->week = $week;
    $this->monday = new \DateTime();
    $this->monday->setISODate($this->monday->format("Y"), $week);
    $dayofweek = $this->monday->format('w');
    if ($dayofweek > $this->numdayweek) {
      $this->monday->add(new \DateInterval("P".(8-$dayofweek)."D"));
    } elseif ($dayofweek < 1) {
      $this->monday->add(new \DateInterval("P1D"));
    } else {
      $this->monday->sub(new \DateInterval("P".($dayofweek-1)."D"));
    }

    $this->week = intval($this->monday->format("W"));
    $this->lastday = new \DateTime($this->monday->format('Y-m-d\TH:i:sP'));
    $this->lastday->add(new \DateInterval("P".($this->numdayweek-1)."D"));

    $sql = "$this->type = '$this->name' AND NOT lessonid=0 AND (mid(week, $this->week, 1) = '1')";
    $result = $DB->get_records_select('timetable_lesson',$sql);
    foreach ($result as $lesson) {
      $lesson->type = "normal";
      if (!lesson_in_lessons($lesson, $this->lessons[$lesson->day][$lesson->period]))
        $this->lessons[$lesson->day][$lesson->period][] = new lesson($lesson);
    }
    $sql = "$this->type = '$this->name' AND lessonid=0 AND (mid(week, $this->week, 1) = '1')";
    $result = $DB->get_records_select('timetable_lesson',$sql);
    foreach ($result as $lesson) {
      $lesson->type = "event";
      if (!lesson_in_lessons($lesson, $this->lessons[$lesson->day][$lesson->period]))
        $this->lessons[$lesson->day][$lesson->period][] = new lesson($lesson);
    }
    $sql = "$this->type = '$this->name' and (mid(week, $this->week, 1) = 'x')";
    $result = $DB->get_records_select('timetable_lesson',$sql);
    foreach ($result as $lesson) {
      $lesson->type = "canceled";
      if (!lesson_in_lessons($lesson, $this->lessons[$lesson->day][$lesson->period]))
        $this->lessons[$lesson->day][$lesson->period][] = new lesson($lesson);
    }

    $day = new \DateTime($this->monday->format('Y-m-d\TH:i:sP'));
    for ($i=0; $i<$this->numdayweek; $i++) {
      $sql = "date = '".$day->format('Ymd')."' AND ({$this->type}a RLIKE '(^|~){$this->name}($|~)' OR {$this->type}b RLIKE '(^|~){$this->name}($|~)')";
      $result = $DB->get_records_select('timetable_substitution',$sql);
      foreach ($result as $substitution) {
        foreach ($this->lessons[$i+1][$substitution->period] as $lesson) {
          $lesson->process_substitution($substitution);
        }
      }

      $types = array('teacher'=>'L', 'class'=>'K', 'room'=>'R');
      $sql = "startdate <= '".$day->format('Ymd')."' AND enddate >= '".$day->format('Ymd')."' AND type = '{$types[$this->type]}' AND name = '{$this->name}'";
      $result = $DB->get_records_select('timetable_absence',$sql);
      foreach ($result as $absence) {
        for ($j=$absence->startperiod; $j<=$absence->endperiod; $j++) {
          foreach ($this->lessons[$i+1][$j] as $lesson) {
            if ($lesson->type == 'event') $lesson->process_absence($absence);
          }
        }
      }

      $day->add(new \DateInterval("P1D"));
    }

    for ($i=0; $i<$this->numdayweek; $i++) {
      foreach($this->lessons[$i+1] as &$lessons) $lessons = collapse_lessons($lessons);
      // not to be done for events???
    }

    if ($this->type == 'teacher') {
      if ($result = $DB->get_record("timetable_$this->type",[$this->type => $this->name])) {
        $this->description = "$result->surname, $result->firstname";
      }
    } else {
      if ($result = $DB->get_record("timetable_$this->type",[$this->type => $this->name])) {
        $this->description = $result->description;
      }
    }

    $sql = "day = 1 ORDER BY period asc";
    $this->times = $DB->get_records_select('timetable_time',$sql);
  }

  public function get_periodmax() {
    //$maxperiod = get_config('timetable', 'numperiod');
    $maxperiod = 0;
    for ($i=0; $i<$this->numdayweek; $i++) {
      foreach($this->lessons[$i+1] as $period => $lessons) 
        if ($period > $maxperiod && count($lessons)) $maxperiod = $period;
    }
    return $maxperiod;
  }

  public function prepare_output() {
    $resultdata = array();

    $numperiod = max($this->get_periodmax(), get_config('timetable', 'numperiod'));

    $numdayweek = 5 + get_config('timetable', 'saturday');
    if ($numdayweek == 6) $resultdata['saturday'] = 1; else $resultdata['saturday'] = 0;

    $resultdata['type'] = $this->type;
    $resultdata['viewteacher'] = ($this->type == 'teacher') ? "1" : "";;
    $resultdata['viewclass'] = ($this->type == 'class') ? "1" : "";;
    $resultdata['viewroom'] = ($this->type == 'room') ? "1" : "";;
    $resultdata['name'] = $this->name;
    $resultdata['description'] = $this->description;
    $resultdata['date'] = $this->monday->format('d.m') . " - " . $this->lastday->format('d.m');
    $resultdata['week'] = $this->week;
    $resultdata['prevweek'] = $this->week-1;
    $resultdata['nextweek'] = $this->week+1;
    $resultdata['id'] = \substr(\md5(\rand()), 0, 7);
    $periods = array();

    for ($period=0; $period<$numperiod; $period++) {
      $days = array();
      for ($day=0; $day<$numdayweek; $day++) {
        $days[$day] = array();
        $days[$day]['substitutionold'] = "";
        $days[$day]['lessons'] = array();
        foreach ($this->lessons[$day+1][$period+1] as $lesson) {
          $mylesson = array();
          $mylesson['class'] = $lesson->class;
          $mylesson['teacher'] = $lesson->teacher;
          $mylesson['room'] = $lesson->room;
          $mylesson['subject'] = $lesson->subject;
          $mylesson['classa'] = $lesson->classa;
          $mylesson['teachera'] = $lesson->teachera;
          $mylesson['rooma'] = $lesson->rooma;
          $mylesson['subjecta'] = $lesson->subjecta;
          $mylesson['classb'] = property_exists($lesson,'classb') ? $lesson->classb : null;
          $mylesson['teacherb'] = property_exists($lesson,'teacherb') ? $lesson->teacherb : null;
          $mylesson['roomb'] = property_exists($lesson,'roomb') ? $lesson->roomb : null;
          $mylesson['subjectb'] = property_exists($lesson,'subjectb') ? $lesson->subjectb : null;
          $mylesson['substitution'] = $lesson->substitution;
          $mylesson['subjectchanged'] = $lesson->subjectchanged;
          $mylesson['teacherchanged'] = $lesson->teacherchanged;
          $mylesson['classchanged']   = $lesson->classchanged;
          $mylesson['roomchanged']    = $lesson->roomchanged;
          $mylesson['cancel'] = "";
          $mylesson['cancel4me'] = "";
          $mylesson['event'] = "";
          $mylesson['status'] = "";
          $mylesson['flag'] = "";
          $mylesson['text'] = $lesson->text;
          $mylesson['subtype'] = Array();
          if ($lesson->subtype) {
            for ($i=0; $i<32; $i++) {
              if ($lesson->subtype & (1<<$i)) $mylesson['subtype'][] = $i+1;
            }
          }
          $days[$day]['substitutionold'] .= $lesson->text;
          if ($lesson->type == 'event') {
            $mylesson['event'] = $lesson->reason ? $lesson->reason : "Event";
            $mylesson['status'] = "1";
            $mylesson['flag'] = "1";
	  } elseif ($lesson->type == 'canceled') {
            $mylesson['cancel'] = "1";
            $mylesson['cancel4me'] = "";
            if (($lesson->teacherchanged && $this->type == 'teacher') ||
              ($lesson->classchanged   && $this->type == 'class')   ||
              ($lesson->roomchanged    && $this->type == 'room')) $mylesson['cancel4me'] = "cancel4me";
            $mylesson['status'] = "1";
            $mylesson['flag'] = "1"; // status und flag werden vertauscht (im Template bzw. extern-lib.php
          }
          $days[$day]['lessons'][] = $mylesson;
        }
      }
      $periods[$period] = array();
      $periods[$period]['days'] = $days;
      $periods[$period]['number'] = $period+1;
      $periods[$period]['starttime'] = substr_replace($this->times[$period+1]->starttime, ":",-2,0);
      $periods[$period]['endtime'] = substr_replace($this->times[$period+1]->endtime, ":",-2,0);
    }
    $resultdata['periods'] = $periods;
    return $resultdata;
  }

}