#include <stdio.h>
#include <stdlib.h>
#include <sstream>
#include <string>
#include <vector>
#include <map>
#include <list>
#include <iterator>
#include <queue>
#include <deque>
#include <stack>
#include <algorithm>
#include <set>
#include <math.h>
#include <assert.h>
#include <limits>
#include <climits>
#include <string>
#include <time.h>
#include <malloc.h>
#include <getopt.h>

#define TEST 1000
#define NO_TEST 0

int nb_rand = NO_TEST;
int nb_rand_circle = TEST;
int nb_rand_line = TEST;
int nb_rand_hline = NO_TEST;
int nb_rand_vline = NO_TEST;


void generate_random(int nbpf, double *xyz)
{
    for (int i = 0; i < nbpf; i++)
    {
        xyz[3*i] = drand48();
        xyz[3*i+1] = drand48();
        xyz[3*i+2] = 0.0;
    }
}

void generate_random_circle(int nbpf, double *xyz)
{
    // generate random point on circle
      double cx = drand48();
      double cy = drand48();
      double cr = drand48();   
      while ((cx-cr)<0.0 || (cx+cr)>1.0 || (cy-cr)<0.0 || (cy+cr)>1.0)
	cr *= 0.9;
      for (int i = 0; i < nbpf; i++)
      {
	double ca = drand48()*2.0*M_PI;
	xyz[3*i] = cx + cr*cos(ca);
	xyz[3*i+1] = cy + cr*sin(ca);
	xyz[3*i+2] = 0.0;
      } 
}

void generate_random_line(int nbpf, double *xyz)
{
      double cdir = drand48();
      double d = drand48();
      
      int sign = rand()%2;
      
      if (sign)
       cdir *= -1.0;      
            
      double tmin = 0.0;
      double tmax = -d/cdir;
      
      if (tmax > 1.0)
	tmax = 1.0;
      
      if (tmax < 0.0)
      {
	tmax = (1.0-d)/cdir;
	if (tmax > 1.0)
	  tmax = 1.0;
      }      
      
      for (int i = 0; i < nbpf; i++)
      {
	double t = drand48();
	xyz[3*i] = tmin+t*(tmax-tmin);
	xyz[3*i+1] = cdir*xyz[3*i] + d;
	xyz[3*i+2] = 0.0;
      }
}

void generate_random_hline(int nbpf, double *xyz)
{
      double d = drand48();
                 
      double tmin = 0.0;
      double tmax = 1.0;
     
      for (int i = 0; i < nbpf; i++)
      {
	double t = drand48();
	xyz[3*i] = t;
	xyz[3*i+1] = d;
	xyz[3*i+2] = 0.0;
      }      
}

void generate_random_vline(int nbpf, double *xyz)
{
      double d = drand48();
                 
      double tmin = 0.0;
      double tmax = 1.0;
     
      for (int i = 0; i < nbpf; i++)
      {
	double t = drand48();
	xyz[3*i] = d;
	xyz[3*i+1] = t;
	xyz[3*i+2] = 0.0;
      }
}

int generate_2D(double sx, double sy, int nb)
{  
      int count_test = 0;
    if (nb_rand)
        count_test++;
    if (nb_rand_circle)
        count_test++;
    if (nb_rand_line)
        count_test++;
    if (nb_rand_hline)
        count_test++;
    if (nb_rand_vline)
        count_test++;

    int nb_test = round((double)nb/(double)(count_test*TEST));

//     printf("nb = %d, nb_test = %d, count_test = %d\n", nb, nb_test, count_test);

    printf("%d\n", count_test*nb_test*TEST);

    double *xyz = new double[3*TEST];

    int count = 0;
    // generate random point
    if (nb_rand)
    {
        for (int i = 0; i < nb_test; i++)
        {
            generate_random(TEST, xyz);
            for (int j = 0; j < TEST; j++)
                printf("%d %.20lf %.20lf %lf\n", count++, xyz[3*j]*sx, xyz[3*j+1]*sy, xyz[3*j+2]);
        }
    }

    // generate random point on circles
    if (nb_rand_circle)
    {
        for (int i = 0; i < nb_test; i++)
        {
            generate_random_circle(TEST, xyz);
            for (int j = 0; j < TEST; j++)
                printf("%d %.20lf %.20lf %lf\n", count++, xyz[3*j]*sx, xyz[3*j+1]*sy, xyz[3*j+2]);
        }
    }

    // generate random point on lines
    if (nb_rand_line)
    {
        for (int i = 0; i < nb_test; i++)
        {
            generate_random_line(TEST, xyz);
            for (int j = 0; j < TEST; j++)
                printf("%d %.20lf %.20lf %lf\n", count++, xyz[3*j]*sx, xyz[3*j+1]*sy, xyz[3*j+2]);
        }
    }

    // generate random point on hlines
    if (nb_rand_hline)
    {
        for (int i = 0; i < nb_test; i++)
        {
            generate_random_hline(TEST, xyz);
            for (int j = 0; j < TEST; j++)
                printf("%d %.20lf %.20lf %lf\n", count++, xyz[3*j]*sx, xyz[3*j+1]*sy, xyz[3*j+2]);
        }
    }
    
    

    // generate random point on vlines
    if (nb_rand_vline)
    {
        for (int i = 0; i < nb_test; i++)
        {
            generate_random_vline(TEST, xyz);
            for (int j = 0; j < TEST; j++)
                printf("%d %.20lf %.20lf %lf\n", count++, xyz[3*j]*sx, xyz[3*j+1]*sy, xyz[3*j+2]);
        }
    }
}


int generate_3D(double sx, double sy, double sz, int nb, int nbpf)
{
    int count = 0;
  
     printf("%d\n", nb*3*nbpf);
    
    // generate random point
    for (int i = 0; i < nb*nbpf; i++)
    {
      	double x = drand48();
	double y = drand48();
	double z = drand48();
      printf("%d %.20lf %.20lf %lf\n", count++, x*sx, y*sy, z*sz);
    }
    
    // generate random point on spheres
    for (int i = 0; i < nb; i++)
    {
      double cx = drand48();
      double cy = drand48();
      double cz = drand48();
      double cr = drand48();   
      while ((cx-cr)<0.0 || (cx+cr)>sx || (cy-cr)<0.0 || (cy+cr)>sy || (cz-cr)<0.0 || (cz+cr)>sz)
	cr *= 0.9;
      for (int j = 0; j < nbpf; j++)
      {
	double ca = drand48()*2.0*M_PI;
	double cb = drand48()*M_PI - M_PI/4.0;
	double x = cx + cr*cos(ca)*cos(cb);
	double y = cy + cr*sin(ca)*cos(cb);
	double z = cz + cr*sin(cb);
	printf("%d %.20lf %.20lf %lf\n", count++, x*sx, y*sy, z*sz);
      }      
    }
    
    // generate random point on planes ax + by + cz + d = 0
    for (int i = 0; i < nb; i++)
    {
      double a = drand48();
      double b = drand48();
      double c = drand48();
      double d = drand48();            
            
/*      double tmin = 0.0;
      double tmax = -d/cdir;
      
      if (tmax > 1.0)
	tmax = 1.0;
      
      if (tmax < 0.0)
      {
	tmax = (1.0-d)/cdir;
	if (tmax > 1.0)
	  tmax = 1.0;
      }      
      
      for (int j = 0; j < nbpf; j++)
      {
	double t = drand48();
	double x = tmin+t*(tmax-tmin);
	double y = cdir*x + d;
	printf("%d %.20lf %.20lf %lf\n", count++, x*sx, y*sy);
      } */     
    }
}


int main(int argc, char** argv)
{
    srand48(time(NULL));
    int nbpf = 1000;

    double sx = 1.0;
    double sy = 1.0;
    double sz = 1.0;
    
    generate_2D(sx, sy, atoi(argv[1]));        
}