/***   [txwind.c]
*
*	テキストウィンドウ 関連		(C)ささがわ
*
*	For GNU C Compiler (GCC)   Version 1.39
*
***/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <jctype.h>
#include <mos.h>
#include "graph.h"
#include "icn.h"
#include "window.h"
#include "windmgr.h"
#include "txwind.h"
#include "others.h"
#include "disp.h"
#include "roll.h"

#define WH_CAN		0		/* ｷｬﾝｾﾙ ﾎﾞﾀﾝ */
#define WH_TITLE	1		/* ﾀｲﾄﾙ */
#define WH_SCVRW	2		/* 垂直ｽｸﾛｰﾙ後 */
#define WH_SCVFF	3		/* 垂直ｽｸﾛｰﾙ前 */
#define WH_SCHRW	4		/* 水平ｽｸﾛｰﾙ後 */
#define WH_SCHFF	5		/* 水平ｽｸﾛｰﾙ前 */
#define WH_BSCV		6		/* 垂直ﾊﾞｰ ｽｸﾛｰﾙ */
#define WH_BSCH		7		/* 水平ﾊﾞｰ ｽｸﾛｰﾙ */
#define WH_EXP		8		/* 拡大・縮小ﾎﾞﾀﾝ */
#define WH_OPT1		9		/* 位置戻りｵﾌﾟｼｮﾝ */
#define WH_OPT2		10		/* 表示属性変更ｵﾌﾟｼｮﾝ */
#define WH_MOJI		11		/* ﾃｷｽﾄ表示領域 */
#define WH_OTHER	-1		/* その他 */

extern int	PAL_MOJI, PAL_Back, PAL_Black;
static int	Xx1, Yy1, Xx2, Yy2, Wx, Wy;
static int	Vw, Hw, Scspd = 2, Vg, Hg;
static struct	txinfo_t	*Info;

static void	SUB_recall(void);
static void	Winsize_change_sub(struct txinfo_t *, int);
static void	SUB_move(int, int);
static void	SUB_close(void);
static int	Where(int, int);
static void	SUB_enlarge(int, int);
static void	Draw_window(char *, int, int, int, int);
static void	SUB_scya(int);
static int	SUB_scya_roll(int);
static void	SUB_scya_bar(int);
static void	Draw_scrollV(void);
static void	Draw_scrollH(void);
static void	SUB_scdr(int, int, int);
static void	SUB_dragScroll(void);
static void	SeigouV(void);
static void	SeigouH(void);
static int	SCROLL(int);
static void	SUB_dispchange(void);

/* ｳｨﾝﾄﾞｳ･ｵｰﾌﾟﾝ m:1のとき文字のみ描画   wxx,wyy:ｽｸﾘｰﾝ･ｵﾌｾｯﾄ */
void TXW_open(int m, int wxx, int wyy) {
	int		x1, y1, x2, y2;
	char	str[80];
	struct RECT		pl;
	
	/* ｸﾞﾛｰﾊﾞﾙ変数ｾｯﾄ */
	Wx = wxx;	Wy = wyy;
	Info = (struct txinfo_t *)WMGR_inf(-1);
	WMGR_cord(-1, &pl);
	Xx1 = pl.x1;	Yy1 = pl.y1;
	Xx2 = pl.x2;	Yy2 = pl.y2;
	
	Vg = Info->fontx + Info->linegap;
	Hg = Info->fontx / 2;
	Vw = (Yy2 - Yy1 - 52 + Info->linegap) / Vg;
	Hw = (Xx2 - Xx1 - 31) / Hg;
	
	if (!m) {
		Cont_path(Info->name, (Xx2 - Xx1 - 122) / 8, str);
		Draw_window(str, Xx1, Yy1, Xx2, Yy2);
	}
	
	x1 = Xx1 + 8;
	y1 = Yy1 + 29;
	x2 = x1 + Hw * Hg - 1;
	y2 = y1 + Vw * Vg - Info->linegap - 1;
	ROL_init(Info, x1 - Wx, y1 - Wy, x2 - Wx, y2 - Wy);
	MOS_disp(0);
	EGB_boxf(x1, y1, x2, y2, 0, 0);
	MOS_disp(1);
	if (!m) {
		Draw_scrollV();
		Draw_scrollH();
	}
}

/* ｳｨﾝﾄﾞｳ･ｸﾛｰｽﾞ */
void TXW_close(void) {
	ROL_end(Wy, Xx1 + 8, Yy1 + 29);
}

/* 番号指定ｳｨﾝﾄﾞｳ･ｵｰﾌﾟﾝ nw:ｳｨﾝﾄﾞｳNo. */
void TXW_draw(int nw) {
	int		i, pVw, pHw, pVg;
	int		pxx1, pyy1, pxx2, pyy2;
	unsigned char	str[80];
	struct bmgr_t	bm;
	struct txinfo_t	*pInfo;
	struct RECT		c;
	
	pxx1 = Xx1;	pyy1 = Yy1;
	pxx2 = Xx2;	pyy2 = Yy2;
	pVw = Vw;	pHw = Hw;
	pInfo = Info;
	
	Info = (struct txinfo_t *)WMGR_inf(nw);
	pVg = Info->fontx + Info->linegap;
	WMGR_cord(nw, &c);
	Xx1 = c.x1;	Yy1 = c.y1;
	Xx2 = c.x2;	Yy2 = c.y2;
	
	Cont_path(Info->name, (Xx2 - Xx1 - 122) / 8, (char *)str);
	Draw_window((char *)str, Xx1, Yy1, Xx2, Yy2);
	
	Hw = (Xx2 - Xx1 - 31) / (Info->fontx / 2);
	Vw = (Yy2 - Yy1 - 52 + Info->linegap) / pVg;
	bm.tabm = Info->tabd;	bm.crm = Info->crd;
	bm.fs = &Info->file;
	bm.l = Info->col;
	bm.r = Info->col + Hw - 1;
	bm.tab = Info->tab;
	MOS_disp(0);
	for (i = 0; i < Vw && i + Info->line < Info->file.line; i++) {
		bm.line = i + Info->line;
		BMGR_String(&bm, str);
		EGB_str3((char *)str, Xx1 + 8, Yy1 + 44 + i * pVg, PAL_MOJI, PAL_Back);
	}
	MOS_disp(1);
	Draw_scrollV();
	Draw_scrollH();
	
	Xx1 = pxx1;
	Yy1 = pyy1;
	Xx2 = pxx2;
	Yy2 = pyy2;
	Vw = pVw;
	Hw = pHw;
	Info = pInfo;
}

/* ﾃｷｽﾄ･ｳｨﾝﾄﾞｳ ﾒｲﾝ関数 x,y:ﾏｳｽ座標 */
void TXW_main(int x, int y) {
	int		wh, mx, my;
	char	mb;
	
	switch (wh = Where(x, y)) {
		case WH_TITLE:	SUB_move(x, y);		break;
		case WH_CAN:	SUB_close();		break;
		case WH_EXP:	SUB_enlarge(x, y);	break;
		case WH_OPT1:	SUB_recall();		break;
		case WH_OPT2:	SUB_dispchange();	break;
		case WH_SCVRW:
		case WH_SCVFF:
		case WH_SCHRW:
		case WH_SCHFF:	SUB_scya(wh - WH_SCVRW);	break;
		case WH_BSCV:
		case WH_BSCH:	SUB_scdr(WH_BSCH - wh, x, y);	break;
		case WH_MOJI:	SUB_dragScroll();	break;
		case WH_OTHER:	while (MOS_rdpos(&mb, &mx, &my), mb & 1);	break;
	}
}

static void SUB_dispchange(void) {
	int		x, y, r;
	
	if (!Button(Xx2 - 46, Yy1 + 6, Xx2 - 27, Yy1 + 25))
		return;
	
	x = Xx2 - 210 - Wx;	y = Yy1 + 32 - Wy;
	if (x + 348 > 639)	x = 639 - 348;
	if (y + 214 > 479)	y = 479 - 214;
	TXW_close();
	Xpage(0, Wx, Wy);
	r = WIND_disp(0, Info, x, y);
	Xpage(1, Wx, Wy);
	EGB_rev(1, Xx2 - 46, Yy1 + 6, Xx2 - 27, Yy1 + 25);
	if (r & 20) {
		int		a;
		
		a = Info->lgcolw ? (Xx2 - Xx1 - 31) / (Info->fontx / 2) : Info->lgcol;
		BMGR_change(a, Info->tab, &Info->file, &Info->line);
		if (Info->col >= a)	Info->col = a - 1;
		TXW_open(0, Wx, Wy);
	} else
		TXW_open(r & 8 ? 0 : 1, Wx, Wy);
}

static void SUB_recall(void) {
	struct RECT	w;
	
	if (!Button(Xx2 - 25, Yy1 + 6, Xx2 - 6, Yy1 + 25))
		return;
	
	WMGR_pcord(-1, &w);
	if (w.x1 < Wx || Wx + 639 < w.x2 || w.y1 < Wy + 40 || Wy + 479 < w.y2) {
		int		a;
		struct txinfo_t	*inf;
		
		a = WMGR_cWind();
		WMGR_vanish(-2, Wx, Wy);
		WMGR_change(a, &w);
		inf = WMGR_inf(a);
		Winsize_change_sub(inf, (w.x2 - w.x1 - 31) / (inf->fontx / 2));
		TXW_draw(a);
	} else {
		WMGR_vanish(-1, Wx, Wy);
		WMGR_change(-1, &w);
		Winsize_change_sub(Info, (w.x2 - w.x1 - 31) / (Info->fontx / 2));
		TXW_open(0, Wx, Wy);
	}
}

static void Winsize_change_sub(struct txinfo_t *inf, int b) {
	if (inf->lgcolw)
		BMGR_change(b, inf->tab, &inf->file, &inf->line);
	else {
		if (inf->col >= (inf->lgcolw ? b : inf->lgcol))
			inf->col = (inf->lgcolw ? b : inf->lgcol) - 1;
	}
}

static void SUB_close(void) {
	if (!Button(Xx1 + 6, Yy1 + 6, Xx1 + 25, Yy1 + 25))
		return;
	
	free(Info->file.buf1);
	free(Info->file.buf2);
	WMGR_vanish(-1, Wx, Wy);
	WMGR_unregi(-1);
}

/* ｳｨﾝﾄﾞｳ移動関数   mx,my:ﾏｳｽ座標 */
static void SUB_move(int mx, int my) {
	struct RECT	w, s;
	
	w.x1 = Xx1;	w.y1 = Yy1;	w.x2 = Xx2;	w.y2 = Yy2;
	s.x1 = Wx;	s.y1 = Wy + 40;	s.x2 = Wx + 639;	s.y2 = Wy + 479;
	if (dragWindow(mx, my, &w, &s, Wx, Wy)) {
		WMGR_vanish(-1, Wx, Wy);
		WMGR_change(-1, &w);
		TXW_open(0, Wx, Wy);
	}
}

/* ﾏｳｽ･ｶｰｿﾙの場所を識別する関数   x,y:ﾏｳｽ座標 */
static int Where(int x, int y) {
	int		i, wh = WH_OTHER;
	const short	*p;
	static const short	t[][9] = {
		{26, -47, 5, 26, 0, 1, 0, 0, WH_TITLE},
		{5, 26, 5, 26, 0, 0, 0, 0, WH_CAN},
		{-21, -5, -21, -5, 1, 1, 1, 1, WH_EXP},
		{-26, -5, 5, 26, 1, 1, 0, 0, WH_OPT1},
		{-47, -26, 5, 26, 1, 1, 0, 0, WH_OPT2},
		{-21, -5, 26, 42, 1, 1, 0, 0, WH_SCVRW},
		{-21, -5, -37, -21, 1, 1, 1, 1, WH_SCVFF},
		{5, 21, -21, -5, 0, 0, 1, 1, WH_SCHRW},
		{-37, -21, -21, -5, 1, 1, 1, 1, WH_SCHFF},
		{-21, -5, 42, -37, 1, 1, 0, 1, WH_BSCV},
		{21, -37, -21, -5, 0, 1, 1, 1, WH_BSCH},
		{8, -24, 28, -24, 0, 1, 0, 1, WH_MOJI}
	};
	
	for (i = 0; i < 12; i++) {
		p = t[i];
		if (p[0] + (p[4] ? Xx2 : Xx1) < x && x < p[1] + (p[5] ? Xx2 : Xx1)
			&& p[2] + (p[6] ? Yy2 : Yy1) < y && y < p[3] + (p[7] ? Yy2 : Yy1)) {
			wh = p[8];
			break;
		}
	}
	
	return wh;
}

int TXW_regi(const char *path, struct txinfo_t **tx, int x1, int x2) {
	int		r;
	struct filestore_t	fl;
	
	if ((*tx = malloc(sizeof(struct txinfo_t))) == NULL)
		return -1;
	
	DSP_set(*tx);
	strcpy((*tx)->name, path);
	if (r = BMGR_set(path, (*tx)->lgcolw ? (x2 - x1 - 31) / ((*tx)->fontx / 2) : (*tx)->lgcol, (*tx)->tab, &fl)) {
		free(*tx);
		return r;
	}
	(*tx)->file = fl;
	
	return 0;
}

static void SUB_enlarge(int x, int y) {
	int		px, py, mx, my, a, b;
	char	mb;
	struct RECT	w;
	
	a = Xx2 - x;	b = Yy2 - y;
	EGB_writeMode(EGB_work, 4);
	MOS_horizon(Xx1 - a + 266, Wx - a + 639);
	MOS_vertical(Yy1 - b + 95, Wy - b + 479);
	
	ICN_mos(4);
	MOS_disp(0);
	EGB_box(Xx1, Yy1, Xx2, Yy2, 15);
	MOS_disp(1);
	px = mx = x;	py = my = y;
	do {
		if (px == mx && py == my)
			continue;
		
		MOS_disp(0);
		EGB_box(Xx1, Yy1, px + a, py + b, 15);
		EGB_box(Xx1, Yy1, mx + a, my + b, 15);
		MOS_disp(1);
		px = mx;	py = my;
	} while (MOS_rdpos(&mb, &mx, &my), mb & 1);
	MOS_disp(0);
	EGB_box(Xx1, Yy1, px + a, py + b, 15);
	MOS_disp(1);
	EGB_writeMode(EGB_work, 0);
	MOS_horizon(Wx, Wx + 639);
	MOS_vertical(Wy, Wy + 479);
	ICN_mos(0);
	if (px == x && py == y)
		return;
	
	if (x > px || y > py)
		WMGR_vanish(-1, Wx, Wy);
	w.x1 = Xx1;	w.y1 = Yy1;
	w.x2 = px + a;	w.y2 = py + b;
	WMGR_change(-1, &w);
	Winsize_change_sub(Info, (px + a - Xx1 - 31) / (Info->fontx / 2));
	TXW_open(0, Wx, Wy);
}

static void Draw_window(char *t, int x1, int y1, int x2, int y2) {
	struct opnwin_t	ot;
	static const int	optw[] = {
		2, 2
	};
	
	ot.title = t;
	ot.x1 = x1;
	ot.y1 = y1;
	ot.x2 = x2;
	ot.y2 = y2;
	ot.canb = 1;
	ot.nopt = 2;
	ot.wopt = optw;
	ot.expb = 1;
	ot.shdw = 0;
	ot.ord = 1;
	
	MOS_disp(0);
	drawWindow(&ot);
	ICN_opt(0, x2 - 23, y1 + 8);
	EGB_str2("★", x2 - 44, y1 + 23, PAL_Black);
	MOS_disp(1);
}

static void SUB_scya(int mode) {
	int		lx, ly, flpush = 1, fllast;
	int		mx, my;
	char	mb;
	
	switch (mode) {
		case 0:	lx = Xx2 - 20;	ly = Yy1 + 27;	break;
		case 1:	lx = Xx2 - 20;	ly = Yy2 - 36;	break;
		case 2:	lx = Xx1 + 6;	ly = Yy2 - 20;	break;
		default:	lx = Xx2 - 36;	ly = Yy2 - 20;	break;
	}
	
	TIMER_set(20);
	EGB_rev(1, lx, ly, lx + 14, ly + 14);
	if (fllast = SUB_scya_roll(mode))
		SUB_scya_bar(mode);
	
	while (MOS_rdpos(&mb, &mx, &my), mb & 1) {
		int		whres;
		
		whres = Where(mx, my) == mode + WH_SCVRW;
		if (whres && !flpush || !whres && flpush) {
			EGB_rev(1, lx, ly, lx + 14, ly + 14);
			flpush = !flpush;
			if (!flpush && !fllast)
				SUB_scya_bar(mode);
		}
		
		if (flpush && TIMER() && !fllast) {
			if (fllast = SUB_scya_roll(mode))
				SUB_scya_bar(mode);
		}
	}
	
	if (!fllast)
		SUB_scya_bar(mode);
	if (flpush)
		EGB_rev(1, lx, ly, lx + 14, ly + 14);
}

static int SUB_scya_roll(int mode) {
	int		result;
	
	switch (mode) {
		case 0:		result = SCROLL(0);		break;
		case 1:		result = SCROLL(1);		break;
		case 2:		result = ROL_horizon(-Hg);	break;
		default:	result = ROL_horizon(Hg);	break;
	}
	
	return result;
}

static int SCROLL(int d) {
	int		r = 0, i = 1, a, b = 0;
	static const short	tab[] = {
		1, 2, 4, 9, 20
	};
	
	for (; i <= tab[Scspd]; i++) {
		a = (10 * Vg * i / tab[Scspd] + 5) / 10;
		if (r = ROL_vertical(d ? a - b : b - a))
			break;
		b = a;
	}
	
	return r;
}

static void SUB_scya_bar(int mode) {
	switch (mode) {
		case 0:	case 1:		Draw_scrollV();	break;
		case 2:	default:	Draw_scrollH();	break;
	}
}

static void Draw_scrollV(void) {
	int		xx, yy, bar, u, l;
	struct sb_t	sb;
	
	xx = Xx2 - 20;
	yy = Yy1 + 43;
	
	bar = Yy2 - Yy1 - 80;
	sb.tl = Info->file.line;	sb.lpp = Vw;
	sb.blen = bar;	sb.bml = 15;
	SCRB_page(&sb, Info->line, &u, &l);
	
	MOS_disp(0);
	if (u > 0)
		EGB_boxf(xx, yy, xx + 14, yy + u - 1, 6, 6);
	DrawButton(0, xx, yy + u, xx + 14, yy + l);
	if (l < bar - 1)
		EGB_boxf(xx, yy + l + 1, xx + 14, yy + bar - 1, 6, 6);
	MOS_disp(1);
}

static void Draw_scrollH(void) {
	int		xx, yy, bar, u, l;
	struct sb_t	sb;
	
	xx = Xx1 + 22;
	yy = Yy2 - 20;
	
	bar = Xx2 - Xx1 - 59;
	sb.tl = Info->lgcolw ? Hw : Info->lgcol;	sb.lpp = Hw;
	sb.blen = bar;	sb.bml = 15;
	SCRB_page(&sb, Info->col, &u, &l);
	
	MOS_disp(0);
	if (u > 0)
		EGB_boxf(xx, yy, xx + u - 1, yy + 14, 6, 6);
	DrawButton(0, xx + u, yy, xx + l, yy + 14);
	if (l < bar - 1)
		EGB_boxf(xx + l + 1, yy, xx + bar - 1, yy + 14, 6, 6);
	MOS_disp(1);
}

void TXW_rollset(int a) {
	Scspd = a;
}

static void SUB_scdr(int mode, int mx, int my) {
	int		flpush = 1, fldir = 0, t;
	char	mb;
	struct sb_t	sb;
	
	ICN_mos(3);
	t = mode ? Yy1 + 43 : Xx1 + 22;
	sb.tl = mode ? Info->file.line : Info->lgcolw ? Hw : Info->lgcol;
	sb.lpp = mode ? Vw : Hw;
	sb.blen = mode ? Yy2 - Yy1 - 79 : Xx2 - Xx1 - 58;	sb.bml = 15;
	SCRB_bar(&sb, (mode ? my : mx) - t, mode ? &Info->line : &Info->col);
	
	mode ? Draw_scrollV() : Draw_scrollH();
	ROL_init(Info, Xx1 + 8 - Wx, Yy1 + 29 - Wy, Xx1 + 7 + Hw * Hg - Wx, Yy1 + 28 + Vw * Vg - Info->linegap - Wy);
	
	while (MOS_rdpos(&mb, &mx, &my), mb & 1) {
		int		a, b, f;
		
		if (Where(mx, my) != (mode ? WH_BSCV : WH_BSCH)) {
			if (flpush) {
				fldir = 0;	flpush = 0;
				mode ? Draw_scrollV() : Draw_scrollH();
			}
			continue;
		}
		
		flpush = 1;
		SCRB_bar(&sb, (mode ? my : mx) - t, &a);
		if ((b = mode ? Info->line : Info->col) > a) {
			mode ? SCROLL(0) : ROL_horizon(-Hg);
			f = 1;
		} else if (b < a) {
			mode ? SCROLL(1) : ROL_horizon(Hg);
			f = -1;
		} else
			f = 0;
		
		if (fldir != f) {
			fldir = f;
			mode ? Draw_scrollV() : Draw_scrollH();
		}
	}
	mode ? Draw_scrollV() : Draw_scrollH();
	ICN_mos(0);
}

static void SUB_dragScroll(void) {
	int		mx, my, xx, yy;
	int		w = 0, flsc = 1;
	char	mb;
	
	ICN_mos(3);
	MOS_motion(&xx, &yy);		/* Initialize */
	do {
		if (MOS_motion(&xx, &yy), !xx && !yy)
			continue;
		
		if (abs(xx) > abs(yy)) {
			if (flsc)
				SeigouV();
			flsc = 0;
			w = -xx;
		} else {
			if (!flsc)
				SeigouH();
			flsc = 1;
			w = -yy;
		}
		if (abs(w) > (flsc ? Vg : Hg)) {
			w = flsc ? Vg : Hg;
			if ((flsc ? -yy : -xx) < 0)
				w *= -1;
		}
		flsc ? ROL_vertical(w) : ROL_horizon(w);
	} while (MOS_rdpos(&mb, &mx, &my), mb & 1 && Where(mx, my) == WH_MOJI);
	ICN_mos(0);
	
	if (xx || yy) {
		int		a;
		
		if (Where(mx, my) != WH_MOJI) {
			do {
				a = flsc ? ROL_vertical(w) : ROL_horizon(w);
			} while (MOS_rdpos(&mb, &mx, &my), mb & 1 && !a);
			if (a) {
				Draw_scrollV();
				Draw_scrollH();
				while (MOS_rdpos(&mb, &mx, &my), mb & 1);
			}
		}
		
		do {
			a = flsc ? ROL_vertical(w) : ROL_horizon(w);
		} while (MOS_rdpos(&mb, &mx, &my), !(mb & 1) && !a);
		if (Info->_line)
			flsc ? ROL_vertical(w < 0 ? Info->_line : Vg - Info->_line) :
				ROL_horizon(w < 0 ? Info->_col : Hg - Info->_col);
	} else {
		flsc ? SeigouV() : SeigouH();
	}
	
	Draw_scrollV();
	Draw_scrollH();
}

/* 垂直方向 整合 */
static void SeigouV(void) {
	if (0 < Info->_line && Info->_line < Vg / 2)
		ROL_vertical(-Info->_line);
	else if (Vg / 2 <= Info->_line && Info->_line < Vg)
		ROL_vertical(Vg - Info->_line);
}

/* 水平方向 整合 */
static void SeigouH(void) {
	if (0 < Info->_col && Info->_col < Hg / 2)
		ROL_horizon(-Info->_col);
	else if (Hg / 2 <= Info->_col && Info->_col < Hg)
		ROL_horizon(Hg - Info->_col);
}
