/*

Copyright: Daniel Bisig, March, 2005

*/


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

#include <netinet/in.h>

#include <limits.h>
#include <netdb.h>
#include <arpa/inet.h>

#include <sys/socket.h>
#include <errno.h>

#include <pthread.h> 

/* Text buffer sizes */

#define LINE_LEN	256
#define BUFFER_LEN	128

/* ----- Configurable items ----- */

unsigned short PORT;
char HOSTNAME[LINE_LEN];
int RATE;

/* =========== Subroutines ============= */

/* ------- Configuration routines  ------- */

void set_defaults()
{
 strcpy (HOSTNAME,"localhost");
 PORT=1522;
 RATE=10;
}

/* ---- Network routines ------- */

/* Converts ASCII text to in_addr struct */

struct in_addr *atoaddr(address)
char *address;
{
  struct hostent *host;
  static struct in_addr saddr;

  /* First try it as aaa.bbb.ccc.ddd. */
  saddr.s_addr = inet_addr(address);
  if (saddr.s_addr != -1) {
    return &saddr;
  }
    
  host = gethostbyname(address);
  if (host != NULL) {
    return (struct in_addr *) *host->h_addr_list;
  }
  return NULL;
}

/* Write buffer to socket connection */
   
int sock_write (int sockfd, char *buf, size_t count)
{
 size_t bytes_sent = 0;
 int this_write;
       
 while (bytes_sent < count) {
  do {
   this_write = write(sockfd, buf, count - bytes_sent);
  } while ( (this_write < 0) && (errno == EINTR) );
  if (this_write <= 0) {
   return(this_write);
  } 
  bytes_sent += this_write;
  buf += this_write;
 }
 return(count);
}

/* Read from socket connection into buffer */

int sock_read (int sockfd, char *buf, size_t count)
{
 size_t bytes_read = 0;
 int this_read;
 fd_set readers;
 struct timeval timeout;
 int pending;

 while (bytes_read < count) {
  do {
   /* Check status of connection */
   pending=0;
   while (pending==0) {
    FD_ZERO(&readers);
    FD_SET(sockfd,&readers);
    timeout.tv_sec=5;
    timeout.tv_usec=0;
    pending=select(FD_SETSIZE,&readers,0,0,&timeout);
    if (pending<0) {
     fprintf (stderr,"Connection closed ...\n");
     return(-1);
    }
   } 
   this_read = read(sockfd, buf, count - bytes_read);
  } while ( (this_read < 0) && (errno == EINTR) );
  if ((this_read==0) && (pending==1)) {
   fprintf (stderr,"Connection closed ...\n");
   return(-1);
  }    
  if (this_read <= 0) {
   return(this_read);
  } 
  bytes_read += this_read;
  buf += this_read;
 }
 return(count);
}

/* Read a string delimited by a newline character from a socket connection */
      
int sock_gets (int sockfd, char *str, size_t count)
{
 int bytes_read;
 int total_count = 0;
 char *current_position;
 char last_read = 0;
 fd_set readers;
 struct timeval timeout;
 int pending;
          
 current_position = str;
 while ((last_read != 10) && (last_read !=13)) {
   /* Check status of connection */
   pending=0;
   while (pending==0) {
    FD_ZERO(&readers);
    FD_SET(sockfd,&readers);
    timeout.tv_sec=5;
    timeout.tv_usec=0;
    pending=select(FD_SETSIZE,&readers,0,0,&timeout);
    if (pending<0) {
     fprintf (stderr,"Connection closed ...\n");
     return(-1);
    }
   } 
   bytes_read = read(sockfd, &last_read, 1);
   if ((bytes_read==0) && (pending==1)) {
    fprintf (stderr,"Connection closed ...\n");
    return(-1);
   }    
   if (bytes_read <= 0) {
    return bytes_read; 
   }
   if ( (total_count < count) && (last_read != 10) && (last_read !=13) ) {
    current_position[0] = last_read;
    current_position++;
    total_count++;
   }
 }
 if (count > 0) current_position[0] = 0;
 return total_count;
}

/* ======== Main processing loop ============= */

void NetworkLoop(int connected_socket)
{
 	int counter=0;
 	int connected;
 	int readloop;
 	int numread;
 	char outbuffer[BUFFER_LEN];
 	char inbuffer[BUFFER_LEN];
 	char filePath[BUFFER_LEN];
 	char commandBuffer[BUFFER_LEN];
 	char* srcPt;
 	int USLEEP;
 	int result;
 
 	/* Calculate rate-throttle pause */
 	USLEEP=1000000/RATE;  
 	/* Processing loop */
 	connected=1;
 	while (connected) 
 	{
  		/* Count iterations */
  		counter++;
  		/* Write POLL to reflector */
  		sprintf(outbuffer,"POLL\n");
  		connected=(sock_write(connected_socket,outbuffer,strlen(outbuffer))>0);
  		/* Read text until OVER has been reached */
  		readloop=1;
  		while (readloop) 
  		{
  			if ( (numread=sock_gets(connected_socket,inbuffer,BUFFER_LEN))>0) 
   			{
    			/* Parse textlines */
    			if (strncasecmp(inbuffer,"OVER",4)==0) 
    			{
     				readloop=0;
    			} 
    			else 
    			{
     				/* Process inbuffer */
     				// parse input buffer
     				printf("%s\n", inbuffer);
     				if(strncmp(inbuffer, " M ", 3) == 0) // check for Music Play Command
     				{
     					//printf("Music Play Command detected");
     					
     					memset(filePath, 0, BUFFER_LEN);
     					memset(commandBuffer, 0, BUFFER_LEN);  			
     							  					
     					srcPt = &inbuffer[3]; // skip of " M " part of inBuffer
     					
     					strncpy(filePath, srcPt, strlen(srcPt));
     					
     					// check for local or remote filepath 					
     					if(strncmp(filePath, "http://", 7) == 0)
     					{
     						//sprintf(commandBuffer, "curl -N \"%s\" | mpg321 -\n", filePath);
     						
     						sprintf(commandBuffer, "curl \"%s\" -o /mnt/card/spoken.mp3\n", filePath);
     						result = system(commandBuffer);
     						
     						sprintf(commandBuffer, "mpg321 /mnt/card/spoken.mp3\n");
     						result = system(commandBuffer);
     					}
     					else
     					{
     						sprintf(commandBuffer, "mpg321 \"%s\"\n", filePath);
     						result = system(commandBuffer);
     					}
    				}
    			}
   			} 
   			else 
   			{
    			readloop=0;
   			} 
		  }
  		/* Pause */
  		usleep(USLEEP);
	}
}

/* Main routine */

int main (int argc, char *argv[])
{
	struct sockaddr_in address; // socket address structure
	static struct in_addr *addr; // address 
	int connected;
	int connected_socket = -1; // socket handle

	/* Print message */  
	printf ("reflector2mp3 - D. Bisig, March 2005\n\n");

	/* Initialize variables */
	set_defaults();
	
	// parse input parameter
	if(argc > 1)
	{
		strcpy (HOSTNAME,argv[1]);
	}
		 
 	/* Setup internet address information */
 	addr = (struct in_addr *)atoaddr((char *)HOSTNAME);
 	if (addr == NULL) 
 	{
  		fprintf(stderr,"Invalid network address: %s",HOSTNAME);
  		exit(-1);
 	}
 	memset((char *) &address, 0, sizeof(address));
 	address.sin_family = AF_INET;
 	address.sin_addr.s_addr = addr->s_addr;
 	address.sin_port = htons(PORT);

 	/* Connect to reflector */ 
 	connected_socket = socket(AF_INET, SOCK_STREAM, 0); // create tcp/ip based socket handle
 	printf("Connecting to %s on port %d ...",inet_ntoa(*addr),PORT);
 	connected = connect(connected_socket, (struct sockaddr *) &address, sizeof(address)); // connect socket to server address
 	if (connected < 0) 
 	{
  		printf("\n");
  		perror("connect()");
  		exit(-1);
 	}
 	printf(" connected.\n");
  
 	/* Start processing the reflector text and generating MIDI controls */
 	printf ("Processing ...\n");
 	NetworkLoop(connected_socket);
 
 	/* Close file/socket */
 	close(connected_socket);
              
 	exit(0);
}

