#include <set>
#include <vdr/plugin.h>
#include <vdr/tools.h>
#include "grabberthread.h"
#include "log.h"
#include "recstatus.h"
#include "tracks.h"

// priority for background thread
#define GRABBER_NICE 19
// delay before first thread activity
#define GRABBER_WAIT 15 // startup wait in seconds
#define GRABBER_INTERVALL 30 // epg check intervall in seconds

#define SLEEPSEC(x) cCondWait::SleepMs(1000 * x);

cString DayDateTimesec(time_t t)
{
  char buffer[32];
  if (t == 0)
     time(&t);
  struct tm tm_r;
  tm *tm = localtime_r(&t, &tm_r);
  snprintf(buffer, sizeof(buffer), "%s %02d.%02d %02d:%02d:%02d", *WeekDayName(tm->tm_wday), tm->tm_mday, tm->tm_mon + 1, tm->tm_hour, tm->tm_min, tm->tm_sec);
  return buffer;
}

cGrabberThread *cGrabberThread::m_Instance = NULL;
set<cChannelSupported> cGrabberThread::channelsSupported;

cGrabberThread::cGrabberThread()
: cThread("Deluxe: epg grabber")
{
    m_Active = false;
}

cGrabberThread::~cGrabberThread() {
    if (m_Active) 
	Stop();
}

void cGrabberThread::Init() 
{
    if (m_Instance == NULL) {
	m_Instance = new cGrabberThread();
	m_Instance->Start();
    }
}

void cGrabberThread::Exit(void) {
    if (m_Instance != NULL) {
	m_Instance->Stop();
	DELETENULL(m_Instance);
    }
}

void cGrabberThread::Stop(void) {
    m_Active = false;
    Cancel(3);
}


set<cChannelSupported>::iterator cGrabberThread::GetChannel(string channelID)
{
    cChannelSupported tempChannel(channelID, UNKNOWN_EPG);
    return  channelsSupported.find(tempChannel);
}

bool cGrabberThread::ChannelSupported(string channelID)
{
    return (GetChannel(channelID) != channelsSupported.end());
}

void cGrabberThread::Action(void) 
{
    LogFile.iSysLog("Entering grabber thread");
    SetPriority(GRABBER_NICE);

    m_Active = true;
    // let VDR do its startup
    for(int wait = 0; wait < GRABBER_WAIT && m_Active; wait++)
	SLEEPSEC(1);


    while (m_Active) 
    {
	// get current EPG from deluxe
	{
	    cSchedulesLock schedulesLock;
	    const cSchedules *schedules;
	    schedules = cSchedules::Schedules(schedulesLock);
	    if (schedules)
	    {
		set<cChannelSupported>::iterator it;
		for (it = channelsSupported.begin(); it != channelsSupported.end(); it++) 
		{
		    if (!it->currentRecs) continue;
		    cChannel* channel = Channels.GetByChannelID(tChannelID::FromString(it->channelID.c_str()));
		    if (!channel) continue;

		    const cSchedule* schedule = schedules->GetSchedule(channel);
		    if (schedule)
		    {
			const cEvent* curEvent = schedule->GetPresentEvent();
			if (curEvent)
			{
			    LogFile.Log(3, "current event on %s is: %s (start: %s)", it->channelID.c_str(), curEvent->Title()?curEvent->Title():"unknown", *DayDateTimesec(curEvent->StartTime()));
			    if (Tracks.IsTrack(curEvent) && !Tracks.InList(curEvent))
			    {
				LogFile.Log(2, "add event on %s is: %s (start: %s)", it->channelID.c_str(), curEvent->Title()?curEvent->Title():"unknown", *DayDateTimesec(curEvent->StartTime()));
				cTrack* track = new cTrack(curEvent);
				if (Tracks.AlreadyDone(curEvent))
				{
				    LogFile.Log(2, "already done");
				    track->status = 1;
				}
				else if (Tracks.Blacklisted(curEvent))
				{
				    LogFile.Log(2, "in blacklist - ignored");
				    track->status = 1;
				}
				Tracks.Add(track);
				Tracks.Save();
			    }
			}
			else
			    LogFile.Log(2, "no current event");
		    }
		}
	    }
	}
	for(int wait = 0; wait < GRABBER_INTERVALL && m_Active; wait++)
	    SLEEPSEC(1);
    };
    LogFile.iSysLog("Leaving grabber thread");
}

