<%pre>

#include <livefeatures.h>
#include <setup.h>
#include <tools.h>
#include <epg_events.h>
#include <recman.h>


#include <vdr/config.h>
using namespace vdrlive;

bool searchNameDesc(RecordingsItemPtr &RecItem, std::list<RecordingsItemPtr> &RecItems, const std::string &Name, const std::string &ShortText, const std::string &Description, long Duration) {
  if(RecItems.begin() == RecItems.end() ) return false;  // there are no recordings

// find all recordings with equal name
  RecordingsItemPtr dummy (new RecordingsItemDummy(Name, ShortText, Description, Duration));
  std::list<RecordingsItemPtr>::iterator recIterLowName = std::lower_bound (RecItems.begin(), RecItems.end(), dummy, RecordingsItemPtrCompare::ByAscendingName);
  std::list<RecordingsItemPtr>::iterator recIterUpName  = std::upper_bound (recIterLowName  , RecItems.end(), dummy, RecordingsItemPtrCompare::ByAscendingName);
  if ( recIterLowName == recIterUpName ) return false; // there is no recording with this name


// find all recordings with matching short text / description
  std::list<RecordingsItemPtr>::iterator recIterLow = std::lower_bound (recIterLowName, recIterUpName, dummy, RecordingsItemPtrCompare::ByAscendingNameDesc);
  std::list<RecordingsItemPtr>::iterator recIterUp = std::upper_bound (recIterLow, recIterUpName, dummy, RecordingsItemPtrCompare::ByAscendingNameDesc);

  if(recIterLow != recIterUp) {   // exact match found
    if (RecordingsItemPtrCompare::FindBestMatch(RecItem, recIterLow, recIterUp, dummy) > 0) return true;
    RecItem = *recIterLow;
    return true;
  }
// no exact match found, get recording with most matching characters
  int numEqualCharsLow = 0;
  int numEqualCharsUp  = 0;

  if(recIterLow != recIterLowName) { 
    --recIterLow;
    RecordingsItemPtrCompare::Compare2(numEqualCharsLow, *recIterLow, dummy);
  }
  if(recIterUp != recIterUpName)
    RecordingsItemPtrCompare::Compare2(numEqualCharsUp , *recIterUp , dummy);

  if ( numEqualCharsLow > numEqualCharsUp ) {
    if( numEqualCharsLow > 5 ) { RecItem = *recIterLow; return true; }
  } else {
    if( numEqualCharsUp  > 5 ) { RecItem = *recIterUp;  return true; }
  }


// no exact match found, get best match
  int num_match_rec = RecordingsItemPtrCompare::FindBestMatch(RecItem, recIterLowName, recIterUpName, dummy);
  if(num_match_rec == 0 || num_match_rec > 5) return false; // no matching lenght or series (too many matching length)
  return true;
}


</%pre>
<%args>
	int channel = -1;
</%args>
<%session scope="global">
bool logged_in(false);
</%session>

<# scope="page" should be enough but does not work with tntnet 3.0 #>
<%request scope="global">
	cChannel* Channel;
</%request>
<%include>page_init.eh</%include>
<%cpp>
if (!logged_in && LiveSetup().UseAuth()) return reply.redirect("login.html");
</%cpp>
<%cpp>
	pageTitle = trVDR("Schedule");

std::vector<std::string> path;
std::list<RecordingsItemPtr> recItems;
RecordingsTreePtr recordingsTree(LiveRecordingsManager()->GetRecordingsTree());

addAllRecordings(recItems, recordingsTree, path);
recItems.sort(RecordingsItemPtrCompare::ByAscendingNameDesc);


#if VDRVERSNUM < 20301
	cSchedulesLock schedulesLock;
	cSchedules const* schedules = cSchedules::Schedules( schedulesLock );

	ReadLock channelsLock( Channels );
	if ( !channelsLock )
		throw HtmlError( tr("Couldn't aquire access to channels, please try again later.") );
#endif

	// cChannel* Channel; (see %request above)
	if ( channel > 0 ) {
#if VDRVERSNUM >= 20301
		LOCK_CHANNELS_READ;
		Channel = (cChannel *)Channels->GetByNumber( channel );
#else
		Channel = Channels.GetByNumber( channel );
#endif
	}
	else {
#if VDRVERSNUM >= 20301
		LOCK_CHANNELS_READ;
#endif
		if (cDevice::CurrentChannel()) {
#if VDRVERSNUM >= 20301
			Channel = (cChannel *)Channels->GetByNumber(cDevice::CurrentChannel());
#else
			Channel = Channels.GetByNumber(cDevice::CurrentChannel());
#endif
		}
		else {
#if VDRVERSNUM >= 20301
			Channel = (cChannel *)Channels->Get( Channels->GetNextNormal( -1 ) );
#else
			Channel = Channels.Get( Channels.GetNextNormal( -1 ) );
#endif
		}
	}
	if ( Channel == 0 )
		throw HtmlError( tr("Couldn't find channel or no channels available. Maybe you mistyped your request?") );

	cSchedule const* Schedule;
#if VDRVERSNUM >= 20301
	{
		LOCK_SCHEDULES_READ;
		Schedule = Schedules->GetSchedule( (const cChannel *)Channel );
	}
#else
	Schedule = schedules->GetSchedule( Channel );
#endif
</%cpp>
<& pageelems.doc_type &>
<html>
	<head>
		<title>VDR Live - <$ pageTitle $></title>
		<& pageelems.stylesheets &>
		<& pageelems.ajax_js &>
	</head>
	<body onload="adjustHeader()" onresize="adjustHeader()">
		<& pageelems.logo &>
		<& menu active=("schedule") component=("schedule.channel_selection") &>
		<div class="inhalt">
<%cpp>
	if ( Schedule == 0 ) {
</%cpp>
			<$ tr("No schedules available for this channel") $>.
<%cpp>
	}
	else {
</%cpp>
		<table class="listing" cellspacing="0" cellpadding="0">
<%cpp>
		std::string current_day = "";
		const cEvent* PresentEvent = Schedule->GetPresentEvent();
		time_t now = time(NULL) - ::Setup.EPGLinger * 60;
                RecordingsItemPtr recItem;
                bool recItemFound;
#if VDRVERSNUM >= 20301
		for (const cEvent *Event = (cEvent *)Schedule->Events()->First(); Event; Event = (cEvent *)Schedule->Events()->Next(Event)) {
#else
		for (const cEvent *Event = Schedule->Events()->First(); Event; Event = Schedule->Events()->Next(Event)) {
#endif
			if (Event->EndTime() <= now && Event != PresentEvent)
				continue;

			EpgInfoPtr epgEvent = EpgEvents::CreateEpgInfo(Channel, Event);

			std::string title(epgEvent->Title());
			std::string short_description(epgEvent->ShortDescr());
			std::string description(epgEvent->LongDescr());
			std::string start(epgEvent->StartTime(tr("%I:%M %p")));
			std::string end(epgEvent->EndTime(tr("%I:%M %p")));
                        int durationMinutes = epgEvent->Duration() / 60;
                        std::string duration(durationMinutes < 0 ? "" : FormatDuration(tr("(%d:%02d)"), durationMinutes / 60, durationMinutes % 60));
			std::string day(epgEvent->StartTime(tr("%A, %b %d %Y")));
			std::string epgid = EpgEvents::EncodeDomId(Channel->GetChannelID(), Event->EventID());

			bool truncated = false;
			bool lastEventCurrentDay = false;

                        recItemFound = searchNameDesc(recItem, recItems, title, short_description, description, epgEvent->Duration() );
			{
#if VDRVERSNUM >= 20301
				cEvent* NextEvent = (cEvent *)Schedule->Events()->Next(Event);
#else
				cEvent* NextEvent = Schedule->Events()->Next(Event);
#endif
				if (!NextEvent) {
					lastEventCurrentDay = true;
				}
				else {
					std::string nday(NextEvent->StartTime() ? FormatDateTime(tr("%A, %b %d %Y"), NextEvent->StartTime()) : "");
					lastEventCurrentDay = (day != nday);
				}
			}

			if (current_day != day) {
				if (current_day != "") {
</%cpp>
				<tr class="spacer">
					<td colspan="5"/>
				</tr>
<%cpp>
				}
</%cpp>
				<tr class="head">
					<td colspan="5"><div class="boxheader"><div><div><$ day $></div></div></div></td>
				</tr>
<%cpp>
				current_day = day;
			}
</%cpp>
				<tr>
					<td class="action leftcol <? lastEventCurrentDay && ! recItemFound ? "bottomrow" ?>"><& pageelems.event_timer epgid=(epgid) &></td>
					<td class="action <? lastEventCurrentDay && ! recItemFound ? "bottomrow" ?>"><%cpp>if (LiveFeatures<features::epgsearch>().Recent() ) { </%cpp><a href="searchresults.html?searchplain=<$ StringUrlEncode(title) $>"><img src="<$ LiveSetup().GetThemedLink("img", "search.png") $>" alt="" <& tooltip.hint text=(tr("Search for repeats.")) &>></img></a><%cpp> } else { </%cpp><img src="img/transparent.png" width="16" height="16"><%cpp> } </%cpp></td>
					<td class="action <? lastEventCurrentDay && ! recItemFound ? "bottomrow" ?>"><& pageelems.imdb_info_href title=(title) &></td>
					<td class="topaligned <? lastEventCurrentDay && ! recItemFound ? "bottomrow" ?>"><div class="withmargin"><$ start $> - <$ end $><br /><$ duration $></div></td>
					<td class="<? (Event == PresentEvent) ? "current" ?> topaligned rightcol <? lastEventCurrentDay && ! recItemFound ? "bottomrow" ?>"><div class="more withmargin"><a <& tooltip.hint text=(StringEscapeAndBreak(StringWordTruncate(description, 300, truncated)) + "<br />" + tr("Click to view details.")) &><& tooltip.display domId=(epgEvent->Id()) &>><span class="title"><$ title $></span><br /><span class="short"><%cpp>if (short_description.empty()) { </%cpp>&nbsp;<%cpp> } </%cpp><$ short_description $></span></a></div></td>

				</tr>
<%cpp>
if(recItemFound) {
                  std::string duration(recItem->Duration() < 0 ? "" : FormatDuration(tr("(%d:%02d)"), recItem->Duration() / 60, recItem->Duration() % 60));
                  std::string shortDescr(recItem->RecInfo()->ShortText() ? recItem->RecInfo()->ShortText() : "");
#if VDRVERSNUM >= 20505
                  int recordingErrors = recItem->RecInfo()->Errors();
#else
                  int recordingErrors = -1;
#endif
                  std::string channelName(recItem->RecInfo()->ChannelName()  ? recItem->RecInfo()->ChannelName() : "");
                  const char *SD_HD_icon = recItem->SD_HD_icon();

                  std::string r_description(recItem->RecInfo()->Description() ? recItem->RecInfo()->Description() : "");
                  std::string hint(tr("Click to view details."));
                  if (!shortDescr.empty()) hint = shortDescr + "<br />" + hint;
                  else if (!r_description.empty()) hint = r_description + "<br />" + hint;
          std::string name(recItem->Name());
          if( *(const char *)recItem->Recording()->Folder() ) {
             name.append(" (");
             name.append( (const char *)recItem->Recording()->Folder() );
             name.append(")");
          }

</%cpp>
<tr>
 <& rec_item_file name=(name) level=(recItem->Level()) id=(recItem->Id()) startTime=(recItem->StartTime()) duration=(duration) hint=(hint) shortDescr=(shortDescr) recordingErrors=(recordingErrors) channelName=(channelName) SD_HD_icon=(SD_HD_icon) archived=(RecordingsManager::GetArchiveDescr(recItem->Recording())) lastEventCurrentDay=(lastEventCurrentDay) &>
</tr>
<%cpp>
}
</%cpp>

<%cpp>
		}
</%cpp>
			</table>
<%cpp>
	}
</%cpp>
		</div>
	</body>
</html>
<%include>page_exit.eh</%include>

<%def channel_selection>
<form action="schedule.html" method="get" id="channels">
   <span>
     <label for="channel"><$ tr("Channel") $>:&nbsp;<span class="bold"><$ std::to_string(Channel->Number()) $></span></label>
     <& channels_widget name=("channel") selected=(Channel ? *Channel->GetChannelID().ToString() : "") onchange=("document.forms.channels.submit()") &>
     <& pageelems.ajax_action_href action="switch_channel" tip=(tr("Switch to this channel.")) param=(Channel->GetChannelID()) image="zap.png" alt="" &>
     <& pageelems.hls_channel channelId=(Channel->GetChannelID()) &>
     <& pageelems.m3u_playlist_channel channelId=(Channel->GetChannelID()) &>
   </span>
</form>
<span class="sep">|</span>
<a href="schedule.html?channel=<$ std::max(0, ((int)Channel->Number() - 1)) $>">« Prev</a>
<span class="sep">|</span>
<a href="schedule.html?channel=<$ (Channel->Number() + 1) $>">Next »</a>
</%def>

<# ---------------------------------------------------------------------- #>

<%def rec_item_file>
<%args>
        std::string name;
        int level;
        std::string id;
        time_t startTime;
        std::string duration;
        std::string hint;
        std::string shortDescr;
        int recordingErrors;
        std::string channelName;
        std::string SD_HD_icon;
        std::string archived;
        bool lastEventCurrentDay;
</%args>
<%cpp> if (!archived.empty()) { </%cpp>
<td colspan="2" style="word-wrap: normal;min-width: 10px;max-width: 70px;" class="leftcol <? lastEventCurrentDay ? "bottomrow" ?>"> <$ tr("Existing Recording:") $>  </td>
<td class="action <? lastEventCurrentDay ? "bottomrow" ?>"> <img src="<$ LiveSetup().GetThemedLink("img", "on_dvd.png") $>" alt="on_dvd" <& tooltip.hint text=(archived) &> /> </td>

<%cpp> } else { </%cpp>
<td colspan="3" style="word-wrap: normal;min-width: 10px;max-width: 70px;" class="leftcol <? lastEventCurrentDay ? "bottomrow" ?>"> <$ tr("Existing Recording:") $> </td>
<%cpp> } </%cpp>

<td class="topaligned <? lastEventCurrentDay ? "bottomrow" ?>"><div class="withmargin"><$ FormatDateTime(tr("%a,"), startTime) $> <$ FormatDateTime(tr("%b %d %y"), startTime) $> <$ FormatDateTime(tr("%I:%M %p"), startTime) $><br /><$ duration $></div></td>

<td class="topaligned rightcol <? lastEventCurrentDay ? "bottomrow" ?>">
<%cpp>
#if VDRVERSNUM >= 20505
std::string recording_errors_icon;
std::string recordingErrorsStr;

if (recordingErrors == 0) {
  recording_errors_icon = "NoRecordingErrors.png";
  recordingErrorsStr = tr("No recording errors");
}
if (recordingErrors == -1) {
  recording_errors_icon = "NotCheckedForRecordingErrors.png";
  recordingErrorsStr = tr("Recording errors unknown") ;
}
if (recordingErrors >   0) {
  recording_errors_icon = "RecordingErrors.png";
  recordingErrorsStr = tr("Number of recording errors:");
  recordingErrorsStr += " " + std::to_string(recordingErrors);
}
</%cpp>
<table><tr><td class="noborder">
                <div class="recording_errors"><img src="<$ LiveSetup().GetThemedLink("img", recording_errors_icon) $>" width = "16px" alt="" <& tooltip.hint text=(recordingErrorsStr) &> /> </div>
</td>
<td class="noborder">
                <div class="recording_sd_hd"><img src="<$ LiveSetup().GetThemedLink("img", SD_HD_icon) $>" width = "25px" alt="" <& tooltip.hint text=(channelName) &> /> </div>
</td>

<td class="noborder">
<%cpp>
#endif
</%cpp>

<div class="more withmargin"><a <& tooltip.hint text=(hint) &><& tooltip.display domId=(id) &>><span class="title"><$ name $></span><br /><span class="short"><%cpp>if (shortDescr.empty()) { </%cpp>&nbsp;<%cpp> } </%cpp><$ shortDescr $></span></a></div>

<%cpp>
#if VDRVERSNUM >= 20505
</%cpp>
</td></tr></table>
<%cpp>
#endif
</%cpp>
</td>
</%def>

<# ---------------------------------------------------------------------- #>
<# <div style="width: 400 px; word-wrap: break-word;"> <$ tr("Existing Recording:") $> </div>  #>
<# word-break:break-all;  #>
