/*  MikMod example player
	(c) 1999 Miodrag Vallat and others - see file AUTHORS for
	complete list.

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.
 
	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.
 
	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the Free Software
	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
	02111-1307, USA.
*/

/*==============================================================================

  $Id: mconfedit.c,v 1.4 1999/07/11 17:50:08 miod Exp $

  The config editor

==============================================================================*/

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <ctype.h>

#include <mikmod.h>
#include "player.h"
#include "mconfedit.h"
#include "mmenu.h"

#define OPT_DRIVER      0
#if LIBMIKMOD_VERSION >= 0x030107
#define OPT_DRV_OPTION  1
#define OPT_STEREO      2
#define OPT_MODE_16BIT  3
#define OPT_FREQUENCY   4
#define OPT_INTERPOLATE 5
#define OPT_HQMIXER     6
#define OPT_SURROUND    7
#define OPT_REVERB      8
#else
#define OPT_STEREO      1
#define OPT_MODE_16BIT  2
#define OPT_FREQUENCY   3
#define OPT_INTERPOLATE 4
#define OPT_HQMIXER     5
#define OPT_SURROUND    6
#define OPT_REVERB      7
#endif

#define OPT_VOLUME      0
#define OPT_VOLRESTRICT 1
#define OPT_FADE        2
#define OPT_LOOP        3
#define OPT_PANNING     4
#define OPT_EXTSPD      5

#define OPT_PM_MODULE   0
#define OPT_PM_MULTI    1
#define OPT_PM_SHUFFLE  2
#define OPT_PM_RANDOM   3

#define OPT_CURIOUS     1
#define OPT_TOLERANT    2
#define OPT_FULLPATHS   3
#define OPT_RENICE      4
#define OPT_STATUSBAR   5

#define OPT_S_CONFIG    0
#define OPT_S_PLAYLIST  1

#define MENU_USE        4
#define MENU_SAVE       5
#define MENU_REVERT     6

static void handle_menu(MMENU *menu);

static MENTRY output_entries[]={
	{NULL,			0,"The device driver for output"},
#if LIBMIKMOD_VERSION >= 0x030107
	{"Driver &options [%s]|Enter driver options:|99|16",
					0,"Driver options (e.g. \"buffer=14,count=16\" for the OSS-driver)"},
#endif
	{"[%c] &Stereo",	0,"mono/stereo output"},
	{"[%c] 16 &bit output",0,"8/16 bit output"},
	{"&Frequency      [%d]|Enter mixing frequency:|4000|60000",
					0,"Mixing frequency in hertz (from 4000 Hz to 60000 Hz)"},
	{"[%c] &Interpolate",0,"Use interpolated mixing"},
	{"[%c] &HQmixer",0,"Use high-quality (but slower) software mixer"},
	{"[%c] S&urround",0,"Use surround mixing"},
	{"&Reverb            [%d]|Enter reverb amount:|0|15",
					0,"Reverb amount from 0 (no reverb) to 15"}};
static MMENU output_menu={0,0,
#if LIBMIKMOD_VERSION >= 0x030107
                              9,
#else
                              8,
#endif
                                1,output_entries,handle_menu,NULL,NULL,1};

static MENTRY playback_entries[]={
	{"&Volume   [%d]|Enter output volume:|0|100",
					0,"Output volume from 0 to 100 in %"},
	{"[%c] &Restrict Volume",0,
		"Restrict volume of player to volume supplied by user (with 1..0,<,>)"},
	{"[%c] &Fadeout",0,"Force volume fade at the end of module"},
	{"[%c] &Loops",	0,"Enable in-module loops"},
	{"[%c] &Panning",0,"Process panning effects"},
	{"[%c] Pro&tracker",0,"Use extended protracker effects"}};
static MMENU playback_menu={0,0,6,1,playback_entries,handle_menu,NULL,NULL,2};

static MENTRY plmode_entries[]={
	{"[%c] Loop &module",0,"Loop current module"},
	{"[%c] Loop &list",	0,"Play the list repeatedly"},
	{"[%c] &Shuffle list",0,"Shuffle list at start and when all entries are played"},
	{"[%c] List &random",0,"Play list in random order"}};
static MMENU plmode_menu={0,0,4,1,plmode_entries,handle_menu,NULL,NULL,4};

static MENTRY exit_entries[]={
	{"[%c] Save &config",0,NULL},
	{"[%c] Save &playlist",0,NULL}};
static MMENU exit_menu={0,0,2,1,exit_entries,handle_menu,NULL,NULL,5};

static MENTRY other_entries[]={
	{"&Playmode            >",&plmode_menu,"Playlist playing mode"},
	{"[%c] &Curious",	0,"Look for hidden patterns in module"},
	{"[%c] &Tolerant",	0,"Don't halt on file access errors"},
	{"[%c] &Full path",  0,"Display full path of files"},
	{"&Scheduling [%o]|Normal|Renice|Realtime",0,
				"Change process priority, MikMod must be restarted to change this"},
	{"Status&bar     [%o]|None|Small|Big",0,"Size of the statusbar"},
	{"&On exit             >",&exit_menu,""}};
static MMENU other_menu={0,0,7,1,other_entries,handle_menu,NULL,NULL,3};

static MENTRY entries[]={
	{"&Output options   >",&output_menu,""},
	{"&Playback options >",&playback_menu,""},
	{"O&ther options    >",&other_menu,""},
	{"-------------",	0,NULL},
	{"&Use config"	,	0,"Activate the edited configuration"},
	{"S&ave config"	,	0,"Save and activate the edited configuration"},
	{"R&evert config",	0,"Reset the configuration to the actual used one"}};
static MMENU menu={0,0,7,0,entries,handle_menu,NULL,NULL,0};

/* set help text of menu entry
 free old menu->help and malloc new entry */
void set_help(MENTRY* entry,char* str,...)
{
	va_list args;
	int len=0;

	if (entry->help) free(entry->help);
	va_start(args,str);
	vsprintf(storage,str,args);
	va_end(str);

	len=MIN(strlen(storage),STORAGELEN);
	entry->help=malloc(sizeof(char)*(len+1));
	strncpy(entry->help,storage,len);
	entry->help[len]='\0';
}

static char* skip_number(char *str)
{
	while (str &&(*str==' ')) str++;
	while (str && isdigit((int)*str)) str++;
	while (str &&(*str==' ')) str++;
	return str;
}

/* extract drivers for the option menu */
static void get_drivers(MENTRY *entry)
{
	char *driver=MikMod_InfoDriver(),*pos,*start;
	int len=0,x=0;
	BOOL end;

	for (pos=skip_number(driver);pos && *pos;pos++) {
		if (*pos=='\n') {
			if (x>35) x=35;
			len+=x;
			x=0;
			pos=skip_number(pos+1);
		}
		x++;
	}
	x--;
	if (*(pos-1)!='\n') len +=(x>=35?35:x);

	if (entry->text) free(entry->text);
	entry->text=malloc(sizeof(char)*(len+25));
	strcpy(entry->text,"&Driver [%o]|Autodetect");

	start=skip_number(driver);
	end=!(start && *start);
	for (pos=start;!end;pos++) {
		end=!*pos;
		if ((*pos=='\n')||(!(*pos)&& *(pos-1)!='\n')) {
			strcat(entry->text,"|");
			len=strlen(entry->text);

			/* don't embed text in braces or 'v#.#' in string */
			for (x=0;x<34 && start+x<=pos;x++) {
				if (*(start+x)=='(') break;
				if (((*(start+x))=='v')&&(isdigit((int)*(start+x+1)))) break;
			}
			while ((x>0)&&(*(start+x-1)==' ')) x--;

			strncat(entry->text,start,x);
			entry->text[len+x]='\0';
			pos=skip_number(pos+1);
			start=pos;
		}
	}
	free(driver);
}

static void config_set_config(CONFIG *config)
{
	output_entries[OPT_DRIVER].data=(void*)(long)config->driver;
#if LIBMIKMOD_VERSION >= 0x030107
	output_entries[OPT_DRV_OPTION].data=config->driveroptions;
#endif
	output_entries[OPT_STEREO].data=(void*)(long)config->stereo;
	output_entries[OPT_MODE_16BIT].data=(void*)(long)config->mode_16bit;
	output_entries[OPT_FREQUENCY].data=(void*)(long)config->frequency;
	output_entries[OPT_INTERPOLATE].data=(void*)(long)config->interpolate;
	output_entries[OPT_HQMIXER].data=(void*)(long)config->hqmixer;
	output_entries[OPT_SURROUND].data=(void*)(long)config->surround;
	output_entries[OPT_REVERB].data=(void*)(long)config->reverb;

	playback_entries[OPT_VOLUME].data=(void*)(long)config->volume;
	playback_entries[OPT_VOLRESTRICT].data=(void*)(long)config->volrestrict;
	playback_entries[OPT_FADE].data=(void*)(long)config->fade;
	playback_entries[OPT_LOOP].data=(void*)(long)config->loop;
	playback_entries[OPT_PANNING].data=(void*)(long)config->panning;
	playback_entries[OPT_EXTSPD].data=(void*)(long)config->extspd;

	plmode_entries[OPT_PM_MODULE].data=(void*)(long)BTST(config->playmode,PM_MODULE);
	plmode_entries[OPT_PM_MULTI].data=(void*)(long)BTST(config->playmode,PM_MULTI);
	plmode_entries[OPT_PM_SHUFFLE].data=(void*)(long)BTST(config->playmode,PM_SHUFFLE);
	plmode_entries[OPT_PM_RANDOM].data=(void*)(long)BTST(config->playmode,PM_RANDOM);
	other_entries[OPT_CURIOUS].data=(void*)(long)config->curious;
	other_entries[OPT_TOLERANT].data=(void*)(long)config->tolerant;
	other_entries[OPT_FULLPATHS].data=(void*)(long)config->fullpaths;
	other_entries[OPT_RENICE].data=(void*)(long)config->renice;
	other_entries[OPT_STATUSBAR].data=(void*)(long)config->statusbar;

	exit_entries[OPT_S_CONFIG].data=(void*)(long)config->save_config;
	exit_entries[OPT_S_PLAYLIST].data=(void*)(long)config->save_playlist;
}

static void config_get_config(CONFIG *config)
{
	config->driver=(long)output_entries[OPT_DRIVER].data;
#if LIBMIKMOD_VERSION >= 0x030107
	config->driveroptions=output_entries[OPT_DRV_OPTION].data;
#endif
	config->stereo=(BOOL)(long)output_entries[OPT_STEREO].data;
	config->mode_16bit=(BOOL)(long)output_entries[OPT_MODE_16BIT].data;
	config->frequency=(long)output_entries[OPT_FREQUENCY].data;
	config->interpolate=(BOOL)(long)output_entries[OPT_INTERPOLATE].data;
	config->hqmixer=(BOOL)(long)output_entries[OPT_HQMIXER].data;
	config->surround=(BOOL)(long)output_entries[OPT_SURROUND].data;
	config->reverb=(long)output_entries[OPT_REVERB].data;

	config->volume=(long)playback_entries[OPT_VOLUME].data;
	config->volrestrict=(BOOL)(long)playback_entries[OPT_VOLRESTRICT].data;
	config->fade=(BOOL)(long)playback_entries[OPT_FADE].data;
	config->loop=(BOOL)(long)playback_entries[OPT_LOOP].data;
	config->panning=(BOOL)(long)playback_entries[OPT_PANNING].data;
	config->extspd=(BOOL)(long)playback_entries[OPT_EXTSPD].data;

	config->playmode=
		(((BOOL)(long)plmode_entries[OPT_PM_MODULE].data)?PM_MODULE:0)|
		(((BOOL)(long)plmode_entries[OPT_PM_MULTI].data)?PM_MULTI:0)|
		(((BOOL)(long)plmode_entries[OPT_PM_SHUFFLE].data)?PM_SHUFFLE:0)|
		(((BOOL)(long)plmode_entries[OPT_PM_RANDOM].data)?PM_RANDOM:0);
	config->curious=(BOOL)(long)other_entries[OPT_CURIOUS].data;
	config->tolerant=(BOOL)(long)other_entries[OPT_TOLERANT].data;
	config->fullpaths=(BOOL)(long)other_entries[OPT_FULLPATHS].data;
	config->renice=(long)other_entries[OPT_RENICE].data;
	config->statusbar=(long)other_entries[OPT_STATUSBAR].data;

	config->save_config=(BOOL)(long)exit_entries[OPT_S_CONFIG].data;
	config->save_playlist=(BOOL)(long)exit_entries[OPT_S_PLAYLIST].data;
}

static void handle_menu(MMENU *menu)
{
	if (!menu->id) {
		switch (menu->cur) {
			case MENU_USE:
				config_get_config(&config);
				Player_SetConfig(&config);
				win_status("Configuration activated");
				break;
			case MENU_SAVE:
				config_get_config(&config);
				CF_Save(&config);
				Player_SetConfig(&config);
				win_status("Configuration saved and activated");
				break;
			case MENU_REVERT:
				config_set_config(&config);
				win_status("Changed configuration reseted");
				break;
		}
	}
}

/* open config editor */
void config_open(void)
{
	char *name=CF_GetFilename();
	set_help(&exit_entries[OPT_S_CONFIG],
			 "Save config at exit in '%s'",name);
	if (name) free(name);
	name=PL_GetFilename();
	set_help(&exit_entries[OPT_S_PLAYLIST],
			 "Save playlist at exit in '%s'",name);
	if (name) free(name);
	get_drivers(&output_entries[OPT_DRIVER]);

	config_set_config(&config);
	menu_open(&menu,5,5);
}

/* ex:set ts=4: */
