#include <iostream.h>
#include <unistd.h>
#include <stdlib.h>

#include <image.h>

typedef struct {
  char *outfile;
  int size[2];
  float color[3];
  float point[3];
  Image::filter_t filter;
  float radius;
  int random;
  int num_dots;
} args_t;

int  parseArgs     (int num, char **argv, args_t &app_info);
int  parseIntVec   (char *vec, int &x, int &y);
int  parseFloatVec (char *vec, float &x, float &y, float &z);
void printUsage    ();

int main (int argc, char **argv) {
  Image *image;
  args_t app;

  srand48(getpid());
  
  if (!parseArgs(argc, argv, app)) {
    printUsage();
    exit(-1);
  }

  image = new Image(app.size, Image::RGB, Image::RECTANGULAR);
  image->bounds[0] = -2.0;
  image->bounds[2] = 2.0;
  
  if (app.random) {
    for (int i = 0; i < app.num_dots; i++) {
      float point[3], color[3], radius;
      int findex;
      Image::filter_t filter;
      
      point[0] = 4.0*drand48() - 2.0;
      point[1] = 2.0*drand48() - 1.0;
      point[2] = 2.0*drand48() - 1.0;
      color[0] = drand48();
      color[1] = drand48();
      color[2] = drand48();
      radius   = drand48() * 0.25;
      findex   = (int)(drand48() * 4.0);

      switch (findex) {
      case 0:
	filter = Image::BOX;
	break;
      case 1:
	filter = Image::TENT;
	break;
      case 2:
	filter = Image::QUADRATIC;
	break;
      case 3:
	filter = Image::CUBIC;
	break;
      default:
	filter = Image::TENT;
	break;
      }
	
      image->drawDot(point, color, radius, filter);
    }
  } else
    image->drawDot(app.point, app.color, app.radius, app.filter);
  
  image->writePPM(app.outfile);

  delete image;
 
  return 0;
}

int parseArgs (int num, char **argv, args_t &app_info) {
  int i, opt_size, val_size;

  app_info.outfile  = NULL;
  app_info.size[0]  = 200;
  app_info.size[1]  = 200;
  app_info.point[0] = 0.0;
  app_info.point[1] = 0.0;
  app_info.point[2] = 0.0;
  app_info.color[0] = drand48();
  app_info.color[1] = drand48();
  app_info.color[2] = drand48();
  app_info.filter   = Image::TENT;
  app_info.radius   = 0.5;
  app_info.random   = 0;
  app_info.num_dots = 0;

  i = 1;
  while (i < num) {

    if (argv[i][0] == '-' && i + 1 == num)
      return 0;
    else if (argv[i][0] == '-' && i + 1 != num) {
      opt_size = strlen(argv[i]);
    
      if (!strncmp(argv[i], "-file", opt_size + 1)) {
        val_size = strlen(argv[i + 1]);
        app_info.outfile = (char *)malloc(sizeof(char) * (val_size + 2));
        strncpy(app_info.outfile, argv[i + 1], val_size + 1);
      }
      else if (!strncmp(argv[i], "-rad", opt_size + 1))
	app_info.radius = atof(argv[i + 1]);
      else if (!strncmp(argv[i], "-random", opt_size + 1)) {
	app_info.num_dots = atoi(argv[i + 1]);
	app_info.random   = 1;
      }
      else if (!strncmp(argv[i], "-filter", opt_size + 1)) {
	switch(atoi(argv[i + 1])) {
	case 1:
	  app_info.filter = Image::BOX;
	  break;
	case 2:
	  app_info.filter = Image::TENT;
	  break;
	case 3:
	  app_info.filter = Image::QUADRATIC;
	  break;
	case 4:
	  app_info.filter = Image::CUBIC;
	  break;
	case 5:
	  app_info.filter = Image::QUARTIC;
	  break;
	default:
	  app_info.filter = Image::TENT;
	  break;
	}
      }
      else if (!strncmp(argv[i], "-size", opt_size + 1)) {
	if (!parseIntVec(argv[i + 1], app_info.size[0], app_info.size[1]))
	  return 0;
      }
      else if (!strncmp(argv[i], "-color", opt_size + 1)) {
	if (!parseFloatVec(argv[i + 1],
			   app_info.color[0],
			   app_info.color[1],
			   app_info.color[2]))
	  return 0;
      }
      else if (!strncmp(argv[i], "-point", opt_size + 1)) {
	if (!parseFloatVec(argv[i + 1],
			   app_info.point[0],
			   app_info.point[1],
			   app_info.point[2]))
	  return 0;
      }
      else {
        return 0;
      }
      i += 2;
    }
    else
      return 0;
  }

  return 1;
}
  
int parseIntVec(char *vec, int &x, int &y) {
  char *ptr;

  ptr = strtok(vec, ",");
  x = atoi(ptr);
  ptr = strtok(NULL, ",");
  if (ptr == NULL)
    return 0;
  y = atoi(ptr);
  ptr = strtok(NULL, ",");
  if (ptr == NULL)
    return 1;
  
  return 0;
}

int parseFloatVec(char *vec, float &x, float &y, float &z) {
  char *ptr;

  ptr = strtok(vec, ",");
  x = atof(ptr);
  ptr = strtok(NULL, ",");
  if (ptr == NULL)
    return 0;
  y = atof(ptr);
  ptr = strtok(NULL, ",");
  if (ptr == NULL)
    return 0;
  z = atof(ptr);
  ptr = strtok(NULL, ",");
  if (ptr == NULL)
    return 1;
  
  return 0;
}

void printUsage () {
  cout << "Usage : drawdot [-file name] "
       << "[-size x,y] [-color r,g,b] [-point x,y,z]" << endl
       << "                [-rad n] [-filter 1..5] [-random num]"
       << endl << endl;
  cout << "Options:" << endl;
  cout << "  -file   name  : Name of file to save image to, "
       << "default=STDOUT" << endl;
  cout << "  -size   x,y   : dimensions of image in pixels, "
       << "default=200x200" << endl;
  cout << "  -color  r,g,b : Color of dot to be drawn, "
       << "default=random color" << endl;
  cout << "  -point  x,y,z : Point in image domain to be drawn, "
       << "default=origin" << endl;
  cout << "  -rad    n     : Radius of dot, same units as image domain, "
       << "default=0.5" << endl;
  cout << "  -filter 1..5  : Filter to be applied to dot." << endl
       << "                  1 = BOX" << endl
       << "                  2 = TENT" << endl
       << "                  3 = QUADRATIC" << endl
       << "                  4 = CUBIC" << endl
       << "                  5 = QUARTIC" << endl
       << "                  default=TENT" << endl;
  cout << "  -random num   : When this argument is set, num randomly "
       << "positioned, filtered,\n                "
       << "colored, and sized dots are drawn."
       << endl;
}
