#include <stdio.h>
#include <stdlib.h>
#include <string>
char receivername[100];
int *filename;
int outnum;
int *loss;
int size;
int num;
int headersize;
#define BUFSIZE 2000
void cpy(int src, int dest, int dir)
{
    FILE *rf;
    FILE *wf;
    int count=0;
    char buff[BUFSIZE];
    sprintf(buff,"%d.txt",10000000+src+1);
    buff[0]='P';
    rf=fopen(buff,"r");
    if (rf==NULL)
    {
	printf("Error: cannot open file %s for the destination %d\n",buff,dest+1);
	exit(2);
    }
    sprintf(buff,"%d/%d.txt",dir,10000000+dest+1);
    buff[2]='P';
    wf=fopen(buff,"w");
    if (wf==NULL)
    {
	printf("Error: cannot open file %s from the source %d\n",buff,src+1);
	exit(2);
    }
    while (!feof(rf))
    {
	int delta=fread(buff,1,BUFSIZE, rf);
	int wres;
	count+=delta;
	if (count>size)
	{
	    printf("Error Packet size of file %d is larger than specified\n",src+1);
	    exit(1);
	}
	wres=fwrite(buff,1,delta,wf);
	if (wres!=delta)
	{
	    printf("Error: when writing from file %d (%d byes) to file %d (%d bytes). \n",src+1,delta,dest+1,wres);
	    exit(2);
	}	
    }
    fclose(wf);
    fclose(rf);
}
void create(int dir)
{
    FILE *rf;
    FILE *wf;
    char buff[BUFSIZE];
    
    sprintf(buff,"%d/test",dir);
    wf=fopen(buff,"w");
    if (wf==NULL)
    {
	printf("Error: cannot open %s for write\n",buff);
	exit(2);
    }
    fprintf(wf,"%s %d %d output.tmp\n",receivername,outnum,size);
    fprintf(wf,"ls output.* -l\n");
    fprintf(wf,"~/cs145ta/lab2/cmp output.tmp output.std\n");

    fclose(wf);
    
    sprintf(buff,"%d/output.std",dir);

    wf=fopen(buff,"w");
    if (wf==NULL)
    {
	printf("Error: cannot open %s for write\n",buff);
	exit(2);
    }
    for (int i=0;i<num;i++)
    if (loss[i]==0)
    {
	int count=0;
	sprintf(buff,"%d.txt",10000000+i+1);
	buff[0]='P';
	rf=fopen(buff,"r");
        if (rf==NULL)
	{
	    printf("Error: cannot open file %s for the standard output\n",buff);
    	    exit(2);
        }
	int hdcount=headersize;
        while (!feof(rf))
	{
	    int delta=fread(buff,1,BUFSIZE, rf);
	    int wres;
	    count+=delta;
	    if (count>size)
	    {
		printf("Error Packet size of file %d is larger than specified\n",i+1);
	        exit(1);
	    }
	    if (hdcount==0)
	    {
	    	wres=fwrite(buff,1,delta,wf);
	    	if (wres!=delta)
	    	{
			printf("Error: when writing from file %d (%d byes) to standard file (%d bytes). \n",i+1,delta,wres);
			exit(2);
	    	}
	    }
	    else
	    if (hdcount>=delta)
	    {
		hdcount-=delta;
	    }
	    else
	    {
		wres=fwrite(buff+hdcount,1,delta-hdcount,wf);
                if (wres!=(delta-hdcount))
                {
                        printf("Error: when writing from file %d (%d byes) to standard file (%d bytes). \n",i+1,(delta-hdcount),wres);
                        exit(2);
                }
		hdcount=0;
	    }
	}	
	fclose(rf);
    }
    else
    {
	buff[0]='#';
        int wres;
	if ((wres=fwrite(buff,1,1,wf))!=1)
        {
            printf("Error: when writing # for file %d to standard file (%d bytes). \n",i+1,wres);
            exit(2);
        }    
    }
    fclose(wf);
    for (int i=0;i<outnum;i++)
    {
	cpy(filename[i],i,dir);	
    }
}
void initloss()
{
    for (int i=0;i<num;i++)
    {
	loss[i]=0;
    }
}
int main(int argc, char* argv[])
{
    if (argc!=5) 
    {
	printf("the format of the grading program is: grade <pkt size> <pkt number> <header_size> <receiver's name>\n");
	exit(2);
    }
    size=atoi(argv[1]);
    num=atoi(argv[2]);
    headersize=atoi(argv[3]);
    strcpy(receivername,argv[4]);
    printf("The pkt size: %d; Number of pkt: %d\n", size, num);
    filename=new int[num*2+10];
    loss=new int[num];
    //case.1: normal
    initloss();
    outnum=num;
    for (int i=0;i<num;i++) filename[i]=i;
    create(1);
    
    //case.2: from 2 to n-1: loss one packet interval: the packet loss happens in the middle
    initloss();
    outnum=num;
    int j=0;int k=0;
    for (int i=0;i<num;i++) 
    {
	if ((j) && ((i+1)<num))
	//not the last one.
	{
	    outnum--;
	    loss[i]=1;
	}
	else
	{
	    filename[k]=i;
	    k++;
	}
	j=1-j;
    }
    if (k!=outnum)  
	printf("Error: k!=outnum in case 2\n");
    create(2);    
    //case.3: from 1 to n-1: loss one packet interval
    initloss();
    outnum=num;
    j=1;k=0;
    for (int i=0;i<num;i++) 
    {
	if ((j) && ((i+1)<num))
	//not the last one.
	{
	    outnum--;
	    loss[i]=1;
	}
	else
	{
	    filename[k]=i;
	    k++;
	}
	if (j==2) j=0;	else j++;
    }  
    if (k!=outnum)  
	printf("Error: k!=outnum in case 3\n");
    create(3);
    
    //case.4: from n to 2: loss one packet interval
    initloss();
    outnum=num;
    j=1;k=0;
    for (int i=num-1;i>=0;i--) 
    {
	if ((j) && (i>0))
	//not the first one.
	{
	    outnum--;
	    loss[i]=1;
	}
	else
	{
	    filename[k]=i;
	    k++;
	}
	if (j==3) j=0;	else	j=j+1;
    }  
    if (k!=outnum)  
	printf("Error: k!=outnum in case 4\n");
    create(4);    
    
    //case.5: reorder 
    initloss();
    outnum=num;
    for (int i=0;i<num;i++) filename[i]=i;    
    int i=0;
    while ((i+1)<num)
    {
	int tmp=filename[i];
	filename[i]=filename[i+1];
	filename[i+1]=tmp;
	i+=2;
    }
    create(5);    
    
    //case.6: duplicate 1, 3*2, 6*3, ...
    initloss();
    outnum=num;
    j=0;k=0;
    int dec=0;
    for (int i=0;i<num;i++)
    {
	filename[k]=i;
	k++;
	if (dec<=0)
	{
	    if (j>0)
	    for (int l=0;l<j;l++)
	    {
		filename[k]=i;
		k++;	
		outnum++;
	    }
	    j++;
	    dec=j;
	}
	else
	    dec--;
    }    
    if (k!=outnum)  
	printf("Error: k!=outnum in case 6\n");
    create(6);
    
    //case.7: random loss (10), reorder(10) and duplicate(10) 
    initloss();
    outnum=num;
    for (int i=0;i<num;i++) filename[i]=i;
    for (int i=0;i<(num/10);i++)
    {
	int ind=random()%outnum;
	if (ind==outnum) ind--;
	loss[filename[ind]]=1;
	outnum--;
	filename[ind]=filename[outnum];
    }
    
    for (int i=0;i<(num/10);i++)
    {
	int ind=random()%outnum;
        if (ind==outnum) ind--;
	filename[outnum]=filename[ind];
	outnum++;
    }
    create(7);
    
    
    delete filename;
    delete loss;
    
    
    
}

