/*
 * Copyright 2009, Haiku, Inc.
 * Distributed under the terms of the MIT License.
 *
 * Authors:
 *		Michael Lotz <mmlr@mlotz.ch>
 */
#ifndef REMOTE_MESSAGE_H
#define REMOTE_MESSAGE_H
 
#ifndef CLIENT_COMPILE
#	include "PatternHandler.h"
#	include <ViewPrivate.h>
#endif
 
#include "StreamingRingBuffer.h"
 
#include <AffineTransform.h>
#include <GraphicsDefs.h>
#include <Region.h>
 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
class BBitmap;
class BFont;
class BGradient;
class BView;
class DrawState;
class Pattern;
class RemotePainter;
class ServerBitmap;
class ServerCursor;
class ServerFont;
struct ViewLineArrayInfo;
 
enum {
	RP_INIT_CONNECTION = 1,
	RP_UPDATE_DISPLAY_MODE,
	RP_CLOSE_CONNECTION,
	RP_GET_SYSTEM_PALETTE,
	RP_GET_SYSTEM_PALETTE_RESULT,
 
	RP_CREATE_STATE = 20,
	RP_DELETE_STATE,
	RP_ENABLE_SYNC_DRAWING,
	RP_DISABLE_SYNC_DRAWING,
	RP_INVALIDATE_RECT,
	RP_INVALIDATE_REGION,
 
	RP_SET_OFFSETS = 40,
	RP_SET_HIGH_COLOR,
	RP_SET_LOW_COLOR,
	RP_SET_PEN_SIZE,
	RP_SET_STROKE_MODE,
	RP_SET_BLENDING_MODE,
	RP_SET_PATTERN,
	RP_SET_DRAWING_MODE,
	RP_SET_FONT,
	RP_SET_TRANSFORM,
 
	RP_CONSTRAIN_CLIPPING_REGION = 60,
	RP_COPY_RECT_NO_CLIPPING,
	RP_INVERT_RECT,
	RP_DRAW_BITMAP,
	RP_DRAW_BITMAP_RECTS,
 
	RP_STROKE_ARC = 80,
	RP_STROKE_BEZIER,
	RP_STROKE_ELLIPSE,
	RP_STROKE_POLYGON,
	RP_STROKE_RECT,
	RP_STROKE_ROUND_RECT,
	RP_STROKE_SHAPE,
	RP_STROKE_TRIANGLE,
	RP_STROKE_LINE,
	RP_STROKE_LINE_ARRAY,
 
	RP_FILL_ARC = 100,
	RP_FILL_BEZIER,
	RP_FILL_ELLIPSE,
	RP_FILL_POLYGON,
	RP_FILL_RECT,
	RP_FILL_ROUND_RECT,
	RP_FILL_SHAPE,
	RP_FILL_TRIANGLE,
	RP_FILL_REGION,
 
	RP_FILL_ARC_GRADIENT = 120,
	RP_FILL_BEZIER_GRADIENT,
	RP_FILL_ELLIPSE_GRADIENT,
	RP_FILL_POLYGON_GRADIENT,
	RP_FILL_RECT_GRADIENT,
	RP_FILL_ROUND_RECT_GRADIENT,
	RP_FILL_SHAPE_GRADIENT,
	RP_FILL_TRIANGLE_GRADIENT,
	RP_FILL_REGION_GRADIENT,
 
	RP_STROKE_POINT_COLOR = 140,
	RP_STROKE_LINE_1PX_COLOR,
	RP_STROKE_RECT_1PX_COLOR,
 
	RP_FILL_RECT_COLOR = 160,
	RP_FILL_REGION_COLOR_NO_CLIPPING,
 
	RP_DRAW_STRING = 180,
	RP_DRAW_STRING_WITH_OFFSETS,
	RP_DRAW_STRING_RESULT,
	RP_STRING_WIDTH,
	RP_STRING_WIDTH_RESULT,
	RP_READ_BITMAP,
	RP_READ_BITMAP_RESULT,
 
	RP_SET_CURSOR = 200,
	RP_SET_CURSOR_VISIBLE,
	RP_MOVE_CURSOR_TO,
 
	RP_MOUSE_MOVED = 220,
	RP_MOUSE_DOWN,
	RP_MOUSE_UP,
	RP_MOUSE_WHEEL_CHANGED,
 
	RP_KEY_DOWN = 240,
	RP_KEY_UP,
	RP_UNMAPPED_KEY_DOWN,
	RP_UNMAPPED_KEY_UP,
	RP_MODIFIERS_CHANGED
};
 
 
class RemoteMessage {
public:
								RemoteMessage(StreamingRingBuffer* source,
									StreamingRingBuffer *target);
								~RemoteMessage();
 
		void					Start(uint16 code);
		status_t				Flush();
		void					Cancel();
 
		status_t				NextMessage(uint16& code);
		uint16					Code() { return fCode; }
		uint32					DataLeft() { return fDataLeft; }
 
		template<typename T>
		void					Add(const T& value);
 
		void					AddString(const char* string, size_t length);
		void					AddRegion(const BRegion& region);
		void					AddGradient(const BGradient& gradient);
		void					AddTransform(const BAffineTransform& transform);
 
#ifndef CLIENT_COMPILE
		void					AddBitmap(const ServerBitmap& bitmap,
									bool minimal = false);
		void					AddFont(const ServerFont& font);
		void					AddPattern(const Pattern& pattern);
		void					AddDrawState(const DrawState& drawState);
		void					AddArrayLine(const ViewLineArrayInfo& line);
		void					AddCursor(const ServerCursor& cursor);
#else
		void					AddBitmap(const BBitmap& bitmap);
#endif
 
		template<typename T>
		void					AddList(const T* array, int32 count);
 
		template<typename T>
		status_t				Read(T& value);
 
		status_t				ReadRegion(BRegion& region);
		status_t				ReadFontState(BFont& font);
									// sets font state
		status_t				ReadViewState(BView& view, ::pattern& pattern);
									// sets viewstate and returns pattern
 
		status_t				ReadString(char** _string, size_t& length);
		status_t				ReadBitmap(BBitmap** _bitmap,
									bool minimal = false,
									color_space colorSpace = B_RGB32,
									uint32 flags = 0);
		status_t				ReadGradient(BGradient** _gradient);
		status_t				ReadTransform(BAffineTransform& transform);
		status_t				ReadArrayLine(BPoint& startPoint,
									BPoint& endPoint, rgb_color& color);
 
		template<typename T>
		status_t				ReadList(T* array, int32 count);
 
private:
		bool					_MakeSpace(size_t size);
 
		StreamingRingBuffer*	fSource;
		StreamingRingBuffer*	fTarget;
 
		uint8*					fBuffer;
		size_t					fAvailable;
		size_t					fWriteIndex;
		uint32					fDataLeft;
		uint16					fCode;
};
 
 
inline
RemoteMessage::RemoteMessage(StreamingRingBuffer* source,
	StreamingRingBuffer* target)
	:
	fSource(source),
	fTarget(target),
	fBuffer(NULL),
	fAvailable(0),
	fWriteIndex(0),
	fDataLeft(0)
{
}
 
 
inline
RemoteMessage::~RemoteMessage()
{
	if (fWriteIndex > 0)
		Flush();
	free(fBuffer);
}
 
 
inline void
RemoteMessage::Start(uint16 code)
{
	if (fWriteIndex > 0)
		Flush();
 
	Add(code);
 
	uint32 sizeDummy = 0;
	Add(sizeDummy);
}
 
 
inline status_t
RemoteMessage::Flush()
{
	if (fWriteIndex == 0 || fTarget == NULL)
		return B_NO_INIT;
 
	uint32 length = fWriteIndex;
	fAvailable += fWriteIndex;
	fWriteIndex = 0;
 
	memcpy(fBuffer + sizeof(uint16), &length, sizeof(uint32));
	return fTarget->Write(fBuffer, length);
}
 
 
template<typename T>
inline void
RemoteMessage::Add(const T& value)
{
	if (!_MakeSpace(sizeof(T)))
		return;
 
	memcpy(fBuffer + fWriteIndex, &value, sizeof(T));
	fWriteIndex += sizeof(T);
	fAvailable -= sizeof(T);
}
 
 
inline void
RemoteMessage::AddString(const char* string, size_t length)
{
	Add((uint32)length);
	if (length > fAvailable && !_MakeSpace(length))
		return;
 
	memcpy(fBuffer + fWriteIndex, string, length);
	fWriteIndex += length;
	fAvailable -= length;
}
 
 
inline void
RemoteMessage::AddRegion(const BRegion& region)
{
	int32 rectCount = region.CountRects();
	Add(rectCount);
 
	for (int32 i = 0; i < rectCount; i++)
		Add(region.RectAt(i));
}
 
 
template<typename T>
inline void
RemoteMessage::AddList(const T* array, int32 count)
{
	for (int32 i = 0; i < count; i++)
		Add(array[i]);
}
 
 
template<typename T>
inline status_t
RemoteMessage::Read(T& value)
{
	if (fDataLeft < sizeof(T))
		return B_ERROR;
 
	if (fSource == NULL)
		return B_NO_INIT;
 
	int32 readSize = fSource->Read(&value, sizeof(T));
	if (readSize < 0)
		return readSize;
 
	if (readSize != sizeof(T))
		return B_ERROR;
 
	fDataLeft -= sizeof(T);
	return B_OK;
}
 
 
inline status_t
RemoteMessage::ReadRegion(BRegion& region)
{
	region.MakeEmpty();
 
	int32 rectCount;
	Read(rectCount);
 
	for (int32 i = 0; i < rectCount; i++) {
		BRect rect;
		status_t result = Read(rect);
		if (result != B_OK)
			return result;
 
		region.Include(rect);
	}
 
	return B_OK;
}
 
 
template<typename T>
inline status_t
RemoteMessage::ReadList(T* array, int32 count)
{
	for (int32 i = 0; i < count; i++) {
		status_t result = Read(array[i]);
		if (result != B_OK)
			return result;
	}
 
	return B_OK;
}
 
 
inline bool
RemoteMessage::_MakeSpace(size_t size)
{
	if (fAvailable >= size)
		return true;
 
	size_t extraSize = size + 20;
	uint8 *newBuffer = (uint8*)realloc(fBuffer, fWriteIndex + extraSize);
	if (newBuffer == NULL)
		return false;
 
	fAvailable = extraSize;
	fBuffer = newBuffer;
	return true;
}
 
#endif // REMOTE_MESSAGE_H

V730 Not all members of a class are initialized inside the constructor. Consider inspecting: fCode.