/*
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include "Be.h"


_IMPEXP_BE const pattern B_SOLID_HIGH = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
_IMPEXP_BE const pattern B_SOLID_LOW = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 };
_IMPEXP_BE const pattern B_MIXED_COLORS = { 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA };


// constructor
BView::BView (BRect frame, const char *name, uint32 resizeMask, uint32 flags) :
BHandler (name),
owner (0),
parent (0),
next_sibling (0),
prev_sibling (0),
first_child (0),
attached (false),
fCachedBounds (frame),
font (const_cast<BFont*>(be_plain_font)),
penSize (1),
lineArray (0)
{
	color.red = 255;
	color.green = 255;
	color.blue = 255;
	color.alpha = 0;

	highColor.red = 0;
	highColor.green = 0;
	highColor.blue = 0;
	highColor.alpha = 0;

	lowColor.red = 255;
	lowColor.green = 255;
	lowColor.blue = 255;
	lowColor.alpha = 0;

	origin.x = 0;
	origin.y = 0;
}


BView::BView (BMessage *archive)
{
}



// destructor
BView::~BView()
{
#ifdef _DEBUG
	winBe::debugMessage ("BView destructor: " + std::string (Name ()));
#endif // _DEBUG

	if (font != be_plain_font && font != be_bold_font && font != be_fixed_font)
		delete font;

	// Delete child views
	for (std::vector<BView*>::iterator i = viewList.begin (); i != viewList.end (); ++i) {
		winBe::destroyView (*i);
		delete *i;
	}
	winBe::destroyView (this);
}


// Archive
status_t BView::Archive (BMessage *data, bool deep) const
{
	return B_ERROR;
}


// AttachedToWindow
void BView::AttachedToWindow ()
{
}


// AllAttached
void BView::AllAttached ()
{
}


// DetachedFromWindow
void BView::DetachedFromWindow ()
{
}


// AllDetached
void BView::AllDetached ()
{
}


void BView::MessageReceived(BMessage *msg)
{
	switch (msg->what) {

		case B_KEY_DOWN:
			KeyDown (msg->FindString ("byte"), msg->FindInt32 ("num_bytes"));
			break;

		case B_KEY_UP:
			KeyUp (msg->FindString ("byte"), msg->FindInt32 ("num_bytes"));
			break;

		case B_MOUSE_DOWN:
			MouseDown (msg->FindPoint ("where"));
			break;

		case B_MOUSE_UP:
			MouseUp (msg->FindPoint ("where"));
			break;

		case B_MOUSE_MOVED:
		{
			BMessage* a_message = 0;
			msg->FindMessage ("a_message", a_message);
			MouseMoved (msg->FindPoint ("where"), msg->FindInt32 ("code"), a_message);
			break;
		}

		case B_VIEW_MOVED:
			FrameMoved (msg->FindPoint ("new_position"));
			break;

		case B_VIEW_RESIZED:
			FrameResized (msg->FindFloat ("new_width"), msg->FindFloat ("new_height"));
			break;

		case B_VALUE_CHANGED:
			//scrollbar->ValueChanged (msg->FindFloat ("new_value"));
			break;

		case B_PULSE:
			Pulse ();
			break;

		default:
			BHandler::MessageReceived (msg);
	}
}


void BView::Draw (BRect updateRect)
{
}


void BView::MouseDown (BPoint where)
{
}


void BView::MouseUp (BPoint where)
{
}


void BView::MouseMoved (BPoint where, uint32 code, const BMessage *a_message)
{
}


void BView::WindowActivated(bool state) {}


void BView::KeyDown(const char *bytes, int32 numBytes) {}


void BView::KeyUp(const char *bytes, int32 numBytes) {}


void BView::Pulse() {}


void BView::FrameMoved(BPoint new_position) {}


void BView::FrameResized(float new_width, float new_height) {}


void BView::TargetedByScrollView(BScrollView *scroll_view) {}


void BView::ConstrainClippingRegion(BRegion *region) {}


void BView::SetDrawingMode(drawing_mode mode) {}


// SetViewColor
void BView::SetViewColor (rgb_color c)
{
	color = c;
	winBe::setViewColor (this, color.red, color.green, color.blue);
}


// ViewColor
rgb_color BView::ViewColor () const
{
	return color;
}


// SetHighColor
void BView::SetHighColor (rgb_color a_color)
{
	highColor = a_color;
	winBe::setPen (this, penSize, highColor.red, highColor.green, highColor.blue);
}


// SetLowColor
void BView::SetLowColor (rgb_color a_color)
{
	lowColor = a_color;
}


void BView::SetFlags (uint32 flags) {
	f_type = flags;
}


uint32 BView::Flags () const
{
	return f_type;
}


void BView::SetResizingMode (uint32 mode) {}


void BView::ScrollTo (BPoint where) {}


void BView::MakeFocus (bool focusState) {}


void BView::Show () {}


void BView::Hide () {}


void BView::GetPreferredSize (float *width, float *height) {}


void BView::ResizeToPreferred () {}


BHandler* BView::ResolveSpecifier (BMessage *msg, int32 index, BMessage *specifier, int32 form, const char *property) { return 0; }


status_t BView::GetSupportedSuites(BMessage *data) { return 0; }


status_t BView::Perform(perform_code d, void *arg) { return 0; }


void BView::DrawAfterChildren(BRect r) {}


void BView::_ReservedView2 () {}


void BView::_ReservedView3 () {}


void BView::_ReservedView4 () {}


void BView::_ReservedView5 () {}


void BView::_ReservedView6 () {}


void BView::_ReservedView7 () {}


void BView::_ReservedView8 () {}


void BView::_ReservedView9 () {}


void BView::_ReservedView10 () {}


void BView::_ReservedView11 () {}


void BView::_ReservedView12 () {}


void BView::_ReservedView13 () {}


void BView::_ReservedView14 () {}


void BView::_ReservedView15 () {}


void BView::_ReservedView16 () {}


// AddChild
void BView::AddChild (BView *child, BView *before)
{
	if (!before)
		viewList.push_back (child);
	else {
		for (std::vector<BView*>::iterator i = viewList.begin (); i != viewList.end (); ++i) {
			if (*i == before) {
				viewList.insert (i, child);
				break;
			}
		}
	}

	child->set_owner (owner);
	child->parent = this;
	child->AttachedToWindow ();
	child->AllAttached ();
}


// RemoveSelf
bool BView::RemoveSelf ()
{
	return false; // not implemented
}


// Parent
BView* BView::Parent () const
{
	return parent;
}


// Frame
BRect BView::Frame () const
{
	return fCachedBounds;
}


// Bounds
BRect BView::Bounds () const
{
	BRect rect = fCachedBounds;
	rect.OffsetBy (-rect.left, -rect.top);
	return rect;
}


// Invalidate
void BView::Invalidate (BRect invalRect)
{
	winBe::invalidate (this, invalRect.left, invalRect.top, invalRect.right, invalRect.bottom);
}


// Invalidate
void BView::Invalidate ()
{
	Invalidate (Bounds ());
}


// set_owner
void BView::set_owner (BWindow* the_owner)
{
	owner = the_owner;
	attached = true;
}


// SetOrigin
void BView::SetOrigin (float x, float y)
{
	SetOrigin (BPoint (x, y));
}


// SetOrigin
void BView::SetOrigin (BPoint pt)
{
	origin = pt;
}


// Origin
BPoint BView::Origin () const
{
	return origin;
}


// SetPenSize
void BView::SetPenSize (float size)
{
	penSize = size;
	winBe::setPen (this, penSize, highColor.red, highColor.green, highColor.blue);
}


// DrawString
void BView::DrawString (const char *aString, int32 length, BPoint location, escapement_delta *delta)
{
	winBe::drawString (this, aString, length, location.x, location.y - font->Size (), highColor.red, highColor.green, highColor.blue);
}


// DrawString
void BView::DrawString (const char *aString, BPoint location, escapement_delta *delta)
{
	DrawString (aString, strlen (aString), location, delta);
}


// StrokeLine
void BView::StrokeLine (BPoint pt0, BPoint pt1, pattern p)
{
	winBe::drawLine (this, pt0.x, pt0.y, pt1.x, pt1.y);
	SetOrigin (pt1);
}


// StrokeLine
void BView::StrokeLine (BPoint pt1, pattern p)
{
	StrokeLine (origin, pt1, p);
}


// StrokeRect
void BView::StrokeRect (BRect r, pattern p)
{
	StrokeLine (r.LeftTop (), r.RightTop (), p);
	StrokeLine (r.RightTop (), r.RightBottom (), p);
	StrokeLine (r.RightBottom (), r.LeftBottom (), p);
	StrokeLine (r.LeftBottom (), r.LeftTop (), p);
}


// BeginLineArray
void BView::BeginLineArray (int32 count)
{
	if (lineArray)
		delete lineArray;
	lineArray = new winBe::LineArray [count];
	lineArrayIndex = 0;
}


// AddLine
void BView::AddLine (BPoint pt0, BPoint pt1, rgb_color col)
{
	lineArray[lineArrayIndex].pt0_x = pt0.x;
	lineArray[lineArrayIndex].pt0_y = pt0.y;
	lineArray[lineArrayIndex].pt1_x = pt1.x;
	lineArray[lineArrayIndex].pt1_y = pt1.y;
	lineArray[lineArrayIndex].red = col.red;
	lineArray[lineArrayIndex].green = col.green;
	lineArray[lineArrayIndex].blue = col.blue;
	lineArrayIndex++;
}


// EndLineArray
void BView::EndLineArray ()
{
	winBe::drawLineArray (this, lineArray, lineArrayIndex, penSize);
	delete lineArray;
	lineArray = 0;
}


// FillRect
void BView::FillRect (BRect r, pattern p)
{
	if (p.data[0] == 0)
		winBe::fillRect (this, r.left, r.top, r.right, r.bottom, lowColor.red, lowColor.green, lowColor.blue);
	else
		winBe::fillRect (this, r.left, r.top, r.right, r.bottom, highColor.red, highColor.green, highColor.blue);
}


// SetFont
void BView::SetFont (const BFont *font, uint32 mask)
{
	if (this->font == be_plain_font || this->font == be_bold_font || this->font == be_fixed_font)
		this->font = new BFont (font);
	else {
		if (mask & B_FONT_FAMILY_AND_STYLE)
			this->font->SetFamilyAndStyle (font->FamilyAndStyle ());
		if (mask & B_FONT_SIZE)
			this->font->SetSize (font->Size ());
		if (mask & B_FONT_SHEAR)
			this->font->SetShear (font->Shear ());
		if (mask & B_FONT_ROTATION)
			this->font->SetRotation (font->Rotation ());
		if (mask & B_FONT_SPACING)
			this->font->SetSpacing (font->Spacing ());
		if (mask & B_FONT_ENCODING)
			this->font->SetEncoding (font->Encoding ());
		if (mask & B_FONT_FACE)
			this->font->SetFace (font->Face ());
		if (mask & B_FONT_FLAGS)
			this->font->SetFlags (font->Flags ());
	}
}


// SetFontSize
void BView::SetFontSize (float size)
{
	BFont font;
	font.SetSize (size);
	SetFont (&font, B_FONT_SIZE);
}


// GetFont
void BView::GetFont (BFont *font) const
{
	*font = *this->font;
}


void BView::GetFontHeight(font_height *height) const
{
	font->GetHeight (height);
}

		
// IsFocus
bool BView::IsFocus () const
{
	return false; // not implemented
}

		
// Window
BWindow* BView::Window () const
{
	return owner;
}


// ResizeTo
void BView::ResizeTo (float width, float height)
{
	fCachedBounds.right = fCachedBounds.left + width;
	fCachedBounds.bottom = fCachedBounds.top + height;
}


// SetMouseEventMask
status_t BView::SetMouseEventMask (uint32 mask, uint32 options)
{
//	if (mask & B_POINTER_EVENTS)
//		winBe::captureMouse (this);
	if (mask & B_KEYBOARD_EVENTS)
		winBe::captureKeyboard (this);

	return 0;
}


// createChildren
// Non-Be function to recurse through child views creating them
void BView::createChildren ()
{
	for (std::vector<BView*>::iterator i = viewList.begin (); i != viewList.end (); ++i) {
		BRect frame = (*i)->Frame ();
		(*i)->set_owner (owner);
		winBe::createView (*i, this, (*i)->Name (), frame.left, frame.top, frame.right, frame.bottom);
		winBe::setViewColor (*i, (*i)->color.red, (*i)->color.green, (*i)->color.blue);
		(*i)->createChildren ();
	}
}


// sendViewMouseUpMessage
void winBe::sendViewMouseUpMessage (BView* view, int buttons, int xpos, int ypos, int modifiers)
{
	BMessage* msg = new BMessage (B_MOUSE_UP);
	msg->AddInt64 ("when", 0);
	msg->AddPoint ("where", BPoint (xpos, ypos));
	msg->AddInt32 ("modifiers", modifiers);
	msg->AddInt32 ("buttons", buttons);
	msg->AddInt32 ("clicks", 1);

	// bypass message queue
	view->MessageReceived (msg);
	delete msg;
}


// sendViewMouseDownMessage
void winBe::sendViewMouseDownMessage (BView* view, int buttons, int xpos, int ypos, int modifiers)
{
	BMessage* msg = new BMessage (B_MOUSE_DOWN);
	msg->AddInt64 ("when", 0);
	msg->AddPoint ("where", BPoint (xpos, ypos));
	msg->AddInt32 ("modifiers", modifiers);
	msg->AddInt32 ("buttons", buttons);
	msg->AddInt32 ("clicks", 1);

	// bypass message queue
	view->MessageReceived (msg);
	delete msg;
}


// sendViewMouseMovedMessage
void winBe::sendViewMouseMovedMessage (BView* view, int xpos, int ypos)
{
	static BPoint lastPos;

	BMessage* msg = new BMessage (B_MOUSE_MOVED);
	msg->AddInt64 ("when", 0);
	msg->AddPoint ("where", BPoint (xpos, ypos));

	int32 code = B_INSIDE_VIEW;
	//...

	lastPos.Set (xpos, ypos);

	// not sure about this one
	msg->AddInt32 ("code", code);

	// bypass message queue
	view->MessageReceived (msg);
	delete msg;
}


// callViewDraw
void winBe::callViewDraw (BView* view, int left, int top, int right, int bottom)
{
	winBe::selectFont (view, view->GetFont ()->nativeFont ());
	view->Draw (BRect (left, top, bottom, right));
}


// Sync
void BView::Sync () const
{
}


float BView::StringWidth (const char *string) const
{
	return StringWidth (string, strlen (string));
}


float BView::StringWidth (const char *string, int32 length) const
{
	return font->StringWidth (string, length);
}


BView* BView::ChildAt (int32 index) const
{
	return index < viewList.size () ? viewList[index] : 0;
}


void BView::StrokeEllipse(	BPoint center, float xRadius, float yRadius, pattern p/* = B_SOLID_HIGH*/)
{
	BRect rect;
	rect.left = center.x - xRadius;
	rect.top = center.y - yRadius;
	rect.right = center.x + xRadius;
	rect.bottom = center.y + yRadius;
	StrokeEllipse (rect, p);
}


void BView::StrokeEllipse (BRect r, pattern p/* = B_SOLID_HIGH*/)
{
	winBe::drawEllipse (this, r.left, r.top, r.right, r.bottom);
}


void BView::FillEllipse (BPoint center, float xRadius, float yRadius, pattern p/* = B_SOLID_HIGH*/)
{
	BRect rect;
	rect.left = center.x - xRadius;
	rect.top = center.y - yRadius;
	rect.right = center.x + xRadius;
	rect.bottom = center.y + yRadius;
	FillEllipse (rect, p);
}


void BView::FillEllipse(BRect r, pattern p/* = B_SOLID_HIGH*/)
{
	winBe::fillEllipse (this, r.left, r.top, r.right, r.bottom, highColor.red, highColor.green, highColor.blue);
}


void BView::MoveTo (BPoint where)
{
	MoveTo (where.x, where.y);
}


void BView::MoveTo (float x, float y)
{
	int xoff = fCachedBounds.left - x;
	int yoff = fCachedBounds.top - y;
	fCachedBounds.OffsetBy (-xoff, -yoff);
}


void BView::ResizeBy (float dh, float dv)
{
	fCachedBounds.right += dh;
	fCachedBounds.bottom += dv;
}


void BView::DrawBitmapAsync (const BBitmap *aBitmap, BPoint where)
{
}

