/***   [roll.c]
*
*	画面スクロール		(C)ささがわ
*
*	For GNU C Compiler (GCC)   Version 1.39
*
***/

#include <stdlib.h>
#include <mos.h>
#include "graph.h"
#include "txwind.h"

extern int	PAL_MOJI, PAL_Back, PAL_Black;
static struct txinfo_t	*Info;
static int	Vg, Hg, Vw, Hw;
static int	CORD[4], DISPOFF;

static void	Draw_line(int);
static void	Seikika(int *);
static void	Cls_line(int);
static void	ROL_horizon_sub(int);

void ROL_init(struct txinfo_t *txi, int x1, int y1, int x2, int y2) {
	int		i;
	
	Info = txi;
	CORD[0] = x1;	CORD[1] = y1;
	CORD[2] = x2;	CORD[3] = y2;
	Vg = Info->fontx + Info->linegap;
	Hg = Info->fontx / 2;
	Vw = (CORD[3] - CORD[1] + 1 + Info->linegap) / Vg;
	Hw = (CORD[2] - CORD[0] + 1) / Hg;
	DISPOFF = 0;
	Info->_line = 0;	Info->_col = 0;
	
	EGB_actPage(0);
	EGB_cls(PAL_Back);
	EGB_Hscrl(0, DISPOFF);
	for (i = 0; i < Vw; i++)
		Draw_line(i);
	EGB_actPage(1);
}

static void Draw_line(int l) {
	int		y;
	struct bmgr_t	bm;
	unsigned char	str[100];
	
	if (Info->line + l >= Info->file.line)
		return;
	
	bm.tabm = Info->tabd;	bm.crm = Info->crd;
	bm.fs = &Info->file;
	bm.line = l + Info->line;
	bm.l = Info->col;
	bm.r = Info->col + Hw - 1;
	bm.tab = Info->tab;
	BMGR_String(&bm, str);
	
	y = (DISPOFF + CORD[1] + l * Vg + Info->fontx - 1) % 512;
	EGB_str3((char *)str, CORD[0], y, PAL_MOJI, PAL_Back);
	if (y < Info->fontx - 1)
		EGB_str3((char *)str, CORD[0], y + 512, PAL_MOJI, PAL_Back);
}

int ROL_vertical(int w) {
	if (w > 0 && Info->line + Vw >= Info->file.line)
		return 1;
	else if (w < 0 && Info->line == 0 && Info->_line == 0)
		return 1;
	else if (w == 0 || abs(w) > Vg)
		return 0;
	
	EGB_actPage(0);
	if (w > 0) {		/* 前進 */
		if (Info->_line == 0)
			Cls_line(1);
		if (Info->_line + w >= Vg) {
			EGB_Hscrl(0, DISPOFF += Vg - Info->_line);
			Seikika(&DISPOFF);
			Info->line++;
			w -= Vg - Info->_line;
			Info->_line = 0;
			Draw_line(Vw - 1);
			if (w != 0 && Info->line + Vw != Info->file.line) {
				Cls_line(1);
				EGB_Hscrl(0, DISPOFF += w);
				Info->_line = w;
			}
		} else {
			EGB_Hscrl(0, DISPOFF += w);
			Info->_line += w;
		}
	} else {		/* 後進 */
		if (Info->_line == 0) {
			Cls_line(0);
			Info->line--;
			EGB_Hscrl(0, DISPOFF += w);
			if (-w == Vg) {
				Seikika(&DISPOFF);
				Draw_line(0);
			} else {
				Info->_line = Vg + Info->_line + w;
			}
		} else if (Info->_line + w <= 0) {
			EGB_Hscrl(0, DISPOFF -= Info->_line);
			Seikika(&DISPOFF);
			w += Info->_line;
			Info->_line = 0;
			Draw_line(0);
			if (w > 0 && Info->line != 0) {
				Cls_line(0);
				EGB_Hscrl(0, DISPOFF += w);
				Info->line--;
				Info->_line = Vg + w;
			}
		} else {
			EGB_Hscrl(0, DISPOFF += w);
			Info->_line += w;
		}
	}
	Seikika(&DISPOFF);
	EGB_actPage(1);
	
	if (w > 0 && Info->line + Vw >= Info->file.line)
		return 1;
	else if (w < 0 && Info->line == 0 && Info->_line == 0)
		return 1;
	else
		return 0;
}

static void Seikika(int *a) {
	if (*a < 0) {
		while (*a < 0)
			*a += 512;
	} else if (*a >= 512) {
		*a %= 512;
	}
}

static void Cls_line(int mode) {
	int		y;
	
	y = DISPOFF + (mode ? CORD[3] + 1 : CORD[1] - Vg);
	Seikika(&y);
	EGB_boxf(CORD[0], y, CORD[2], y + Vg - 1, PAL_Back, PAL_Back);
	if (y >= 512 - Vg) {
		y -= 512;
		EGB_boxf(CORD[0], y, CORD[2], y + Vg - 1, PAL_Back, PAL_Back);
	}
}

int ROL_horizon(int w) {
	if (w > 0 && Info->col + Hw >= (Info->lgcolw ? Hw : Info->lgcol))
		return 1;
	else if (w < 0 && Info->col == 0 && Info->_col == 0)
		return 1;
	else if (w == 0 || abs(w) > Hg)
		return 0;
	
	EGB_actPage(0);
	if (w > 0) {		/* 前進 */
		if (Info->_col + w >= Hg) {
			Info->col++;
			ROL_horizon_sub(1);
			if (Info->col + Hw == (Info->lgcolw ? Hw : Info->lgcol))
				Info->_col = 0;
			else
				Info->_col = Info->_col + w - Hg;
		} else {
			Info->_col += w;
		}
	} else {		/* 後進 */
		if (Info->_col + w < 0) {
			Info->col--;
			ROL_horizon_sub(0);
			if (Info->col == 0)
				Info->_col = 0;
			else
				Info->_col = Hg + Info->_col + w;
		} else {
			Info->_col += w;
		}
	}
	EGB_actPage(1);
	
	if (w > 0 && Info->col + Hw >= (Info->lgcolw ? Hw : Info->lgcol))
		return 1;
	else if (w < 0 && Info->col == 0 && Info->_col == 0)
		return 1;
	else
		return 0;
}

#define FNTV	(Info->fontx)
#define FNTH	(Info->fontx / 2)
#define PRINT(x, y)		EGB_str3((char *)buf, x, y, PAL_MOJI, PAL_Back);
static void ROL_horizon_sub(int c) {
	int		l, a, y1, y2;
	unsigned char	buf[5];
	struct bmgr_t	bm;
	struct bmgrctype_t	ct;
	
	y1 = (DISPOFF + CORD[1]) % 512;
	y2 = y1 + FNTV - 1;
	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;
	
	EGB_actPage(0);
	for (l = 0; l < Vw && l + Info->line < Info->file.line; l++) {
		bm.line = l + Info->line;
		BMGR_ctype(&bm, &ct);
		if (c) {
			if (ct.r == 1) {
				buf[0] = ct.rcode;
				buf[1] = '\0';
			} else if (ct.r == 3) {
				buf[0] = ct.rcode >> 8;
				buf[1] = ct.rcode & 0xff;
				buf[2] = '\0';
			}
			
			a = ct.r == 0 || ct.r == 2 ? 1 : 0;
			EGB_scrl(a, CORD[0], y1, CORD[2], y2, -FNTH, 0);
			if (y2 >= 512)
				EGB_scrl(a, CORD[0], 0, CORD[2], y2 - 512, -FNTH, 0);
			
			if (ct.r == 1) {
				PRINT(CORD[2] - FNTH + 1, y2);
				if (y2 >= 512)
					PRINT(CORD[2] - FNTH + 1, y2 - 512);
			} else if (ct.r == 3) {
				PRINT(CORD[2] - FNTV + 1, y2);
				if (y2 >= 512)
					PRINT(CORD[2] - FNTV + 1, y2 - 512);
			}
			
			if (ct.l == 3) {
				EGB_boxf(CORD[0], y1, CORD[0] + FNTH - 1, y2, PAL_Back, PAL_Back);
				if (y2 >= 512)
					EGB_boxf(CORD[0], y1 - 512, CORD[0] + FNTH - 1, y2 - 512, PAL_Back, PAL_Back);
			}
		} else {
			if (ct.l == 1) {
				buf[0] = ct.lcode;
				buf[1] = '\0';
			} else if (ct.l == 2) {
				buf[0] = ct.lcode >> 8;
				buf[1] = ct.lcode & 0xff;
				buf[2] = '\0';
			}
			
			a = ct.l == 0 || ct.l == 3 ? 1 : 0;
			EGB_scrl(a, CORD[0], y1, CORD[2], y2, FNTH, 0);
			if (y2 >= 512)
				EGB_scrl(a, CORD[0], 0, CORD[2], y2 - 512, FNTH, 0);
			
			if (ct.l == 1) {
				PRINT(CORD[0], y2);
				if (y2 >= 512)
					PRINT(CORD[0], y2 - 512);
			} else if (ct.l == 2) {
				PRINT(CORD[0], y2);
				if (y2 >= 512)
					PRINT(CORD[0], y2 - 512);
			}
			
			if (ct.r == 2) {
				EGB_boxf(CORD[2] - FNTH + 1, y1, CORD[2], y2, PAL_Back, PAL_Back);
				if (y2 >= 512)
					EGB_boxf(CORD[2] - FNTH + 1, y1 - 512, CORD[2], y2 - 512, PAL_Back, PAL_Back);
			}
		}
		y1 += Vg;
		y1 %= 512;
		y2 = y1 + FNTV - 1;
	}
	EGB_actPage(1);
}
#undef FNTV
#undef FNTH
#undef PRINT

void ROL_end(int wy, int x, int y) {
	MOS_disp(0);
	if (DISPOFF + CORD[1] >= 512) {
		EGB_mycopy(0, CORD[0], DISPOFF + CORD[1] - 512, CORD[2], DISPOFF + CORD[3] - 512, 1, x, y);
	} else if (DISPOFF + CORD[3] < 512) {
		EGB_mycopy(0, CORD[0], DISPOFF + CORD[1], CORD[2], DISPOFF + CORD[3], 1, x, y);
	} else {
		EGB_mycopy(0, CORD[0], DISPOFF + CORD[1], CORD[2], 511, 1, x, y);
		EGB_mycopy(0, CORD[0], 0, CORD[2], DISPOFF + CORD[3] - 512, 1, x, 512 - DISPOFF + wy);
	}
	MOS_disp(1);
}
