#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

typedef struct fileResult {
	int index; /*index in argv, used to access filename*/
	int noExist; /*see if the file exist*/
	int word;
	int line;
	int byte;
	struct fileResult *next;
} fileResult;

int countWord(FILE *fp);
int countWord1(FILE *fp);
int countByte(FILE *fp);
int	countLine(FILE *fp); 
void checkArg(char arg);
void noArgMessage(char arg);

int lastArgFlag = 0;
int wordFlag = 0;
int byteFlag = 0;
int lineFlag = 0;

int length;

fileResult *head = NULL;
fileResult *tail = NULL;
fileResult *tmp = NULL;

/* final return value*/
int ret = 0;

int main(int argc, char *argv[])
{
	int i, j;
	FILE *fp = NULL;
	/* check each argument */
	for(i=1;i<argc;++i) {
		/* if -- && -- not presented yet*/
		if(!strcmp("--", argv[i]) && !lastArgFlag) {
			lastArgFlag = 1;
		}
		/* if start with - && -- not presented yet*/ 
		else if(argv[i][0] == '-' && !lastArgFlag) {
			length = strlen(argv[i]);
			for(j=1;j<length;++j)
				checkArg(argv[i][j]);
		}
		/* else it should be a file*/
		else {
			/* malloc it and initialize */
			tmp = malloc(sizeof(fileResult));
			tmp->index = i;
			tmp->noExist = 0;
			tmp->word = -1;
			tmp->line = -1;
			tmp->byte = -1;
			tmp->next = NULL;

			/* link the list together */
			if(head == NULL)
				head = tail = tmp;
			else {
				tail->next = tmp;	
				tail = tail->next;
			}
		}
	}

	tmp = head;
	while(tmp != NULL) {

		fprintf(stdout, "couting %s\n", argv[tmp->index]);
		/* open file */ 
		fp = fopen(argv[tmp->index], "r");	
		if(fp == NULL) {
			fprintf(stderr, "lwc: %s: ", argv[tmp->index]);
			perror("");
			ret = 1;
			tmp->noExist = 1;
		}

		if(!(tmp->noExist)) {
			/* count the stuff */
			tmp->byte = countByte(fp);
			if(lineFlag)
				tmp->line = countLine(fp); 
			if(wordFlag)
				tmp->word = countWord(fp);
		}
		tmp = tmp->next;
	}

	while(head != NULL) {
		/* print the stuff */
		printf("%d|%d|%d|%s\n", head->byte, head->line, head->word, argv[head->index]);
		/*
			Use %*d to automatically align the stuff
		*/
		/* move the pointer */
		tmp = head;
		head = head->next;
		/* free memory */
		free(tmp);
	}
	return ret;	
}

void checkArg(char arg)
{
	switch(arg) {
		case 'c': 
			byteFlag = 1;
			break;
		case 'w':
			wordFlag = 1;	
			break;
		case 'l':
			lineFlag = 1;
			break;
		default:
			noArgMessage(arg);
			exit(1);
	}
	return;
}

void noArgMessage(char arg)
{
	fprintf(stderr, "lwc: invalid option -- '%c'\n", arg);
	fprintf(stderr, "Try 'lwc --help' for more information.\n");
	return;
}

/* spec specified that all the value won't exceed integer limit */
int countByte(FILE *fp)
{
	long size;
	fseek(fp, 0L, SEEK_END);	
	size = ftell(fp);
	rewind(fp);
	return (int)size;
}

int	countLine(FILE *fp) 
{
	int i;
	int ret = 0;
	unsigned char buf[1000];
	int newline = 0;
	while(!feof(fp)) {
		ret = fread(buf, 1, sizeof(buf), fp);
		for(i=0;i<ret;++i) {
			if(buf[i] == '\n')
				newline++;	
		}
	}	
	rewind(fp);
	return newline;
}


int countWord(FILE *fp)
{
	int i;
	int ret = 0;
	unsigned char buf[1000];
	int word = 0;
	unsigned char lastBufLast = ' ';
	unsigned char last = ' ';
	while(!feof(fp)) {
		ret = fread(buf, 1, sizeof(buf), fp);
		for(i=0;i<ret;++i) {
			if(isgraph(buf[i])) {
				if(!i) // at the start of a buffer
					last = lastBufLast;
				else // in the middle of a buffer
					last = buf[i-1];
				if(!isgraph(last))
					word++;
			}
		}
		if(ret > 0)
			last = buf[ret-1];
	}	
	rewind(fp);
	return word;
}

int countWord1(FILE *fp)
{
	int i;
	int ret = 0;
	unsigned char buf[1000];
	int word = 0;
	unsigned char lastBufLast = ' ';
	unsigned char last = ' ';
	while(!feof(fp)) {
		ret = fread(buf, 1, sizeof(buf), fp);
		for(i=0;i<ret;++i) {
			if(isalnum(buf[i])) {
				if(!i) // at the start of a buffer
					last = lastBufLast;
				else // in the middle of a buffer
					last = buf[i-1];
				if(!isalnum(last))
					word++;
			}
		}
		if(ret > 0)
			last = buf[ret-1];
	}	
	rewind(fp);
	return word;
}

// another version that uses sscanf? 

/*
1. -- mark the end of all argument for this program
if file exceed int limit
*/
