#include "tools.h"
#include "epgsearchext.h"
#include "epgsearchcats.h"
#include "epgsearchcfg.h"
#include "svdrpclient.h"


#ifdef HAVE_PCREPOSIX
#include <pcreposix.h>
#else
#include <regex.h>
#endif
#include <ctype.h>

char* IndentMenuItem(const char* szString)
{
    char* szIndented = NULL;
    asprintf(&szIndented, "  %s", szString);
    return szIndented;
}

void PatchFont(eDvbFont DvbFont)
{
    const cFont *font = cFont::GetFont(DvbFont);
    int num_rows_global = font->Height();
    int num_rows = num_rows_global+2;
    int i,j,num_char;
    cFont::tPixelData* font_data = new cFont::tPixelData[225*(num_rows)];
    for (i = 0; i < 225; i++)
	for (j = 0; j < num_rows; j++)
	    font_data[(i*num_rows)+j]=0x0000000000000000;
    font_data[0+0]=6;//font->CharData(0)->width;
    font_data[0+1]=num_rows_global;
    for(num_char=33, i = 1; num_char<256; i++, num_char++)
    {
	const cFont::tCharData* char_data = font->CharData(num_char);
	font_data[i*num_rows+0] = (num_char>=127 && num_char<=129)?6:char_data->width;
	font_data[i*num_rows+1] = char_data->height;
	for(j = 0; j<(int)char_data->height; j++)
	{
	    cFont::tPixelData Data = (cFont::tPixelData)char_data->lines[j];
	    if (j>5 && j<(DvbFont==fontOsd?23:18))
	    {
		if (num_char == 127)
		    Data = (cFont::tPixelData)0x0000007f;
		if (num_char == 128)
		    Data = (cFont::tPixelData)0x0000000f;
		if (num_char == 129)
		    Data = (cFont::tPixelData)0x00000070;
	    }
	    font_data[(i*num_rows)+2+j] = Data;
	}
    }
    cFont::SetFont(DvbFont, font_data);
}

#if VDRVERSNUM <= 10310    
time_t LastModifiedTime(const char *FileName)
{
  struct stat fs;
  if (stat(FileName, &fs) == 0)
     return fs.st_mtime;
  return 0;
}
#endif

bool MatchesSearchMode(char* szTest, char* searchText, int mode, const char* delim)
{
    if (strlen(szTest) > 0)
    {
	if (mode == 0) // substring
	    return (strstr(szTest, searchText) != NULL); 
	if (mode == 1 || mode == 2) // AND or OR
	{ 
	    bool bTesting = false;
 	    char *pstrSearchToken, *pptr;
	    bool bFirst=true;
	    char *pstrSearch=strdup(searchText);
	    pstrSearchToken=strtok_r(pstrSearch, delim, &pptr);
	    while(pstrSearchToken) 
	    {
		if(szTest && strstr(szTest, pstrSearchToken)) 
		{ 
		    if(mode==1) 
		    { // means AND
			if(bFirst) 
			{
			    bTesting=true;
			    bFirst=false;
			} 
			else
			    bTesting&=true;
		    }
		    else
			bTesting|=true;
		} 
		else 
		{// not found!!
		    if(mode==1) 
		    { // means AND
			bTesting=false;
			bFirst=false;
		    }
		}
		pstrSearchToken=strtok_r(NULL, delim, &pptr);
	    }
	    free(pstrSearch);
	    return bTesting;
	}
	if (mode == 3) // match exactly
	{
	    if (strcmp(szTest, searchText) == 0)
		return true;
	    else
		return false;
	} 
	if (mode == 4)
	{
	    regex_t re;
	    bool bTesting = true;
	    if ( 0 == regcomp(&re, searchText, REG_EXTENDED) )
	    {
		if ( REG_NOMATCH == regexec( &re, szTest, 0, NULL, 0))
		{
		    regfree(&re);
		    return false;
		}
		else
		    bTesting = true;
		regfree(&re);
	    }
	    else
		bTesting = false;
	    return bTesting;
	}	
	return false;
    }
    return false;
}

void ToLower(char* szText)
{
    if (!szText)
	return;
    for (int loop = 0; szText[loop] !=0; loop++)
	szText[loop] = tolower(szText[loop]);
}

char* GetExtEPGValue(const cEvent* e, cSearchExtCat* SearchExtCat)
{
    if (isempty(e->Description()))
	return NULL;
    char* tmp = NULL;
    
    // search the category, must be at beginnig of a line
    asprintf(&tmp, "\n%s: ", SearchExtCat->name);
    char* descr = strdup(e->Description());
    char* cat = NULL;
    if ((cat = strstr(descr, tmp)) == NULL)
    {
	free(descr);
	free(tmp);
	return NULL;
    }
    else
	cat++; // skip linefeed

    // search the value to appear before the next line feed or end 
    char* end = strchr(cat, '\n');
    int endpos = strlen(cat);
    if (end)
	endpos = end - cat;
    cat[endpos] = 0;

    char* value = NULL;
    asprintf(&value, "%s", cat + strlen(tmp)-1);
    free(descr);
    free(tmp);

    return value;
}

// search s2 in s1 ignoring the case of s2
char* strstri(const char* s1, const char* s2)
{
    char* tmp_s1 = strdup(s1);
    char* tmp_s2 = strdup(s2);
    ToLower(tmp_s1);
    ToLower(tmp_s2);
    char* p = strstr(tmp_s1, tmp_s2);
    int of = -1;
    if (p)
	of = p - tmp_s1;
	
    free(tmp_s1);
    free(tmp_s2);
    
    if (of == -1)
	return NULL;
    else
	return (char*)(s1 + of);
}

// replace s1 with s2 in s ignoring the case of s1
char *strreplacei(char *s, const char *s1, const char *s2)
{
    char *p = strstri(s, s1);
    if (p) {
	int of = p - s;
	int l  = strlen(s);
	int l1 = strlen(s1);
	int l2 = strlen(s2);
	if (l2 > l1)
	    s = (char *)realloc(s, strlen(s) + l2 - l1 + 1);
	if (l2 != l1)
	    memmove(s + of + l2, s + of + l1, l - of - l1 + 1);
	strncpy(s + of, s2, l2);
    }
    return s;
}

void sleepMSec(long ms)
{
#if VDRVERSNUM >= 10314
    cCondWait::SleepMs(ms);
#else
    usleep(1000 * ms);
#endif
}

void sleepSec(long s)
{
    sleepMSec(s * 1000);
}

void SendViaSVDRP(const char* SVDRPcmd) 
{
    char *cmdbuf = NULL;
    if (EPGSearchConfig.useExternalSVDRP)
    {
	asprintf(&cmdbuf, "%s -p %d \"%s\"", 
		 SVDRPSendCmd,
		 EPGSearchConfig.SVDRPPort,
		 SVDRPcmd);

	FILE *p = popen(cmdbuf, "r");
	if (p)
	    pclose(p);
	else
	    esyslog("EPGSearch: can't open pipe for command '%s'", cmdbuf);
    }
    else
    {
	asprintf(&cmdbuf, "%s", SVDRPcmd);
	cSVDRPClient client(EPGSearchConfig.SVDRPPort);
	if (!client.SendCmd(cmdbuf))
	    esyslog("EPGSearch: command '%s' failed", cmdbuf);
    }
    free(cmdbuf);
}

void SendMsg(const char* Message) 
{
    char *cmdbuf = NULL;
    asprintf(&cmdbuf, "MESG %s", Message);
    SendViaSVDRP(cmdbuf);
    free(cmdbuf);
}


bool InEditMode(const char* ItemText, const char* ItemName, const char* ItemValue)
{
    bool bEditMode = true;
    // ugly solution to detect, if in edit mode
    char* value = strdup(ItemText);
    strreplace(value, ItemName, "");
    strreplace(value, ":\t", "");
    // for bigpatch
    strreplace(value, "\t", "");
    if (strlen(value) == strlen(ItemValue))
	bEditMode = false;
    free(value);
    return bEditMode;
}
