/* synchronous.c
 *
 * $Id: synchronous.c,v 1.12 2000/12/10 16:05:52 alderman Exp $
 *
 * Read synchronously through the filesystem.
 */

#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <math.h>

#include "global.h"
#include "options.h"
#include "timer.h"
#include "since.h"

/* The version has a single thread that reads several streams
 * synchronously.
 */

struct streamdata {		/* data structure for each stream */
	int fileno;		/* The filenumber for this stream */
	int pos;		/* The position in the file */
	int fd;			/* The file's file descriptor */
	int size;		/* The file size. */
	int done;               /* True when this stream is done. */
} streamdata[MAX_STREAMS];

/* This is the size of the file in bytes.  Calculated from
 * streamdata[0].size */
int how_big;

// int readStream(int streamno);
int readMeg(char *buf, int fd);


int main(int argc, char *argv[]) {
	int i = 0, j = 0;
	int rv;
	char buf[MAX_BUF_SIZE];
	char *filename;
	int fd;
	int ctr = 0, errctr = 0;
	struct stat sbuf;

	/* see options.c */
	extern int block_size, num_streams, bit_rate, num_blocks;

	/* see options.c */
        parseArgs(argc, argv);
        if(validateParams() != VALIDATION_SUCCESS) {
                printUsage();
                exit(1);
        }

	/* Not necessary */
	// memset(buf,'\0', NUMBYTES);

	/* Initialize the data structures which contain per stream info
	 * including opening files */
	for (i = 0; i < num_streams; i++) {
		streamdata[i].fileno = i;
		streamdata[i].done = 0;
		filename = malloc(256);
	        if(filename == NULL) {
       			fprintf(stderr, "Can't malloc for filename.\n");
                	exit(1);
        	}
        
        	rv = snprintf(filename, 255, "bf/%2.2d",i);
        	if(rv != 5) {
                	fprintf(stderr, "Can't snprintf for filename.\n");
        	}

        
		fd = open(filename, O_RDONLY, NULL);
        	if(fd < 1) {
                	printf("open error: fd %d on %s\n",fd, filename);
			exit(1);
        	}
		free(filename);
		streamdata[i].fd = fd;

		rv = fstat(fd, &sbuf);
		if(rv != 0) {
			printf("fstat error: %d\n",rv);
			exit(1);
		}
		streamdata[i].size = sbuf.st_size;
#ifdef DEBUG		
		printf("Initialized stream: %d\n",i);
#endif
	}

	how_big = num_blocks;
        if(how_big > streamdata[0].size / block_size) {
                fprintf(stderr, "Can't read %d blocks from file!!\n", how_big);
                exit(1);
        }
        
#ifdef DEBUG
	printf("how_big: %d, block_size: %d, file_size: %d\n",
		how_big, block_size, how_big * block_size);
#endif
        
	/* See timer.c */
	init_timer(block_size, bit_rate);
	
	/* See since.c */
	init_since();

	for (i = 0; i < how_big; i++) {
                now_since();
		for(j = 0; j < num_streams; j++) {
#ifdef DEBUG
                	printf("Reading chunk %d in stream %d.\n",i, j);
#endif
                	if(readMeg(buf, streamdata[j].fd) < 0) {
                       		fprintf(stderr, "Exiting because of stream %d.\n", j);
                        	exit(1);
                	}
#ifdef DEBUG
                	fprintf (stderr, "Stream %d block %d.\n", j, i);
#endif
		}
                since();
		++ctr;
		if(sleep_end_quantum_increment()) {
			++errctr;
		}
		printf("Period %d, %d errors\n",ctr,errctr);
        }
        end_since();
        printf("Total errors: %d\n", errctr);
	exit(0);
}

int readMeg(char *buf, int fd) {
        int curByte = 0;
        int rv;

	extern int block_size;

        while(1) {
#ifdef DEBUG
		fprintf(stderr, "Commencing read %d, %d, %d, %d\n", fd, (int)&buf, block_size, curByte);
#endif
                rv = read(fd, buf, block_size - curByte);
#ifdef DEBUG
                fprintf(stderr, "Read %d bytes.\n",rv);
#endif
                curByte += rv;
                if(rv > 0) {
                        // fprintf(stderr, "Read %d bytes.\n",rv);
                        if (curByte < block_size) {
                                continue;
                        } else {
				return curByte;
			}
                } else if (rv == 0) {
                        fprintf(stderr, "Read Zero bytes.\n");
                        return rv;
                } else {
                        fprintf(stderr, "Read returned negative: %d.\n", rv);
                        return rv;
                }
        }
        return rv;
}
