#include "ofQtVideoGrabber.h"



//--------------------------------------------------------------------
Boolean SeqGrabberModalFilterUPP (DialogPtr theDialog, const EventRecord *theEvent, short *itemHit, long refCon);
Boolean SeqGrabberModalFilterUPP (DialogPtr theDialog, const EventRecord *theEvent, short *itemHit, long refCon){
	#pragma unused(theDialog, itemHit)  
  	Boolean  handled = false;
  	if ((theEvent->what == updateEvt) && 
    ((WindowPtr) theEvent->message == (WindowPtr) refCon))
  	{
    	BeginUpdate ((WindowPtr) refCon);
    	EndUpdate ((WindowPtr) refCon);
    	handled = true;
  	}
  	return (handled);
}

//--------------------------------------------------------------------
ofQtVideoGrabber::ofQtVideoGrabber(){
	initializeQuicktime();
	vgd 		= new videoGrabberData();
	bVerbose 			= false;
	bSgGrabberInited 	= false;
	bUseTexture			= true;
	bShowDialog			= false;
}

//--------------------------------------------------------------------
void ofQtVideoGrabber::setVerbose(bool bTalkToMe){
	bVerbose = bTalkToMe;
}

//--------------------------------------------------------------------
void ofQtVideoGrabber::setShowDialog(bool bTalkToMe){
	bShowDialog = bTalkToMe;
}

//---------------------------------------------------------------------------
unsigned char * ofQtVideoGrabber::getPixels(){
	return vgd->pixels;
}

//---------------------------------------------------------------------------
bool  ofQtVideoGrabber::isFrameNew(){
	if (bSgGrabberInited == true){
		bool bNew = false;
		if (vgd->bHavePixelsChanged == true){
			bNew = true;
			vgd->bHavePixelsChanged = false;
		}
		
		return bNew;
	} else {
		return false;
	}
}

//--------------------------------------------------------------------
void ofQtVideoGrabber::grabFrame(){
	if (bSgGrabberInited == true){
		SGIdle(vgd->gSeqGrabber);
		// set the top pixel alpha = 0, so we can know if it 
		// was a new frame or not..
		// or else we will process way more than necessary
		// (ie opengl is running at 60fps +, capture at 30fps)
		if (vgd->offscreenGWorldPixels[0] != 0x00){
			vgd->offscreenGWorldPixels[0] = 0x00;
			vgd->bHavePixelsChanged = true;
			convertPixels(vgd->offscreenGWorldPixels, vgd->pixels, vgd->w, vgd->h);
			
			if (bUseTexture){
				tex.loadData(vgd->pixels, vgd->w, vgd->h, GL_RGB);
			}
		} 
	}
}

//--------------------------------------------------------------------
void ofQtVideoGrabber::close(){
	//thanks eloi!
	if (vgd->gSeqGrabber != 0L){
		CloseComponent (vgd->gSeqGrabber);
		vgd->gSeqGrabber = 0L;
	}
}

//--------------------------------------------------------------------
void ofQtVideoGrabber::videoSettings(void){
	
	Rect	curBounds, curVideoRect;
	ComponentResult	err;

	// Get our current state
	err = SGGetChannelBounds (vgd->gVideoChannel, &curBounds);
	if (err != noErr){
		printf("Error in SGGetChannelBounds \n");
		return;
	}
	err = SGGetVideoRect (vgd->gVideoChannel, &curVideoRect);
	if (err != noErr){
		printf("Error in SGGetVideoRect \n");
		return;
	}

	// Pause
	err = SGPause (vgd->gSeqGrabber, true);
	if (err != noErr){
		printf("Error in SGPause\n");
		return;
	}
	
	#ifdef TARGET_OSX
		static SGModalFilterUPP gSeqGrabberModalFilterUPP = NewSGModalFilterUPP(SeqGrabberModalFilterUPP);
		ComponentResult result = SGSettingsDialog(vgd->gSeqGrabber,  vgd->gVideoChannel, 0, nil, seqGrabSettingsPreviewOnly, gSeqGrabberModalFilterUPP, nil);
		if (err != noErr){
		printf("error in  dialogue\n");
		return;
	}
	#else 
		SGSettingsDialog(vgd->gSeqGrabber, vgd->gVideoChannel, 0, nil, seqGrabSettingsPreviewOnly, NULL, 0);
	#endif

	SGSetChannelBounds(vgd->gVideoChannel, &vgd->videoRect);
	SGPause (vgd->gSeqGrabber, false);	
	
}


//--------------------------------------------------------------------
void ofQtVideoGrabber::initGrabber(int w, int h){
	
	vgd->w = w;
	vgd->h = h;
	
	ComponentDescription 	    theDesc;
	Component 					sgCompID = NULL;
	char name[256];
 	char info[256];
	Handle componentName=NULL;
 	Handle componentInfo=NULL;
 	ComponentDescription info_description;
	componentName=NewHandle(sizeof(name));
	componentInfo=NewHandle(sizeof(info));
	
	if (bVerbose == true){
		printf ("\n");
		printf ("-------------------------------------\n");
		printf ("attempting to set up ofQtVideoGrabber\n");
	}
	
	vgd->gSeqGrabber 		= 0L;
	vgd->gVideoChannel 		= 0L;
	
	theDesc.componentType = SeqGrabComponentType;
	theDesc.componentSubType = 0L;
	theDesc.componentManufacturer = 0L;
	theDesc.componentFlags = 0L;
	theDesc.componentFlagsMask = 0L;
	sgCompID = FindNextComponent(sgCompID, &theDesc);
	while (sgCompID != 0){
		GetComponentInfo(sgCompID,&info_description, componentName, componentInfo,nil);
		if (bVerbose == true){
			printf("found a device to capture with \n");
			printf("Type: %s\n", &info_description.componentType);
			printf("Manufacturer: %s\n", &info_description.componentManufacturer);
			printf("Name: %s\n", *componentName ? p2cstr((StringPtr)*componentName) : "-" );
			printf("Name: %s\n", *componentInfo ? p2cstr((StringPtr)*componentInfo) : "-");
		}
		vgd->gSeqGrabber = OpenComponent(sgCompID);
		sgCompID 	= FindNextComponent(sgCompID, &theDesc);
	} 
 	
	//--------------------------------------------
	// setup the gworld and digitizing.
	OSStatus err;
	err = SGInitialize(vgd->gSeqGrabber);
	if (err != noErr){
		printf("***** Error in SGInitialize (check cam drivers, vdig or winvidg)*****\n");
		return;
	}
	
	MacSetRect(&(vgd->videoRect),0, 0, w, h);	
	
	width = w;
	height = h;
	
	//---------------------------------- buffer allocation
	// Create a buffer big enough to hold the video data, 
	// make sure the pointer is 32-byte aligned.
	// also the rgb image that people will grab
	
	vgd->offscreenGWorldPixels 	= (unsigned char*)malloc(4 * w * h + 32);
	vgd->pixels					= new unsigned char[w*h*3];
	
	QTNewGWorldFromPtr (&vgd->videogworld, k32ARGBPixelFormat, &vgd->videoRect, NULL, NULL, 0, vgd->offscreenGWorldPixels, 4 * w);
	LockPixels(GetGWorldPixMap(vgd->videogworld));
	
	SetGWorld (vgd->videogworld, NULL);
	
	err = SGSetGWorld(vgd->gSeqGrabber, vgd->videogworld, nil);
	if ( err != noErr ) goto bail;
	
	err = SGNewChannel(vgd->gSeqGrabber, VideoMediaType, &vgd->gVideoChannel);
	if ( err != noErr ) goto bail;
	
	//err = SGSetDataRef(vgd->gSeqGrabber, 0, 0, seqGrabDontMakeMovie); 
 	//if ( err != noErr ) goto bail;
	
 	err = SGSetChannelUsage(vgd->gVideoChannel,seqGrabPreview);
	if ( err != noErr ) goto bail;
	
	err = SGSetChannelBounds(vgd->gVideoChannel, &vgd->videoRect);
	if ( err != noErr ) goto bail;
	
	if (SGSetFrameRate(vgd->gVideoChannel,30) != noErr) printf( "error setting 30 fps \n");
	else{
		if (bVerbose == true){
			printf ("set to capture at 30 fps \n");
		}
	}
	
	err = SGPrepare(vgd->gSeqGrabber,  true, false); //theo swapped so preview is true and capture is false
	if ( err != noErr ) goto bail;
	
	err = SGStartPreview(vgd->gSeqGrabber);
	if ( err != noErr ) goto bail;
	
	
	if (bVerbose){
		printf ("end setup ofQtVideoGrabber\n");
		printf ("-------------------------------------\n");
		printf ("\n");
	}
	
	
	if (bUseTexture){
		// create the texture, set the pixels to black and 
		// upload them to the texture (so at least we see nothing black the callback)
		tex.allocate(w,h,GL_RGB);
		memset(vgd->pixels, 0, w*h*3);
		tex.loadData(vgd->pixels, w, h, GL_RGB);
	}

	if(bShowDialog)videoSettings();
	
	bSgGrabberInited = true;
	return;				// good catch eloi/theo
	
	//--------------------- (bail) something's wrong -----	
	bail:
		
		if (bVerbose){
			printf ("***** ofQtVideoGrabber error *****\n");
			printf ("-------------------------------------\n");
			printf ("\n");
		}
		
		bSgGrabberInited = false;
		return;
	
}

//------------------------------------
void ofQtVideoGrabber::setUseTexture(bool bUse){
	bUseTexture = bUse;
}
		
		
//------------------------------------
void ofQtVideoGrabber::draw(float _x, float _y, float _w, float _h){
	if (bUseTexture){
		tex.draw(_x, _y, _w, _h);
	}
}

//------------------------------------
void ofQtVideoGrabber::draw(float _x, float _y){
	draw(_x, _y, width, height);
}

