#include <stdio.h>
#include <math.h>
#include <unistd.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <netdb.h>
#include "radio_mixer.h"
#include "vu.h"


float divisor;
STATS stats;
void usage(void);
extern STATS stats;

void
do_vu()
{
  int best = 0,t_best=0, counter, flag = TRUE, channel;
  short holder[MAX_CHANNELS], temp_holder;
  float peak_amp, crude, average = 0;
  long time = 0;
  long block_duration;
  char stereo_flip_flop = 0;
  int max_c;
	

	/***** READ TO END OF INPUT *****/
	while(flag == TRUE){

		best = 0;

		max_c=(int)((float)stats.sample_rate / stats.display_rate);
		for(counter = 0; counter <= max_c; ++counter){
		
			/***** DO A SAMPLE FRAME *****/
			for(channel = 0; channel < stats.num_channels; ++channel){
				holder[channel] = 0;
				/***** READ A SAMPLE *****/
				if(fread(holder + channel , (stats.sample_width / 8), 1, stdin) != 1){
					flag = FALSE;
					break;
				}
				time++; 
				
				/***** CORRECT SAMPLE AND TEST FOR GREATEST VALUE SO FAR *****/
				temp_holder = (stats.sample_width == 8 ? holder[channel] - 128 : holder[channel]);
				if(temp_holder < -divisor){
					temp_holder = -divisor;
				}
				t_best=abs(temp_holder);
				if( t_best > best){
					best = t_best;
				}

			}

				/***** TO WRITE... *****/
				for(channel = 0; channel < stats.num_channels; ++channel){
				 /***** WRITE THE SAMPLE BACK OUT *****/
				 if(fwrite(&holder[channel] , stats.sample_width / 8, 1, stdout) != 1){
					 flag = FALSE;
					 break;
				 }
				}

		}

		send_samples(best);
	}
}

int
service_timer(int current_amp)
{

	if(sqrt((float)current_amp / divisor) * 100 > stats.threshold){
		stats.decay_position = stats.decay_length;
	}
	if(stats.decay_position){
		return stats.decay_position--;
	} else {
		return 0;
	}


}


int
send_samples(int samples)
{
  int sockfd;	
  struct sockaddr_in serv_addr;
  char *serv_host = "localhost";
  struct hostent *host_ptr;
  int port;
  int buff_size = 0;
  char message[MAX_SIZE];
 
  port = SERV_TCP_PORT;
  
  /* get the address of the host */
  if((host_ptr = gethostbyname(serv_host)) == NULL) {
     perror("gethostbyname error for");
     exit(1);
  }
  
  if(host_ptr->h_addrtype !=  AF_INET) {
     perror("unknown address type");
     exit(1);
  }
  
  bzero((char *) &serv_addr, sizeof(serv_addr));
  serv_addr.sin_family = AF_INET;
  serv_addr.sin_addr.s_addr = 
     ((struct in_addr *)host_ptr->h_addr_list[0])->s_addr;
  serv_addr.sin_port = htons(port);
  

  /* open a TCP socket */
  if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
     perror("can't open stream socket");
     exit(1);
  }

  /* connect to the server */    
  if(connect(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
     perror("can't connect to server");
  }
  else {
    /* write a message to the server */
    sprintf(message, "%d",samples);
    write(sockfd, message, sizeof(message));
  }
  close(sockfd);

}




main(int argc, char *argv[])
{
void get_sound_stats(void), parse_args(int argc, char *argv[]);
void init_sound_stats();

	init_sound_stats();
	get_sound_stats();

	parse_args(argc, argv);


	do_vu();

	exit(0);

}

void 
init_sound_stats()
{
int x;
	stats.sample_width	= 16;
	stats.num_channels	= 1;
	stats.sample_rate	= 44100;
	stats.display_rate	= 1;
	stats.graph_gain	= 1;
	stats.show_graph	= YES;
	stats.show_percent	= YES;
	stats.show_raw		= YES;
	stats.show_time		= YES;
	stats.threshold		= 0;
	stats.decay_length	= 0;

	for(x = 0; x < MAX_CHANNELS; ++x){
		stats.invert_channel[x] = 1;
	}
	divisor = pow(2, (float)stats.sample_width ) / 2.0 - 1.0;
}

void
parse_args(int argc, char *argv[]){
unsigned char index1;
int c;
char ch;
char emessage[256];
float optval;
void die(char *);

	while( (c = getopt(argc, argv, "m:g:b:s:d:c:i::GTPR")) != EOF){
		if( (c == 'b') | (c == 's') | (c == 'd') | (c == 'c') | (c == 'm') ){
			optval = atof(optarg);
		}
		switch(c){
			case 'm':
				if((optval < 1.0) || (optval > 16384.0)){
					fprintf(stderr, "%f -m gain must be between 1 and 16384\n", optval);
					usage();
				}
				stats.graph_gain = (int)optval;
				break;
			case 'b':
				if((optval != 8.0) && (optval != 16.0)){
					usage();
				}
				stats.sample_width = (int)optval;
				break;
			case 's':
				if(optval < 0.0){
					usage();
				}
				stats.sample_rate = (int)optval;
				break;
			case 'd':
				if(optval < 0.0){
					usage();
				}
				stats.display_rate = optval;
				break;
			case 'c':
				if( (optval < 1) || (optval > 8) ){
					sprintf(emessage, "Number of channels must be between 1 an %d", MAX_CHANNELS);
					die(emessage);
				}
				stats.num_channels = (int)optval;
				break;
			case 'g':
				stats.threshold = atoi(strtok(optarg, ":"));
				stats.decay_length = atoi(strtok(NULL, ":"));
				break;

			/***** CHANNEL INVERSION *****/
			case 'i':
				if( optarg != 0 ){
					for(index1 = 0; index1 < strlen(optarg); ++index1){
						ch = *(optarg + index1);
						if(isdigit( ch )){
							stats.invert_channel[ch] = -stats.invert_channel[ch];
						} else {
							switch(*(optarg + index1)){
								case 'l' :
									stats.invert_channel[0] = -stats.invert_channel[0];
									break;
								case 'r' :
									stats.invert_channel[1] = -stats.invert_channel[1];
									break;
								default:
									usage();
							}
						}
					}
				} else {
					stats.invert_channel[0] = -stats.invert_channel[0];
				}
				break;

			case 'G':
				stats.show_graph = !stats.show_graph;	
				break;
			case 'T':
				stats.show_time = !stats.show_time;	
				break;
			case 'P':
				stats.show_percent = !stats.show_percent;	
				break;
			case 'R':
				stats.show_raw = !stats.show_raw;	
				break;

		
		}
	}

	stats.decay_length = stats.decay_length * stats.sample_rate;

}

void
usage()
{
	fprintf(stderr, "vu: usage: vu [-b:s:c:r:GTPR]");
	exit(-1);
}

void
die(char *message)
{
	fprintf(stderr, "\n\nvu: %s\n\n", message);
	exit(-1);
	
}
