/*
 
 This code is slightly modified in order to support programming
 the game of set. When the user hits the 'S' (capital S), nine
 windows holding set cards (from .\\setImages) appear.
 
 Images for the cards and separate images for drawing on top of
 the cards are available after this: they are in setimages and
 setimages_painted.
 
 The function processSetCard is a place-holder for your code
 that will determine the number, color, fill, and shape of the
 symbols on a particular set card.
 
 Also, once the code determines the symbols on all nine cards, 
 it should somehow indicate which three cards (if any) comprise a set... .
 This will have to be done in a function outside processSetCard.
 
 
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 How to get OpenCV and this working?
 
 1. Download and install OpenCV for Windows
 2. You'll need XCode 3.0 (the Mac OS X suite of developer tools)
    - it's free from Apple or Tim Buchheim if you don't have them...
 3. Double-click the "project" file (SetMacOS.xcodeproj)
 4. Compile (hopefully!) and run.
 5. If you don't have a camera, it's not as much fun :-) Still images are supported, though.
 6. Some key presses (with focus on the undistored image window) matter...
 see the code for what each one does. A couple of important ones:
 The 'r' key toggles on and off the selected color
 The 's' key starts/stops the image grabbing
 The ' ' (space bar) moves through saved images (in ./setImages)
 
 7. It is listening on port PORT_NUMBER (default 2000) for a client (in any language)
 8. The client.py file can be used as a starting point!
 
 Q. The program quits when you hit the escape key when the focus in on the OpenCV program or if you send it
 a 'q' from the client. 
 
 */



/*
 * a small function to see if j is in the first
 * N of imageIndices's elements
 */
bool alreadyHaveIt(int j, int* imageIndices, int N)
{
	for (int i=0 ; i<N ; ++i)
        if (imageIndices[i] == j) return true;
	return false;
}


/*
 * set your OS!
 *
 * in order to include the correct files...
 */

//#define WINDOWS_OS
#define MAC_OS

/*
 * include files for Mac OS X
 */
#ifdef MAC_OS

#include <OpenCV/OpenCV.h>
#include <stdio.h>
#include <ctype.h>
#include <math.h>
#include <pthread.h>
#include <stdlib.h>
#include <string.h>       // for memset
#include <unistd.h>
#include <sys/types.h> 
#include <sys/socket.h>
#include <netinet/in.h>
#include <BlobResult.h>

#include <fstream> 
#include <iostream>
using namespace std;

//#define ROOT_FOLDER "/Users/bfsnet/Desktop/SetWithOpenCV/"
//#define ROOT_FOLDER "/Users/admin/Desktop/SetWithOpenCV/"
//#define ROOT_FOLDER "/Users/dodds/Desktop/SetMacOS30/"
// This should point to the containing folder...
#define ROOT_FOLDER "../../../SetMacOS30/"

#endif

/*
 * code for Set specifically
 */

#define NUM_WINDOWS 9

char *setwnd[] = {"set0","set1","set2","set3","set4","set5","set6","set7","set8","set9","set10","set11"};
static IplImage** setimages;
//static IplImage** setimage_frames;
static IplImage** setimages_painted;
// a set-card-processing function
void processSetCard(int i);
bool firstTimeForSet = true;



/* 
 * global data for passing among 
 *   the main loop (in main)
 *   the mouse-event handler (in mouseEventHandler)
 *   the server (in runServerThread)
 */
IplImage *inputImage=0;  // shared between mouse events and main loop
int swapVerticalValues = 0;  // shared between mouse events and main loop

int drawingRectangle=0;  // shared between mouse events and main loop
CvPoint origin;          // more rectangle/line-selection data
CvRect selection;

int runAlgorithm = 0;    // shared between server and main loop
int timeToQuitNow = 0;   // shared between server and main loop
int blobsAreOn = 1; // allows us to turn blob detection on and off
int removePixels = 0;



#define MAXCOLORS 5

#include "mainHelperBG.h"
BlobData colorData[30];   // actually, not all 30 of these will be used... likely only MAXCOLORS
#include "colorArrayBG.h"
#include "serverStuffSabreen6408.h"


ArrayColorDef currentColorArray;
ArrayColorDef totalColorArray[MAXCOLORS];
char* colorNames[MAXCOLORS];




/*
 * Mouse-event handling routine
 */
void mouseEventHandler( int event, int x, int y, int flags, void* param )
{
  int r,g,b;
  double h,s,v;
	
	if ( !inputImage )  return;  // no image, do nothing
  if (swapVerticalValues)  y = inputImage->height - y;   // platform-dependent!
  
  if ( event == CV_EVENT_MOUSEMOVE && drawingRectangle ) // are we pulling the corner of a rectangle?
  {
    // handle the geometry of the rectangle:
    selection.x = MIN(x,origin.x);  selection.y = MIN(y,origin.y);
    selection.width = MIN( selection.x + CV_IABS(x - origin.x), inputImage->width ) - MAX( selection.x, 0 );
    selection.height = MIN( selection.y + CV_IABS(y - origin.y), inputImage->height ) - MAX( selection.y, 0 );
  } // end of rectangle-drawing
    
  if ( event == CV_EVENT_RBUTTONDOWN && !(removePixels)) // did we right-click (or control-click?)
  {
    getrgb( inputImage, x, y, r, g, b );
	RGBtoHSV( r, g, b, h, s, v );
    printf("      right-click at (%d,%d): rgb=(%d,%d,%d)\n", x, y, r, g, b ) ;
	printf("		hsv=(%6.3f,%6.3f,%6.3f)\n",h,s,v);
    int N = 7;  // acceptable color width 
    currentColorArray.expandToFit( r, g, b, N ); // box of side 2N: upper corner
    //currentColor.expandToFit( r-N, g-N, b-N ); // and lower corner
    //currentColor.print();
  }
  
  if ( event == CV_EVENT_RBUTTONDOWN && removePixels)
  {
	getrgb( inputImage, x, y, r, g, b );
	RGBtoHSV( r, g, b, h, s, v );
    printf("      right-click at (%d,%d): rgb=(%d,%d,%d)\n", x, y, r, g, b ) ;
	printf("		hsv=(%6.3f,%6.3f,%6.3f)\n",h,s,v);
    int N = 7;  // acceptable color width 
    currentColorArray.subtractRange( r, g, b, N ); // box of side 2N: upper corner
    //currentColor.expandToFit( r-N, g-N, b-N ); // and lower corner
    //currentColor.print();
   }
		  
	if ( event == CV_EVENT_LBUTTONDOWN ) // did we left-click?
  {
    if (!drawingRectangle) // if we weren't drawing, now we start drawing a rectangle
    {
      origin = cvPoint(x,y);
      selection = cvRect(x,y,1,1);
      drawingRectangle = 1;
	  printf("begin drawing rectangle. \n");
    }
	
    else if(drawingRectangle && removePixels) // we'll remove the pixels in the enclosed rectangle
    {
      //currentColorArray.reset();
      for ( int col=selection.x ; col<=selection.x+selection.width ; ++col)
      {
        for ( int row=selection.y ; row<=selection.y+selection.height ; ++row) 
        {
		  int N = 10; // acceptable color width
          getrgb( inputImage, col, row, r, g, b );
          currentColorArray.subtractRange( r, g, b, N);
        }
      }
	  drawingRectangle = 0;
	  printf("end drawing subtraction rectangle. \n");
	  }
	  
	  
	else // drawing rectangle and adding pixels
	{
		 for ( int col=selection.x ; col<=selection.x+selection.width ; ++col)
      {
			for ( int row=selection.y ; row<=selection.y+selection.height ; ++row) 
        {
			int N = 10; // acceptable color width
			getrgb( inputImage, col, row, r, g, b );
			currentColorArray.expandToFit( r, g, b, N);
		}
      }
	  
      drawingRectangle = 0;
	  printf("end drawing addition rectangle. \n");
	  }
  }
	  
	  
	//printf("end of mouse event handler \n");
} // end of mouse event handler

void pixelsInArraybw(IplImage* INPUT, ArrayColorDef colorArray, IplImage* OUTPUT)
 {
	//printf(" beginning bw \n");
	int imageWidth  = INPUT-> width;
	int imageHeight = INPUT-> height;
	int r,g,b;
	for ( int col = 0; col < imageWidth; col++)
	{
		for ( int row = 0; row < imageHeight; row++)
		{
			getrgb(INPUT, col, row, r, g, b);
			if (colorArray.pixelMatch(r,g,b))
			{
				setbw(OUTPUT, col, row, 255);
				//printf("pixel set");
			}
			else
			{
				setbw(OUTPUT, col, row, 0);
			}
		}
	}
	
		 
}

void drawBorder(IplImage* IMAGE)
{

	int imageWidth  = IMAGE-> width;
	int imageHeight = IMAGE-> height;
	
	for( int col = 0; col < 3; col++)
	{
		for( int row = 0; row < imageHeight; row++)
		{
			setbw(IMAGE, col, row, 0);
		}
	}
	
	for( int col = imageWidth-3; col < imageWidth; col++)
	{
		for( int row = 0; row < imageHeight; row++)
		{
			setbw(IMAGE, col, row, 0);
		}
	}
	
	for( int col = 0; col < imageWidth; col++)
	{
		for( int row = 0; row < 3; row++)
		{
			setbw(IMAGE, col, row, 0);
		}
	}
	
	for( int col = 0; col < imageWidth; col++)
	{
		for( int row = imageHeight-3; row < imageHeight; row++)
		{
			setbw(IMAGE, col, row, 0);
		}
	}
}

/** 
  * totalColorArray handler -- allows us to load in an array with color definitions
  * for each color we look at.
  **/
  
  void tCAHandler()
  {
	char filename[255];
	colorNames[0] = "red";
	colorNames[1] = "yellow";
	colorNames[2] = "blue"; 
	colorNames[3] = "green";
	colorNames[4] = "pink";

	for( int i = 0; i < MAXCOLORS; i++)
	{
		currentColorArray.reset();
		sprintf(filename, "%s%sColorDef%d.txt", ROOT_FOLDER, colorNames[i], COLOR_STEP_SIZE);
		currentColorArray.loadFromFile( filename);
		totalColorArray[i].setAs(currentColorArray);
	}
   }

/*
 * MAIN
 */
int main( int argc, char** argv )
{	
  /*
   * set up vision server
   */
  int runServer = true;    

#ifdef MAC_OS               
  pthread_t serverThread;   // the identifier for the thread
  if (runServer)            // do we want to run the server?
  {
    printf("Creating serverThread.\n");
    int rc = pthread_create(&serverThread, NULL, runServerThread, NULL);
    if (rc) printf("ERROR in pthread_create: %d.\n", rc);
  }
#endif
  //printf("end setting up vision server\n");
  /*
   * set up image input source
   */
  enum { IMAGES_FROM_CAMERA, IMAGES_FROM_FOLDER, IMAGES_FROM_AVI_FILE };
  int captureType = IMAGES_FROM_CAMERA; 
  captureType = IMAGES_FROM_FOLDER;
  
  char* MOVIE_NAME = ROOT_FOLDER "path0.mpg"; 
  char* FOLDER_NAME = ROOT_FOLDER "setImages"; 
  printf("FOLDER_NAME: %s", FOLDER_NAME);
  int MAX_FILE_NUMBER =34;  // the number of images in the folder
  int nextFileNumber = 0;    // the next file number to read 
  
  enum { LIVE, ONEFRAME, STILL };  // how are we now capturing
  int captureStatus = ONEFRAME;
  
  CvCapture* capture = 0;  // the capture object to grab frames from a camera/avi file

  if ( captureType == IMAGES_FROM_CAMERA )   // initialize "capture," the image source
    capture = cvCaptureFromCAM( 0 );         // camera number zero, which is usually the one attached
  else if ( captureType == IMAGES_FROM_AVI_FILE )
    capture = cvCaptureFromAVI( MOVIE_NAME ); 
  else // captureType = IMAGES_FROM_FOLDER;
    capture = 0;
  //printf("end image input setup\n");
  
  /*
   * create windows for displaying images
   */
  cvNamedWindow( "InputImage", CV_WINDOW_AUTOSIZE );
  int windowXCoord = 1275;
  int windowYCoordOrig = 100;
  int windowYCoordDelta = 300;
  cvMoveWindow( "InputImage", windowXCoord, windowYCoordOrig );
  cvSetMouseCallback( "InputImage", mouseEventHandler, 0 );  // Crazy, but it just might work
  cvNamedWindow( "OutputImage", CV_WINDOW_AUTOSIZE );
  cvMoveWindow( "OutputImage", windowXCoord, windowYCoordOrig + windowYCoordDelta );
  cvSetMouseCallback( "OutputImage", mouseEventHandler, 0);
  cvNamedWindow( "BinaryImage", CV_WINDOW_AUTOSIZE );
  cvMoveWindow( "BinaryImage", windowXCoord, windowYCoordOrig + 2*windowYCoordDelta );
  
	//printf("created windows for displaying images\n");
  /*
   * create an initial image, displayImage, and any other images...
   */
  inputImage = cvCreateImage( cvSize(10,10), 8, 1 );
  IplImage* outputImage = NULL;
  IplImage* frame = NULL;  // image grabbed from camera
  IplImage* binaryImage = NULL;
  //printf("created inital images\n");
  
  /*
   * blob handling
   */
  CBlobResult blobs; 
  CBlob blobToShow;

  /*
   * Load in the tCA
   */
	if (blobsAreOn)
		tCAHandler();
  
  /*
   * MAIN LOOP
   */
  while (!timeToQuitNow)
  {//printf("beginning main loop\n");
    /*
     * INPUT IMAGE SETUP
     *
     * the goal here is to populate the _image_ variable with pixels
     *   depending on the source in captureType
     */
    if (captureStatus != STILL) 
    {
      if (captureType == IMAGES_FROM_FOLDER)
      {
        char filename[255];
        
        if (nextFileNumber > MAX_FILE_NUMBER || nextFileNumber < 0) nextFileNumber = 0;
        sprintf(filename,"%s/image%05d.bmp", FOLDER_NAME, nextFileNumber++);
        printf("About to read the file %s.\n", filename);
        inputImage = cvLoadImage(filename, -1); // -1 means determine number of channels from format
      }
      else // captureType == IMAGES_FROM_AVI_FILE or IMAGES_FROM_CAMERA
      {
        frame = cvQueryFrame( capture );  
        if ( !frame  )
        {
          printf( "Frame not obtained when capturing!\n");
          printf( "Setting captureStatus to STILL.\n");
          captureStatus = STILL;
        }
		else
		{
		CvSize frameSize = cvGetSize(frame);
		/* REDUCTION_FACTOR
           */
          
          /* old code
          if ( frameSize.width != inputImage->width || frameSize.height != inputImage->height )
          {
            cvReleaseImage( &inputImage );
            inputImage = cvCreateImage( frameSize, 8, 3 );
            inputImage->origin = frame->origin;
          } // image is OK and the right size, now
          cvCopy( frame, inputImage, 0 );  // copy the frame data into the image
           end of OLD CODE
           */
          int REDUCTION_FACTOR = 2;
          int desiredInputWidth = (frameSize.width/REDUCTION_FACTOR);
          int desiredInputHeight = (frameSize.height/REDUCTION_FACTOR);
          if ( desiredInputWidth != inputImage->width || desiredInputHeight != inputImage->height )
          {
            cvReleaseImage( &inputImage );
            CvSize newInputImageSize = cvSize(desiredInputWidth, desiredInputHeight);
            inputImage = cvCreateImage( newInputImageSize, 8, 3 );
            inputImage->origin = frame->origin; // hmmm?
          } // image is OK and the right size, now
          /* copy it over ... */
          int b,r,g;
          // loop over the input image
          for ( int col=0 ; col<inputImage->width ; ++col) 
          {
            for ( int row=0 ; row<inputImage->height ; ++row) 
            {
              // get pixel from across the full frame
              getrgb( frame, col*REDUCTION_FACTOR, row*REDUCTION_FACTOR, r, g, b );
              // place into the inputImage
              setrgb( inputImage, col, row, r, g, b);
            } // end row
          } // end col
        } // end grab of camera image ("else")
      } // end of captureType == IMAGES_FROM_AVI_FILE or IMAGES_FROM_CAMERA block
			
      if (captureStatus == ONEFRAME)  captureStatus = STILL; // we got our one frame...
      // now, we keep that image until an event asks to grab a new one
	//printf("finished input image setup\n InputImage : %s", inputImage);
	
    } // end of (captureStatus != STILL) block
    
    /*
     * OUTPUT IMAGE SETUP
     *
     * we need to make sure to set up the output images before processing!
     * (or other intermediate images)  we check to be sure they're the right size...
     */
    if ( outputImage == NULL || 
         ( inputImage->width != outputImage->width  || inputImage->height != outputImage->height ) ) 
    { 
      if (outputImage) cvReleaseImage( &outputImage );
      outputImage = cvCreateImage( cvGetSize(inputImage), 8, 3 );
    }
    cvCopy(inputImage, outputImage, NULL);  // copy input to output image as a starting point for outputImage
    
    if ( binaryImage == NULL ||
          ( inputImage->width != binaryImage->width || inputImage->height != binaryImage->height ) )
    {
      if (binaryImage) cvReleaseImage( &binaryImage );
      binaryImage = cvCreateImage( cvGetSize(inputImage), 8, 1);
    }
	
	if (!blobsAreOn)
	{
	   pixelsInArraybw( inputImage, currentColorArray, binaryImage);
	   cvErode(binaryImage, binaryImage, NULL, 2);
	}
				
	//printf("finished output image setup\n");
	
    /*
     * OUR ALGORITHM/PROCESSING/VISUALIZATION
     */
    if (runAlgorithm)
    {
      int b,r,g;
      // loop over the input image
      for ( int col=0 ; col<inputImage->width ; ++col) 
      {
        for ( int row=0 ; row<inputImage->height ; ++row) 
        {
          
          getrgb( inputImage, col, row, r, g, b );
          if ( currentColorArray.pixelMatch(r,g,b))
            {setrgb( outputImage, col, row, 0, 255, 255 ); // cyan for the color-defining color
			//setrgb( inputImage, col, row, 255, 255, 255);
			}
		  //if (col > 315 && col < 325)
		  //{
			//setrgb( outputImage, col, row, 147, 147, 147);
			//}
		  
		
          
        } // end row
      } //printf("end algorithm processing\n");// end col
    }
	
	
	//arrayified version... work please...
	if(blobsAreOn)
	{
        //CBlob allDestBlobs [30];
        CBlob destinationBlobs [3];


        for(int i=0; i < MAXCOLORS; ++i) 
        {
         
            pixelsInArraybw(inputImage, totalColorArray[i], binaryImage);
            drawBorder(binaryImage); // erase pixels around the edges
            //cvErode(binaryImage, binaryImage, NULL, 1);
            //cvDilate(binaryImage, binaryImage, NULL, 1);

            blobs = CBlobResult( binaryImage, NULL, 100, true );

            // get blobs with more than 50 pixels
            blobs.Filter( blobs, B_INCLUDE, CBlobGetArea(), B_GREATER, 50); 
            
            // get blobs whose gray-scale value is greater than 200
            // keep in mind that we are "blobbing" the binary image, so any value
            // between 1 and 254 would work!
            blobs.Filter( blobs, B_INCLUDE, CBlobGetMean(), B_GREATER, 200 ); 
            
            // Here, we could filter out the long rectangular blobs. We'd only go to it if we had single
            // color blobs, as there won't be many long ones if we have 2 or 3 color blobs.

            // tCA = {red, yellow, blue, green, pink}
            int rr = (i==0 )? 255: (i==1)? 255: (i==2)? 0:   (i == 3)? 0:   255; //gets the proper color for the different cases
            int gg = (i==0)? 0:    (i==1)? 255: (i==2)? 0:   (i == 3)? 255:  20;
            int bb = (i==0)? 0:    (i==1)? 0:   (i==2)? 255: (i == 3)? 0:   147;
            
            CBlobGetArea getArea = CBlobGetArea(); 
            CBlobGetMinX getMinX = CBlobGetMinX();   
            CBlobGetMaxX getMaxX = CBlobGetMaxX();
            CBlobGetMinY getMinY = CBlobGetMinY();
            CBlobGetMaxY getMaxY = CBlobGetMaxY();
            
            //printf("-------------------------\n");
            
            for(int j=0; j<3;j++) 
            {
                blobs.GetNthBlob( CBlobGetArea(), j, destinationBlobs[j] ); 
                //double area = getArea(destinationBlobs[j]);
                //printf("area for blob #%d is = %f\n", j, area);
                
                int minxarea = (int) getMinX(destinationBlobs[j]);
                int maxxarea = (int) getMaxX(destinationBlobs[j]);
                int minyarea = (int) getMinY(destinationBlobs[j]);
                int maxyarea = (int) getMaxY(destinationBlobs[j]);
                colorData[i].xmin[j]=minxarea;
                colorData[i].xmax[j]=maxxarea;
                colorData[i].ymin[j]=minyarea;
                colorData[i].ymax[j]=maxyarea;
                colorData[i].colour= i;
                
                //printf("\nafter assignment\n");
                //printf("minx = %d\n", colorData[i].xmin[j]);
                //printf("maxx = %d\n", colorData[i].xmax[j]);
                //printf("miny = %d\n", colorData[i].ymin[j]);
                //printf("maxy = %d\n", colorData[i].ymax[j]);
                //printf("colour number is: %d\n\n", colorData[i].colour);  //1 is red, 2 is yellow, 3 is blue, 4 is green 
                destinationBlobs[j].FillBlob( outputImage, CV_RGB( rr, gg , bb ) );
		    } // end of for(int j=0; j<3;j++) -- top three blobs
            
		  //allDestBlobs[i] = destinationBlobs;
		  //CBlobGetArea getArea = CBlobGetArea();
            
        } // end of  for(int i=0; i < MAXCOLORS; ++i)  -- go through each color
     } // end of ifBlobsAreOn


////////////////////////////////////////////////////////////////////////////////////////////////////////////

	//printf("end blob processing\n");
        /*
		 * DRAW THE IMAGES TO SCREEN
		 */
		if (drawingRectangle)  // shows a yellow rectangle when selecting a region
		  cvRectangle(outputImage, cvPoint(selection.x,selection.y),   // from here
                  cvPoint(selection.x+selection.width, selection.y+selection.height),  // to here
                  CV_RGB(255,255,0),1,8,0);  // yellow, 1 pixel thick, 8-connected
    
    cvShowImage( "InputImage", inputImage );    // render the input image
    cvShowImage( "OutputImage", outputImage );  // render the output image
    cvShowImage( "BinaryImage", binaryImage );  // render the binary image
    
	//printf("end drawing images\n");
    /*
     * HANDLE KEY PRESSES to an OpenCV window
     */
	char filename[255];
    char cchar = (char) cvWaitKey(10);   // waits for 10 ms to get a keypress
                                         // use cvWaitKey(0) in order to wait forever...
    if ( cchar == 27 )  break;           // breaks on ESCape key
    int imageNumber;					 // Allows us to save files 
    switch( cchar )                      // handle other key presses
    {        

      case ' ': // stop and get one more frame
      {
        captureStatus = ONEFRAME;
        //runAlgorithm = true;
        break;
      }
           
      case 'L': // restart live capturing
      {
        captureStatus = LIVE;
        printf("Getting one frame.\n");
        break;
      }

	 case 'C': // go to camera
	 {
		captureType = IMAGES_FROM_CAMERA;
		printf("Switching to Camera");
		break;
	  }
	 case 'F': // go to folder
	 {
		captureType = IMAGES_FROM_FOLDER;
		printf("Switching to Folder\n");
		break;
		}
        
      case 'R': // reset the current color definition
      {
        currentColorArray.reset();
		break;
      }
        
      case 'A': // turn on or off algorithm running
      {
        if (runAlgorithm) runAlgorithm = false;
        else runAlgorithm = true;
		printf("Algorithm Status is %d\n", runAlgorithm);
        break;
      }
      
      case 'B': //run backwards through the pictures
      {
        nextFileNumber = nextFileNumber - 2;
        if (nextFileNumber < 0) nextFileNumber = MAX_FILE_NUMBER;
        captureStatus = ONEFRAME;
        //runAlgorithm = true;
        break;
      }

	  case 'S': // save the current image
	 {
		sprintf(filename, "%stmp/image%04d.bmp", ROOT_FOLDER, imageNumber++);
		printf("Saving File: %s \n", filename);
		cvSaveImage(filename, inputImage);
	 }

	case '0': // turns blobs on or off
	  {
		if (blobsAreOn)
			blobsAreOn = false;
		else blobsAreOn = true;
		break;
	   }

	 case 'P': // print current array
	 {
		currentColorArray.print();
		break;
	  }
	  
	  
	  case '!': // save alternate color array (Red)
	  {
		
		sprintf(filename, "%sredColorDef%d.txt", ROOT_FOLDER, COLOR_STEP_SIZE);
		currentColorArray.saveToFile( filename);
        break;
	  }
	  case '@': // save alternate color defintions (Yellow)
	  {
		sprintf(filename, "%syellowColorDef%d.txt", ROOT_FOLDER, COLOR_STEP_SIZE);
		currentColorArray.saveToFile( filename);
        break;

	  }
	  case '#': // save alternate color defintions (Blue)
	  {
		char filename[255];
		sprintf(filename, "%sblueColorDef%d.txt", ROOT_FOLDER, COLOR_STEP_SIZE);
		currentColorArray.saveToFile( filename);
        break;

	  }
	  case '$': // save alternate color defintions (Green)
	  {
		sprintf(filename, "%sgreenColorDef%d.txt", ROOT_FOLDER, COLOR_STEP_SIZE);
		currentColorArray.saveToFile( filename);
        break;

	  }
	  
	  case '%': // save alternate color defintions (Pink)
	  {
		sprintf(filename, "%spinkColorDef%d.txt", ROOT_FOLDER, COLOR_STEP_SIZE);
		currentColorArray.saveToFile( filename);
        break;

	  }
	  
	  case '1': // load alternate color array (Red)
	  {
		currentColorArray.reset();
		sprintf(filename, "%sredColorDef%d.txt", ROOT_FOLDER, COLOR_STEP_SIZE);
		currentColorArray.loadFromFile( filename);
        break;
	  }
	  case '2': // load alternate color array (Yellow)
	  {
		currentColorArray.reset();
		sprintf(filename, "%syellowColorDef%d.txt", ROOT_FOLDER, COLOR_STEP_SIZE);
		currentColorArray.loadFromFile( filename);
        break;
	  }
	  case '3': // load alternate color array (Blue)
	  {
		currentColorArray.reset();
		sprintf(filename, "%sblueColorDef%d.txt", ROOT_FOLDER, COLOR_STEP_SIZE);
		currentColorArray.loadFromFile( filename);
        break;	  }
	  case '4': // load alternate color array (Green)
	  {
		currentColorArray.reset();
		sprintf(filename, "%sgreenColorDef%d.txt", ROOT_FOLDER, COLOR_STEP_SIZE);
		currentColorArray.loadFromFile( filename);
        break;
	  }
	  
	  case '5': // load alternate color array (Pink)
	  {
		currentColorArray.reset();
		sprintf(filename, "%spinkColorDef%d.txt", ROOT_FOLDER, COLOR_STEP_SIZE);
		currentColorArray.loadFromFile( filename);
        break;
	  }
	  
	  case 'Z': // Reload color definitons
	  {
		tCAHandler();
		break;
	   }
	   
	   case '-': // remove pixels from current definiton
	   {
		if (removePixels)
			removePixels = false;
		else removePixels = true;
		printf("The next rectangle will %s pixels.\n",
		         (removePixels ? "remove" : "add")); 
		break;
	   }
		 
            
            
            /*
             * a lower-case 's' toggles playing set...
             */
        case 's':
		{
			captureStatus = ONEFRAME;       // we're no longer capturing...
			char filenameset[500];          // holds our set file names... 
            
			if (firstTimeForSet)     // need to set up the windows if it's
			{                        // the first time playing set...
				for (int i=0 ; i<NUM_WINDOWS ; ++i) {  
					cvNamedWindow( setwnd[i], CV_WINDOW_AUTOSIZE );
					cvMoveWindow( setwnd[i], i%3 * 335, i/3 * 280);  
				} 
				srand( (unsigned)time( NULL ) );       // seed for future random #s
				cout << "Setting up set!" << endl;     // Hi!
				setimages = new IplImage*[NUM_WINDOWS]; // should delete these somewhere...
				setimages_painted = new IplImage*[NUM_WINDOWS]; // for overlays
                
				for (int i=0 ; i<NUM_WINDOWS ; ++i)
				{
					sprintf(filenameset,"../../setImages/image%05d.bmp",i);
                    printf("loading file %s.\n", filenameset);
					//cvReleaseImage(&undis_frame);
					setimages[i] = cvLoadImage(filenameset); // load image0 numWindows times.
					setimages_painted[i] = cvLoadImage(filenameset);
					cout << "Setting up window " << i << " named " << setwnd[i] << endl;
					cvShowImage(setwnd[i], setimages[i]);
				}	
                
				firstTimeForSet = false; // make sure we do this only once
			}
			// don't really want an "else" here
			{
				cout << "Reading in random images..." << endl;
                
				int imageIndices[NUM_WINDOWS];         // list of indices
				for (int i=0 ; i<NUM_WINDOWS ; ++i) {  // set them all to -1
					imageIndices[i] = -1; 
				}
                
				for (int i=0 ; i<NUM_WINDOWS ; ++i)
				{
					cout << "i is " << i << endl;     // keep us updated
					while (true) 
					{
						int randImage = (int)(81.0*rand()/RAND_MAX);
						if (randImage < 0 || randImage > 80) continue;
						cout << "  randImage is " << randImage << endl;
						
						if (!alreadyHaveIt(randImage,imageIndices,i))
                            imageIndices[i] = randImage;
						else
						{
							cout << "Have it ";
							for (int i=0 ; i<NUM_WINDOWS ; ++i)
								cout << imageIndices[i] << " ";
							cout << endl;
							continue;
						}
						break;
					}
                    
					/*
					 * now load image i
					 */
					sprintf(filenameset,"../../setImages/image%05d.bmp",imageIndices[i]);
					cout << "Reading in the file " << filenameset << " for #" << i << endl;
					//cvReleaseImage(&(setimages[i]));
					setimages[i] = cvLoadImage(filenameset);         // for proceesing
					setimages_painted[i] = cvLoadImage(filenameset); // for showing results
					cout << "Setting up window " << i << " named " << setwnd[i] << " with image #" << imageIndices[i] << endl;
					cvShowImage(setwnd[i], setimages[i]);
				}
			}
			/*
			 * now, process the cards
			 */
			int i=3;
			processSetCard( i );
            
		} // end of case 's'
            break;
            


      default:
        break;
    } // end of the keypress-handling switch statement
    
  } // end of the main image input - process - output loop
  
  /*
   * If we're here, some event triggered the main loop to quit
   */
  timeToQuitNow = 1;    // set our signal for the serverThread to quit
  
  printf("Main thread quitting...\n");

/**#ifdef MAC_OS
  sleep(1.0);             // give it a moment...
#endif
#ifdef WINDOWS_OS
  Sleep(1000);
#endif
**/
  
  /*
   * release the OpenCV resources
   */
  cvReleaseCapture(&capture);
  cvDestroyWindow( "InputImage" );
  cvDestroyWindow( "OutputImage" );
  cvDestroyWindow( "BinaryImage" );
  
  return 0;
}



/*
 * here is where the set-processing happens
 * for image #i
 */
void processSetCard(int i) 
{
	// we know that the images to process are in setimages,
	// and we will draw on setimages_painted
    IplImage* sourceImage = setimages[i];
	IplImage* destinationImage = setimages_painted[i];
	char* destinationWindow = setwnd[i];
    
	// show where the point 30,30 is in the image
	CvPoint pt; pt.x = 30; pt.y = 200;
	cvCircle( destinationImage, pt, 10,  CV_RGB(255,255,0), /*thickness*/ 4 );
    
	// show some pixel manipulation - pixels are handled as uchar*'s
	int r,g,b,realrow;
	uchar* sourcepix;     // a pixel in the input
	uchar* destpix;   // a pixel in the output
	int row_offset = -50;
	int col_offset = -50;
	for (int row=10 ; row<30 ; ++row)
	{
		for (int col=200 ; col < 230 ; ++col)
		{
			// realrow = row;
			realrow = sourceImage->height - row;
			sourcepix = cvPtr2D(sourceImage,realrow,col);    // get the pixel we care about
			r = (int)(sourcepix[2]);  // the red component of the pixel we care about
			g = (int)(sourcepix[1]);  // the green component of the pixel we care about
			b = (int)(sourcepix[0]);  // the blue component of the pixel we care about
			destpix = cvPtr2D(destinationImage,realrow+row_offset,col+col_offset);    // get the pixel we (might) change
			destpix[0] = 0; /*blue*/ destpix[1] = 0; /*green*/ destpix[2] = 255; /*red*/
		}
	}
	cvShowImage(destinationWindow, destinationImage);
}



