<%pre>
#include <list>
#include <vdr/plugin.h>
#include <vdr/channels.h>
#include <vdr/epg.h>
#include <vdr/config.h>
#include <vdr/device.h>
#include "exception.h"
#include "livefeatures.h"
#include "setup.h"
#include "tools.h"
#include "timers.h"
#include "epg_events.h"
#include "i18n.h"

using namespace std;
using namespace vdrlive;

struct SchedEntry {
	string title;
	string short_description;
	string description;
	string description_trunc;
	string start;
	string end;
	string day;
	string epgid;
        bool truncated;
        bool has_timer;
	int start_row;
	int row_count;
};

        std::vector<std::string> channel_groups_names;
        std::vector<std::string> times_names;
        std::vector<time_t>      times_start;
</%pre>
<%args>
	unsigned int channel = 0;
	unsigned int time_para = 0;
</%args>
<%session scope="global">
bool logged_in(false);
</%session>
<%request scope="page">
        unsigned int channel_group=0;
        unsigned int time_selected=0;
</%request>
<%include>page_init.eh</%include>
<%cpp>
if (!logged_in && LiveSetup().UseAuth()) return reply.redirect("login.html");
pageTitle = trVDR("Schedule");

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

#define MAX_CHANNELS 5 
#define MAX_DAYS 3
#define MAX_HOURS 8
#define MINUTES_PER_ROW 5
#define CHARACTERS_PER_ROW 30

        // build the groups of channels to display
        std::vector< std::vector<int> > channel_groups_numbers;
        channel_groups_names.clear();
        int cur_group_count=0;
	for ( cChannel *listChannel = Channels.First(); listChannel; listChannel = Channels.Next( listChannel ) ) 
        {
		if ( listChannel->GroupSep() || *listChannel->Name() == '\0' )
			continue;

                if ( cur_group_count==0 )
                {
                  // first entry in this group
                  channel_groups_names.push_back( std::string() );
                  channel_groups_numbers.push_back( std::vector<int>( MAX_CHANNELS) );
                }
                else channel_groups_names.back() += " - ";

                channel_groups_names.back() += std::string( listChannel->Name() );
                channel_groups_numbers.back()[ cur_group_count ] = listChannel->Number();

                cur_group_count++;
                if ( cur_group_count >= MAX_CHANNELS )
                  // we need a new group next round
                  cur_group_count = 0;
	}
        if ( channel >= channel_groups_numbers.size() )
          channel = channel_groups_numbers.size()-1;
        channel_group = channel;
{
    // build time list
    times_names.clear();
    times_start.clear();
    
    // calculate time of midnight (localtime) and convert back to GMT
    time_t now = time(NULL);
    time_t now_local = time(NULL);
    struct tm tm_r;
    if ( localtime_r( &now_local, &tm_r ) == 0 ) {
        ostringstream builder;
        builder << "cannot represent timestamp " << now_local << " as local time";
        throw runtime_error( builder.str() );
    }
    tm_r.tm_hour=0;
    tm_r.tm_min=0;
    tm_r.tm_sec=0;
    time_t midnight = mktime( &tm_r );

    // default is now rounded to full hour
    times_names.push_back( tr("Now") );
    times_start.push_back( 3600 * ( now /3600 ) );

    int i =0;
    // skip allready passed times
    while ( now>midnight+MAX_HOURS*3600*i)
        i++;

    for (; i<4*MAX_DAYS ; i++ )
    {
        times_names.push_back(FormatDateTime( tr("%A, %x"), midnight + MAX_HOURS*3600*i)
                              +std::string(" ")+ FormatDateTime( tr("%I:%M %p"), midnight + MAX_HOURS*3600*i) );
        //times_names.push_back("today 0:00");
        times_start.push_back( midnight + MAX_HOURS*3600*i );
    }
    if ( time_para >= times_names.size() )
        time_para = times_names.size()-1;
    time_selected=time_para;
}
</%cpp>
<& pageelems.doc_type &>
<html>
	<head>
		<title>VDR Live - <$ pageTitle $></title>
		<& pageelems.stylesheets &>
		<& pageelems.ajax_js &>
	</head>
	<body>
		<& pageelems.logo &>
		<& menu active=("multischedule") component=("multischedule.channel_selection") &>
		<div class="inhalt">
<%cpp>
	cSchedulesLock schedulesLock;
	cSchedules const* schedules = cSchedules::Schedules( schedulesLock );
       
        time_t now = time(NULL);
        if ( time_para >= times_start.size() )
            time_para = times_start.size()-1;
        time_t sched_start = times_start[ time_para ]; 
        time_t sched_end = sched_start + 60 * 60 * MAX_HOURS;
        int sched_end_row = ( sched_end - sched_start ) / 60 / MINUTES_PER_ROW;
        std::list<SchedEntry> table[MAX_CHANNELS];
        string channel_names[ MAX_CHANNELS];
        if ( channel >= channel_groups_numbers.size() )
          channel = channel_groups_numbers.size()-1;
        //for ( int chan = 0; chan<MAX_CHANNELS; chan++)
        for ( int j = 0; j<MAX_CHANNELS; j++)
        {
          int prev_row = -1;


          int chan = channel_groups_numbers[ channel ][ j ];

          cChannel* Channel = Channels.GetByNumber( chan );
          if ( ! Channel )
            continue;
          if ( Channel->GroupSep() || Channel->Name() == '\0' )
            continue;
          channel_names[ j ] = Channel->Name();

          cSchedule const* Schedule = schedules->GetSchedule( Channel );
          if ( ! Schedule )
            continue;
          for (const cEvent *Event = Schedule->Events()->First(); Event; 
               Event = Schedule->Events()->Next(Event) ) 
          {
            if (Event->EndTime() <= sched_start )
              continue;
            if (Event->StartTime() >= sched_end )
              continue;

            EpgInfoPtr epgEvent = EpgEvents::CreateEpgInfo(Channel, Event);
            if ( prev_row < 0 && Event->StartTime() > sched_start + MINUTES_PER_ROW )
            {
              // insert dummy event at start
              table[ j ].push_back( SchedEntry() );
              SchedEntry &en=table[ j ].back();
              int event_start_row = (Event->StartTime() - sched_start) / 60 / MINUTES_PER_ROW;
              en.start_row = 0;
              en.row_count = event_start_row;
              // no title and no start time = dummy event
              en.title = "";
              en.start = "";
              prev_row = en.start_row + en.row_count;
            }
            table[ j ].push_back( SchedEntry() );
            SchedEntry &en=table[j].back();

            en.title = epgEvent->Title();
            en.short_description = epgEvent->ShortDescr();
            en.description = epgEvent->LongDescr();
            en.start = epgEvent->StartTime(tr("%I:%M %p"));
            en.end = epgEvent->EndTime(tr("%I:%M %p"));
            en.day = epgEvent->StartTime(tr("%A, %b %d %Y"));
            en.epgid = EpgEvents::EncodeDomId(Channel->GetChannelID(), Event->EventID());
            en.has_timer = LiveTimerManager().GetTimer(Event->EventID(), Channel->GetChannelID() ) != 0;

            en.start_row = prev_row > 0 ? prev_row : 0;
            int end_time = Schedule->Events()->Next(Event) ? 
              Schedule->Events()->Next(Event)->StartTime() :
              Event->EndTime();
            int next_event_start_row = (end_time - sched_start) / 60 / MINUTES_PER_ROW;
            en.row_count = next_event_start_row - en.start_row;
            if ( en.row_count < 1 )
              en.row_count = 1;
            prev_row = en.start_row + en.row_count;

            // truncate description if too long
            en.truncated=false;
            en.description_trunc=StringWordTruncate( en.description,
                                                     CHARACTERS_PER_ROW*(en.row_count-2),
                                                     en.truncated );



          };
          if ( table[ j ].begin() == table[ j ].end() )
          {
            // no entries... create a single dummy entry       
            table[ j ].push_back( SchedEntry() );
            SchedEntry &en=table[ j ].back();
            en.start_row = 0;
            en.row_count = sched_end_row;
            // no title and no start time = dummy event
            en.title = "";
            en.start = "";
          }
        }
</%cpp>
		<table class="mschedule" cellspacing="0" cellpadding="0">
<%cpp>
</%cpp>
	       <tr class=" topaligned ">
	       <td > <div class="boxheader"> <div><div><$ tr("Time") $></div></div> </div></td>
	       <td class="time spacer"> &nbsp; </td>
<%cpp>
                for ( int channel = 0; channel< MAX_CHANNELS ; channel++)
                {
</%cpp>
	       <td> <div class="boxheader"> <div> <div><$ StringEscapeAndBreak(channel_names[channel]) $> </div></div> </div></td>
	       <td class="time spacer"> &nbsp; </td>
<%cpp>
                }
</%cpp>
	       </tr>
<%cpp>
                bool odd=true;
                std::list<SchedEntry>::iterator  cur_event[ MAX_CHANNELS ];
                for (int i=0;i<MAX_CHANNELS;i++)
                        cur_event[i]=table[i].begin();
                for (int row = 0 ; row < sched_end_row; row++ )
		{
                       int minutes= ( (sched_start +  row * 60 * MINUTES_PER_ROW ) % 3600 ) / 60;
                       string row_class;
                       if ( minutes == 0 )
                       {
                         // full hour, swap odd/even
                         odd = !odd;
                       };
                       if (  (sched_start +  row * 60 * MINUTES_PER_ROW ) <= now &&
                             (sched_start +  (row+1) * 60 * MINUTES_PER_ROW ) > now )
                       {
                         row_class +=" current_row ";
                       }
                       row_class += odd ? " odd " : " even ";

</%cpp>
		       <tr class=" <$ row_class $>">
		       <td class=" time leftcol ">
<%cpp>
			if (  minutes == 0 )
			{
</%cpp>
		       <$ FormatDateTime( tr("%I:%M %p"), sched_start +  row * 60 * MINUTES_PER_ROW )  $>
<%cpp>
			}
			else
			{
</%cpp>
			 &nbsp;
<%cpp>
		        }	
</%cpp>
		       </td>
<%cpp>
                        for ( int channel = 0; channel< MAX_CHANNELS ; channel++)
                        {
                                // output spacer column
</%cpp>
		                <td class = " time spacer " > &nbsp; </td>
<%cpp>
                                if ( cur_event[channel] == table[channel].end() 
                                     || cur_event[channel]->start_row != row )
                                  // no new event in this channel, skip it
                                  continue;
                                
                                SchedEntry &en=*cur_event[channel];
                                if (en.title.empty() && en.start.empty() )
                                {
                                  // empty dummy event
</%cpp>
			<td class="event topaligned leftcol rightcol" rowspan="<$ en.row_count $>">
                        </td>
<%cpp>
				  ++cur_event[channel];
                                  continue;
                                        
                                }
                                // output an event cell
</%cpp>
			<td class="event topaligned leftcol rightcol <$ en.has_timer ? "has_timer" : "" $>" rowspan="<$ en.row_count $>">
                        <div class=" content1 " >
                        <div class=" tools1 " >
                          <& pageelems.event_timer epgid=(en.epgid) &>
<%cpp>
                           if (LiveFeatures<features::epgsearch>().Recent() ) { 
</%cpp>
                          <a href="searchresults.html?searchplain=<$ StringUrlEncode(en.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>
                          <& pageelems.imdb_info_href title=(en.title) &>
                         </div><div class= "start withmargin"><$ en.start $></div>
			  <div class="title withmargin"><a <& tooltip.hint text=(StringEscapeAndBreak(tr("Click to view details."))) &><& tooltip.display domId=en.epgid &>><$ en.title $></a></div>
<%cpp>
                         if ( en.row_count>2 && !en.short_description.empty() ) 
                         {
</%cpp>
                          <div class="short withmargin"><$ en.short_description.empty() ? "&nbsp;" : en.short_description $></div>
<%cpp>
                         }
                         if ( en.row_count>3 && ! en.description_trunc.empty() )
                         {
</%cpp>
                          <div class="description withmargin"><$en.description_trunc$>...
<%cpp>
                           if ( en.truncated )
                           {
</%cpp>
                           <a <& tooltip.hint text=(StringEscapeAndBreak(tr("Click to view details."))) &><& tooltip.display domId=en.epgid &>> <$ tr("more") $></a>
<%cpp>
                           }
</%cpp>
                           </div>
<%cpp>
                         }
</%cpp>
                          </div></div>
                          </td>
<%cpp>
                          // move to next event for this channel
                          ++cur_event[channel];
                        }
</%cpp>
		       </tr>
<%cpp>
		}
</%cpp>
			</table>
		</div>
	</body>
</html>
<%include>page_exit.eh</%include>

<%def channel_selection>
<form action="multischedule.html" method="get" id="channels">
   <span>
     <label for="channel"><$ tr("Channel") $>:&nbsp;<span class="bold"></span></label>
     <select name="channel" id="channel"  onchange="document.forms.channels.submit()" >
%	for ( unsigned int i = 0; i < channel_groups_names.size(); ++i ) {
%
		<option value="<$ i $>"
%                      if ( i == channel_group )
%                      {
			selected="selected"
%                      }
                        ><$ channel_groups_names[i] $></option>
%	}
     </select>
     <label for="time_para"><$ tr("Time") $>:&nbsp;<span class="bold"></span></label>
     <select name="time_para" id="time_para"  onchange="document.forms.channels.submit()" >
%	for ( unsigned int i = 0; i < times_names.size(); ++i ) {
%
		<option value="<$ i $>"
%                      if ( i == time_selected )
%                      {
			selected="selected"
%                      }
                        ><$ times_names[i] $></option>
%	}
     </select>
% //     <& pageelems.ajax_action_href action="switch_channel" tip=(tr("Switch to this channel.")) param=(Channel->GetChannelID()) image="zap.png" alt="" &>
% //     <& pageelems.vlc_stream_channel channelId=(Channel->GetChannelID()) &>
   </span>
</form>
</%def>