#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <esd.h>
#include <time.h>
#include <signal.h>
#include <sys/wait.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <pthread.h>
#include "radio_mixer.h"

time_t otime=-1;
int count=0;
char* names[ ] = { "fallback", "line-in"};

pthread_mutex_t g_mutex=PTHREAD_MUTEX_INITIALIZER;
int g_volume=0;


int state[NUM_STREAMS]={ON,ON};

get_stream_info(int esd,int id[],int vol[])
{
  int i;
  esd_info_t *all_info = NULL;
  esd_player_info_t *playerlist;


  all_info = esd_get_all_info( esd );
  playerlist = all_info->player_list;
  if(playerlist) {
   for(i=0;i<NUM_STREAMS;i++) {
    if(!strcmp(playerlist->name,names[i])) {
      id[i]=playerlist->source_id;
      vol[i] = playerlist->left_vol_scale;
     }
    
   }

   while(playerlist->next) {
    playerlist=playerlist->next;
    for(i=0;i<NUM_STREAMS;i++) {
      if(!strcmp(playerlist->name,names[i])) {
			  	  id[i]=playerlist->source_id;
	        vol[i] = playerlist->left_vol_scale;
      }
    } 
   }
  }
  esd_free_all_info( all_info );  
  return(1);
}

ramp_handler(samples,esd)
{
  time_t now=time(NULL);
  int npid, s;
  int i,j,k;
  int id[NUM_STREAMS];
  int vol[NUM_STREAMS];
  int line_in;
  int active=-1;
  if(otime==-1) {
    otime=now;
  }

  for(i=0;i<NUM_STREAMS;i++) {
    vol[i] = 0;
    id[i]=0;
  }

  get_stream_info(esd,id,vol);
 
  for(j=0;j<NUM_STREAMS;j++) {
    if(!strcmp(names[j],"line-in")) {
      line_in=j;

    }
  }

  for(i=NUM_STREAMS-1;i>=0;i--) {
    if(id[i] && i!=line_in) {
      active=i;
      i=-1;
    }
  }

  if(samples > LIMIT)
    otime=time(NULL);
    
  if((now-otime)<DELAY && active<line_in)
    active=line_in;
  
  for(j=0;j<NUM_STREAMS;j++) {
    if(state[j]==OFF && vol[j] && j!=active) {
      esd_set_stream_pan( esd, id[j], 0, 0 );
    }
    else if(j!=active) {
      if(state[j]!=OFF) {
	k=vol[active];
	for(i=vol[j];i>=0;i-=20) {
	  k+=20; if(k>255) k=255;	  
	  esd_set_stream_pan( esd, id[j], i, i );
	  esd_set_stream_pan( esd, id[active], k, k );
	}
	state[active]=ON;
      }
      state[j]=OFF;
      if(vol[j]>0)
	esd_set_stream_pan( esd, id[j], 0, 0 );
      if(vol[active]<250)
	esd_set_stream_pan( esd, id[active], 255, 255 );
    }
  }
  // printf("%d - %d - %d\n",active,now-otime,samples);
  return(0);
}


void *line_server(void *arg)
{
  int sockfd, newsockfd, clilen;
  struct sockaddr_in cli_addr, serv_addr;
  int port;
  char string[MAX_SIZE];
  int len;    
  port = SERV_TCP_PORT;

  
  /* open a TCP socket (an Internet stream socket) */
  if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
     perror("can't open stream socket");
     exit(1);
  }
  	
  /* bind the local address, so that the cliend can send to server */
  bzero((char *) &serv_addr, sizeof(serv_addr));
  serv_addr.sin_family = AF_INET;
  //serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
  serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
  serv_addr.sin_port = htons(port);
  
  if(bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
     perror("can't bind local address");
     exit(1);
  }
	
  /* listen to the socket */
  listen(sockfd, 5);
  


  for(;;) {
     /* wait for a connection from a client; this is an iterative server */
     clilen = sizeof(cli_addr);
     newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
		
     if(newsockfd < 0) {
        perror("can't bind local address");
     }
   
     /* read a message from the client */
     len = read(newsockfd, &string, MAX_SIZE); 
     /* make sure it's a proper string */
     string[len] = 0;

			pthread_mutex_lock(&g_mutex);
		  g_volume=atoi(string);
		  pthread_mutex_unlock(&g_mutex);
     close(newsockfd);
  }  

}



int main(int argc, char *argv[])
{
  pthread_t line_s;
  int esd;
  int  iret1, iret2;
  /* Create independant threads each of which will execute function */
  if ( pthread_create( &line_s, NULL, line_server, NULL) ) {
   printf("error creating thread.");
   abort();
  }

  /*   connect to the esd   */
  esd = esd_open_sound( (char *)0 );
  for(;;) {
		pthread_mutex_lock(&g_mutex);
		//printf("value: %d\n",g_volume);	 
		ramp_handler(g_volume,esd);
		g_volume=0;
		pthread_mutex_unlock(&g_mutex); 
	 	usleep(500);  
  }
  pthread_join( line_s, NULL); 

  printf("Thread 1 returns: %d\n",iret1);
  printf("Thread 2 returns: %d\n",iret2);
  esd_close(esd);  

  exit(0);
}
