/*
  **
  ** conf.c
  **
  ** I originaly wrote conf.c as part of the drpoxy package 
  ** thanks to Matthew Pratt and others for their additions. 
  **
  ** Copyright 1999 Jeroen Vreeken (pe1rxq@chello.nl)
  **
  ** This software is licensed under the terms of the GNU General 
  ** Public License (GPL). Please see the file COPYING for details.
  ** 
  **
*/

/**
 * How to add a config option :
 *
 *   1. think twice, there are settings enough
 *
 *   2. add a field to 'struct config' (conf.h) and 'struct config conf'
 *
 *   4. add a entry to the config_params array below, if your
 *      option should be configurable by the config file.
 */ 
#include "conf.h"
#include "motion.h"

#ifdef TRACKING
#include "track.h"
#endif

struct config conf = {
	DEF_WIDTH,
	DEF_HEIGHT,
	DEF_QUALITY,
	DEF_CHANGES,
	0,
	1,
	0,
	DEF_GAP,
	0,
	IN_DEFAULT,
	0,
	DEF_MAXFRAMERATE,
	0,
	0,
	0,
	DEF_NOISELEVEL,
	0, /* min gap */
	VIDEO_DEVICE,
	NULL,
	NULL,
	NULL,
	NULL,
	NULL,	/* mask file */
};



static void copy_bool(char *, void *);
static void copy_int(char *, void *);
static void copy_string(char *, void *);
static void usage(void);

config_param config_params[] = {
	{
	"always_changes",
	&conf.always_diff,
	copy_bool
	},
	{
	"deamon",
	&deamon,
	copy_bool
	},
	{
	"snapshots",
	&alarmtime,
	copy_int
	},
	{
	"threshold",
	&conf.max_changes,
	copy_int
	},
	{
	"framerate",
	&conf.frame_limit,
	copy_int
	},
	{
	"locate",
	&conf.locate,
	copy_bool
	},
	{
	"output_motion",
	&conf.motion_img,
	copy_bool
	},
	{
	"output_normal",
	&conf.new_img,
	copy_bool
	},
	{
	"target_dir",
	&conf.filepath,
	copy_string
	},
	{
	"videodevice",
	&conf.device,
	copy_string
	},
	{
	"input",
	&conf.input,
	copy_int
	},
	{
	"norm",
	&conf.norm,
	copy_int
	},
	{
	"quality",
	&conf.quality,
	copy_int
	},
	{
	"quiet",
	&conf.quiet,
	copy_bool
	},
	{
	"ppm",
	&conf.ppm,
	copy_bool
	},
	{
	"width",
	&conf.width,
	copy_int
	},
	{
	"height",
	&conf.height,
	copy_int
	},
	{
	"execute",
	&conf.externcommand,
	copy_string
	},
	{
	"mail",
	&conf.mail_address,
	copy_string
	},
	{
	"sms",
	&conf.sms_nr,
	copy_string
	},
	{
	"gap",
	&conf.gap,
	copy_int
	},
	{
	"minimum_gap",
	&conf.mingap,
	copy_int
	},
	{
	"mpeg_encode",
	&conf.mpeg,
	copy_bool
	},
	{
	"noise_level",
	&conf.noise,
	copy_int
	},
	{
	"mask_file",
	&conf.mask_file,
	copy_string
	},
#ifdef TRACKING
	{
	"track_port",
	&track.port,
	copy_int	
	},
	{
	"track_baud",
	&track.baud,
	copy_int
	},
	{
	"track_servox",
	&track.servox,
	copy_int
	},
	{
	"track_servoy",
	&track.servoy,
	copy_int
	},
	{
	"track_maxx",
	&track.maxx,
	copy_int
	},
	{
	"track_maxy",
	&track.maxy,
	copy_int
	},
	{
	"track_step",
	&track.step,
	copy_int
	},
	{
	"track_wait",
	&track.wait,
	copy_int
	},
#endif
  { NULL, NULL , NULL }
};


void conf_cmdline (int argc, char **argv)
{
	int c;

        while ((c=getopt(argc, argv, "a:BCc:d:E:DF:f:G:g:hi:lL:M:mNn:pQq:S:s:t:"))!=EOF) 
                switch (c) {                                                    
                        case 'a':                                               
                                sscanf (optarg, "%d", &alarmtime);              
                                break;
			case 'B':
				conf.mpeg=1;
				break;                                          
                        case 'C':                                               
                                conf.always_diff=1;                                  
                                break;                                          
                        case 'c':                                               
                                sscanf (optarg, "%d", &conf.max_changes);            
                                break;                                          
                        case 'd':                                               
                                conf.device=optarg;                                  
                                break;                                          
                        case 'E':                                               
                                conf.externcommand=optarg;                           
                                break;                                          
                        case 'D':                                               
                                deamon=1;                                       
                                break;
			case 'F':
				conf.mask_file=optarg;
				break;                                          
                        case 'f':                                               
                                sscanf (optarg, "%d", &conf.frame_limit);            
                                break;
			case 'G':
				sscanf (optarg, "%d", &conf.mingap);
				break;                                          
                        case 'g':                                               
                                sscanf (optarg, "%d", &conf.gap);                    
                                break;                                          
                        case 'i':                                               
                                sscanf (optarg, "%d", &conf.input);                  
                                break;                                          
                        case 'l':                                               
                                conf.locate=1;                                       
                                break;
			case 'L':
				sscanf (optarg, "%d", &conf.noise);
				break;                                          
                        case 'M':                                               
                                conf.mail_address=optarg;                            
                                break;                                          
                        case 'm':                                               
                                conf.motion_img=1;                                   
                                break;                                          
                        case 'N':                                               
                                conf.new_img=0;                                      
                                break;                                          
                        case 'n':                                               
                                if (!strcmp(optarg, "pal")) conf.norm=NORM_PAL;      
                                if (!strcmp(optarg, "ntsc")) conf.norm=NORM_NTSC;    
                                if (!strcmp(optarg, "secam")) conf.norm=NORM_SECAM;  
                                break;
			case 'p':
				conf.ppm=1;
				break;                                          
                        case 'S':                                               
                                conf.sms_nr=optarg;                                  
                                break;                                          
                        case 'q':                                               
                                sscanf (optarg, "%d", &conf.quality);                
                                break;                                          
		        case 'Q':
			        conf.quiet=1;
			        break;
                        case 's':                                               
                                sscanf (optarg, "%dx%d", &conf.width, &conf.height);      
                                break;                                          
                        case 't':                                               
                                conf.filepath=optarg;                                
                                break;                                          
                        case 'h':                                               
                        /* Do the same as an invallid option, but without the   
                         * 'invalid option' error.... */                        
                        default:                                                
                                usage();                                        
                                exit(1);                                       
                }                        
}

/**************************************************************************
    Main function, called from motion.c
*/
int conf_load (int argc, char **argv)
{
	FILE *fp;
	char line[256], *cmd = NULL, *arg1 = NULL;
  
	fp = fopen ("motion.conf", "r");
	if (!fp) {	/* specified file does not exist... try default file */
		fp = fopen ("/etc/motion.conf", "r");
		if (!fp) {	/* there is no config file.... use defaults */
			perror("no config file");
		}
	} 
	if (fp) {
		while (fgets(line, 256, fp)) {
			if (!(line[0]=='#')) {	/* skip lines with comment */
				if(strlen(line))
					line[strlen(line) - 1] = 0; /*kill'\n'*/
				else
					line[0]=0;
				cmd = strtok( line, " =" );
				arg1 = strtok( NULL, " =");
				conf_cmdparse(cmd, arg1);
			}
		}
		fclose(fp);
	}
	
	conf_cmdline(argc, argv);
	
	return 0;
}
/*****************************************************************************/
void conf_cmdparse(char *cmd, char *arg1)
{
	int i = 0;

	if( !cmd )return;
	if( !arg1 )return;
  
	while( config_params[i].param_name != NULL ) {
		if(!strncasecmp(cmd, config_params[i].param_name , 255 + 50)) {
			config_params[i].copy( arg1, config_params[i].conf_value );
			return;
		}
		i++;
        }

	fprintf( stderr, "Unkown config option: \"%s\"\n", cmd ); 
        return;
}

/************************************************************************
 * copy functions 
 *
 *   copy_bool   - convert a bool representation to int
 *   copy_int    - convert a string to int
 *   copy_string - just a string copy
 *   
 * @param str -   A char *, pointing to a string representation of the
 *                value.
 * @param value - points to the place where to store the value. 
************************************************************************/
static void copy_bool (char *str, void * val)
{
	if ( !strcmp(str, "1") || 
	     !strcasecmp(str, "yes") || 
	     !strcasecmp(str,"on")) 
	{
		*((int *)val) = 1;
	} else {
		*((int *)val) = 0;
	}
}
static void copy_int(char *str, void * val) {
	*((int *)val) = atoi(str);
}
static void copy_string(char *str, void * val) {
	*(char **)val=malloc(255);
	strncpy(*(char **)val, str, 255);	
}

static void usage (void)
{
        printf("motion Version "VERSION", Copyright 2000 Jeroen Vreeken\n");
        printf("\nusage:\tmotion [options]\n");
        printf("\n");
        printf("Overall settings:\n");
        printf("-C\t\tOutput changes count for every frame, usable for tuning\n");
        printf("-D\t\tDeamonize\n");
        printf("-a seconds\ttime between two automated snapshots, default: 0\n");
        printf("-c changes\tthreshold for detecting a change, default: %d\n", DEF_CHANGES);
	printf("-F file\t\tppm mask file to use as a motion filter.\n");
        printf("-f nr\t\tMaximum nr of frames per second, default: none\n");
	printf("-G sec\t\tMinimum gap between two shots in seconds, default: 0\n");
	printf("-L noise\tNoise level, default: %d\n", DEF_NOISELEVEL);
        printf("-l\t\tLocate and mark motion on output pictures\n");
        printf("-m\t\tOutput 'motion' images\n");
        printf("-N\t\tDon't output normal images\n");
	printf("-p\t\tOutput ppm images instead of jpeg, uses a lot of diskspace\n");
        printf("-t target dir\tdestination for snapshots.\n");
	printf("-Q\t\tBe quiet, don't output beeps when detecting motion\n");
        printf("\nDevice settings:\n");
        printf("-d device\tvideo4linux capture device, default: "VIDEO_DEVICE"\n");
        printf("-i input\tinput channel to use, default: not set\n");
        printf("-n norm\t\tnorm to use (pal/ntsc/secam), default: pal\n");
        printf("-q quality\tJPEG image quality, default: %d\n", DEF_QUALITY);
        printf("-s widthxheight\tPicture size, default: %dx%d\n", DEF_WIDTH, DEF_HEIGHT);
        printf("\nActions:\n");
        printf("-B\t\tEncode all jpg images to mpeg after a event using mpeg_encode\n");
        printf("-E command\tExecute 'command' when detecting motion.\n");
        printf("-M address\tSend a mail to 'address' when detecting motion.\n");
        printf("-S nr\t\tSend a SMS to nr using sms_client when detecting motion.\n");
        printf("-g seconds\tminimum gap between events, default %d\n", DEF_GAP);
        printf("\n");
}
                                                                                                                                                                                                                                                                                                                                                                                                                            