#include "../bootpack.h"

Sheet::Sheet()
	: pict_(), flags_(FLAG_UNUSED),
	xpos_(0), ypos_(0), height_(0), col_inv_(0x0000), mouse_(false),
	fixed_(false)
{
}

/*
void SheetController::expand()
{
	dword i;
	sheetsnum_ = sheetsnum_ * 2; // 2倍に拡張
	List<Sheet>* newsheets0_ = new List<Sheet>[sheetsnum_];
	List<Sheet*>* newsheets_ = new List<Sheet*>[sheetsnum_];
	if (newsheets0_ == NULL || newsheets_ == NULL) {
		// newが出来なかった
		delete[] newsheets0_; // NULLポインタを渡してもOK
		delete[] newsheets_;
	} else if (sheets0_ != NULL && sheets_ != NULL) {
		for (i = 0; i < sheetsnum_ / 2; i++) {
			newsheets0_[i] = sheets0_[i];
			newsheets_[i] = sheets_[i];
		}
		for (; i < sheetsnum_; i++) {
			newsheets0_->operator [](i)
		}
		delete[] sheets0_;
		delete[] sheets_;
		sheets0_ = newsheets0_;
		sheets_ = newsheets_;
	}
	for (i = 
}
*/



SheetController::SheetController()
	: sheets0_(new Sheet[MAX_SHEETS]),
	sheets_(new Sheet*[MAX_SHEETS]),
	map_(g_screen->get_xsize(), g_screen->get_ysize()),
	map_nomouse_(g_screen->get_xsize(), g_screen->get_ysize()),
	exist_mouse_(false),
	taskids_(new int[MAX_SHEETS]),
	top_(-1)
{
	// sheets0_の中身のSheetクラスは、自動的にコンストラクタが呼ばれる
	for (int i = 0; i < MAX_SHEETS; i++) {
		taskids_[i] = -1;
	}
}

SheetController::~SheetController() {
	delete[] sheets0_;
	delete[] sheets_;
	delete[] taskids_;
}

Sheet* SheetController::alloc(int taskid, bool mouse) {
	Sheet* sht = NULL;
	for (int i = 0; i < MAX_SHEETS; i++) {
		if (!sheets0_[i].used()) {
			sht = sheets0_ + i;
			sht->use(); // 使用中マークをつける
			sht->set_height(-1);
			taskids_[i] = taskid;
			break;
		}
	}
	if (exist_mouse_ == false && mouse == true) {
		exist_mouse_ = true;
		sht->set_mouse(true);
	}
	return sht;
}

void SheetController::free(Sheet* sht) {
	if (sht->get_height() != -1) {
		// 非表示にする
		updown(sht, -1);
	}
	// 未使用マークをつける
	sht->release();
	taskids_[get_sheetid(sht)] = -1;
}

void SheetController::updown(Sheet* sht, int new_height) {
	int h, old_height = sht->get_height();

	/* 指定が低すぎや高すぎだったら、修正する */
	if (sheets_[top_]->get_mouse() == false && new_height > top_ + 1) {
		new_height = top_ + 1;
	}
	if (sheets_[top_]->get_mouse() == true && new_height > top_) {
		// new_heightがtop_ + 1になって良いのはマウスだけ
		if (old_height == -1) {
			new_height = top_;
		} else {
			new_height = top_ - 1;
		}
	}
	if (new_height < -1) {
		new_height = -1;
	}
	if (sht->get_mouse() == true) {
		// マウスシートなら、一番上か非表示の２択
		if (new_height != -1) {
			sht->set_height(top_ + 1);
		} else {
			sht->set_height(-1);
		}
	} else {
		sht->set_height(new_height); /* 高さを設定 */
	}
	Picture* pict = sht->get_buffer();

	/* 以下は主にsheets_[]の並べ替え */
	if (old_height > new_height) {	/* 以前よりも低くなる */
		if (new_height >= 0) {
			/* 間のものを引き上げる */
			for (h = old_height; h > new_height; h--) {
				sheets_[h] = sheets_[h - 1];
				sheets_[h]->set_height(h);
			}
			sheets_[new_height] = sht;
			refresh_map(sht->get_xpos(), sht->get_ypos(), sht->get_xpos() + pict->get_xsize(), sht->get_ypos() + pict->get_ysize(), new_height + 1);
			refresh_sub(sht->get_xpos(), sht->get_ypos(), sht->get_xpos() + pict->get_xsize(), sht->get_ypos() + pict->get_ysize(), new_height + 1, old_height);
		} else {	/* 非表示化 */
			if (top_ > old_height) {
				/* 上になっているものをおろす */
				for (h = old_height; h < top_; h++) {
					sheets_[h] = sheets_[h + 1];
					sheets_[h]->set_height(h);
				}
			}
			top_--; /* 表示中の下じきが一つ減るので、一番上の高さが減る */
			refresh_map(sht->get_xpos(), sht->get_ypos(), sht->get_xpos() + pict->get_xsize(), sht->get_ypos() + pict->get_ysize(), 0);
			refresh_sub(sht->get_xpos(), sht->get_ypos(), sht->get_xpos() + pict->get_xsize(), sht->get_ypos() + pict->get_ysize(), 0, old_height - 1);
		}
	} else if (old_height < new_height) {	/* 以前よりも高くなる */
		if (old_height >= 0) {
			/* 間のものを押し下げる */
			for (h = old_height; h < new_height; h++) {
				sheets_[h] = sheets_[h + 1];
				sheets_[h]->set_height(h);
			}
			sheets_[new_height] = sht;
		} else {	/* 非表示状態から表示状態へ */
			/* 上になるものを持ち上げる */
			for (h = top_; h >= new_height; h--) {
				sheets_[h + 1] = sheets_[h];
				sheets_[h + 1]->set_height(h + 1);
			}
			sheets_[new_height] = sht;
			top_++; /* 表示中の下じきが一つ増えるので、一番上の高さが増える */
		}
		refresh_map(sht->get_xpos(), sht->get_ypos(), sht->get_xpos() + pict->get_xsize(), sht->get_ypos() + pict->get_ysize(), new_height);
		refresh_sub(sht->get_xpos(), sht->get_ypos(), sht->get_xpos() + pict->get_xsize(), sht->get_ypos() + pict->get_ysize(), new_height, new_height);
	}
}

void SheetController::updown(int old_height, int new_height) {
	if (old_height >= 0) {
		updown(sheets_[old_height], new_height);
	}
}

void SheetController::refresh(const Sheet* sht, int x0, int y0, int x1, int y1) {
	if (sht->get_height() != -1) {
		refresh_sub(sht->get_xpos() + x0, sht->get_ypos() + y0,
			sht->get_xpos() + x1, sht->get_ypos() + y1,
			sht->get_height(), sht->get_height());
	}
}

void SheetController::refresh_winframe(const Sheet* sht) {
	if (sht->get_height() != -1) {
		const Picture* buf = sht->get_buffer();
		int xsize = buf->get_xsize();
		int ysize = buf->get_ysize();
		int xpos = sht->get_xpos();
		int ypos = sht->get_ypos();
		int height = sht->get_height();
		refresh_sub(xpos, ypos, xpos + xsize, ypos + 28, height, height);
		refresh_sub(xpos, ypos, xpos + 3, ypos + ysize, height, height);
		refresh_sub(xpos + xsize - 3, ypos, xpos + xsize, ypos + ysize, height, height);
		refresh_sub(xpos, ypos + ysize - 3, xpos + xsize, ypos + ysize, height, height);
	}
}

void SheetController::refresh_sub(int x0, int y0, int x1, int y1, int h0, int h1) {
	int h, bx, by, vx, vy, bx0, by0, bx1, by1;
	color_16 sid;
	Sheet *sht;
	if (x0 < 0) x0 = 0;
	if (y0 < 0) y0 = 0;
	if (x1 > g_screen->get_xsize()) x1 = g_screen->get_xsize();
	if (y1 > g_screen->get_ysize()) y1 = g_screen->get_ysize();
	for(h = h0; h <= h1; h++)
	{
		sht = sheets_[h];
		sid = sht - sheets0_;
		Picture* pict = sht->get_buffer();
		
		bx0 = x0 - sht->get_xpos(); // bx0 : 画像の左端を基準としたx位置
		by0 = y0 - sht->get_ypos(); // by0 : 画像の上端を基準としたy位置
		bx1 = x1 - sht->get_xpos();
		by1 = y1 - sht->get_ypos();
		if (bx0 < 0) bx0 = 0;
		if (by0 < 0) by0 = 0;
		if (bx1 > pict->get_xsize()) bx1 = pict->get_xsize();
		if (by1 > pict->get_ysize()) by1 = pict->get_ysize();
		for(by = by0; by < by1; by++)
		{
			vy = sht->get_ypos() + by;
			for (bx = bx0; bx < bx1; bx++)
			{
				vx = sht->get_xpos() + bx;
				if (map_.get_color(vx, vy) == sid)
				{
					g_screen->point(vx, vy, pict->get_color(bx, by));
				}
			}
		}
	}
}

void SheetController::refresh_sub_dragframe(int x0, int y0, int x1, int y1, int h0, int h1) {
	int h, bx, by, vx, vy, bx0, by0, bx1, by1;
	int sxpos, sypos;
	color_16 sid;
	Sheet *sht;
	Picture* pict;
	if (x0 < 0) x0 = 0;
	if (y0 < 0) y0 = 0;
	if (x1 > g_screen->get_xsize()) x1 = g_screen->get_xsize();
	if (y1 > g_screen->get_ysize()) y1 = g_screen->get_ysize();
	for(h = h0; h <= h1; h++)
	{
		sht = sheets_[h];
		sid = sht - sheets0_;
		pict = sht->get_buffer();
		
		bx0 = x0 - sht->get_xpos(); // bx0 : 画像の左端を基準としたx位置
		by0 = y0 - sht->get_ypos(); // by0 : 画像の上端を基準としたy位置
		bx1 = x1 - sht->get_xpos();
		by1 = y1 - sht->get_ypos();
		sxpos = sht->get_xpos();
		sypos = sht->get_ypos();
		if (bx0 < 0) bx0 = 0;
		if (by0 < 0) by0 = 0;
		if (bx1 > pict->get_xsize()) bx1 = pict->get_xsize();
		if (by1 > pict->get_ysize()) by1 = pict->get_ysize();
		
		// 上の線
		for(by = by0; by < 2; by++)
		{
			vy = sypos + by;
			for (bx = bx0; bx < bx1; bx++)
			{
				vx = sxpos + bx;
				if (map_.get_color(vx, vy) == sid)
				{
					g_screen->point(vx, vy, pict->get_color(bx, by));
				}
			}
		}
		
		// 側面の線
		for(by = 2; by < by1 - 2; by++)
		{
			vy = sypos + by;
			for (bx = bx0; bx < 2; bx++)
			{
				vx = sxpos + bx;
				if (map_.get_color(vx, vy) == sid)
				{
					g_screen->point(vx, vy, pict->get_color(bx, by));
				}
			}
			for (bx = bx1 - 2; bx < bx1; bx++)
			{
				vx = sxpos + bx;
				if (map_.get_color(vx, vy) == sid)
				{
					g_screen->point(vx, vy, pict->get_color(bx, by));
				}
			}
		}
		
		// 下の線
		for(by = by1 - 2; by < by1; by++)
		{
			vy = sypos + by;
			for (bx = bx0; bx < bx1; bx++)
			{
				vx = sxpos + bx;
				if (map_.get_color(vx, vy) == sid)
				{
					g_screen->point(vx, vy, pict->get_color(bx, by));
				}
			}
		}
	}
}

void SheetController::refresh_map(int x0, int y0, int x1, int y1, int h0) {
	int h, bx, by, vx, vy;
	int bx0, by0, bx1, by1; // 画像内での相対座標
	color_16 sid; // mapを格納するのにPictureクラスを使うので、color_16型がよい
	Sheet* sht;
	if (x0 < 0) x0 = 0;
	if (y0 < 0) y0 = 0;
	if (x1 > g_screen->get_xsize()) x1 = g_screen->get_xsize();
	if (y1 > g_screen->get_ysize()) y1 = g_screen->get_ysize();
	//for (h = h0; h <= top_; h++)
	for (h = h0; h <= top_ - 1; h++)
	{
		sht = sheets_[h];
		Picture* pict = sht->get_buffer();
		sid = sht - sheets0_; // sheets0の先頭アドレスを基準として、shtは何番目か計算。

		bx0 = x0 - sht->get_xpos(); // bx0 : 画像の左端を基準としたx位置
		by0 = y0 - sht->get_ypos(); // by0 : 画像の上端を基準としたy位置
		bx1 = x1 - sht->get_xpos();
		by1 = y1 - sht->get_ypos();
		if (bx0 < 0) bx0 = 0;
		if (by0 < 0) by0 = 0;
		if (bx1 > pict->get_xsize()) bx1 = pict->get_xsize();
		if (by1 > pict->get_ysize()) by1 = pict->get_ysize();
		for (by = by0; by < by1; by++)
		{
			vy = sht->get_ypos() + by;
			for (bx = bx0; bx < bx1; bx++)
			{
				vx = sht->get_xpos() + bx;
				if (pict->get_color(bx, by) != sht->get_invisible_color())
				{
					map_.point(vx, vy, sid);
					map_nomouse_.point(vx, vy, sid);
				}
			}
		}
	}
	// 以下は h == top_ の処理
	{
		sht = sheets_[h];
		Picture* pict = sht->get_buffer();
		sid = sht - sheets0_; // sheets0の先頭アドレスを基準として、shtは何番目か計算。

		bx0 = x0 - sht->get_xpos(); // bx0 : 画像の左端を基準としたx位置
		by0 = y0 - sht->get_ypos(); // by0 : 画像の上端を基準としたy位置
		bx1 = x1 - sht->get_xpos();
		by1 = y1 - sht->get_ypos();
		if (bx0 < 0) bx0 = 0;
		if (by0 < 0) by0 = 0;
		if (bx1 > pict->get_xsize()) bx1 = pict->get_xsize();
		if (by1 > pict->get_ysize()) by1 = pict->get_ysize();
		for (by = by0; by < by1; by++)
		{
			vy = sht->get_ypos() + by;
			for (bx = bx0; bx < bx1; bx++)
			{
				vx = sht->get_xpos() + bx;
				if (pict->get_color(bx, by) != sht->get_invisible_color())
				{
					map_.point(vx, vy, sid);
					// nomouse版には書き込まない
				}
			}
		}
	}
}

void SheetController::refresh_map_dragframe(int x0, int y0, int x1, int y1, int h0) {
	int h, bx, by, vx, vy;
	int bx0, by0, bx1, by1; // 画像内での相対座標
	int sxpos, sypos;
	color_16 sid; // mapを格納するのにPictureクラスを使うので、color_16型がよい
	Sheet* sht;
	Picture* pict;
	if (x0 < 0) x0 = 0;
	if (y0 < 0) y0 = 0;
	if (x1 > g_screen->get_xsize()) x1 = g_screen->get_xsize();
	if (y1 > g_screen->get_ysize()) y1 = g_screen->get_ysize();
	//for (h = h0; h <= top_; h++)
	for (h = h0; h <= top_ - 1; h++)
	{
		sht = sheets_[h];
		pict = sht->get_buffer();
		sid = sht - sheets0_; // sheets0の先頭アドレスを基準として、shtは何番目か計算。

		bx0 = x0 - sht->get_xpos(); // bx0 : 画像の左端を基準としたx位置
		by0 = y0 - sht->get_ypos(); // by0 : 画像の上端を基準としたy位置
		bx1 = x1 - sht->get_xpos();
		by1 = y1 - sht->get_ypos();
		sxpos = sht->get_xpos();
		sypos = sht->get_ypos();
		if (bx0 < 0) bx0 = 0;
		if (by0 < 0) by0 = 0;
		if (bx1 > pict->get_xsize()) bx1 = pict->get_xsize();
		if (by1 > pict->get_ysize()) by1 = pict->get_ysize();
		for (by = by0; by < 2; by++)
		{
			vy = sypos + by;
			for (bx = bx0; bx < bx1; bx++)
			{
				vx = sxpos + bx;
				if (pict->get_color(bx, by) != sht->get_invisible_color())
				{
					map_.point(vx, vy, sid);
					map_nomouse_.point(vx, vy, sid);
				}
			}
		}
		for (; by < by1 - 2; by++)
		{
			vy = sypos + by;
			for (bx = bx0; bx < 2; bx++)
			{
				vx = sxpos + bx;
				if (pict->get_color(bx, by) != sht->get_invisible_color())
				{
					map_.point(vx, vy, sid);
					map_nomouse_.point(vx, vy, sid);
				}
			}
			for (bx = bx1 - 2; bx < bx1; bx++)
			{
				vx = sxpos + bx;
				if (pict->get_color(bx, by) != sht->get_invisible_color())
				{
					map_.point(vx, vy, sid);
					map_nomouse_.point(vx, vy, sid);
				}
			}
		}
		for (; by < by1; by++)
		{
			vy = sypos + by;
			for (bx = bx0; bx < bx1; bx++)
			{
				vx = sxpos + bx;
				if (pict->get_color(bx, by) != sht->get_invisible_color())
				{
					map_.point(vx, vy, sid);
					map_nomouse_.point(vx, vy, sid);
				}
			}
		}
	}
	// 以下は h == top_ の処理
	{
		sht = sheets_[h];
		Picture* pict = sht->get_buffer();
		sid = sht - sheets0_; // sheets0の先頭アドレスを基準として、shtは何番目か計算。

		bx0 = x0 - sht->get_xpos(); // bx0 : 画像の左端を基準としたx位置
		by0 = y0 - sht->get_ypos(); // by0 : 画像の上端を基準としたy位置
		bx1 = x1 - sht->get_xpos();
		by1 = y1 - sht->get_ypos();
		if (bx0 < 0) bx0 = 0;
		if (by0 < 0) by0 = 0;
		if (bx1 > pict->get_xsize()) bx1 = pict->get_xsize();
		if (by1 > pict->get_ysize()) by1 = pict->get_ysize();
		for (by = by0; by < by1; by++)
		{
			vy = sht->get_ypos() + by;
			for (bx = bx0; bx < bx1; bx++)
			{
				vx = sht->get_xpos() + bx;
				if (pict->get_color(bx, by) != sht->get_invisible_color())
				{
					map_.point(vx, vy, sid);
					// nomouse版には書き込まない
				}
			}
		}
	}
}

void SheetController::slide(Sheet* sht, int xpos, int ypos) {
	int old_xpos = sht->get_xpos(), old_ypos = sht->get_ypos();
	Picture* pict = sht->get_buffer();
	sht->set_xpos(xpos);
	sht->set_ypos(ypos);
	if (sht->get_height() >= 0) { /* もしも表示中なら、新しい下じきの情報に沿って画面を描き直す */
		refresh_map(old_xpos, old_ypos, old_xpos + pict->get_xsize(), old_ypos + pict->get_ysize(), 0);
		refresh_map(xpos, ypos, xpos + pict->get_xsize(), ypos + pict->get_ysize(), sht->get_height());
		refresh_sub(old_xpos, old_ypos, old_xpos + pict->get_xsize(), old_ypos + pict->get_ysize(), 0, sht->get_height() - 1);
		refresh_sub(xpos, ypos, xpos + pict->get_xsize(), ypos + pict->get_ysize(), sht->get_height(), sht->get_height());
	}
}

void SheetController::slide_dragframe(Sheet* sht, int xpos, int ypos) {
	int old_xpos = sht->get_xpos(), old_ypos = sht->get_ypos();
	Picture* pict = sht->get_buffer();
	sht->set_xpos(xpos);
	sht->set_ypos(ypos);
	if (sht->get_height() >= 0) { /* もしも表示中なら、新しい下じきの情報に沿って画面を描き直す */
		int xsize = pict->get_xsize();
		int ysize = pict->get_ysize();
//		//refresh_map(old_xpos, old_ypos, old_xpos + xsize, old_ypos + ysize, 0);
		refresh_map(old_xpos, old_ypos, old_xpos + xsize, old_ypos + 2, 0);
		refresh_map(old_xpos, old_ypos + ysize - 2, old_xpos + xsize, old_ypos + ysize, 0);
		refresh_map(old_xpos, old_ypos, old_xpos + 2, old_ypos + ysize, 0);
		refresh_map(old_xpos + xsize - 2, old_ypos, old_xpos + xsize, old_ypos + ysize, 0);
//		//refresh_map(xpos, ypos, xpos + xsize, ypos + ysize, sht->get_height());
//		refresh_map(xpos, ypos, xpos + xsize, ypos + 2, sht->get_height());
//		refresh_map(xpos, ypos + ysize - 2, xpos + xsize, ypos + ysize, sht->get_height());
//		refresh_map(xpos, ypos, xpos + 2, ypos + ysize, sht->get_height());
//		refresh_map(xpos + xsize - 2, ypos, xpos + xsize, ypos + ysize, sht->get_height());
		refresh_sub(old_xpos, old_ypos, old_xpos + xsize, old_ypos + 2, 0, sht->get_height() - 1);
		refresh_sub(old_xpos, old_ypos + ysize - 2, old_xpos + xsize, old_ypos + ysize, 0, sht->get_height() - 1);
		refresh_sub(old_xpos, old_ypos, old_xpos + 2, old_ypos + ysize, 0, sht->get_height() - 1);
		refresh_sub(old_xpos + xsize - 2, old_ypos, old_xpos + xsize, old_ypos + ysize, 0, sht->get_height() - 1);
//		refresh_sub(xpos, ypos, xpos + xsize, ypos + 2, sht->get_height(), sht->get_height());
//		refresh_sub(xpos, ypos + ysize - 2, xpos + xsize, ypos + ysize, sht->get_height(), sht->get_height());
//		refresh_sub(xpos, ypos, xpos + 2, ypos + ysize, sht->get_height(), sht->get_height());
//		refresh_sub(xpos + xsize - 2, ypos, xpos + xsize, ypos + ysize, sht->get_height(), sht->get_height());
//		refresh_map(old_xpos, old_ypos, old_xpos + pict->get_xsize(), old_ypos + pict->get_ysize(), 0);
		refresh_map_dragframe(xpos, ypos, xpos + pict->get_xsize(), ypos + pict->get_ysize(), sht->get_height());
//		refresh_sub(old_xpos, old_ypos, old_xpos + pict->get_xsize(), old_ypos + pict->get_ysize(), 0, sht->get_height() - 1);
		refresh_sub_dragframe(xpos, ypos, xpos + pict->get_xsize(), ypos + pict->get_ysize(), sht->get_height(), sht->get_height());
	}
}

int SheetController::get_sheetid(int x, int y) {
	return map_nomouse_.get_color(x, y);
}

int SheetController::get_sheetid_test(int x, int y) {
	return map_.get_color(x, y);
}

int SheetController::get_sheetid(Sheet* sht) {
	return sht - sheets0_;
}

Sheet* SheetController::get_sheet(int sheetid) {
	Sheet* sht = NULL;
	if (sheetid >= 0 && sheetid < MAX_SHEETS) {
		sht = sheets0_ + sheetid;
	}
	return sht;
}

int SheetController::get_taskid(int sheetid) {
	int taskid = -1;
	if (sheetid >= 0 && sheetid < MAX_SHEETS) {
		taskid = taskids_[sheetid];
	}
	return taskid;
}


Sheet* system::get_sheet_taskid(int taskid) {
	Sheet* sht = NULL;
	for (int i = 0; i < SheetController::MAX_SHEETS; i++) {
		if (g_shtctl->get_taskid(i) == taskid) {
			sht = g_shtctl->get_sheet(i);
			break;
		}
	}
	return sht;
}
