<%args>
$ShowSidebar => 0
$Standalone => 0
</%args>

% if ( $ShowSidebar ) {
<div class="calendar-container <% $ShowSidebar ? 'with-sidebar' : '' %>  <% $Standalone ? 'calendar-standalone' : '' %>">
% }

<&| /Widgets/TitleBox,
     title => loc('Calendar'),
     title_href => $RT::WebPath . "/Search/Calendar.html?Month=$Month&Year=$Year&$QueryString",
     titleright => loc('Download Spreadsheet'),
     titleright_href => $RT::WebPath. "/Search/Results.tsv?". $DownloadQueryString,
     &>
<div class="row">
% if ($ShowSidebar) {
  <& /Elements/CalendarSidebar,
    BaseQuery => $BaseQuery,
    Month => $Month,
    Year => $Year,
    Format => $Format,
    Order => $Order,
    OrderBy => $OrderBy,
    RowsPerPage => $RowsPerPage,
    FilterOnStatus => \@FilterOnStatus,
    Dates => \@Dates,
    Standalone => $Standalone,
  &>
% }

<div class="calendar-content <% $ShowSidebar ? 'col' : 'col-12' %> ">
<table width="100%">
<tr>
<td align="left">
% my ($PMonth, $PYear) = ($Month - 1, $Year);
% if ($PMonth < 0) {
%    $PYear--;
%    $PMonth = 11;
% }
% if ( $Standalone ) {
  <a href="?Month=<%$PMonth%>&Year=<%$PYear%>&<%$QueryString%>">&laquo; <%$rtdate->GetMonth($PMonth)%></a>
% } else {
  <a onclick="reloadElement(this.closest('[hx-get]'), {'hx-vals': '<% JSON({ Month => $PMonth, Year => $PYear }) %>'}); return false;" href="#">&laquo; <%$rtdate->GetMonth($PMonth)%></a>
% }
</td>
<th class="h5 text-center">
  <% $rtdate->GetMonth($Month). " $Year" %>
</th>
<td align="right">
% my ($NMonth, $NYear) = ($Month + 1, $Year);
% if ($NMonth > 11) {
%    $NYear++;
%    $NMonth = 0;
% }
% if ( $Standalone ) {
  <a href="?Month=<%$NMonth%>&Year=<%$NYear%>&<%$QueryString%>"><%$rtdate->GetMonth($NMonth)%> &raquo;</a>
% } else {
  <a onclick="reloadElement(this.closest('[hx-get]'), {'hx-vals': '<% JSON({ Month => $NMonth, Year => $NYear }) %>'}); return false;" href="#"><%$rtdate->GetMonth($NMonth)%> &raquo;</a>
% }
</td>
</tr>
</table>

<table class="rtxcalendar">

<thead>
<tr>
% for ( @{$week{$weekstart}} ) {
<th width="14%"><%$rtdate->GetWeekday($_)%></th>
% }
</tr>
</thead>

<tbody>
<tr>
<%perl>
# We use %week_ticket_position to control the display of tickets on the
# calendar. It has the following structure:
# {
#   1 => { id => 123, TicketObj => $t },
#   2 => { id => 312, TicketObj => $t },
#   3 => { id => '', TicketObj => undef }, # empty position
#   4 => { id => 111, TicketObj => $t },
# }
# where the key is the position/line of the ticket in the current week
# when an event ends during the week, it's removed from the hash, openning
# the position for a new ticket to be placed at the same line on the week,
# saving some height on the calendar.
# This variable is cleaned every time we start a new week.
my %week_ticket_position;
my $day_of_week = 1;

while ($date <= $end) {
  my @classes = ();
  push @classes, "offmonth"  if $date->month != ($Month + 1);
  push @classes, "today"     if (DateTime->compare($today,     $date) == 0);
  push @classes, "yesterday" if (DateTime->compare($yesterday, $date) == 0);
  push @classes, "aweekago"  if (DateTime->compare($aweekago,  $date) == 0);
  push @classes, "weekday-$day_of_week";

  for my $t ( @{ $Tickets->{ $date->strftime("%F") } || [] } ) {
    # check if ticket was already displayed this week, if not, we need to find a
    # position for it
    unless ( grep { $week_ticket_position{$_}{id} eq $t->id } keys %week_ticket_position ) {
      # new tickets should assume the first empty spot.
      my $i = 1;
      my $free_index = 0;
      for my $index ( sort { $a <=> $b } keys %week_ticket_position ) {
        if ( $week_ticket_position{$index}{id} eq "" ) {
          $free_index = $i;
          last;
        }
        $i++;
      }
      # if we found a free spot, we place the ticket there
      if ( $free_index != 0 ) {
        $week_ticket_position{$free_index}{id} = $t->id;
        $week_ticket_position{$free_index}{TicketObj} = $t;
      }
      # if not, we add it to the end of the hash
      else {
        $week_ticket_position{((scalar keys %week_ticket_position)+1)}{id} = $t->id;
        $week_ticket_position{((scalar keys %week_ticket_position))}{TicketObj} = $t;
      }
    }
  }
</%perl>

    <td class="<% join(' ', @classes) %>"><div class="inside-day">
      <div class="calendardate"><%$date->day%></div>
%     for my $index ( sort { $a <=> $b } keys %week_ticket_position ) {
%       if ( grep { $_->id eq $week_ticket_position{$index}{id} }
%                 @{ $Tickets->{ $date->strftime("%F") } || [] } ) {
%         my $t = $week_ticket_position{$index}{TicketObj};
        <& /Elements/CalendarEvent,
          Object              => $t,
          Date                => $date,
          DateTypes           => \%DateTypes,
          DayOfWeek           => $day_of_week,
          TicketsSpanningDays => $TicketsSpanningDays,
          WeekTicketPosition  => \%week_ticket_position,
          CurrentPostion      => $index,
        &>
%       }
%       else {
%         # if there's no ticket for this position, we add an empty space
             <div class="day">&nbsp;</div>
%       }
%     }
    </div></td>

%   $date = $set->next($date);
%   if ( $date->day_of_week == $startday_of_week ) {
% #   we start a new week with empty positions
%     %week_ticket_position = ();
%     $day_of_week=1;
      </tr><tr>
%   }
%   else {
%     $day_of_week = $day_of_week + 1;
%   }
% }
</tr>
</tbody>
</table>

<table width="100%">
<tr>
<td align="left">
% if ( $Standalone ) {
  <a href="?Month=<%$PMonth%>&Year=<%$PYear%>&<%$QueryString%>">&laquo; <%$rtdate->GetMonth($PMonth)%></a>
% } else {
  <a onclick="reloadElement(this.closest('[hx-get]'), {'hx-vals': '<% JSON({ Month => $PMonth, Year => $PYear }) %>'}); return false;" href="#">&laquo; <%$rtdate->GetMonth($PMonth)%></a>
% }
</td>

<td valign="top" align="center">
<form class="row justify-content-center" action="?<% $QueryString %>">
<div class="col-auto">
<select name="SelectedMonth" class="selectpicker form-select">
% for (0..11) {
<option value="<%$_%>" <% $_ == $Month ? 'selected' : ''%> ><%$rtdate->GetMonth($_)%></option>
% }
</select>
</div>
<div class="col-auto">
% my $year = (localtime)[5] + 1900;
<select name="SelectedYear" class="selectpicker form-select">
% for ( ($year-5) .. ($year+5)) {
<option value="<%$_%>" <% $_ == $Year ? 'selected' : ''%>><%$_%></option>
% }
</select>
</div>
<div class="col-auto">
  <input type="submit" value="<% loc('Submit') %>" class="btn btn-primary <% $Standalone ? '' : 'calendar-reload' %>" />
</div>


</form>
</td>

<td align="right">
% if ( $Standalone ) {
  <a href="?Month=<%$NMonth%>&Year=<%$NYear%>&<%$QueryString%>"><%$rtdate->GetMonth($NMonth)%> &raquo;</a>
% } else {
  <a onclick="reloadElement(this.closest('[hx-get]'), {'hx-vals': '<% JSON({ Month => $NMonth, Year => $NYear }) %>'}); return false;" href="#"><%$rtdate->GetMonth($NMonth)%> &raquo;</a>
% }
</td>
</tr>
</table>

</div>
</&>


% if ( $ShowSidebar ) {
  </div>
% }
<%INIT>
my $NotFirstAccess = $DECODED_ARGS->{NotFirstAccess};
my $Month = $DECODED_ARGS->{SelectedMonth} // $DECODED_ARGS->{Month} // (localtime)[4];
my $Year = $DECODED_ARGS->{SelectedYear} // $DECODED_ARGS->{Year}  || (localtime)[5] + 1900;
my $Query = $DECODED_ARGS->{Query};
my $Format = $DECODED_ARGS->{Format};
my $Order = $DECODED_ARGS->{Order};
my $OrderBy = $DECODED_ARGS->{OrderBy};
my $RowsPerPage = $DECODED_ARGS->{RowsPerPage};
my $NewQuery = $DECODED_ARGS->{NewQuery};
my $BaseQuery = $DECODED_ARGS->{BaseQuery};
my $FilterOnStatusClear = $DECODED_ARGS->{FilterOnStatusClear};
my @FilterOnStatus;
if ( $DECODED_ARGS->{NewFilterOnStatus} ) {
  if ( ref $DECODED_ARGS->{NewFilterOnStatus} eq 'ARRAY' ) {
    @FilterOnStatus = @{$DECODED_ARGS->{NewFilterOnStatus}};
  }
  else {
    push @FilterOnStatus, $DECODED_ARGS->{NewFilterOnStatus};
  }
}
# This comes from the month changing form and link
elsif ( $DECODED_ARGS->{FilterOnStatus} ) {
  if ( ref $DECODED_ARGS->{FilterOnStatus} eq 'ARRAY' ) {
    @FilterOnStatus = @{$DECODED_ARGS->{FilterOnStatus}};
  }
  else {
    push @FilterOnStatus, $DECODED_ARGS->{FilterOnStatus};
  }
} else {
  @FilterOnStatus = @{RT->Config->Get('CalendarFilterDefaultStatuses')}
    unless $NotFirstAccess;
}
$NotFirstAccess = 1;

if ($FilterOnStatusClear) {
  $Query = $BaseQuery if $BaseQuery;
  @FilterOnStatus = ();
}
$BaseQuery ||= $Query;
my $title = loc("Calendar");

my @DateTypes = qw/Created Starts Started Due LastUpdated Resolved/;

my $rtdate = RT::Date->new($session{'CurrentUser'});

my $weekstart = 'Sunday'; #RT::SiteConfig?  user pref?
my %week = (
  'Saturday' => [6,0..5],
  'Sunday'   => [0..6],
  'Monday'   => [1..6,0],
);
my $startday_of_week = ${$week{$weekstart}}[0]  || 7;
my $endday_of_week   = ${$week{$weekstart}}[-1] || 7;

my $today = DateTime->today;
my $yesterday = $today->clone->subtract( days=>1 );
my $aweekago  = $today->clone->subtract( days=>7 );
my $date = RTx::Calendar::FirstDay($Year, $Month + 1, $startday_of_week );
my $end  = RTx::Calendar::LastDay ($Year, $Month + 1, $endday_of_week );

# use this to loop over days until $end
my $set = DateTime::Set->from_recurrence(
    next => sub { $_[0]->truncate( to => 'day' )->add( days => 1 ) }
);

# Default Query and Format
my $TempFormat = "__Starts__ __Due__";
my $TempQuery = "( Status = 'new' OR Status = 'open' OR Status = 'stalled')
 AND ( Owner = '" . $session{CurrentUser}->Id ."' OR Owner = 'Nobody'  )
 AND ( Type = 'reminder' OR 'Type' = 'ticket' )";

if ( my $Search = RTx::Calendar::SearchDefaultCalendar($session{CurrentUser}) ) {
    my $content = $Search->Content || {};
    $TempFormat = $content->{'Format'};
    $TempQuery = $content->{'Query'};
}

# we overide them if needed
$TempQuery  = $Query  if $Query;
$TempFormat = $Format if $Format;
$Format = $TempFormat unless $Format;

my $QueryString =
      $m->comp(
        '/Elements/QueryString',
        Query   => $BaseQuery,
        FilterOnStatus => \@FilterOnStatus,
        Format  => $Format,
        Order   => $Order,
        OrderBy => $OrderBy,
        Rows    => $RowsPerPage,
        NotFirstAccess => $NotFirstAccess,
      );

$QueryString ||= 'NewQuery=1&NotFirstAccess=1';

# we search all date types in Format string
my @CoreDates    = grep { $TempFormat =~ m/__${_}(Relative)?__/ } @DateTypes;
my @CustomFields = ( $TempFormat =~ /__(CustomField\.\{.*\})__/g );
my @DateCustomFields;

for my $CustomField (@CustomFields) {
    my $LintCustomField = $CustomField;
    $LintCustomField =~ s/CustomField\.\{(.*)\}/$1/;
    my $CustomFieldObj = RT::CustomField->new( RT->SystemUser );
    $CustomFieldObj->LoadByName( Name => $LintCustomField );
    push @DateCustomFields, $CustomField
        if $CustomFieldObj->id
        && ( $CustomFieldObj->Type eq 'Date'
        || $CustomFieldObj->Type eq 'DateTime' );
}

my @Dates = (@CoreDates, @DateCustomFields);
@Dates = map { $_ =~ s/^CustomField\.(.*)$/CF.$1/; $_ } @Dates;

# used to display or not a date in Element/CalendarEvent
my %DateTypes = map { $_ => 1 } @Dates;

$TempQuery .= RTx::Calendar::DatesClauses(\@Dates, $date->strftime("%F"), $end->strftime("%F"));

if (@FilterOnStatus) {
  my $StatusClause = join " OR ", map { "Status = '$_'" } @FilterOnStatus;
  $TempQuery .= " AND " if $TempQuery;
  $TempQuery .= "($StatusClause)";
}

# For back compatibility
$m->callback( CallbackName => 'BeforeFindTickets', ARGSRef => \%ARGS, QueryRef => \$TempQuery, FormatRef => \$TempFormat, CallbackPage => '/Search/Calendar.html' ) if $m->request_path eq '/Search/Calendar.html';

$m->callback( CallbackName => 'BeforeFindTickets', ARGSRef => \%ARGS, QueryRef => \$TempQuery, FormatRef => \$TempFormat );

my $DownloadQueryString =
      $m->comp(
        '/Elements/QueryString',
        Query   => $TempQuery,
        Format  => $Format,
        Order   => $Order,
        OrderBy => $OrderBy,
      );

my ($Tickets, $TicketsSpanningDays);

# This is the expensive part of the processing, so only run this when
# htmx is rendering the main content.
if ( $m->request_path =~ /^(?:\/SelfService)?\/Views/ ) {
    ($Tickets, $TicketsSpanningDays) = RTx::Calendar::FindTickets($session{'CurrentUser'}, $TempQuery, \@Dates, $date->strftime("%F"), $end->strftime("%F"));
}

</%INIT>
