/* API */

#include "bootpack.h"

int *api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax)
{
	struct task *task = task_now();
	int ds = task->ds;
	int *reg = &eax + 1;	/* 戻るデータ用のアドレス
				 * reg[0] = edi, reg[1] = esi, reg[2] = ebp, reg[3] = esp
				 * reg[4] = ebx, reg[5] = edx, reg[6] = ecx, reg[7] = eax
				 */

	if(eax == 0) {		/* アプリ終了 */
		return &(task->tss.esp0);
	} else if(eax == 1) {	/* 一文字表示 */
		api_putc(task, reg, ds, edi, esi, ebp, esp, ebx, edx, ecx, eax);
	} else if(eax == 2) {	/* 文字列表示 */
		api_puts(task, reg, ds, edi, esi, ebp, esp, ebx, edx, ecx, eax);
	} else if(eax == 3) {	/* 指定文字列表示 */
		api_nputs(task, reg, ds, edi, esi, ebp, esp, ebx, edx, ecx, eax);
	} else if(eax == 4) {	/* キーコード取得 */
		api_getd(task, reg, ds, edi, esi, ebp, esp, ebx, edx, ecx, eax);
	} else if(eax == 5) {	/* マウス取得 */
		api_getmouse(task, reg, ds, edi, esi, ebp, esp, ebx, edx, ecx, eax);
	} else if(eax == 6) {	/* コマンドライン取得 */
		api_getcmd(task, reg, ds, edi, esi, ebp, esp, ebx, edx, ecx, eax);
	} else if(eax == 7) {	/* メモリ取得 */
		api_malloc(task, reg, ds, edi, esi, ebp, esp, ebx, edx, ecx, eax);
	} else if(eax == 8) {	/* メモリ開放 */
		api_mfree(task, reg, ds, edi, esi, ebp, esp, ebx, edx, ecx, eax);
	} else if(eax == 9) {	/* タイマ獲得 */
		api_talloc(task, reg, ds, edi, esi, ebp, esp, ebx, edx, ecx, eax);
	} else if(eax == 10) {	/* タイマ開放 */
		api_tfree(task, reg, ds, edi, esi, ebp, esp, ebx, edx, ecx, eax);
	} else if(eax == 11) {	/* タイマデータ設定 */
		api_tinit(task, reg, ds, edi, esi, ebp, esp, ebx, edx, ecx, eax);
	} else if(eax == 12) {	/* タイマ時間設定 */
		api_tset(task, reg, ds, edi, esi, ebp, esp, ebx, edx, ecx, eax);
	} else if(eax == 13) {	/* ファイルオープン */
		api_fopen(task, reg, ds, edi, esi, ebp, esp, ebx, edx, ecx, eax);
	} else if(eax == 14) {	/* ファイルクローズ */
		api_fclose(task, reg, ds, edi, esi, ebp, esp, ebx, edx, ecx, eax);
	} else if(eax == 15) {	/* ファイルサイズの取得 */
		api_fsize(task, reg, ds, edi, esi, ebp, esp, ebx, edx, ecx, eax);
	} else if(eax == 16) {	/* ファイルシーク */
		api_fseek(task, reg, ds, edi, esi, ebp, esp, ebx, edx, ecx, eax);
	} else if(eax == 17) {	/* ファイルリード */
		api_fread(task, reg, ds, edi, esi, ebp, esp, ebx, edx, ecx, eax);
	} else if(eax == 18) {	/* ファイルライト */
		api_fwrite(task, reg, ds, edi, esi, ebp, esp, ebx, edx, ecx, eax);
	} else if(eax == 19) {	/* ファイル削除 */
		api_fdelete(task, reg, ds, edi, esi, ebp, esp, ebx, edx, ecx, eax);
	} else if(eax == 20) {	/* BEEPサウンド */
		api_beep(task, reg, ds, edi, esi, ebp, esp, ebx, edx, ecx, eax);
	} else if(eax == 21) {	/* 時計取得 */
		api_getclock(task, reg, ds, edi, esi, ebp, esp, ebx, edx, ecx, eax);
	} else if(eax == 22) {	/* ウィンドウ表示 */
		api_wopen(task, reg, ds, edi, esi, ebp, esp, ebx, edx, ecx, eax);
	} else if(eax == 23) {	/* ウィンドウを閉じる */
		api_wclose(task, reg, ds, edi, esi, ebp, esp, ebx, edx, ecx, eax);
	} else if(eax == 24) {	/* ウィンドウに点表示 */
		api_wpoint(task, reg, ds, edi, esi, ebp, esp, ebx, edx, ecx, eax);
	} else if(eax == 25) {	/* ウィンドウに線表示 */
		api_wline(task, reg, ds, edi, esi, ebp, esp, ebx, edx, ecx, eax);
	} else if(eax == 26) {	/* ウィンドウに四角形表示 */
		api_wbox(task, reg, ds, edi, esi, ebp, esp, ebx, edx, ecx, eax);
	} else if(eax == 27) {	/* ウィンドウの文字列表示 */
		api_wputs(task, reg, ds, edi, esi, ebp, esp, ebx, edx, ecx, eax);
	} else if(eax == 28) {	/* ウィンドウの指定文字列表示 */
		api_wnputs(task, reg, ds, edi, esi, ebp, esp, ebx, edx, ecx, eax);
	} else if(eax == 29) {	/* ウィンドウのリフレッシュ */
		api_wrefresh(task, reg, ds, edi, esi, ebp, esp, ebx, edx, ecx, eax);
	} else if(eax == 30) {	/* 画像ファイル情報の取得 */
		api_getpinfo(task, reg, ds, edi, esi, ebp, esp, ebx, edx, ecx, eax);
	} else if(eax == 31) {	/* 画像ファイルの表示 */
		api_wpict(task, reg, ds, edi, esi, ebp, esp, ebx, edx, ecx, eax);
	}
	return 0;
}

void api_putc(struct task *task, int *reg, int ds, int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax)
{
	struct console *cons = task->cons;

	cons_font(cons, edx & 0xff, 1);
	return;
}

void api_puts(struct task *task, int *reg, int ds, int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax)
{
	struct console *cons = task->cons;

	cons_fonts(cons, (char *) (edx + ds));
	return;
}

void api_nputs(struct task *task, int *reg, int ds, int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax)
{
	struct console *cons = task->cons;
	int i;

	for(i = 0; i < ecx; i++) {
		cons_font(cons, (char) (edx + ds + i), 1);
	}
	return;
}

void api_getd(struct task *task, int *reg, int ds, int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax)
{
	struct console *cons = task->cons;
	int i;

	for(;;) {
		cli();
		if(fifo_stat(&task->fifo) == 0) {
			if(ebx != 0) {
				task_sleep(task);
			} else {
				sti();
				reg[7] = -1;
				return;
			}
		}
		i = fifo_get(&task->fifo);
		sti();
		if(i <= 1) {
			timer_init(cons->cur, &task->fifo, 1);
			timer_set(cons->cur, 50);
		} else if(i == 2) {
			cons->cc = COLOR_FFFFFF;
		} else if(i == 3) {
			cons->cc = -1;
		} else if(i == 4) {	/* コンソールのみを閉じる */
			timer_cancel(cons->cur);
			cli();
			fifo_put(&fifo, cons->sht - shts->sheet + 1280);
			cons->sht = 0;
			sti();
		} else if(i >= 256) {
			reg[7] = i - 256;
			return;
		}
	}
	return;
}

void api_getmouse(struct task *task, int *reg, int ds, int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax)
{
	struct mouse *mouse;
	struct sheet *sht;

	mouse = (struct mouse *) (ebx + ds);
	sht = (struct sheet *) edx;
	if(ecx == 0) {	/* 画面の絶対値 */
		mouse->x = mdec.mx;
		mouse->y = mdec.my;
	} else {	/* 指定のウィンドウからの相対値 */
		mouse->x = mdec.mx - sht->x;
		mouse->y = mdec.my - sht->y;
	}
	mouse->btn = mdec.btn;
	mouse->stat = mdec.stat;
	return;
}

void api_getcmd(struct task *task, int *reg, int ds, int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax)
{
	char *s;
	int i, j;

	s = (char *) (ebx + ds);
	for(i = 0;i < ecx;i++) {
		s[i] = task->line[i];
	}
	if(edx != 0) {	/* アプリケーション名を含める */
		reg[7] = (int) ebx;
	} else {	/* アプリケーション名を含めない */
		for(j = 0; s[j] != ' '; j++) { }	/* スペースまで読み飛ばす */
		for(; s[j] == ' '; j++) { }		/* スペースを読み飛ばす */
		reg[7] = (int) (ebx + j);
	}
	return;
}

void api_malloc(struct task *task, int *reg, int ds, int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax)
{
	if((task->flag & TASK_MEMMAN) != 0) {
		memory_init((struct memorys *) (ebx + ds));
		memory_free((struct memorys *) (ebx + ds), (unsigned int) (ebx + ds + 32768), (unsigned int) edx);
		task->flag |= TASK_MEMMAN;
	}
	reg[7] = memory_alloc((struct memorys *) (ebx + ds), ecx);
	return;
}

void api_mfree(struct task *task, int *reg, int ds, int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax)
{
	memory_free((struct memorys *) (ebx + ds), edx, ecx);
	return;
}

void api_talloc(struct task *task, int *reg, int ds, int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax)
{
	reg[7] = (int) timer_alloc();
	((struct timer *) reg[7])->flag |= TIMER_ACANCEL;
	return;
}

void api_tfree(struct task *task, int *reg, int ds, int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax)
{
	timer_free((struct timer *) ebx);
	return;
}

void api_tinit(struct task *task, int *reg, int ds, int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax)
{
	timer_init((struct timer *) ebx, &task->fifo, 256 + ecx);
	return;
}

void api_tset(struct task *task, int *reg, int ds, int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax)
{
	timer_set((struct timer *) ebx, ecx);
	return;
}

void api_fopen(struct task *task, int *reg, int ds, int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax)
{
	struct file *file;
	struct fhandle *fh;
	int i, j, k;
	char mode = ecx & 0xff;

	for(i = 0;i < 8;i++) {
		if(task->fh[i].buf == 0) {
			break;
		}
	}
	fh = &task->fh[i];
	reg[7] = 0;
	if(i < 8) {
		file = file_search((char *) (ebx + ds));
		if(mode == 'r') {	/* 読み込みモード */
			if(file == 0) {
				return;
			}
			reg[7] = (int)fh;
			fh->f = file;
			fh->flag = FHANDLE_NONE;
			fh->pos = 0;
			fh->size = file->size;
			fh->buf = (char *)file_read(file->cno, &fh->size);
			fh->cno = file->cno;
			fh->bsize = fh->size;
			fh->bpos = 0;
			return;
		} else if(mode == 'w') {	/* 新規読み書きモード */
			file = file_create((char *) (ebx + ds));
			if(file == 0) {
				return;
			}
			reg[7] = (int)fh;
			fh->f = file;
			fh->flag = FHANDLE_NONE;
			fh->size = 0;
			fh->pos = 0;
			fh->buf = (char *) memory_alloc(mem, 4096);
			if(fh->buf == 0) {
				reg[7] = 0;
				return;
			}
			fh->cno = file->cno;
			fh->bsize = 4096;
			fh->bpos = 0;
		} else if(mode == 'a') { /* 追加読み書きモード */
			if(file == 0) {
				return;
			}
			reg[7] = (int)fh;
			fh->f = file;
			fh->flag = FHANDLE_NONE;
			fh->pos = file->size;
			fh->size = file->size;
			fh->buf = (char *)file_read(file->cno, &fh->size);
			fh->cno = file->cno;
			fh->bsize = fh->size;
			fh->bpos = fh->size;
			j = fh->cno;
			k = file->size;
			for(; ; ) {
				if(k <= 512) {
					break;
				}
				k -= 512;
				j = fat[j];
			}
			file_setbuf(fh, fat, j);
			return;
		} else {	/* 無効なモード */
			return;
		}
	}
	return;
}

void api_fclose(struct task *task, int *reg, int ds, int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax)
{
	struct fhandle *fh;

	fh = (struct fhandle *) ebx;
	if(fh->flag != FHANDLE_NONE) {
		file_write(fh, fat, fh->bpos);
	}
	memory_free(mem, (int) fh->buf, fh->size);
	fh->buf = 0;
	return;
}

void api_fsize(struct task *task, int *reg, int ds, int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax)
{
	struct fhandle *fh;

	fh = (struct fhandle *) ebx;
	if(ecx == 0) {
		reg[7] = fh->size;
	} else if(ecx == 1) {
		reg[7] = fh->pos;
	} else if(ecx == 2) {
		reg[7] = fh->pos - fh->size;
	}
	return;
}

void api_fseek(struct task *task, int *reg, int ds, int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax)
{
	struct fhandle *fh;
	int i, j;

	fh = (struct fhandle *) ebx;
	if(fh->flag != FHANDLE_NONE) {
		file_write(fh, fat, fh->bpos);
	}
	if(edx == 0) {
		fh->pos = ecx;
	} else if(edx == 1) {
		fh->pos += ecx;
	} else if(edx == 2) {
		fh->pos = fh->size + ecx;
	}

	if(fh->pos < 0) {
		fh->pos = 0;
	}
	if(fh->pos > fh->size) {
		fh->pos = fh->size;
	}

	/* バッファの切り替え。FATを解析してセクタ番号を取得 */
	i = fh->pos;
	j = fh->f->cno;
	for(; i > 512; ) {
		i -= 512;
		j = fat[j];
	}
	file_setbuf(fh, fat, j);
	fh->bpos = i;
	fh->flag = FHANDLE_NONE;
	reg[7] = fh->pos;
	return;
}

void api_fread(struct task *task, int *reg, int ds, int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax)
{
	struct fhandle *fh;
	int i;

	fh = (struct fhandle *) ebx;
	for(i = 0; i < ecx; i++) {
		if(fh->bpos == fh->size) {
			break;
		}
		*((char *) (edx + ds + i)) = fh->buf[fh->bpos++];
		fh->pos++;
	}
	reg[7] = i;
	return;
}

void api_fwrite(struct task *task, int *reg, int ds, int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax)
{
	struct fhandle *fh;
	int size, i;
	char *buf;

	fh = (struct fhandle *) ebx;
	buf = (char *) (edx + ds);
	size = ecx;
	fh->flag = FHANDLE_CH;
	reg[7] = 0;
	for(; ; ) {
		if(fh->bpos + size < fh->bsize) {
			if(size <= 512) {
				for(i = 0; i < size; i++) {
					fh->buf[fh->bpos++] = buf[i];
				}
				fh->pos += i;
				reg[7] += i;
				return;
			}
			for(i = 0; i < 512; i++) {
				fh->buf[fh->bpos++] = buf[i];
			}
			fh->pos += 512;
			size -= 512;
			buf += 512;
			reg[7] += 512;
		} else {
			file_write(fh, fat, fh->bpos);
		}
	}
	return;
}

void api_fdelete(struct task *task, int *reg, int ds, int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax)
{
	struct fhandle *fh;
	int i;

	fh = (struct fhandle *) ebx;
	i = file_delete(fh->f);
	if(i != 0) {
		reg[7] = 1;
		return;
	}
	memory_free(mem, (int) fh->buf, fh->size);
	fh->buf = 0;
	reg[7] = 0;
	return;
}

void api_beep(struct task *task, int *reg, int ds, int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax)
{
	beep(ecx);
	return;
}

void api_getclock(struct task *task, int *reg, int ds, int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax)
{
	struct clock clck;

	clock_get(&clck);
	reg[7] = (int) &clck;
	return;
}

void api_wopen(struct task *task, int *reg, int ds, int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax)
{
	struct sheet *sht;

	/* シートを取得し、属性を指定 */
	sht = sheet_alloc();
	sht->task = task;
	sht->flag |= SHEET_FROMAPP;

	/* シートを設定し、ウィンドウを書く */
	sheet_set(sht, (unsigned char *) (ebx + ds), ecx, edx, edi);
	window_open(sht, (char *) (esi + ds), 0);

	/* 位置と高さを調節し、アクティブ化をシステムタスクに要求 */
	sheet_slide(sht, ((shts->xsize - ecx) / 2) & ~3, (shts->ysize - edx) / 2);
	sheet_updown(sht, shts->top - 1);
	fifo_put(&fifo, 1);
	reg[7] = (int)sht;
	return;
}

void api_wclose(struct task *task, int *reg, int ds, int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax)
{
	sheet_free((struct sheet *) ebx);
	return;
}

void api_wpoint(struct task *task, int *reg, int ds, int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax)
{
	struct sheet *sht;

	sht = (struct sheet *) ebx;
	sht->buf[edx * sht->sx + ecx] = esi;
	return;
}

void api_wline(struct task *task, int *reg, int ds, int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax)
{
	struct sheet *sht;
	int x, y, dx, dy, len, i;

	sht = (struct sheet *) ebx;
	dx = esi - ecx;
	dy = edi - edx;
	x = ecx << 10;	/* 小数点のような正確さを求めるため */
	y = edx << 10;
	if(dx < 0)
		dx = -dx;
	if(dy < 0)
		dy = -dy;
	if(dx >= dy) {	/* 差の多いほうをlenとしたほうがまとめて行えるためいい */
		len = dx + 1;
		if(ecx > esi)
			dx = -1024;
		else
			dx = 1024;
		if(edx <= edi)	/* 数値を戻して、lenで割ることでlen後の移動量が決まる */
			dy = ((edi - edx + 1) << 10) / len;
		else
			dy = ((edi - edx - 1) << 10) / len;
	} else {
		len = dy + 1;
		if(edx > edi)
			dy = -1024;
		else
			dy = 1024;
		if(ecx <= esi)
			dx = ((esi - ecx + 1) << 10) / len;
		else
			dx = ((esi - ecx - 1) << 10) / len;
	}
	for(i = 0;i < len;i++) {
		sht->buf[(y >> 10) * sht->sx + (x >> 10)] = ebp;
		x += dx;
		y += dy;
	}
	return;
}


void api_wbox(struct task *task, int *reg, int ds, int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax)
{
	struct sheet *sht;

	sht = (struct sheet *) ebx;
	graphic_box(sht, ebp, ecx, edx, esi, edi);
	return;
}

void api_wputs(struct task *task, int *reg, int ds, int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax)
{
	struct sheet *sht;

	sht = (struct sheet *) ebx;
	graphic_fonts(sht, -1, edi, ecx, edx, (char *) (esi + ds));
	return;
}

void api_wnputs(struct task *task, int *reg, int ds, int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax)
{
	struct sheet *sht;

	sht = (struct sheet *) ebx;
	graphic_nfonts(sht, -1, edi, ecx, edx, (char *) (esi+ds), ebp);
	return;
}

void api_wrefresh(struct task *task, int *reg, int ds, int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax)
{
	struct sheet *sht;

	sht = (struct sheet *) ebx;
	sheet_refresh(sht, ecx, edx, esi + 1, edi + 1);
	return;
}

void api_getpinfo(struct task *task, int *reg, int ds, int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax)
{
	struct fhandle *fh;
	struct dll_strpicenv *env;
	struct pict *pict;
	int size, info[8];
	char *fbuf;

	fh = (struct fhandle *) ebp;
	pict = (struct pict *) (ebx + ds);
	reg[7] = 0;

	size = fh->f->size;
	fbuf = file_read(fh->f->cno, &size);
	if(fbuf == 0) {
		memory_free(mem, (unsigned int) fbuf, size);
		return;
	}

	env = (struct dll_strpicenv *) memory_alloc(mem, sizeof(struct dll_strpicenv));
	if(info_JPEG(env, info, size, fbuf) != 0) {	/* jpegである */
		pict->sx = info[2];
		pict->sy = info[3];
		pict->mode = 2;	/* .jpg */
	} else if(info_BMP(env, info, size, fbuf) != 0) {	/* bmpである */
		pict->sx = info[2];
		pict->sy = info[3];
		pict->mode = 1;	/* .bmp */
	} else {	/* 画像ファイルではない */
		reg[7] = 1;
	}
	memory_free(mem, (unsigned int) fbuf, size);
	memory_free(mem, (unsigned int) env, sizeof(struct dll_strpicenv));
	return;
}

void api_wpict(struct task *task, int *reg, int ds, int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax)
{
	struct sheet *sht;
	struct fhandle *fh;
	struct dll_strpicenv *env;
	struct rgb *pbuf = 0, *q;
	int size, info[8], x, y, sx, sy, i, j;
	char *fbuf, *p;

	fh = (struct fhandle *) ebx;
	sht = (struct sheet *) ebp;
	x = ecx;
	y = edx;
	sx = edi;
	sy = esi;

	reg[7] = 1;
	i = 1;
	size = fh->f->size;
	fbuf = file_read(fh->f->cno, &size);
	if(fbuf == 0) {
		memory_free(mem, (unsigned int) fbuf, size);
		return;
	}

	env = (struct dll_strpicenv *) memory_alloc(mem, sizeof(struct dll_strpicenv));
	if(info_JPEG(env, info, size, fbuf) != 0) {	/* jpegである */
		pbuf = (struct rgb *) memory_alloc(mem, info[2] * info[3] * sizeof(struct rgb));
		i = decode0_JPEG(env, size, fbuf, 4, (char *) pbuf, 0);
	}  else if(info_BMP(env, info, size, fbuf) != 0) {	/* bmpである */
		pbuf = (struct rgb *) memory_alloc(mem, info[2] * info[3] * sizeof(struct rgb));
		i = decode0_BMP(env, size, fbuf, 4, (char *) pbuf, 0);
	}

	if(i == 0) {	/* 解読に成功 */
		for(i = 0; i < sy; i++) {
			p = sht->buf + (y + i) * sht->sx;
			q = pbuf + i * info[2];
			for(j = 0; j < sx; j++) {
				p[x + j] = rgb2pal(q[j].r, q[j].g, q[j].b, j, i);
			}
		}
		reg[7] = 0;
	}

	if(pbuf != 0) {
		memory_free(mem, (unsigned int) pbuf, info[2] * info[3] * sizeof(struct rgb));
	}
	memory_free(mem, (unsigned int) fbuf, size);
	memory_free(mem, (unsigned int) env, sizeof(struct dll_strpicenv));
	return;
}
