#include <stdio.h>

#include "concorde.h"
#include "ysmaze2.h"
#include "mzedit.h"
#include "YsMacro.h"
#include "ysgui.h"

#include <stdlib.h>
#include <string.h>
#include <winb.h>
#include <te.h>
#include <fntb.h>
#include <gui.h>
#include <wgb.h>

int ActiveWin;
MAZEWIN mzWin[MAZEWIN_NUM];


extern int Ys11Id;

#define swapI(a,b) {(b)=(a)-(b);(a)=(a)-(b);(b)=(b)+(a);}


void InputWall(MAZEMAP *mz,int winX1,int winY1,POINT *start);
void InsertWallMark(MAZEMAP *mz,int winX1,int winY1,POINT *st,POINT *ed);
void InsertWallWin(MAZEMAP *mz,int winX1,int winY1,int x,int y,int d);
void InsertFloorWin(MAZEMAP *mz,int winX1,int winY1,int x,int y,int d);
void FirstInputWall(MAZEMAP *mz,int winX1,int winY1,POINT *start);
void ResetWindow(int winn);
void ResetWindowScrollBar(int winn);




int	CreateNewMaze()
{
	int neo;

	neo=CheckOpenWindow();
	if(neo<0)
	{
		YsConfirm(Ys11Id,"これ以上ウィンドウが開きません.","確認");
		return NOERR;
	}

	OpenNewWindow(neo);

	return NOERR ;
}



int CheckOpenWindow()
{
	int fre;

	for(fre=0; fre<MAZEWIN_NUM; fre++)
	{
		if(mzWin[fre].openflag==FALSE)
		{
			return fre;
		}
	}
	return -1;
}



int OpenNewWindow(int fre)
{
	extern int Ys11Id,mazeWin,mazeWinBarV,mazeWinBarH;
	int win,vbar,hbar;
	HYPER hyp;
	FRAME org,siz;

	ActiveWin=fre;
	mzWin[fre].openflag=TRUE;
	win=mzWin[fre].win;
	vbar=mzWin[fre].vbar;
	hbar=mzWin[fre].hbar;

	MMI_SendMessage(mazeWin, MM_GETHYPER, 1, &hyp);
	MMI_SendMessage(win, MM_SETHYPER, 1, &hyp);
	MMI_SendMessage(mazeWin, MM_GETUSER, 2, &org, &siz);
	MMI_SendMessage(win, MM_SETUSER, 2, &org, &siz);

	MMI_SendMessage(mazeWinBarV, MM_GETHYPER, 1, &hyp);
	MMI_SendMessage(vbar, MM_SETHYPER, 1, &hyp);

	MMI_SendMessage(mazeWinBarH, MM_GETHYPER, 1, &hyp);
	MMI_SendMessage(hbar, MM_SETHYPER, 1, &hyp);

	MMI_SendMessage(win,  MM_ATTACH, 1, Ys11Id);
	MMI_SendMessage(vbar, MM_ATTACH, 1, win);
	MMI_SendMessage(hbar, MM_ATTACH, 1, win);

	MMI_SendMessage(win, MM_MOVE, 2, fre*8, fre*8);

	ResetWindow(fre);

	sprintf(mzWin[fre].tit,"迷路 %2d",fre);
	MMI_SendMessage(win, MM_SETMSG, 1, mzWin[fre].tit);

	MMI_SendMessage(win, MM_WAKE, 0);
	MMI_SendMessage(win, MM_SHOW, 0);

	return win;
}


void ResetWindow(int winn)
{
	MAZEMAP *mz;
	HYPER winAt;
	int winId,WinX,WinY;
	FRAME UsrFr,UsrSz;
	int MazX,MazY,PixX,PixY;
	int SpcX,SpcY;

	mz=&mzWin[winn].map;
	winId=mzWin[winn].win;

	MMI_SendMessage(winId , MM_GETUSER,2,&UsrFr,&UsrSz);
	MMI_SendMessage(winId , MM_GETHYPER,1,&winAt);

	WinX = winAt.fr.rdwx-winAt.fr.lupx+2;
	WinY = winAt.fr.rdwy-winAt.fr.lupy+2;
	SpcX = WinX-UsrFr.rdwx;
	SpcY = WinY-UsrFr.rdwy;

	MazX=mz->lx;
	MazY=mz->ly;
	PixX= MazX * MAZE_BLOCK_LEN_DSP + 8;
	PixY= MazY * MAZE_BLOCK_LEN_DSP + 8;
	UsrSz.rdwx = small(512,PixX)+SpcX;
	UsrSz.rdwy = small(408,PixY)+SpcY;

	UsrFr.rdwx= small(UsrFr.rdwx, PixX);
	UsrFr.rdwy= small(UsrFr.rdwy, PixY);

	WinX=  UsrFr.lupx +UsrFr.rdwx +SHADE_SIZE +BAR_SIZE;
	WinY=  UsrFr.lupy +UsrFr.rdwy +SHADE_SIZE +BAR_SIZE;
	winAt.fr.rdwx = winAt.fr.lupx+WinX-1;
	winAt.fr.rdwy = winAt.fr.lupy+WinY-1;

	MMI_SendMessage(winId , MM_SETHYPER,1,&winAt);
	MMI_SendMessage(winId , MM_SETUSER,2,&UsrFr,&UsrSz);

	ResetWindowScrollBar(winn);
}

void ResetWindowScrollBar(int winn)
{
	MAZEMAP *mz;
	HYPER vbarAt,hbarAt;
	int vbarId,hbarId;
	HYPER winAt;
	int winId,WinX1,WinY1,WinX2,WinY2;
	FRAME UsrFr,UsrSz;
	int PixX,PixY,UsrX,UsrY;
	int n,m;

	mz=&mzWin[winn].map;
	winId=mzWin[winn].win;
	vbarId=mzWin[winn].vbar;
	hbarId=mzWin[winn].hbar;

	PixX= mz->lx * MAZE_BLOCK_LEN_DSP + 8;
	PixY= mz->ly * MAZE_BLOCK_LEN_DSP + 8;

	MMI_SendMessage(vbarId, MM_GETHYPER,1,&vbarAt);
	MMI_SendMessage(hbarId, MM_GETHYPER,1,&hbarAt);
	MMI_SendMessage(winId , MM_GETUSER,2,&UsrFr,&UsrSz);
	MMI_SendMessage(winId , MM_GETHYPER,1,&winAt);

	UsrX= UsrFr.rdwx;
	UsrY= UsrFr.rdwy;

	WinX1 = winAt.fr.lupx;
	WinY1 = winAt.fr.lupy;
	WinX2 = winAt.fr.rdwx;
	WinY2 = winAt.fr.rdwy;

	vbarAt.fr.lupx = WinX2 -(SHADE_SIZE+BAR_SIZE)+1;
	vbarAt.fr.lupy = WinY1 +UsrFr.lupy;
	vbarAt.fr.rdwx = WinX2 -(SHADE_SIZE)+1;
	vbarAt.fr.rdwy = WinY2 -(SHADE_SIZE+BAR_SIZE);
	MMI_SendMessage(vbarId,MM_SETHYPER,1,&vbarAt);

	hbarAt.fr.lupx = WinX1 +1;
	hbarAt.fr.lupy = WinY2 -(SHADE_SIZE+BAR_SIZE)+1;
	hbarAt.fr.rdwx = WinX2 -(SHADE_SIZE+BAR_SIZE);
	hbarAt.fr.rdwy = WinY2 -(SHADE_SIZE);
	MMI_SendMessage(hbarId,MM_SETHYPER,1,&hbarAt);

	m=PixY;  /* m項目のデータ */
	n=UsrY;  /* n項目の窓 */
	MMI_SendMessage(vbarId,MM_SETSCROLL,5,n-1,n-1,(m<n)?(n-1):(m-1),n,16);

	m=PixX;  /* m項目のデータ */
	n=UsrX;  /* n項目の窓 */
	MMI_SendMessage(hbarId,MM_SETSCROLL,5,n-1,n-1,(m<n)?(n-1):(m-1),n,16);
}






/*	initDataMZWIN:mazeWinBarV:MJ_SCRLL40の呼び出し関数	*/
int	SlideMazeWinV(int kobj)
{
	int winn,winId;

	for(winn=0; winn<MAZEWIN_NUM; winn++)
	{
		if(mzWin[winn].vbar==kobj)
		{
			break;
		}
	}

	winId=mzWin[winn].win;
	YsRepaintWindowUserArea(winId);

	return NOERR ;
}

/*	initDataMZWIN:mazeWinBarH:MJ_SCRLL40の呼び出し関数	*/
int	SlideMazeWinH(int kobj)
{
	int winn,winId;

	for(winn=0; winn<MAZEWIN_NUM; winn++)
	{
		if(mzWin[winn].hbar==kobj)
		{
			break;
		}
	}

	winId=mzWin[winn].win;
	YsRepaintWindowUserArea(winId);

	return NOERR ;
}



/*	initDataMZWIN:mazeWin:MJ_WINDOWL40の呼び出し関数	*/
int	ManageMazeWindow(int kobj,int messId,int argc,EVENT *pev)
{
	char *egb;
	int winX1,winY1;
	int winn,winId,vbarId,hbarId;
	int prt,min,max,len,page;
	FRAME org,siz;
	HYPER winAt;
	MAZEMAP *mz;

	egb=MMI_GetEgbPtr();

	for(winn=0; winn<MAZEWIN_NUM; winn++)
	{
		if(mzWin[winn].win==kobj)
		{
			break;
		}
	}

	mz=&mzWin[winn].map;
	winId=mzWin[winn].win;
	vbarId=mzWin[winn].vbar;
	hbarId=mzWin[winn].hbar;

	MMI_SendMessage(hbarId,MM_GETSCROLL,5,&prt,&min,&max,&len,&page);
	winX1 = prt-min-4;
	MMI_SendMessage(vbarId,MM_GETSCROLL,5,&prt,&min,&max,&len,&page);
	winY1 = prt-min-4;

	if(messId==MM_ERASE)
	{
		mzWin[winn].openflag = FALSE;
	}
	else if(messId==MM_WAKE)
	{
		mzWin[winn].openflag = TRUE;
		ActiveWin = winn;
	}
	else if(messId==MM_SHOW)
	{
		mzWin[winn].openflag = TRUE;
		MazeClearMapWin(egb);
		MazeDrawMapWin
		    (egb,mz,-winX1,-winY1,0,0,mz->lx-1,mz->ly-1,MAZE_BLOCK_LEN_DSP);
	}
	else if(messId==MM_MOUSEON)
	{
		mzWin[winn].saveflag=FALSE;
		FirstInputWall(mz,winX1,winY1,(POINT *)&pev->info);
		InputWall(mz,winX1,winY1,(POINT *)&pev->info);
	}
	else if(messId==MM_UPDATE)
	{
		mzWin[winn].openflag = TRUE;
		MMI_SendMessage( winId , MM_GETUSER , 2 , &org , &siz ) ;
		printf("ManageMazeWindow(9A)\n");
		MMI_SendMessage( winId , MM_GETHYPER , 1 , &winAt ) ;
		printf("ManageMazeWindow(9B)\n");
		org.rdwx = winAt.fr.rdwx -
		           ( SHADE_SIZE + BAR_SIZE )-winAt.fr.lupx - org.lupx;
		org.rdwy = winAt.fr.rdwy - 
		           ( SHADE_SIZE + BAR_SIZE )-winAt.fr.lupy - org.lupy;
		MMI_SendMessage( winId , MM_SETUSER, 2, &org, &siz );

		ResetWindowScrollBar(winn);
	}

	return NOERR ;
}


static void FirstInputWall(MAZEMAP *mz,int winX1,int winY1,POINT *start)
{
	extern int InputWallN;
	POINT p1;
	int CenX,CenY,ModX,ModY;

	p1=(*start);
	MG_GlobalToLocal(&p1);
	p1.x+=winX1;
	p1.y+=winY1;

	switch(InputWallN)
	{
	case INPUT_KIND_WALL:
		CenX=(p1.x+MAZE_BLOCK_LEN_DSP/2)/MAZE_BLOCK_LEN_DSP;
		CenY=(p1.y+MAZE_BLOCK_LEN_DSP/2)/MAZE_BLOCK_LEN_DSP;
		ModX=YsAbs(p1.x-CenX*MAZE_BLOCK_LEN_DSP);
		ModY=YsAbs(p1.y-CenY*MAZE_BLOCK_LEN_DSP);

		if(ModY<=MAZE_BLOCK_PLATE &&
		   ModX> MAZE_BLOCK_PLATE)
		{
			CenX=p1.x/MAZE_BLOCK_LEN_DSP;
			InsertWallWin(mz,winX1,winY1,CenX,CenY,0);
		}
		else if(ModX<=MAZE_BLOCK_PLATE &&
		        ModY> MAZE_BLOCK_PLATE)
		{
			CenY=p1.y/MAZE_BLOCK_LEN_DSP;
			InsertWallWin(mz,winX1,winY1,CenX,CenY,1);
		}
		break;
	case INPUT_KIND_FLOOR:
		p1.x/=MAZE_BLOCK_LEN_DSP;
		p1.y/=MAZE_BLOCK_LEN_DSP;
		InsertFloorWin(mz,winX1,winY1,p1.x,p1.y,0);
		break;
	}
}


static void InputWall(MAZEMAP *mz,int winX1,int winY1,POINT *start)
{
	int edf;
	EVENT *pev;
	POINT p1,p2;

	p1=(*start);
	MG_GlobalToLocal(&p1);

	p1.x+=winX1;
	p1.y+=winY1;

	edf=FALSE;
	printf("Begin Dragging.\n");
	while(edf==FALSE)
	{
		MMI_iosense();
		if(MMI_GetEvnt(EVMOSUP | EVMOSDRAG,&pev)==0)
		{
			if((pev->what & EVMOSUP)!=0)
			{
				edf=TRUE;
			}
			else if((pev->what & EVMOSDRAG)!=0)
			{
				p2=*((POINT *)&pev->info);
				MG_GlobalToLocal(&p2);
				p2.x+=winX1;
				p2.y+=winY1;

				InsertWallMark(mz,winX1,winY1,&p1,&p2);

				p1=p2;
			}
		}
	}
}

static void InsertWallMark(MAZEMAP *mz,int winX1,int winY1,POINT *st,POINT *ed)
{
	int x,y,x1,y1,x2,y2,vx,vy;
	extern int InputWallN;

	x1=st->x;
	y1=st->y;
	x2=ed->x;
	y2=ed->y;

	switch(InputWallN)
	{
	case INPUT_KIND_WALL:
		x1=(x1+MAZE_BLOCK_LEN_DSP/2)/MAZE_BLOCK_LEN_DSP;
		y1=(y1+MAZE_BLOCK_LEN_DSP/2)/MAZE_BLOCK_LEN_DSP;
		x2=(x2+MAZE_BLOCK_LEN_DSP/2)/MAZE_BLOCK_LEN_DSP;
		y2=(y2+MAZE_BLOCK_LEN_DSP/2)/MAZE_BLOCK_LEN_DSP;

		vx=YsSgn(x2-x1);
		vy=YsSgn(y2-y1);
		if(x1>x2)swapI(x1,x2);
		if(y1>y2)swapI(y1,y2);

		if(x1<0)x1=0;
		if(y1<0)y1=0;
		if(x2>mz->lx)x2=mz->lx;
		if(y2>mz->ly)y2=mz->ly;

		for(x=x1; x<x2; x++)
		{
			/* 常に,移動前のyでの横線をひく */
			if(vy>0)
			{
				InsertWallWin(mz,winX1,winY1,x,y1,0);
			}
			else
			{
				InsertWallWin(mz,winX1,winY1,x,y2-1,2);
			}
		}
		for(y=y1; y<y2; y++)
		{
			/* 常に,移動後のxでの縦線をひく */
			if(vx>0)
			{
				InsertWallWin(mz,winX1,winY1,x2-1,y,3);
			}
			else
			{
				InsertWallWin(mz,winX1,winY1,x1,y,1);
			}
		}

		break;
	case INPUT_KIND_FLOOR:
		x2/=MAZE_BLOCK_LEN_DSP;
		y2/=MAZE_BLOCK_LEN_DSP;
		InsertFloorWin(mz,winX1,winY1,x2,y2,3);
		break;
	}

}

static void InsertWallWin(MAZEMAP *mz,int winX1,int winY1,int x,int y,int d)
{
	extern int InputWallN;     /* 入力壁の種類 */
	int lx,ly;
	char *egb;

	egb=MMI_GetEgbPtr();

	switch(InputWallN)
	{
	case WALL_WALL:
		InsertWall(mz,x,y,d,1,1);
		break;
	case WALL_PASS:
		InsertWall(mz,x,y,d,1,0);
		break;
	case WALL_DOOR:
		InsertWall(mz,x,y,d,2,0);
		break;
	case WALL_INVISIBLE:
		InsertWall(mz,x,y,d,0,1);
		break;
	case WALL_DELETE:
		InsertWall(mz,x,y,d,0,0);
		break;
	}

	MG_mosDisp(2);
	MazeDrawMapWin(egb,mz,-winX1,-winY1,x,y,x,y,MAZE_BLOCK_LEN_DSP);

	lx=mz->lx;
	ly=mz->ly;
	if(x==0)
	{
		MazeDrawMapWin(egb,mz,-winX1,-winY1,lx-1,y,lx-1,y,MAZE_BLOCK_LEN_DSP);
	}
	else if(x==lx)
	{
		MazeDrawMapWin(egb,mz,-winX1,-winY1,lx-1,y,lx-1,y,MAZE_BLOCK_LEN_DSP);
		MazeDrawMapWin(egb,mz,-winX1,-winY1,0   ,y,0   ,y,MAZE_BLOCK_LEN_DSP);
	}

	if(y==0)
	{
		MazeDrawMapWin(egb,mz,-winX1,-winY1,x,ly-1,x,ly-1,MAZE_BLOCK_LEN_DSP);
	}
	else if(y==ly)
	{
		MazeDrawMapWin(egb,mz,-winX1,-winY1,x,ly-1,x,ly-1,MAZE_BLOCK_LEN_DSP);
		MazeDrawMapWin(egb,mz,-winX1,-winY1,x,0   ,x,0   ,MAZE_BLOCK_LEN_DSP);
	}

	MG_mosDisp(3);
}

static void InsertFloorWin(MAZEMAP *mz,int winX1,int winY1,int x,int y,int d)
{
	extern int InputWallN;     /* 入力壁の種類 */
	extern int InputNum;
	char *egb;

	egb=MMI_GetEgbPtr();

	switch(InputWallN)
	{
	case FLOOR_FLOOR:
		SetFloor(mz,x,y);
		break;
	case FLOOR_CEILING:
		SetCeiling(mz,x,y);
		break;
	case FLOOR_NUMBER:
		SetNumber(mz,x,y,InputNum);
		break;
	case FLOOR_DELFLOOR:
		ResetFloor(mz,x,y);
		break;
	case FLOOR_DELCEILING:
		ResetCeiling(mz,x,y);
		break;
	}

	MG_mosDisp(2);
	MazeDrawMapWin(egb,mz,-winX1,-winY1,x,y,x,y,MAZE_BLOCK_LEN_DSP);
	MG_mosDisp(3);
}
