/**************************************************************************************
*
*	EyeTVPluginSample
*	
*   The EyeTV Plug-In Sample has been included with the Plug-In SDK as an easy way 
*   to demonstrate EyeTVŐs plug-in functionality. The plug-in displays information 
*   about the MPEG-2 transport stream that is captured at the moment. 
*
*   To see the EyeTV Plug-In Sample in action, open EyeTVPluginSampleX.xcode in Xcode, 
*   build the plug-in target and move the built product to the newly created 
*   /Contents/Plugins folder inside of the EyeTV application package.
*   The Console will show the plug-inŐs output once EyeTV has been relaunched.
*
*   To create your own plug-in project in Xcode, create a new project using the 
*   Bundle -> CFPlugIn Bundle template and implement the EyeTVPluginDispatcher 
*   function according to the specifications in this document.
*
*
*	Revision History:
*
*	02/27/2004:		Initial Release.
*
**************************************************************************************/


#include "EyeTVPluginDefs.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

/*#include <sys/types.h>
#include <sys/stat.h>*/
#include <semaphore.h>
#include <sys/mman.h>
#include <unistd.h>

#include <CoreServices/CoreServices.h>
/*#include "FSCopyObject.h"*/

#define MAX_PIDS			256
#define MAX_ACTIVE_PIDS		256
#define MAX_DEVICES			16

#pragma push
#pragma pack(1)

#define SEM_DEVICEINFO "cytv_sem_deviceinfo"
#define SHM_DEVICEINFO "cytv_shm_deviceinfo"
#define SEM_PREFIX "cytv_sem_"
#define SHM_PREFIX "cytv_shm_"
#define MAX_PACKETS 50000
#define MAX_LOCAL_PACKETS 50

#define LOG_FILE_PATH "

/*static char cytv_temp_path[256] = { 0 };
Boolean cytv_error = false;*/


/**************************************************************************************
*
*	Structure for TS-Packets
*
**************************************************************************************/
typedef struct {
	/*unsigned long			sync_byte : 8,
							transport_error_indicator : 1,
							payload_unit_start_indicator : 1,
							transport_priority : 1,
							PID : 13,
							transport_scrambling_control : 2,
							adaptation_field_control : 2,
							continuity_counter : 4;
	*/				
	unsigned char			data[188/*-4*/];
					
} TransportStreamPacket;

#pragma pop




/**************************************************************************************
*
*	Structure for holding Information on devices
*
*	(more Information about typedefs and definitions can be found in 'EyeTVPluginDefs.h')
*
**************************************************************************************/
typedef struct {
	EyeTVPluginDeviceID			deviceID;
	EyeTVPluginDeviceType		deviceType;
	
	long						headendID;
	long						transponderID;
	long						serviceID;
									
	long						pidsCount;
	long						pids[MAX_PIDS];
	
	EyeTVPluginPIDInfo			activePIDs[MAX_ACTIVE_PIDS];
	long						activePIDsCount;
	
    sem_t                       *deviceSem;
    int                         deviceShmFd;
    uint64_t                    *deviceShm;
    uint8_t                     localBuffer[188*MAX_LOCAL_PACKETS];
    long                        packetsInLocalBuffer;
} DeviceInfo;


/**************************************************************************************
*
*	Structure for holding global data
*
*	(more Information about typedefs and definitions can be found in 'EyeTVPluginDefs.h')
*
**************************************************************************************/
typedef struct {
	EyeTVPluginCallbackProc			callback;
	long							deviceCount;
	DeviceInfo						devices[MAX_DEVICES];
	long long						packetCount;
    long long                       filterCount;
    long long                       passCount;
    sem_t                           *deviceInfoSem;
    int                             deviceInfoShmFd;
    uint64_t                        *deviceInfoShm;
    FILE                            *logFile;
} EyeTVPluginSampleGlobals;




static void logMsg(EyeTVPluginSampleGlobals *globals, const char *logMessage) {
    if (globals) {
        if (globals->logFile) {
            fwrite(logMessage, strlen(logMessage), 1, globals->logFile);
            fflush(globals->logFile);
        }
    }
}




/**************************************************************************************
*	GetDeviceInfo,
*	
*	- *globals : The globals
*	- *deviceInfo : the DeviceID
*	
*	Description:
*		Returns the DeviceInfo with ID deviceID.
*
**************************************************************************************/
static DeviceInfo *GetDeviceInfo(EyeTVPluginSampleGlobals *globals, EyeTVPluginDeviceID deviceID)
{
	int i;
	
	if (globals) 
	{
		for (i=0;i<globals->deviceCount;i++) 
		{
			if (globals->devices[i].deviceID == deviceID) 
			{
				return &globals->devices[i];
			}
		}
	}
	
	return NULL;
}



#pragma mark -





/******************************************************************************************
*	EyeTVPluginSampleInitialize,
*
*	- **globals : Pointer to the globals 
*	- apiVersion : Version of the API
*
*	Description:
*		Initializes the plug-in.
*
******************************************************************************************/
static long EyeTVPluginSampleInitialize(EyeTVPluginSampleGlobals** globals, long apiVersion, EyeTVPluginCallbackProc callback)
{
	printf("EyeTV Plug-In Sample: Initialize\n");
	long		result = 0;
	
	*globals = (EyeTVPluginSampleGlobals*) calloc(1,sizeof(EyeTVPluginSampleGlobals));
    if (*globals) {
        (*globals)->callback = callback;
        
        // create (or append to) our log file
        FSRef logFolder;
        if (FSFindFolder(kUserDomain, kDomainLibraryFolderType, kDontCreateFolder, &logFolder) == noErr) {
            char path[1024];
            if (FSRefMakePath(&logFolder, (UInt8 *)path, 1024) == noErr) {
                const char* logFileName = "/Logs/cytv_eyetv_plugin.log";
                if (strlen(logFileName) + strlen(path) < 1024) {
                    strcat(path, logFileName);
                    //printf("Path: %s\n", path);
                    (*globals)->logFile = fopen(path, "a");
                }
            }
        }
        char formattedTime[100];
        time_t now = time(NULL);
        if (strftime(formattedTime, 100, "%c\n", localtime(&now))) {
            logMsg(*globals, formattedTime);
            char underline[100];
            int i;
            int l = strlen(formattedTime) - 1;
            for (i = 0; i < l; ++i) {
                underline[i] = '=';
            }
            underline[i++] = '\n';
            underline[i] = '\0';
            logMsg(*globals, underline);
        }
        logMsg(*globals, "EyeTV started\n");
        
        // create the device info semaphore and shm
        (*globals)->deviceInfoShm = (uint64_t *)-1;
        (*globals)->deviceInfoSem = (sem_t *)SEM_FAILED;
        (*globals)->deviceInfoShmFd = -1;
        sem_unlink(SEM_DEVICEINFO);     // in case we crashed before
        (*globals)->deviceInfoSem = sem_open(SEM_DEVICEINFO, O_CREAT | O_EXCL, 0600, 1);
        if ((*globals)->deviceInfoSem != (sem_t *)SEM_FAILED) {
            printf("Device info semaphore created\n");
            sem_wait((*globals)->deviceInfoSem);
            shm_unlink(SHM_DEVICEINFO);     // in case we crashed before
            (*globals)->deviceInfoShmFd = shm_open(SHM_DEVICEINFO, O_RDWR | O_CREAT | O_EXCL, 0600);
            if ((*globals)->deviceInfoShmFd == -1) {
                sem_post((*globals)->deviceInfoSem);
                sem_close((*globals)->deviceInfoSem);
                sem_unlink(SEM_DEVICEINFO);
            } else {
                printf("Device info shared memory created\n");
                ftruncate((*globals)->deviceInfoShmFd, 2*8 + MAX_DEVICES*8);
                (*globals)->deviceInfoShm = mmap(0, 2*8 + MAX_DEVICES*8, PROT_READ|PROT_WRITE, MAP_SHARED, (*globals)->deviceInfoShmFd, 0);
                if ((*globals)->deviceInfoShm == (uint64_t *)-1) {
                    close((*globals)->deviceInfoShmFd);
                    shm_unlink(SHM_DEVICEINFO);
                    sem_post((*globals)->deviceInfoSem);
                    sem_close((*globals)->deviceInfoSem);
                    sem_unlink(SEM_DEVICEINFO);
                } else {
                    (*globals)->deviceInfoShm[0] = 0;
                    (*globals)->deviceInfoShm[1] = 0;
                    sem_post((*globals)->deviceInfoSem);
                    printf("Device info shared memory mapped\n");
                    logMsg(*globals, "Device info shared memory mapped\n");
                }
            }
        }

        // create the temp dir for sempaphores and shms
        /*cytv_error = true;
        FSRef tempFolderRef;
        if (FSFindFolder(kUserDomain, kTemporaryFolderType, kCreateFolder, &tempFolderRef) == noErr) {
            if (FSRefMakePath(&tempFolderRef, (UInt8 *)cytv_temp_path, 200) == noErr) {
                printf("Temp path: %s\n", cytv_temp_path);
                strcat(cytv_temp_path, "/CyTV");
                // delete any existing folder
                if (FSPathMakeRef((UInt8 *)cytv_temp_path, &tempFolderRef, NULL) == noErr) {
                    if (FSDeleteObjects(&tempFolderRef) == noErr) {
                        if (mkdir(cytv_temp_path, 0700) == 0) {
                            cytv_error = false;
                        }
                    }
                }
            }
        }*/
    }
    
	return result;
}



/******************************************************************************************
*	EyeTVPluginSampleTerminate,
*
*	- *globals : the globals
*
*	Description: 
*		Called when the plug-in should terminate
*
******************************************************************************************/
static long EyeTVPluginSampleTerminate(EyeTVPluginSampleGlobals *globals)
{
	printf("EyeTV Plug-In Sample: Terminate\n");
    logMsg(globals, "EyeTV terminated\n\n");
	
	long		result = 0;
	
	if (globals) 
	{
        if (globals->deviceInfoSem != (sem_t *)SEM_FAILED) {
            sem_wait(globals->deviceInfoSem);
            globals->deviceInfoShm[0] = 0xffffffffffffffffll;
            munmap(globals->deviceInfoShm, 2*8 + MAX_DEVICES*8);
            close(globals->deviceInfoShmFd);
            shm_unlink(SHM_DEVICEINFO);
            sem_post(globals->deviceInfoSem);
            sem_close(globals->deviceInfoSem);
            sem_unlink(SEM_DEVICEINFO);
            long i;
            for (i = 0; i < globals->deviceCount; ++i) {
                DeviceInfo *deviceInfo = &(globals->devices[i]);
                if (deviceInfo->deviceSem != (sem_t *)SEM_FAILED) {
                    sem_wait(deviceInfo->deviceSem);
                    deviceInfo->deviceShm[0] = 0xffffffffffffffffll;
                    munmap(deviceInfo->deviceShm, 4*8 + MAX_PACKETS*188);
                    close(deviceInfo->deviceShmFd);
                    char shmName[50];
                    sprintf(shmName, "%s%.16llx", SHM_PREFIX, deviceInfo->deviceID);
                    shm_unlink(shmName);
                    sem_post(deviceInfo->deviceSem);
                    sem_close(deviceInfo->deviceSem);
                    char semName[50];
                    sprintf(semName, "%s%.16llx", SEM_PREFIX, deviceInfo->deviceID);
                    sem_unlink(semName);
                }
            }
        }
        if (globals->logFile) {
            fclose(globals->logFile);
        }
		free(globals);
	}
    
    // delete the temp dir for semaphores and shms
    //FSRef tempFolderRef;
    //if (FSPathMakeRef((UInt8 *)cytv_temp_path, &tempFolderRef, NULL) == noErr) {
    //    FSDeleteObjects(&tempFolderRef);
    //}
	return result;
}





/******************************************************************************************
*	EyeTVPluginSampleGetInformation,
*
*	- *globals : the globals
*	- *outVersion :  Version of the plug-in API
*	- *outName : Name of the plug-in
*	- *outDescription : Description of the plug-in
*
*	Description:
*		EyeTV asks for Information about your plug-in
*
*
******************************************************************************************/
static long EyeTVPluginSampleGetInformation(EyeTVPluginSampleGlobals *globals, long* outAPIVersion, char* outName, char *outDescription)
{
	printf("EyeTV Plug-In Sample: GetInfo\n");
	long		result = 0;
	
	if (globals) 
	{
		if (outAPIVersion)
		{
			*outAPIVersion = EYETV_PLUGIN_API_VERSION;
		}
		
		if (outName)
		{
			char* name = "EyeTV Plug-In Sample";
			strcpy(&outName[0], name);
		}
		
		if (outDescription)
		{
			char* desc = "This Plug-In is just a Sample...";
			strcpy(&outDescription[0], desc);
		}
	}
	
	return result;
}





/******************************************************************************************
*	EyeTVPluginSampleDeviceAdded,
*
*	- *globals : the globals
*	- deviceID : ID of the added device (see 'EyeTVPluginDefs.h')
*	- deviceType : Type of added device (see 'EyeTVPluginDefs.h')
*	
*	Description: 
*		Called if a device is added. 
*
*
******************************************************************************************/
static long EyeTVPluginSampleDeviceAdded(EyeTVPluginSampleGlobals *globals, EyeTVPluginDeviceID deviceID, EyeTVPluginDeviceType deviceType)
{
	printf("EyeTV Plug-In Sample: DeviceAdded\n");
    logMsg(globals, "Device added\n");
	long		result = 0;
	DeviceInfo *deviceInfo;
	
	if (globals) 
	{
		if (globals->deviceCount < MAX_DEVICES) 
		{
			deviceInfo = &(globals->devices[globals->deviceCount]);
			memset(deviceInfo, 0, sizeof(DeviceInfo));
			
			deviceInfo->deviceID = deviceID;
			deviceInfo->deviceType = deviceType;
			
			globals->deviceCount++;

            deviceInfo->deviceShm = (uint64_t *)-1;
            deviceInfo->deviceSem = (sem_t *)SEM_FAILED;
            deviceInfo->deviceShmFd = -1;
            if (globals->deviceInfoSem != (sem_t *)SEM_FAILED) {
                char semName[50];
                sprintf(semName, "%s%.16llx", SEM_PREFIX, (uint64_t)deviceID);
                char shmName[50];
                sprintf(shmName, "%s%.16llx", SHM_PREFIX, (uint64_t)deviceID);
                sem_unlink(semName);    // in case we crashed before
                deviceInfo->deviceSem = sem_open(semName, O_CREAT | O_EXCL, 0600, 1);
                if (deviceInfo->deviceSem != (sem_t *)SEM_FAILED) {
                    printf("Device semaphore created\n");
                    sem_wait(deviceInfo->deviceSem);
                    shm_unlink(shmName);    // in case we crashed before
                    deviceInfo->deviceShmFd = shm_open(shmName, O_RDWR | O_CREAT | O_EXCL, 0600);
                    if (deviceInfo->deviceShmFd == -1) {
                        sem_post(deviceInfo->deviceSem);
                        sem_close(deviceInfo->deviceSem);
                        sem_unlink(semName);
                    } else {
                        printf("Device shared memory created\n");
                        ftruncate(deviceInfo->deviceShmFd, 4*8 + MAX_PACKETS*188);
                        deviceInfo->deviceShm = mmap(0, 4*8 + MAX_PACKETS*188, PROT_READ|PROT_WRITE, MAP_SHARED, deviceInfo->deviceShmFd, 0);
                        if (deviceInfo->deviceShm == (uint64_t *)-1) {
                            close(deviceInfo->deviceShmFd);
                            shm_unlink(shmName);
                            sem_post(deviceInfo->deviceSem);
                            sem_close(deviceInfo->deviceSem);
                            sem_unlink(semName);
                        } else {
                            deviceInfo->deviceShm[0] = 0;
                            deviceInfo->deviceShm[1] = 0;
                            deviceInfo->deviceShm[2] = 0;
                            deviceInfo->deviceShm[3] = 0;
                            sem_post(deviceInfo->deviceSem);
                            printf("Device shared memory mapped\n");
                            logMsg(globals, "Device shared memory mapped\n");
                        }
                    }
                }
                
                // add the device id to the device info shm
                if (deviceInfo->deviceSem != (sem_t *)SEM_FAILED) {
                    sem_wait(globals->deviceInfoSem);
                    globals->deviceInfoShm[1] = (uint64_t)globals->deviceCount;
                    globals->deviceInfoShm[globals->deviceCount + 1] = (uint64_t)deviceID;
                    sem_post(globals->deviceInfoSem);
                }
            }
        }
	}
	
    // create a semaphore
    /*char semName[256];
    sprintf(semName, "cytv_sem_%.16llx", cytv_temp_path, (unsigned long long)deviceID);
    printf("Semaphore name: %s\n", semName);
    if (sem_open(semName, O_CREAT | O_EXCL, 0600, 1) == (sem_t *)SEM_FAILED) {
        printf("Semaphore creation failed with error: %d\n", (int)errno);
    }*/
    
	return result;
}




/******************************************************************************************
*	EyeTVPluginSampleDeviceRemoved,
*
*	- *globals : the globals
*	- deviceID : The Device Identifier  
*
*	Description:
*		Called, if a device is removed. 
*
******************************************************************************************/
static long EyeTVPluginSampleDeviceRemoved(EyeTVPluginSampleGlobals *globals, EyeTVPluginDeviceID deviceID)
{
	printf("EyeTV Plug-In Sample: DeviceRemoved\n");
    logMsg(globals, "Device removed\n");
	long		result = 0;
	long        i;
    long        j;
	
	if (globals) 
	{
        for (i = 0; i < globals->deviceCount; i++)
		{
			if (globals->devices[i].deviceID == deviceID) 
			{
                if (globals->deviceInfoSem != (sem_t *)SEM_FAILED) {
                    DeviceInfo *deviceInfo = &(globals->devices[i]);
                    if (deviceInfo->deviceSem != (sem_t *)SEM_FAILED) {
                        sem_wait(globals->deviceInfoSem);
                        for (j = 0; j < globals->deviceCount; ++j) {
                            if (globals->deviceInfoShm[j+2] == deviceID) {
                                long k;
                                for (k = j; k < globals->deviceCount - 1; ++k) {
                                    globals->deviceInfoShm[k+2] = globals->deviceInfoShm[k+3];
                                }
                                globals->deviceInfoShm[1] = (uint64_t)(globals->deviceCount-1);
                                break;
                            }
                        }
                        sem_post(globals->deviceInfoSem);
                        sem_wait(deviceInfo->deviceSem);
                        deviceInfo->deviceShm[0] = 0xffffffffffffffffll;
                        munmap(deviceInfo->deviceShm, 4*8 + MAX_PACKETS*188);
                        close(deviceInfo->deviceShmFd);
                        char shmName[50];
                        sprintf(shmName, "%s%.16llx", SHM_PREFIX, deviceID);
                        shm_unlink(shmName);
                        sem_post(deviceInfo->deviceSem);
                        sem_close(deviceInfo->deviceSem);
                        char semName[50];
                        sprintf(semName, "%s%.16llx", SEM_PREFIX, deviceID);
                        sem_unlink(semName);
                    }
                }

                globals->deviceCount--;

				if (i<globals->deviceCount)
				{
					globals->devices[i] = globals->devices[globals->deviceCount];
				}
                break;
			}
		}
	}
	
	return result;
}





/******************************************************************************************
*	EyeTVPluginSamplePacketsArrived,
*
*	- *globals : The plug-in Globals
*	- deviceID : Id of the active Device
*	- **packets : Pointer to the data
*	- packetsCount : number of packets
*
*	Description:
*		This function is called, whenever packets are received by EyeTV. For reasons of
*		performance, the data is the original data, not a copy. That means, EyeTV waits
*		until this method is finished. Therefore all in this method should be as fast as possible.
*
*
******************************************************************************************/
int i=0;
static long EyeTVPluginSamplePacketsArrived(EyeTVPluginSampleGlobals *globals, EyeTVPluginDeviceID deviceID, long **packets, long packetsCount)
{
	long		result = 0;
	long 		/*i,*/ j/*, isNewPID*/;
    long        pid;
	TransportStreamPacket *packet;
	
	
	if (globals) 
	{
		DeviceInfo		*deviceInfo = GetDeviceInfo(globals, deviceID);
		
		if (deviceInfo) 
		{
            //if (deviceInfo->deviceSem != (sem_t *)SEM_FAILED) {
            //    sem_wait(deviceInfo->deviceSem);
            //}
            TransportStreamPacket *dst = (TransportStreamPacket *)(deviceInfo->localBuffer + deviceInfo->packetsInLocalBuffer*188);
			for (i = 0; i < packetsCount; i++) 
			{
				packet		= (TransportStreamPacket*)packets[i];
                long pid = ((long)(packet->data[1] & 0x1f)) << 8 | ((long)(packet->data[2]));
				//isNewPID	= 1;
				
				/*
				*	search for PID
				*/
				//for (j = 0; j < deviceInfo->pidsCount; j++) 
				//{
				//	if (packet->PID == deviceInfo->pids[j]) 
				//	{
				//		isNewPID = 0;
				//		break;
				//	}
				//}
				
				
				/*
				*	add new PIDs to the DeviceInfo
				*/
				//if (isNewPID) 
				//{
				//	printf ("EyeTV Plug-In Sample: SamplePacketsArrived, newPID = %6d\n", packet->PID);
				//	
				//	if (deviceInfo->pidsCount < MAX_PIDS) 
				//	{
				//		deviceInfo->pids[deviceInfo->pidsCount++] = packet->PID;
				//	}
				//}
				
				
				globals->packetCount++;
				
				if (globals->packetCount == 50000) //%10000 == 0) 
					//printf("->  %lld Packets received so far...\n",globals->packetCount);
                    logMsg(globals, "50000 packets received\n");
                
                int pidFound = 0;
                for (j = 0; j < deviceInfo->activePIDsCount; ++j) {
                    if (pid == deviceInfo->activePIDs[j].pid) {
                        pidFound = 1;
                        break;
                    }
                }
                if (pidFound) {
                    globals->passCount++;
                    if (globals->passCount == 50000) {
                        logMsg(globals, "50000 packets stored in shared memory\n");
                    }
                }
                //if (!pidFound) {
                //    globals->filterCount++;
                //    if (globals->filterCount%10000 == 0) 
                //        printf("->  %lld Packets filtered so far...\n",globals->filterCount);
                //}
                if (pidFound && deviceInfo->deviceSem != (sem_t *)SEM_FAILED) {
                    *dst++ = *packet;
                    deviceInfo->packetsInLocalBuffer++;
                    if (deviceInfo->packetsInLocalBuffer == MAX_LOCAL_PACKETS) {
                        dst = (TransportStreamPacket *)(deviceInfo->localBuffer);
                        deviceInfo->packetsInLocalBuffer = 0;
                        sem_wait(deviceInfo->deviceSem);
                        uint64_t currentPacketCount = deviceInfo->deviceShm[1];
                        uint64_t currentPacketIndex = deviceInfo->deviceShm[2];
                        if (currentPacketIndex >= MAX_PACKETS) {
                            currentPacketIndex = 0;     // prevent overflow
                        }
                        long packetsToCopy = MAX_PACKETS - currentPacketIndex;
                        if (packetsToCopy > MAX_LOCAL_PACKETS) {
                            packetsToCopy = MAX_LOCAL_PACKETS;
                        }
                        TransportStreamPacket *localSrc = dst;
                        TransportStreamPacket *shmDst =
                            (TransportStreamPacket *)(((uint8_t *)deviceInfo->deviceShm) + 4*8 + 188*currentPacketIndex);
                        for (j = 0; j < packetsToCopy; ++j) {
                            *shmDst++ = *localSrc++;
                        }
                        currentPacketIndex += packetsToCopy;
                        if (currentPacketIndex == MAX_PACKETS) {
                            //printf("Buffer wraparound (%ld packets)\n", (long)packetsCount);
                            //int k;
                            //for (k = 0; k < packetsCount; ++k) {
                            //    printf("%lx\n", (unsigned long)packets[k]);
                            //}
                            deviceInfo->deviceShm[3]++;
                            if (packetsToCopy < MAX_LOCAL_PACKETS) {
                                shmDst = (TransportStreamPacket *)(((uint8_t *)deviceInfo->deviceShm) + 4*8);
                                localSrc = (TransportStreamPacket *)(deviceInfo->localBuffer + 188*packetsToCopy);
                                packetsToCopy = MAX_LOCAL_PACKETS - packetsToCopy;
                                for (j = 0; j < packetsToCopy; ++j) {
                                    *shmDst++ = *localSrc++;
                                }
                                currentPacketIndex = packetsToCopy;
                            } else {
                                currentPacketIndex = 0;
                            }
                        }
                        deviceInfo->deviceShm[2] = currentPacketIndex;
                        currentPacketCount += MAX_LOCAL_PACKETS;
                        if (currentPacketCount > MAX_PACKETS) {
                            currentPacketCount = MAX_PACKETS;
                        }
                        deviceInfo->deviceShm[1] = currentPacketCount;
                        sem_post(deviceInfo->deviceSem);
                    }
                }
			}
		}
	}
	
	return result;
}

			


/******************************************************************************************
*	EyeTVPluginSampleServiceChanged,
*
*	- *globals		: The plug-in Globals
*	- deviceID		: Identifies the active Device
*   - headendID		: The HeadendID, for e300 it's the orbital position of the satelite in 
*					  tenth degrees east
*   - transponderID : The Frequency in kHz
*   - serviceID		: original ServiceID from the DVB-Stream (e300, e400)
*	- pidList		: List of active PIDs	
*
*	Description:
*		Whenever a service changes, this function is called. Service-related plug-in data
*		should be updated here.
*
*
******************************************************************************************/
static long EyeTVPluginSampleServiceChanged(EyeTVPluginSampleGlobals *globals, 
											EyeTVPluginDeviceID deviceID, 
											long headendID, 
											long transponderID, 
											long serviceID, 
											EyeTVPluginPIDInfo *pidList, 
											long pidsCount)
{
	long		result = 0;
	int			i;
	
	//printf("\nEyeTV Plug-In Sample: ServiceChanged:\n");
	//printf(  "=====================================\n");
	
	if (globals) 
	{
		DeviceInfo		*deviceInfo = GetDeviceInfo(globals, deviceID);
		if (deviceInfo) 
		{
			
			deviceInfo->headendID = headendID;
			//printf("HeadendID: %ld, ", headendID);
			
			deviceInfo->transponderID = transponderID;
			//printf("TransponderID: %ld, ", transponderID);
			
			deviceInfo->serviceID = serviceID;
			//printf("ServiceID: %ld\n\n", serviceID);
			
			deviceInfo->activePIDsCount = pidsCount;

			for(i = 0; i < pidsCount; i++)
			{
				deviceInfo->activePIDs[i] = pidList[i];
				//printf("Active PID: %ld, type: %ld\n", pidList[i].pid, pidList[i].pidType);
			}

			deviceInfo->pidsCount = 0;
			
		}
	}
	//printf(  "=====================================\n");
	return result;
}






#pragma mark -
/******************************************************************************************
*	EyeTVPluginDispatcher,
*
*	- selector : See 'EyeTVPluginDefs.h'
*	- *refCon :  The RefCon to the plug-in-related Data
*	- deviceID : Identifies the Device
*	- params : Parameters for functioncall
*
*	Description:
*		This function is a part of the interface for the communication with EyeTV. If something
*		happens, EyeTV thinks, your plug-in should know of, it calls this function with the 
*		corresponding selector. For more Information see 'EyeTVPluginDefs.h' and the 
*		About the EyeTV Plug-In SDK document.
*
*
******************************************************************************************/
#pragma export on

long EyeTVPluginDispatcher (EyeTVPluginParams* params)
{
	long		result = 0;

	switch (params->selector) 
	{
		case kEyeTVPluginSelector_Initialize:
			result = EyeTVPluginSampleInitialize((EyeTVPluginSampleGlobals**)params->refCon, 
									params->initialize.apiVersion, params->initialize.callback);
			break;
			
		case kEyeTVPluginSelector_Terminate:
			result = EyeTVPluginSampleTerminate((EyeTVPluginSampleGlobals*)params->refCon);
			break;

		case kEyeTVPluginSelector_GetInfo:
			result = EyeTVPluginSampleGetInformation((EyeTVPluginSampleGlobals*)params->refCon, 
									params->info.pluginAPIVersion, params->info.pluginName, params->info.description);
			break;

		case kEyeTVPluginSelector_DeviceAdded:
			result = EyeTVPluginSampleDeviceAdded((EyeTVPluginSampleGlobals*)params->refCon, 
									params->deviceID, params->deviceAdded.deviceType);
			break;
		
		case kEyeTVPluginSelector_DeviceRemoved:
			result = EyeTVPluginSampleDeviceRemoved((EyeTVPluginSampleGlobals*)params->refCon, params->deviceID);
			break;

		case kEyeTVPluginSelector_PacketsArrived:
			result = EyeTVPluginSamplePacketsArrived((EyeTVPluginSampleGlobals*)params->refCon, params->deviceID, 
									params->packetsArrived.packets, params->packetsArrived.packetCount);
			break;

		case kEyeTVPluginSelector_ServiceChanged:
			result = EyeTVPluginSampleServiceChanged((EyeTVPluginSampleGlobals*)params->refCon, 
									params->deviceID, params->serviceChanged.headendID, 
									params->serviceChanged.transponderID, params->serviceChanged.serviceID, 
									params->serviceChanged.pidList, params->serviceChanged.pidCount);
			break;
	}
	
	return result;
}



