/***   [beep.c]
*
*	警告音 関連		(C)ささがわ
*
*	For GNU C Compiler (GCC)   Version 1.39
*
***/

#include <io.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dos.h>
#include <jstring.h>
#include "graph.h"
#include "mos.h"
#include "window.h"
#include "beep.h"
#include "others.h"
#include "icn.h"
#include "optparse.h"

#define WH_OTHER	0
#define WH_OCTM		1
#define WH_OCTP		10
#define WH_KEY		2
#define WH_VOLM		3
#define WH_VOLP		11
#define WH_VOL		12
#define WH_FILE		4
#define WH_EPCM		5
#define WH_EBEEP	6
#define WH_ENULL	7
#define WH_CAN		8
#define WH_TITLE	9

struct Par {
	void	*data;
	long	size;
	char	name[20];
	short	oct, ontei, onryo;
};

extern int	PAL_Black, PAL_Button;
static int	wx, wy;
static int	Mode, Pcm;
static struct Par	Main, Sub;

static void	Move(int, int);
static void	Draw_window(void);
static int	Where(int, int);
static void Set_name(const unsigned char *, char *);
static int	SUB_file(void);
static void	errord(void);
static void	Draw_oct(void);
static void	Draw_ontei(void);
static void	Draw_onryo(void);
static void	SUB_key(int, int);
static int	Where_key(int, int);
static void	Draw_mes(int);
static void	SUB_oct(int);
static int	SUB_oct_sub(int);
static void	Draw_volbar(void);
static void SUB_vol(int);
static int	SUB_vol_sub(int);
static void	SUB_voldr(int, int);
static int	Where_vol(int, int);
static void	pcm_enable(void);
static int	Settings(struct Par *, char *);

int BEP_init(void) {
	int		r = 0;
	char	path[90];
	
	if ((Mode = OPT_WarnS(path)) != 1)
		return 0;
	
	ICN_mos(1);
	Set_name((unsigned char *)path, Main.name);
	if (Settings(&Main, path)) {
		r = 1;
		Mode = 0;
		WIND_error(4, path);
	}
	ICN_mos(0);
	
	return r;
}

void BEP_on(void) {
	union REGS		regs;
	struct SREGS	sregs;
	
	switch (Mode) {
		case 1:
			if (SND_pcm_status(71))
				SND_pcm_play_stop(71);
			SND_pcm_play(71, Main.ontei, Main.onryo, Main.data);
			break;
		
		case 2:
			regs.h.ah = 0x02;
			int86x(0x9e, &regs, &regs, &sregs);
			break;
		
		default:
			break;
	}
}

int WIND_beep(void) {
	int		ret = 0;
	struct RECT	a, b;
	
	wx = 151;
	wy = 122;
	a.x1 = 319;	a.y1 = 259;
	a.x2 = 320;	a.y2 = 260;
	b.x1 = wx;	b.y1 = wy;
	b.x2 = wx + 337;	b.y2 = wy + 236;
	afterImage(&a, &b);
	
	if (Mode == 1) {
		Pcm = 1;
		Sub = Main;
		if ((Sub.data = malloc(Sub.size)) == NULL) {
			WIND_error(1, NULL);
			return -1;
		}
		memcpy(Sub.data, Main.data, Sub.size);
	} else {
		Pcm = 0;
		Sub.oct = 4;
		Sub.ontei = 60;
		Sub.onryo = 127;
		Sub.name[0] = '\0';
	}
	
	Draw_window();
	while (!ret) {
		char	mb;
		int		mx, my;
		
		CLOCK(0);
		if (MOS_rdpos(&mb, &mx, &my), !(mb & 1))
			continue;
		
		switch (Where(mx, my)) {
			case WH_CAN:
				if (Button(wx + 6, wy + 6, wx + 25, wy + 25))
					ret = 2;
				break;
			case WH_FILE:
				if (Button(wx + 195, wy + 138, wx + 308, wy + 155)) {
					if (SUB_file()) {
						Mode = 0;
						ret = -1;
					}
				}
				break;
			case WH_KEY:	SUB_key(mx, my);	break;
			case WH_OCTM:	SUB_oct(1);		break;
			case WH_OCTP:	SUB_oct(0);		break;
			case WH_VOLM:	SUB_vol(1);		break;
			case WH_VOLP:	SUB_vol(0);		break;
			case WH_VOL:	SUB_voldr(mx, my);	break;
			case WH_EPCM:
				if (!Pcm)	break;
				if (Button(wx + 25, wy + 198, wx + 102, wy + 219)) {
					void	*p;
					
					p = Main.data;
					Main = Sub;
					Sub.data = p;
					Mode = 1;
					ret = 1;
				}
				break;
			case WH_EBEEP:
				if (Button(wx + 130, wy + 198, wx + 207, wy + 219)) {
					free(Main.data);
					Main.data = NULL;
					Mode = 2;
					ret = 1;
				}
				break;
			case WH_ENULL:
				if (Button(wx + 235, wy + 198, wx + 312, wy + 219)) {
					free(Main.data);
					Main.data = NULL;
					Mode = 0;
					ret = 1;
				}
				break;
			case WH_TITLE:	Move(mx, my);	break;
			default:	while (MOS_rdpos(&mb, &mx, &my), mb & 1);	break;
		}
	}
	free(Sub.data);
	Sub.data = NULL;
	
	return (ret < 0 ? -1 : 0);
}

static void Move(int mx, int my) {
	struct RECT	s, w;
	
	w.x1 = wx;	w.y1 = wy;
	w.x2 = wx + 337;	w.y2 = wy + 236;
	s.x1 = 0;	s.y1 = 40;	s.x2 = 639;	s.y2 = 463;
	if (dragWindow(mx, my, &w, &s, 0, 0)) {
		wx = w.x1;	wy = w.y1;
		MOS_disp(0);
		EGB_cls(0);
		MOS_disp(1);
		Draw_window();
	}
}

static void Draw_window(void) {
	int		i, c;
	struct opnwin_t	opw;
	
	opw.title = "警  告  音";
	opw.x1 = wx;
	opw.y1 = wy;
	opw.x2 = opw.x1 + 337;
	opw.y2 = opw.y1 + 236;
	opw.shdw = 1;
	opw.canb = 1;
	opw.nopt = 0;
	opw.wopt = NULL;
	opw.expb = 0;
	opw.ord = 0;
	MOS_disp(0);
	drawWindow(&opw);
	
	EGB_str2("オクターブ", wx + 14, wy + 54, PAL_Black);
	DrawButton(1, wx + 102, wy + 37, wx + 121, wy + 56);
	EGB_box(wx + 121, wy + 37, wx + 140, wy + 56, PAL_Black);
	DrawButton(1, wx + 140, wy + 37, wx + 159, wy + 56);
	EGB_boxf(wx + 107, wy + 46, wx + 116, wy + 47, PAL_Black, PAL_Black);	/* - */
	EGB_boxf(wx + 145, wy + 46, wx + 154, wy + 47, PAL_Black, PAL_Black);	/* + */
	EGB_boxf(wx + 149, wy + 42, wx + 150, wy + 51, PAL_Black, PAL_Black);
	Draw_oct();
	
	for (i = 0; i < 7; i++)
		EGB_boxf(wx + i * 19 + 20, wy + 67, wx + i * 19 + 39, wy + 156, PAL_Black, 15);
	for (i = 0; i < 2; i++)
		EGB_boxf(wx + i * 21 + 31, wy + 67, wx + i * 21 + 45, wy + 116, PAL_Black, 8);
	for (i = 0; i < 3; i++)
		EGB_boxf(wx + i * 21 + 87, wy + 67, wx + i * 21 + 101, wy + 116, PAL_Black, 8);
	
	EGB_str2("音程 No.", wx + 180, wy + 54, PAL_Black);
	Draw_ontei();
	EGB_str2("音量", wx + 180, wy + 74, PAL_Black);
	Draw_onryo();
	
	EGB_str2("音量", wx + 180, wy + 104, PAL_Black);
	DrawButton(1, wx + 220, wy + 89, wx + 236, wy + 105);
	EGB_boxf(wx + 236, wy + 89, wx + 307, wy + 105, PAL_Black, 6);
	DrawButton(1, wx + 307, wy + 89, wx + 323, wy + 105);
	EGB_line(wx + 224, wy + 97, wx + 232, wy + 97, PAL_Black);	/* - */
	EGB_line(wx + 311, wy + 97, wx + 319, wy + 97, PAL_Black);	/* + */
	EGB_line(wx + 315, wy + 93, wx + 315, wy + 101, PAL_Black);
	Draw_volbar();
	
	EGB_str2("サウンドファイル名", wx + 180, wy + 134, PAL_Black);
	EGB_box(wx + 194, wy + 137, wx + 309, wy + 156, PAL_Black);
	EGB_str2(Sub.name, wx + 204, wy + 154, PAL_Black);
	
	c = Pcm ? PAL_Black : 7;
	DrawButton(1, wx + 24, wy + 197, wx + 103, wy + 220);
	for (i = 0; i < 2; i++)
		EGB_str2("Ｐ Ｃ Ｍ", wx + 32 + i, wy + 216, c);
	DrawButton(1, wx + 129, wy + 197, wx + 208, wy + 220);
	for (i = 0; i < 2; i++)
		EGB_str2("ＢＥＥＰ", wx + 137 + i, wy + 216, PAL_Black);
	DrawButton(1, wx + 234, wy + 197, wx + 313, wy + 220);
	for (i = 0; i < 2; i++)
		EGB_str2(" な  し ", wx + 242 + i, wy + 216, PAL_Black);
	
	MOS_disp(1);
	Draw_mes(0);
}

static int Where(int x, int y) {
	int		i, ret = WH_OTHER;
	static const short	tab[][5] = {
		{ 102, 121, 37, 56, WH_OCTM},	{ 140, 159, 37, 56, WH_OCTP},
		{ 20, 153, 67, 156, WH_KEY},	{ 220, 236, 89, 105, WH_VOLM},
		{ 236, 307, 89, 105, WH_VOL},	{ 307, 323, 89, 105, WH_VOLP},
		{ 194, 309, 137, 156, WH_FILE},	{ 24, 103, 197, 220, WH_EPCM},
		{ 129, 208, 197, 220, WH_EBEEP},{ 234, 313, 197, 220, WH_ENULL},
		{ 5, 26, 5, 26, WH_CAN},		{ 26, 332, 5, 26, WH_TITLE}
	};
	
	x -= wx;
	y -= wy;
	for (i = 0; i < 12; i++) {
		const short	*p = tab[i];
		
		if (p[0] < x && x < p[1] && p[2] < y && y < p[3]) {
			ret = p[4];
			break;
		}
	}
	
	return ret;
}

static void Set_name(const unsigned char *str, char *buf) {		/* ﾆﾎﾝｺﾞ ﾀｲｵｳ */
	int		i;
	unsigned char	a[100], *p;
	
	strcpy((char *)a, (const char *)str);
	p = a;
	while ((p = jstrchr(p, '\\')) != NULL)	*(p++) = '\x01b';
	
	for (i = strlen((char *)a) - 1; i > 0; i--) {
		if (a[i - 1] == '\x01b' || a[i - 1] == ':')
			break;
	}
	
	if (strlen((char *)a + i) > 12) {
		buf[0] = '\0';
		strncat(buf, (char *)a + i, strLE((char *)a + i, 12));
	} else
		strcpy(buf, (char *)a + i);
	strlow(1, (unsigned char *)buf);
}

static int SUB_file(void) {
	int		ret, res;
	char	path[85];
	
	MOS_disp(0);
	EGB_cls(0);
	MOS_disp(1);
	res = WIND_filesel("サウンドファイル", path);
	MOS_disp(0);
	EGB_cls(0);
	MOS_disp(1);
	
	switch (res) {
		case 1:
			ret = 0;
			if (SND_pcm_status(71))
				SND_pcm_play_stop(71);
			Set_name((unsigned char *)path, Sub.name);
			Draw_window();
			ICN_mos(1);
			if (Settings(&Sub, path)) {
				ICN_mos(0);
				errord();
				break;
			}
			MOS_disp(0);
			Draw_oct();
			Draw_ontei();
			MOS_disp(1);
			pcm_enable();
			ICN_mos(0);
			break;
		case -1:	ret = -1;	break;
		default:
			Draw_window();
			ret = 0;
			break;
	}
	
	return ret;
}

static void errord(void) {
	int		i;
	
	Draw_mes(1);
	MOS_disp(0);
	for (i = 0; i < 2; i++)
		EGB_str2("Ｐ Ｃ Ｍ", wx + 32 + i, wy + 216, 7);
	MOS_disp(1);
	Pcm = 0;
	return;
}

static void pcm_enable(void) {
	int		i;
	
	Draw_mes(0);
	MOS_disp(0);
	for (i = 0; i < 2; i++)
		EGB_str2("Ｐ Ｃ Ｍ", wx + 32 + i, wy + 216, PAL_Black);
	MOS_disp(1);
	Pcm = 1;
	return;
}

static void Draw_oct(void) {
	unsigned char	buf[5];
	unsigned short	code;
	
	code = Sub.oct + 0x824f;
	buf[0] = (code >> 8) & 0xff;
	buf[1] = code & 0xff;
	buf[2] = '\0';
	EGB_str3((char *)buf, wx + 123, wy + 54, PAL_Black, 7);
}

static void Draw_ontei(void) {
	char	buf[5];
	
	sprintf(buf, "%3d", Sub.ontei);
	EGB_str3(buf, wx + 252, wy + 54, PAL_Black, 7);
}

static void Draw_onryo(void) {
	char	buf[5];
	
	sprintf(buf, "%3d", Sub.onryo);
	EGB_str3(buf, wx + 252, wy + 74, PAL_Black, 7);
}

static void Draw_volbar(void) {
	int		i;
	
	i = wx + Sub.onryo * 55 / 127 + 244;
	if (i - 7 > wx + 237)
		EGB_boxf(wx + 237, wy + 90, i - 8, wy + 104, 6, 6);
	DrawButton(0, i - 7, wy + 90, i + 7, wy + 104);
	if (i + 7 < wx + 306)
		EGB_boxf(i + 8, wy + 90, wx + 306, wy + 104, 6, 6);
}

static void SUB_key(int x, int y) {
	int		wh, d, fl;
	char	mb;
	
	if (!Pcm)	return;
	ICN_mos(2);
	wh = Where_key(x, y);
	Sub.ontei = (Sub.oct - 1) * 12 + 24 + wh;
	Draw_ontei();
	if (SND_pcm_mode_set(71))
		SND_pcm_play_stop(71);
	switch (SND_pcm_play(71, Sub.ontei, Sub.onryo, Sub.data)) {
		case 6:
		case 8:
		case 9:		Draw_mes(2);	break;
		case 11:	Draw_mes(3);	break;
		default:	Draw_mes(0);	break;
	}
	fl = 1;
	while (MOS_rdpos(&mb, &d, &d), mb & 1) {
		if (fl && !SND_pcm_status(71)) {
			ICN_mos(0);
			fl = 0;
		}
	}
	ICN_mos(0);
}

static int Where_key(int x, int y) {
	int		i;
	
	x -= (wx + 20);
	y -= (wy + 67);
	
	for (i = 0; i < 2; i++) {
		if (i * 21 + 11 < x && x < i * 21 + 25 && 0 < y && y < 49)
			return (i * 2 + 1);
	}
	for (i = 0; i < 3; i++) {
		if (i * 21 + 67 < x && x < i * 21 + 81 && 0 < y && y < 49)
			return (i * 2 + 6);
	}
	for (i = 0; i < 3; i++) {
		if (i * 19 < x && x < (i + 1) * 19 && 0 < y && y < 89)
			return (i * 2);
	}
	for (i = 0; i < 4; i++) {
		if (i * 19 + 57 < x && x < (i + 1) * 19 + 57 && 0 < y && y < 89)
			return (i * 2 + 5);
	}
	
	return -1;
}

static void Draw_mes(int no) {
	int		i;
	static const char	mes[][38] = {
		"上記の設定は、ＰＣＭでのみ有効です",
		"サウンドの読み込みに失敗しました",
		"サウンドデータに異常があります",
	};
	
	if (no < 0 || 2 < no)
		return;
	i = wx + 6 + (326 - strlen(mes[no]) * 8) / 2;
	
	MOS_disp(0);
	EGB_boxf(wx + 6, wy + 167, i - 1, wy + 186, 7, 7);
	EGB_str3(mes[no], i, wy + 184, PAL_Black, 7);
	EGB_boxf(i + strlen(mes[no]) * 8, wy + 167, wx + 331, wy + 186, 7, 7);
	MOS_disp(1);
}

static void SUB_oct(int m) {
	int		flpush = 1, fllast;
	int		mx, my, lx, ly;
	char	mb;
	
	lx = wx + (m ? 103 : 141);
	ly = wy + 38;
	
	EGB_rev(1, lx, ly, lx + 17, ly + 17);
	fllast = SUB_oct_sub(m);
	TIMER_set(20);
	
	while (MOS_rdpos(&mb, &mx, &my), mb & 1) {
		int		whres;
		
		whres = Where(mx, my) == (m ? WH_OCTM : WH_OCTP);
		if (!whres && flpush || whres && !flpush) {
			EGB_rev(1, lx, ly, lx + 17, ly + 17);
			flpush = !flpush;
		}
		
		if (flpush && TIMER() && !fllast) {
			fllast = SUB_oct_sub(m);
			TIMER_set(20);
		}
	}
	
	if (flpush)
		EGB_rev(1, lx, ly, lx + 17, ly + 17);
}

static int SUB_oct_sub(int m) {
	int		result = 1;
	
	if (m && Sub.oct > 1 || !m && Sub.oct < 8) {
		m ? Sub.oct-- : Sub.oct++;
		MOS_disp(0);
		Draw_oct();
		MOS_disp(1);
		result = 0;
	}
	
	return result;
}

static void SUB_vol(int m) {
	int		flpush = 1, fllast, lx, ly;
	int		mx, my;
	char	mb;
	
	lx = wx + (m ? 221 : 308);
	ly = wy + 90;
	
	EGB_rev(1, lx, ly, lx + 14, ly + 14);
	fllast = SUB_vol_sub(m);
	TIMER_set(20);
	
	while (MOS_rdpos(&mb, &mx, &my), mb & 1) {
		int		whres;
		
		whres = Where(mx, my) == (m ? WH_VOLM : WH_VOLP);
		if (!whres && flpush || whres && !flpush) {
			EGB_rev(1, lx, ly, lx + 14, ly + 14);
			flpush = !flpush;
		}
		
		if (flpush && TIMER() && !fllast)
			fllast = SUB_vol_sub(m);
	}
	
	if (flpush)
		EGB_rev(1, lx, ly, lx + 14, ly + 14);
}

static int SUB_vol_sub(int m) {
	int		result = 1;
	
	if (m && Sub.onryo > 0 || !m && Sub.onryo < 127) {
		m ? Sub.onryo-- : Sub.onryo++;
		MOS_disp(0);
		Draw_volbar();
		Draw_onryo();
		MOS_disp(1);
		result = 0;
	}
	
	return result;
}

static void SUB_voldr(int x, int y) {
	int		wh;
	char	mb;
	
	if ((wh = Where_vol(x, y)) < 0)
		return;
	
	ICN_mos(3);
	Sub.onryo = wh * 127 / 55;
	MOS_disp(0);
	Draw_volbar();
	Draw_onryo();
	MOS_disp(1);
	
	while (MOS_rdpos(&mb, &x, &y), mb & 1) {
		if ((wh = Where_vol(x, y)) < 0)
			continue;
		
		wh = wh * 127 / 55;		/* NOT wh *= 127 / 55 */
		if (wh != Sub.onryo) {
			wh < Sub.onryo ? Sub.onryo-- : Sub.onryo++;
			MOS_disp(0);
			Draw_volbar();
			Draw_onryo();
			MOS_disp(1);
		}
	}
	ICN_mos(0);
}

static int Where_vol(int x, int y) {
	int		ret;
	
	if (Where(x, y) != WH_VOL) {
		ret = -1;
	} else {
		ret = x - (wx + 244);
		if (ret < 0)
			ret = 0;
		else if (ret > 55)
			ret = 55;
	}
	
	return ret;
}

static int Settings(struct Par *p, char *path) {
	FILE	*fp;
	
	free(p->data);
	p->data = NULL;
	if ((fp = fopen(path, "rb")) == NULL)
		return 1;
	if ((p->size = filelength(fileno(fp))) <= 32) {
		fclose(fp);
		return 2;
	}
	if ((p->data = malloc(p->size)) == NULL) {
		fclose(fp);
		return 3;
	}
	clearerr(fp);
	fread(p->data, 1, p->size, fp);
	if (ferror(fp) || feof(fp)) {
		fclose(fp);
		free(p->data);
		p->data = NULL;
		return 1;
	}
	if (p->size < *((unsigned long *)((char *)p->data + 12)) + 32) {
		fclose(fp);
		free(p->data);
		p->data = NULL;
		return 2;
	}
	fclose(fp);
	
	p->ontei = *((unsigned char *)p->data + 28);
	if (p->ontei < 24 || 119 < p->ontei)	p->ontei = 60;
	p->oct = (p->ontei - 24) / 12 + 1;
	p->onryo = 127;
	
	return 0;
}
