/*
    Simulacia sirenia trhliny
    Copyright (C) 2008 Samuel Kupka

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
#include <time.h>
#include "sim.h"

void main_die(int code,char *buf)
{
    if(strlen(buf)>0){
        printf("ERROR: %s\n",buf);
    }
    exit(code);
}

void main_check(void)
{
    if(cudaThreadSynchronize()!=0){
        main_die(2,"Kernel failed!");
    }
}

void main_print_information(cudaDeviceProp deviceProp)
{
    printf("Device: \"%s\"\n",deviceProp.name); 
    printf("Revision number: %d.%d\n",deviceProp.major,deviceProp.minor);
    printf("Total amount of global memory: %.2f Mbytes\n",(float)deviceProp.totalGlobalMem/1024/1024);
    printf("Total amount of constant memory: %d bytes\n",deviceProp.totalConstMem); 
    printf("Total amount of shared memory per block: %d bytes\n",deviceProp.sharedMemPerBlock);
    printf("Total number of registers available per block: %d\n",deviceProp.regsPerBlock);
    printf("Warp size: %d\n",deviceProp.warpSize);
    printf("Maximum number of threads per block: %d\n",deviceProp.maxThreadsPerBlock);
    printf("Maximum sizes of each dimension of a block: %d x %d x %d\n",deviceProp.maxThreadsDim[0],deviceProp.maxThreadsDim[1],deviceProp.maxThreadsDim[2]);
    printf("Maximum sizes of each dimension of a grid: %d x %d x %d\n",deviceProp.maxGridSize[0],deviceProp.maxGridSize[1],deviceProp.maxGridSize[2]);
    printf("Maximum memory pitch: %d bytes\n",deviceProp.memPitch);
    printf("Texture alignment: %d bytes\n",deviceProp.textureAlignment);
    printf("Clock rate: %.2f GHz\n",(float)deviceProp.clockRate/1024/1024);  
}

void main_usage(char *name)
{
    printf("Usage: %s DimX DimY DimZ K1 K2 [options]\n\n",name);
    printf("Options:\n");
    printf("--save filename : Save results to file\n");
    printf("--trajectory    : Save trajectory\n");
    printf("--info          : Show information about graphic card and quit\n");
    printf("--help          : Show this text and quit\n");
    main_die(1,"");
}

int main(int argc,char* argv[]) 
{
    srand(time(0));
    CUT_DEVICE_INIT();
    cudaDeviceProp deviceProp;
    cudaGetDeviceProperties(&deviceProp,0);
    if(deviceProp.major<1||(deviceProp.major==1&&deviceProp.minor<1)){
        main_die(1,"Unsupported device!");
    }
    
    char fname[1024]="";
    char tbuf[1024];
    dim3 d;
    float k1,k2;
    bool traj=false;
    
    printf("Simulacia sirenia trhliny\n");
    printf("Copyright (C) 2008 Samuel Kupka\n\n");
    
    if(argc<6) main_usage(argv[0]);
    for(int i=6;i<argc;i++){
      if(!strcmp(argv[i],"--info")){
        main_print_information(deviceProp);
        return 1;
      }
      if(!strcmp(argv[i],"--help")){
        main_usage(argv[0]);
      }
      if(!strcmp(argv[i],"--trajectory")){
        traj=true;
      }
      if(!strcmp(argv[i],"--save")){
        i++;
        if(argc<=i){
          printf("Missing filename!\n\n");
          main_usage(argv[0]);
        }
        strcpy(fname,argv[i]);
        
        FILE *s=fopen(fname,"w");
        if(s==0){
          printf("Unable to write to file!\n\n");
          main_usage(argv[0]);
        }
        fclose(s);        
      }
    }
    
    if(!strcmp(fname,"")){
      traj=false;
    }
    
    sprintf(tbuf,"%s %s %s %s %s",argv[1],argv[2],argv[3],argv[4],argv[5]);
    if(sscanf(tbuf,"%d %d %d %f %f",&d.x,&d.y,&d.z,&k1,&k2)!=5||k1<0.001||k2<=0.001||k1>10||k2>10||d.x<10||d.y<10||d.z<10||d.x>1020||d.y>1020||d.z>1020){
      printf("Wrong parameters!\n\n");
      main_usage(argv[0]);
    }
      
    unsigned int timer = 0;
    CUT_SAFE_CALL(cutCreateTimer(&timer));
    CUT_SAFE_CALL(cutStartTimer(timer)); 

    simulate_start(fname,d,traj,k1,k2,deviceProp.maxThreadsPerBlock,make_int2(deviceProp.maxGridSize[0],deviceProp.maxGridSize[1]));

    CUT_SAFE_CALL(cutStopTimer(timer));
    printf("Processing time: %.2fs\n",cutGetTimerValue(timer)/1000);
    CUT_SAFE_CALL(cutDeleteTimer(timer));

    return 0;
}
