<?php
declare(strict_types=1);
namespace MRBS\Calendar;

use MRBS\DateTime;
use function MRBS\day_of_MRBS_week;
use function MRBS\escape_html;
use function MRBS\format_iso_date;
use function MRBS\get_end_last_slot;
use function MRBS\get_entries_by_area;
use function MRBS\get_rooms;
use function MRBS\get_start_first_slot;
use function MRBS\get_vocab;
use function MRBS\multisite;


class CalendarMultidayMultiroom extends Calendar
{

  private $day_start_interval;
  private $n_days;
  private $start_dow;

  public function __construct(string $view, int $view_all, int $year, int $month, int $day, int $area_id, int $room_id)
  {
    global $weekstarts, $resolution;

    parent::__construct($view, $view_all, $year, $month, $day, $area_id, $room_id);

    // Calculate/get:
    //    the first day of the interval
    //    how many days there are in it
    //    the day of the week of the first day in the interval
    $time = mktime(12, 0, 0, $this->month, $this->day, $this->year);
    switch ($this->view)
    {
      case 'week':
        $skipback = day_of_MRBS_week($time);
        $this->day_start_interval = $this->day - $skipback;
        $this->n_days = DAYS_PER_WEEK;
        $this->start_dow = $weekstarts;
        break;
      case 'month':
        $this->day_start_interval = 1;
        $this->n_days = (int) date('t', $time);
        $this->start_dow = (int) date('N', mktime(12, 0, 0, $this->month, 1, $this->year));
        break;
      default:
        trigger_error("Unsupported view '$this->view'", E_USER_WARNING);
        break;
    }

    $this->start_date = (new DateTime())->setTimestamp(get_start_first_slot($this->month, $this->day_start_interval, $this->year));
    $this->end_date = (new DateTime())->setTimestamp(get_end_last_slot($this->month, $this->day_start_interval + $this->n_days-1, $this->year));

    // Get the data.  It's much quicker to do a single SQL query getting all the
    // entries for the interval in one go, rather than doing a query for each day.
    $entries = get_entries_by_area($this->area_id, $this->start_date, $this->end_date);

    // We want to build an array containing all the data we want to show and then spit it out.
    $this->map = new Map($this->start_date, $this->end_date, $resolution);
    $this->map->addEntries($entries);
  }


  // TODO: Handle the case where there is more than one booking per slot
  public function innerHTML(): string
  {
    global $row_labels_both_sides, $column_labels_both_ends;
    global $view_all_always_go_to_day_view;

    // It's theoretically possible to display a transposed table with rooms along the top and days
    // down the side.  However, it doesn't seem a very useful display and so hasn't yet been implemented.
    // The problem is that the results don't look good whether you have the flex direction as 'row' or
    // 'column'.  If you set it to 'row' the bookings are read from left to right within a day, but from
    // top to bottom within the interval (week/month), so you have to read the display by snaking down
    // the columns, which is potentially confusing.  If you set it to 'column' then the bookings are in
    // order reading straight down the column, but the text within the bookings is usually clipped unless
    // the booking lasts the whole day.  When the days are along the top and the text is clipped you can
    // at least see the first few characters which is useful, but when the days are down the side you only
    // see the top of the line.
    //
    // As a result $days_along_top is always true, but is here so that there can be stubs in the code in
    // case people want a transposed view in future.
    $days_along_top = true;

    $rooms = get_rooms($this->area_id);
    $n_rooms = count($rooms);

    // Check to see whether there are any rooms in the area
    if ($n_rooms == 0)
    {
      // Add an 'empty' data flag so that the JavaScript knows whether this is a real table or not
      return "<tbody data-empty=1><tr><td><h1>" . get_vocab("no_rooms_for_area") . "</h1></td></tr></tbody>";
    }

    // TABLE HEADER
    $thead = '<thead';

    $slots = $this->getSlots($this->month, $this->day_start_interval, $this->year, $this->n_days, true);
    if (isset($slots))
    {
      // Add some data to enable the JavaScript to draw the timeline
      $thead .= ' data-slots="' . escape_html(json_encode($slots)) . '"';
      $thead .= ' data-timeline-vertical="' . (($days_along_top) ? 'true' : 'false') . '"';
      $thead .= ' data-timeline-full="true"';
    }

    $thead .= ">\n";

    if ($days_along_top)
    {
      $header_inner_rows = $this->multidayHeaderRowsHTML($this->day_start_interval, $this->n_days, $this->start_dow);
    }
    else
    {
      // See comment above
      trigger_error("Not yet implemented", E_USER_WARNING);
    }

    $thead .= implode('', $header_inner_rows);
    $thead .= "</thead>\n";

    // Now repeat the header in a footer if required
    $tfoot = ($column_labels_both_ends) ? "<tfoot>\n" . implode('',array_reverse($header_inner_rows)) . "</tfoot>\n" : '';

    // TABLE BODY LISTING BOOKINGS
    $tbody = "<tbody>\n";

    $room_link_vars = [
      'view'      => $this->view,
      'view_all'  => 0,
      'page_date' => format_iso_date($this->year, $this->month, $this->day),
      'area'      => $this->area_id
    ];

    if ($days_along_top)
    {
      // the standard view, with days along the top and rooms down the side
      foreach ($rooms as $room)
      {
        $room_id = $room['id'];
        $room_link_vars['room'] = $room_id;
        $tbody .= "<tr>\n";
        $row_label = $this->roomCellHTML($room, $room_link_vars);
        $tbody .= $row_label;

        for ($j = 0, $date = clone $this->start_date; $j < $this->n_days; $j++, $date->modify('+1 day'))
        {
          if ($date->isHiddenDay())
          {
            continue;
          }

          // Add classes for weekends, holidays, etc.
          $classes = $this->getDateClasses($date);

          $tbody .= '<td';
          if (!empty($classes))
          {
            $tbody .= ' class="' . implode(' ', $classes) . '"';
          }
          $tbody .= '>';
          $vars = [
            'view_all'  => $this->view_all,
            'page_date' => $date->getISODate(),
            'area'      => $this->area_id,
            'room'      => $room['id']
          ];

          // If there is more than one slot per day, then it can be very difficult to pick
          // out an individual one, which could be just one pixel wide, so we go to the
          // day view first where it's easier to see what you are doing.  Otherwise, we go
          // direct to edit_entry.php if the slot is free, or view_entry.php if it is not.
          // Note: the structure of the cell, with a single link and multiple flex divs,
          // only allows us to direct to the booking if there's only one slot per day.
          if ($view_all_always_go_to_day_view || (self::getNTimeSlots() > 1))
          {
            $page = 'index.php';
            $vars['view'] = 'day';
          }
          else
          {
            $vars['view'] = $this->view;
            $this_slot = $this->map->slot($room_id, $j, Calendar::morningSlotsSeconds());
            if (empty($this_slot))
            {
              $page = 'edit_entry.php';
            }
            else
            {
              $page = 'view_entry.php';
              $vars['id'] = $this_slot[0]['id'];
            }
          }

          $link = "$page?" . http_build_query($vars, '', '&');
          $link = multisite($link);
          $tbody .= '<a href="' . escape_html($link) . "\">\n";
          $tbody .= $this->flexDivsHTML($room_id, $j, $j);
          $tbody .= "</a>\n";
          $tbody .= "</td>\n";
        }

        if ($row_labels_both_sides)
        {
          $tbody .= $row_label;
        }
        $tbody .= "</tr>\n";
      }
    }
    else
    {
      // See comment above
      trigger_error("Not yet implemented", E_USER_WARNING);
    }

    $tbody .= "</tbody>\n";
    return $thead . $tfoot . $tbody;
  }

}
