// CMAMEWindow.cpp
// A window for a display
// Casey Fleser
// November 1, 1997

#include <BeHeaders>

#include "CMAMEWindow.h"
#include "CIOThread.h"
#include "LMenuBar.h"
#include "Defines.h"

#pragma optimization_level 4

extern int gQuitting;

#pragma mark ---Window---

CMAMEWindow::CMAMEWindow(
	const char	*inName,
	BRect		inRect) :
		BWindow(inRect, inName, B_TITLED_WINDOW, B_NOT_ZOOMABLE | B_NOT_RESIZABLE)
{
	BRect 	menuRect(0, 0, inRect.Width(), kMenuBarHeight);
	BRect 	frameRect(inRect);
	
	mCurPt.Set(-1,-1);
	mLastPt.Set(-1,-1);
	frameRect.OffsetTo(B_ORIGIN);
	frameRect.top += kMenuBarHeight + 1;
	
	SetupMenus(menuRect);
	SetupViews(frameRect);
	
	mIO = new CIOThread(this);
	mIO->Go();
}

CMAMEWindow::~CMAMEWindow()
{
	delete mIO;
}

void
CMAMEWindow::SetupMenus(
	BRect	inRect)
{
	BMenu	*fileMenu;
	
	LMenuBar *aMenuBar = new LMenuBar(inRect, "mainMenu");
	AddChild (aMenuBar);
	
	aMenuBar->MainMenu()->AddItem(new BMenuItem("About BeMAME", new BMessage(B_ABOUT_REQUESTED)));
	aMenuBar->MainMenu()->SetTargetForItems(be_app);

	fileMenu = new BMenu("File");
	fileMenu->AddItem(new BMenuItem("Select Game...", new BMessage(eWhat_SelectROM),  'O'));
	fileMenu->AddSeparatorItem();
	fileMenu->AddItem(new BMenuItem("Quit", new BMessage(B_QUIT_REQUESTED),  'Q'));
	fileMenu->SetTargetForItems(be_app);
	aMenuBar->AddItem(fileMenu);
}

void
CMAMEWindow::SetupViews(
	BRect	inRect)
{
	mView = new CMAMEView(inRect);

	AddChild (mView);
	mView->MakeFocus(true);
}

void
CMAMEWindow::Quit()
{
	if (!gQuitting)
		gQuitting = 1;
	else
		BWindow::Quit();
}

void
CMAMEWindow::FrameMoved(
	BPoint		new_position)
{
	mView->FixFrame();
}

void
CMAMEWindow::WindowActivated(
	bool			inState)
{
	mIO->Activate(inState);
}

void
CMAMEWindow::Show()
{
	BWindow::Show();
//	set_thread_priority(Thread(), B_DISPLAY_PRIORITY + 1);
}

void
CMAMEWindow::MessageReceived(
	BMessage	 *inMessage)
{
	if (inMessage->what == eWhat_PollMouse) {
		uint32	button;
		
		mView->GetMouse(&mCurPt, &button);
		if (mLastPt.x == -1)
			mLastPt = mCurPt;
	}
	else						
		BWindow::MessageReceived(inMessage);
}

void
CMAMEWindow::Init()
{
	Show();
	mView->FixFrame();
}

void
CMAMEWindow::Exit()
{
	PostMessage(B_QUIT_REQUESTED);
}

void
CMAMEWindow::InitPalette()
{
	BScreen	theScreen(this);
	int32	i;
		
	for (i=0;i<256; i++) {
		mPalette[i] = theScreen.ColorForIndex(i);
		mPenIndex[i] = i;
	}
}

void
CMAMEWindow::SetPen(
	int16		inPen,
	uchar		inRed,
	uchar		inGreen,
	uchar		inBlue)
{
	BScreen		theScreen(this);
	
	mPalette[inPen].red = inRed;
	mPalette[inPen].green = inGreen;
	mPalette[inPen].blue = inBlue;
	mPenIndex[inPen] = theScreen.IndexForColor(mPalette[inPen]);
}

void
CMAMEWindow::GetPen(
	int16		inPen,
	uchar		*outRed,
	uchar		*outGreen,
	uchar		*outBlue)
{
	*outRed = mPalette[inPen].red;
	*outGreen = mPalette[inPen].green;
	*outBlue = mPalette[inPen].blue;
}

void
CMAMEWindow::Resize(
	int16		inWidth,
	int16		inHeight)
{
	Lock();
	mView->Resize(inWidth, inHeight);
	Unlock();
}

void
CMAMEWindow::CopyBits(
	void			*inSrc,
	int16		inHeight,
	int16		inWidth)
{
// This seems reasonably fast, but if someone finds a faster way...
	uchar	*src = (uchar *)inSrc;
	uint32	*dst = (uint32 *)mView->Bitmap()->Bits(), longWrd;
	uchar	*pen = &mPenIndex[0];
	int32	byteCount = inHeight * inWidth;

	while (byteCount >= 4) {
		longWrd = (*(pen + *src) << 24) | (*(pen + *(src + 1)) << 16) | (*(pen + *(src + 2)) << 8) | *(pen + *(src + 3));
		*dst = longWrd;
		src += 4;
		dst++;
		byteCount -= 4;
	}
	while (byteCount--) {
		*(uchar *)dst = *(pen + *src);
		src++;
		((uchar *)dst)++;
	}
	PostMessage('draw', mView);
}

void
CMAMEWindow::PollMouse()
{
	PostMessage(eWhat_PollMouse);
}

void
CMAMEWindow::ReadMouse(
	int16		*outX,
	int16		*outY)
{
	*outX = (int16)(mCurPt.x - mLastPt.x);
	*outY = (int16)(mCurPt.y - mLastPt.y);
	mLastPt = mCurPt;
}

#pragma mark ---View---

// CGameView.cpp

CMAMEView::CMAMEView(
	BRect	inRect) :
		 BView (inRect, "MAMEView", B_FOLLOW_ALL, B_WILL_DRAW | B_NAVIGABLE)
{
	inRect.InsetBy(1,1);
	inRect.OffsetTo(0,0);
	
	SetViewColor(16,16,16);
	mBitmap = new BBitmap(inRect, B_COLOR_8_BIT);
}

CMAMEView::~CMAMEView()
{
	delete mBitmap;
}

void
CMAMEView::Resize(
	float	inWidth,
	float	inHeight)
{
	Window()->ResizeTo(inWidth+1, inHeight + kMenuBarHeight + 2);
	ResizeTo(inWidth+1, inHeight+2);
	
	delete mBitmap;
	
	mBitmap = new BBitmap(BRect(0,0,inWidth-1, inHeight-1), B_COLOR_8_BIT, false, true);
}

void
CMAMEView::Draw(
	BRect	 inRect)
{
	DrawBitmapAsync(mBitmap, BPoint(0, 0));
}

void
CMAMEView::MessageReceived(
	BMessage	 *inMessage)
{
	if (inMessage->what == 'draw') {
		DrawBitmapAsync(mBitmap, BPoint(0, 0));
		Flush();
	}
	else						
		BView::MessageReceived(inMessage);
}

void
CMAMEView::FixFrame()
{
	BPoint	bmPoint(0,0);
	uint32	x;
	
	Window()->Lock();
	ConvertToScreen(&bmPoint);
	x = bmPoint.x;
	x %= 8;
	if (x)
		Window()->MoveBy(x, 0);
	Window()->Unlock();
}
