/* keyboard controls translation */

#include "liveice.h"
#include "mixer.h"
#include "controls.h"
#include "playlist.h"

/*
  struct keybind {
  int cmd_type;
  int channel;
  int n_params;
  float params[10];
  } key_bindings[256];
  
  
  
  void clear_bindings(void){
  int i;
  for (i=0;i<256;i++){
  key_bindings[i].cmd_type=NO_COMMAND;
  key_bindings[i].channel=0;
  key_bindings[i].n_params=0;
  }
  }
*/


/* reads detailed commands from stdin */
/* legitimate command is prefixed by a * */
int get_frontend_command(int *channel,float *parms,char *names){
	int inch,cmd;

	inch=fgetc(stdin);
	while((inch!=-1)&&(inch!='*')){
		inch=fgetc(stdin);
	}
	if(inch=='*'){
		fscanf(stdin,"%d",&cmd);
		switch(cmd){
		case NO_COMMAND:
			/* do nothing */
			break;
		case CHANGE_TRACK:
			fscanf(stdin,"%d %f",channel,&parms[0]);
			break;
		case SET_VOLUME:
			fscanf(stdin,"%d %f",channel,&parms[0]);
			break;
		case SET_SPEED:
			fscanf(stdin,"%d %f",channel,&parms[0]);
			break;
		case SEEK:
			fscanf(stdin,"%d %f",channel,&parms[0]);
			break;
		case START_STOP:
			fscanf(stdin,"%d %f",channel,&parms[0]);
			break;		
		case STICKY_MODE:
			fscanf(stdin,"%d %f",channel,&parms[0]);
			break;	
		case SOUNDCARD_INPUT:
			fscanf(stdin,"%f",&parms[0]);
			break;		
		case RESET_CONTROL_FILE:
			break;		
		case RE_READ_PLAYLIST:
			fscanf(stdin,"%s",names);
			break;
		case EFFECT_COMPRESSOR:
			fscanf(stdin,"%f",&parms[0]);
			break;
		case OUTPUT_SET:
			fscanf(stdin,"%f",&parms[0]);
			break;
		case TERMINATE:
			break;
		}
		return cmd;
	} else {
		return NO_COMMAND;
	}
}



/* turns a keyboard command into an internal command */
int translate_command(char inp,int *channel,float *parms,char *names){
	int cmd;
	switch(inp){
	case '1': 
		*channel=0;
		parms[0]=1;
		cmd=CHANGE_TRACK;
		break;
	case 'q':
	        *channel=0;
		parms[0]=-1;
		cmd=CHANGE_TRACK;
		break;
	case 'w':
		*channel=0;
		parms[0]=0;
		cmd=CHANGE_TRACK;
		break;
	case '2':
		parms[0]=!mixer.c_list[0]->on;
		*channel=0;
		cmd=START_STOP;
		break;
	case 'a': 
		*channel=1;
		parms[0]=1;
		cmd=CHANGE_TRACK;
		break;
	case 'z':
		*channel=1;
		parms[0]=-1;
		cmd=CHANGE_TRACK;
		break;
	case 'x':
		*channel=1;
		parms[0]=0;
		cmd=CHANGE_TRACK;
		break;
	case 's':
		parms[0]=!mixer.c_list[1]->on;
		*channel=1;
		cmd=START_STOP;
		break;
	case '3':
		parms[0]=mixer.c_list[0]->volume+0.05;
		*channel=0;
		cmd=SET_VOLUME;
		break;
	case 'e':
		parms[0]=mixer.c_list[0]->volume-0.05;
		*channel=0;
		cmd=SET_VOLUME;
		break;
	case 'd':
		parms[0]=mixer.c_list[1]->volume+0.05;
		*channel=1;
		cmd=SET_VOLUME;
		break;
	case 'c':
		parms[0]=mixer.c_list[1]->volume-0.05;
		*channel=1;
		cmd=SET_VOLUME;
		break;
	case '4':
		parms[0]=mixer.c_list[0]->speed+0.01;
		*channel=0;
		cmd=SET_SPEED;
		break;
	case 'r':
		parms[0]=mixer.c_list[0]->speed-0.01;
		*channel=0;
		cmd=SET_SPEED;
		break;
	case 'f':
		parms[0]=mixer.c_list[1]->speed+0.01;
		*channel=1;
		cmd=SET_SPEED;
		break;
	case 'v':
		parms[0]=mixer.c_list[1]->speed-0.01;
		*channel=1;
		cmd=SET_SPEED;
		break;
	case '$':
		parms[0]=mixer.c_list[0]->speed+0.05;
		*channel=0;
		cmd=SET_SPEED;
		break;
	case 'R':
		parms[0]=mixer.c_list[0]->speed-0.05;
		*channel=0;
		cmd=SET_SPEED;
		break;
	case 'F':
		parms[0]=mixer.c_list[1]->speed+0.05;
		*channel=1;
		cmd=SET_SPEED;
		break;
	case 'V':
		parms[0]=mixer.c_list[1]->speed-0.05;
		*channel=1;
		cmd=SET_SPEED;
		break;

	case 'g':
		switch(mixer.c_list[1]->stayon){
		case 0:
			parms[0]=1;
			break;
		case 1:
			parms[0]=-1;
			break;
		case -1:
			parms[0]=0;
			break;
		}
		*channel=1;
		cmd=STICKY_MODE;
		break;
	case '5':
		switch(mixer.c_list[0]->stayon){
		case 0:
			parms[0]=1;
			break;
		case 1:
			parms[0]=-1;
			break;
		case -1:
			parms[0]=0;
			break;
		}
	
		*channel=0;
		cmd=STICKY_MODE;
		break;   
	case 't':
		if(mixer.out_mode==1)
			parms[0]=0;
		else
			parms[0]=1;
		cmd=OUTPUT_SET;
		break;
	case 'b':
		if(mixer.out_mode==2)
			parms[0]=0;
		else 
			parms[0]=2;
		cmd=OUTPUT_SET;
		break;
	case '6':
		cmd=SEEK;
		parms[0]=1000;
		*channel=0;
		break;
	case 'y':
		cmd=SEEK;
		parms[0]=-1000;
		*channel=0;
		break;
	case 'h':
		cmd=SEEK;
		parms[0]=1000;
		*channel=1;
		break;
	case 'n':
		cmd=SEEK;
		parms[0]=-1000;
		*channel=1;
		break;
	case 'm':
		cmd=CHANGE_TRACK;
		parms[0]=random_number(&(g_conf.random_seed))*mixer.t_number;
		*channel=1;
		break;
	case 'u':
		cmd=CHANGE_TRACK;
		parms[0]=random_number(&(g_conf.random_seed))*mixer.t_number;
		*channel=0;	
		break;
	case ' ':
		parms[0]=(!mixer.soundcard) && g_conf.soundcard;
		cmd=SOUNDCARD_INPUT;
		break;
	case '[':
		parms[0]=mixer.compression_power - 0.1;
		cmd=EFFECT_COMPRESSOR;
		break;
	case ']':
		parms[0]=mixer.compression_power + 0.1;
		cmd=EFFECT_COMPRESSOR;
		break;
	case '#':
		cmd=RE_READ_PLAYLIST;
		break;
	case '+':
		cmd=TERMINATE;
		break;
	default:
		cmd=NO_COMMAND;
		channel=0;
		parms[0]=0.0;
	}
	return cmd;
}

char * command_name(int cmd){
	char *c_str;
	switch(cmd){
	case(NO_COMMAND):
		c_str="NO_COMMAND";
		break;
	case(CHANGE_TRACK):
		c_str="CHANGE_TRACK";
		break;
	case(START_STOP):
		c_str="START_STOP";
		break;
	case(SET_VOLUME):
		c_str="SET_VOLUME";
		break;
	case(OUTPUT_SET):
		c_str="OUTPUT_SET";
		break;
	case(STICKY_MODE):
		c_str="STICKY_MODE";
		break;
	case(SOUNDCARD_INPUT):
		c_str="SOUNDCARD_INPUT";
		break;
	case(SET_SPEED):
		c_str="SET_SPEED";
		break;
	case(SEEK):
		c_str="SEEK";
		break;
	case(RESET_CONTROL_FILE):
		c_str="RESET_CONTROL_FILE";
		break;
	case(RE_READ_PLAYLIST):
		c_str="RE_READ_PLAYLIST";
		break;
	case(EFFECT_COMPRESSOR):
		c_str="EFFECT_COMPRESSOR";
		break;
	default:
		c_str="ooops";
	}
	return c_str;
}

/* individual functions for all the interesting stuff */

void exec_change_track(int channel,float *parms,char *names){
	change_channel(mixer.c_list[channel],parms[0]);
}

void exec_start_stop(int channel,float *parms,char *names){
	mixer.c_list[channel]->on=parms[0];
#ifdef HAVE_LIBCURSES
	init_channel_display(mixer.c_list[channel]);
#else
	printf("Channel %s On: %d\n",mixer.c_list[channel]->name,mixer.c_list[channel]->on);
#endif
}

void exec_set_volume(int channel,float *parms,char *names){
	if(parms[0]<0.0) parms[0]=0.0;
	mixer.c_list[channel]->volume=parms[0];
#ifndef HAVE_LIBCURSES
	printf("Ch: %d Vol: %f\n",channel,mixer.c_list[channel]->volume);
#endif
}

void exec_set_speed(int channel,float *parms,char *names){
	if(parms[0]<0.01) parms[0]=0.01;
	else if(parms[0]>4) parms[0]=4;
	mixer.c_list[channel]->speed=parms[0];
#ifndef HAVE_LIBCURSES
	printf("Ch: %d Speed: %f\n",channel,mixer.c_list[channel]->speed);
#endif
}

void exec_seek(int channel,float *parms,char *names){
/* different stream types need different seek architechture */
	if((mixer.c_list[channel]->on)&&(mixer.c_list[channel]->curnt->t_type==MPEG)){
		if(parms[0]>0)
			write(mixer.c_list[channel]->control,"F",1);
		else 
				write(mixer.c_list[channel]->control,"C",1);
	}
}

void exec_output_set(int channel,float *parms,char *names){
	mixer.out_mode=parms[0];
}

void exec_sticky_mode(int channel,float *parms,char *names){
	mixer.c_list[channel]->stayon=parms[0];
#ifndef HAVE_LIBCURSES
	printf("Channel %s Sticky Mode: %d\n",mixer.c_list[channel]->name,mixer.c_list[channel]->stayon);
#endif
}

void exec_soundcard_input(int channel,float *parms,char *names){
	if(g_conf.soundcard){
		mixer.soundcard=parms[0];
		if(!g_conf.full_duplex){
			write_message("Toggling Soundcard IO",0);
			close_soundcard();
				/* lazy - whatever is done next will determine read/write*/
			open_soundcard(O_RDWR);
		}
	} else {
		write_message("soundcard not enabled",0);
	}
}

void exec_reset_control_file(int channel,float *parms,char *names){
	if(g_conf.mix_control!=0){
		fclose(mixer.control_file);
		if(g_conf.mix_control==2)
			/* this is silly - we really need to change the timer*/
			mixer.control_file=fopen(g_conf.mix_control_file,"r"); 
		else 
			mixer.control_file=fopen(g_conf.mix_control_file,"w");
	}
}

void exec_re_read_playlist(int channel,float *parms,char *names){
	reread_playlist(&(mixer.t_list));
	reset_track_pointers();
}

void exec_effect_compressor(int channel,float *parms,char *names){
	char mesg[256];
	mixer.compression_power=parms[0];
	if(mixer.compression_power>1.0)  mixer.compression_power=1;
	if(mixer.compression_power<0)  mixer.compression_power=0;
	sprintf(mesg,"Volume Compression %d%%",(int)(mixer.compression_power*100));
	write_message(mesg,0);
}

/* actually performs the config change.... */
void exec_command(int cmd,int channel,float *parms,char *names){
	switch(cmd){
	case  CHANGE_TRACK:
		exec_change_track(channel,parms,names);
		break;
	case START_STOP:
		exec_start_stop(channel,parms,names);
		break;
	case SET_VOLUME:
		exec_set_volume(channel,parms,names);
		break;
	case SET_SPEED:
		exec_set_speed(channel,parms,names);
		break;
	case SEEK:
		exec_seek(channel,parms,names);
		break;
	case OUTPUT_SET:
		exec_output_set(channel,parms,names);
		break;
	case STICKY_MODE:
		exec_sticky_mode(channel,parms,names);
		break;
	case SOUNDCARD_INPUT:
		exec_soundcard_input(channel,parms,names);
		break;
	case RESET_CONTROL_FILE:
		exec_reset_control_file(channel,parms,names);
		break;
	case RE_READ_PLAYLIST:
		exec_re_read_playlist(channel,parms,names);
		break;
	case EFFECT_COMPRESSOR:
		exec_effect_compressor(channel,parms,names);		
		break;
	}
}

int check_command_file(int *channel,float *parms,char *names){
	static double next_time;
	static int start=1;
	int cmd;
	if(start) {
		start=0;
		fscanf(mixer.control_file,"%lg",&next_time);
	}
	if ( next_time < (mixer.seq_time + 0.5 * mixer.time_resolution)){
		write_message("execing command from file",1);
		fscanf(mixer.control_file,"%d %d",&cmd,channel);
		switch(cmd){
		case START_STOP:
		case CHANGE_TRACK:
		case SET_VOLUME:
		case SET_SPEED:
			fscanf(mixer.control_file,"%g",&parms[0]);
			break;
		}
	        fscanf(mixer.control_file,"%lg",&next_time);
		if(feof(mixer.control_file)){
			fclose(mixer.control_file);
			g_conf.mix_control=0;
			write_message("control file exhausted",1);
		}
		return cmd;
	} else {
		return NO_COMMAND;
	}
}

/* assumes teh output file is already open */
void log_command(int cmd,int channel,float *parms,char *names){
	int n_param=0,no_log,i;
	
	switch(cmd){
	case OUTPUT_SET:	
	case STICKY_MODE:
	case SOUNDCARD_INPUT:
	case NO_COMMAND:
		no_log=1;
		break;
	case RE_READ_PLAYLIST:
		no_log=0;
		n_param=0;
		break;
	case START_STOP:
	case CHANGE_TRACK:
	case SET_VOLUME:
	case SET_SPEED:
	case EFFECT_COMPRESSOR:
		no_log=0;
		n_param=1;
		break;
	default:
		no_log=1;
	}
	if(!no_log){
		fprintf(mixer.control_file,"%f\t%d\t%d\t",mixer.seq_time,cmd,channel);
		for(i=0;i<n_param;i++) 
			fprintf(mixer.control_file,"%f\t",parms[i]);
		fprintf(mixer.control_file,"\n");
	}
}

/* new control system is required */
char do_mixer_control(void){
	char inp=0;
	int cmd=NO_COMMAND;
	int channel;
	float parms[10];
	char names[4096];
	names[0]=0;
	mixer.seq_time+=mixer.time_resolution;
	do {
	  cmd=NO_COMMAND;
	  if(g_conf.mix_control!=2){
	    if(g_conf.frontend == FE_PIPE){
	      cmd=get_frontend_command(&channel,parms,names);
	    } else {
	      inp=get_inp_char();
	      cmd=translate_command(inp,&channel,parms,names);
	    }
	  } else {
	    cmd=check_command_file(&channel,parms,names);
	  }
	  
	  if(g_conf.mix_control==1)
	    log_command(cmd,channel,parms,names);
	  if(cmd==TERMINATE){
	    inp='+';
	  }
	  exec_command(cmd,channel,parms,names);
	} while ((cmd!= NO_COMMAND) && (cmd!=TERMINATE));
	return inp;
}

void simple_frontend(void){
char line[4096],cmd[4096];
char inch;
long timeout;
time_t now;
int i;

inch=fgetc(stdin);
 while((inch!=-1)&&(inch!='*')){
	 inch=fgetc(stdin);
 }
 if(inch=='*'){
	 /* get the command */
	 fscanf(stdin,"%s",cmd);
	 i=0;
	 while(cmd[i]!=0) {
		 cmd[i]=toupper(cmd[i]);
		 i++;
	 }
	 /* get the parameters */
	 i=0;
	 line[0]=fgetc(stdin);
	 while(((line[0]==' ') || (line[0]=='\t'))&&(!feof(stdin))){
		 line[0]=fgetc(stdin);
	 }
	 while((line[i]!='\n')&&(!feof(stdin))){
		 i++;
		 line[i]=fgetc(stdin);
	 }
	 line[i]=0;
	 if(!strcmp(cmd,"STOP")){
		 g_conf.terminate_now=1;
	 } else if (!strcmp(cmd,"TIMEOUT")){
		 sscanf(line,"%ld",&timeout);
		 if(timeout<=0){
			 g_conf.end_time=0;
		 } else {
			 time(&now);
			 g_conf.end_time=now+timeout;
		 }
	 } else if (!strcmp(cmd,"UPDATE_NAME")){
		 update_all_servers (line,NULL);
	 } else {
		 fprintf(stderr,"%s %s\n",cmd,line);
	 }
 }
}

/* simepl mode command interpreter */
void do_simple_command(void){
	char inp;
	if(g_conf.frontend != FE_PIPE){
		inp=get_inp_char();
		if(inp=='+')
			g_conf.terminate_now=1;
	} else {
		simple_frontend();
	}
	
}
