/*************************************************************************
 *
 *  $RCSfile: b2dmbase.hxx,v $
 *
 *  $Revision: 1.2 $
 *
 *  last change: $Author: aw $ $Date: 2000/11/13 10:44:42 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library 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
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef _B2D_MBASE_HXX
#define _B2D_MBASE_HXX

#ifndef _B2D_MATRIX3D_HXX
#include <goodies/matrix3d.hxx>
#endif

#ifndef _SV_GEN_HXX
#include <tools/gen.hxx>
#endif

#ifndef _SV_COLOR_HXX
#include <vcl/color.hxx>
#endif

#ifndef _SV_BITMAPEX_HXX
#include <vcl/bitmapex.hxx>
#endif

#ifndef _SV_REGION_HXX
#include <vcl/region.hxx>
#endif

#ifndef _SV_POLY_HXX
#include <vcl/poly.hxx>
#endif

#ifndef _SV_TIMER_HXX
#include <vcl/timer.hxx>
#endif

#ifndef _RTTI_HXX
#include <tools/rtti.hxx>
#endif

#ifndef _LIST_HXX
#include <tools/list.hxx>
#endif

#ifndef _VDEVCACHE_HXX
#include <goodies/vdevcache.hxx>
#endif

//************************************************************
//   Vorausdeklarationen
//************************************************************

class B2dIAOManager;
class OutputDevice;
class Window;
class B2dIAOElementProvider;

//************************************************************
//   Defines
//************************************************************

// number of geometric point objects to be allocated per
// allocation request
#define	B2D_NUM_IAOPIXEL_TO_ALLOCATE			(2048)
#define	B2D_NUM_IAOBITMAP_TO_ALLOCATE			(256)
#define	B2D_NUM_IAOBMPREF_TO_ALLOCATE			(1024)
#define	B2D_NUM_IAOBMPVDEV_TO_ALLOCATE			(256)

// number of IAOPixels to handle in Input/Output-calls
// per run
#define	B2D_NUM_IAOPIXEL_PER_IOOPERATION		(4096)

//************************************************************
//   Basic geometric point object
//
// The manager does have a pool of them which can be allocated
// by the IAOs. Each IAO uses them to build their Geometry.
// They are given back to the Manager on deletion or new
// geometry creation of the IAO and can be reused.
//
//************************************************************

#define	B2D_IAO_ELEMENT_PIXEL			(0x0000)
#define	B2D_IAO_ELEMENT_BITMAP			(0x0001)
#define	B2D_IAO_ELEMENT_BITMAPREFERENCE	(0x0002)
#define	B2D_IAO_ELEMENT_BMPVDEV			(0x0003)

class B2dIAOElement
{
	friend class				B2dIAOPixelProvider;
	friend class				B2dIAOBitmapProvider;
	friend class				B2dIAOBmpRefProvider;
	friend class				B2dIAOBmpVDevProvider;

	B2dIAOElement*				pNext;	// IAO-local list
	signed						nXpos : 15;
	signed						nYpos : 15;
	unsigned					nType : 2;

public:
	// type control
	BOOL IsPixel() const { return (nType == B2D_IAO_ELEMENT_PIXEL); }
	BOOL IsBitmap() const { return (nType == B2D_IAO_ELEMENT_BITMAP); }
	BOOL IsBmpRef() const { return (nType == B2D_IAO_ELEMENT_BITMAPREFERENCE); }
	BOOL IsBmpVDev() const { return (nType == B2D_IAO_ELEMENT_BMPVDEV); }

	// pixel move for corrections
	void Move(const Point& rDelta) { nXpos += rDelta.X(); nYpos += rDelta.Y(); }

	// positioning
	INT16 GetPositionX() const { return nXpos; }
	INT16 GetPositionY() const { return nYpos; }
	void SetPosition(const Point& rNew) { nXpos = rNew.X(); nYpos = rNew.Y(); }

	// cliptest
	BOOL IsInside(const Region& rRegion);
	BOOL IsOutside(const Region& rRegion);

	// chaining
	B2dIAOElement* GetNext() const { return pNext; }

	// geometry list chain
	B2dIAOElement* AddToList(B2dIAOElement* pList) { pNext = pList; return this; }
	B2dIAOElement* RemFromList(B2dIAOElement* pList, B2dIAOElement* pPrev)
		{ if(pPrev)	pPrev->pNext = pNext; else pList = pNext; pNext = NULL;	return pList; }
	B2dIAOElement* RemFirstFromList(B2dIAOElement* pList)
		{ pList = pNext; pNext = NULL;	return pList; }
};

class B2dIAOPixel : public B2dIAOElement
{
	friend class				B2dIAOPixelProvider;

	Color						aColor;

public:
	Color GetColor() const { return aColor; }
	void SetColor(Color aNew) { aColor = aNew; }
};

class B2dIAOBitmap : public B2dIAOElement
{
	friend class				B2dIAOBitmapProvider;

	BitmapEx					aBitmap;

public:
	const BitmapEx& GetBitmap() const { return aBitmap; }
	void SetBitmap(const BitmapEx& rNew) { aBitmap = rNew; }
};

class B2dIAOBmpRef : public B2dIAOElement
{
	friend class				B2dIAOBmpRefProvider;

	BitmapEx*					pBitmap;

public:
	B2dIAOBmpRef() : pBitmap(NULL) {}
	const BitmapEx* GetBitmap() const { return pBitmap; }
	void SetBitmap(BitmapEx* pNew) { pBitmap = pNew; }
};

class B2dIAOBmpVDev : public B2dIAOElement
{
	friend class				B2dIAOBmpVDevProvider;

	VDevCacheEntry*				pEntry;

public:
	B2dIAOBmpVDev() : pEntry(NULL) {}
	VDevCacheEntry* GetEntry() { return pEntry; }
	void SetEntry(VDevCacheEntry* pNew) { pEntry = pNew; }
};

//************************************************************
//   Geometric Point Object provider
//
// A store for geometric Elements, can always provide
// one and take back one. Entries are reused. All entries
// will be freed on destruction and then be invalid (!)
//
//************************************************************

class B2dIAOPixelProvider
{
	friend class				B2dIAOManager;

	// List of allocated memory blocks
	List						aMemList;

	// chained list of free entries
	B2dIAOPixel*				pFirst;

	// Entry creator
	void CreateNewEntries();

	// called on manager destruction
	void TryToReleaseSomeMemory();

public:
	B2dIAOPixelProvider() 
	:	aMemList(64, 4, 4), 
		pFirst(NULL)
	{}
	~B2dIAOPixelProvider() 
		{ for(void* pObj = aMemList.First(); pObj; pObj = aMemList.Next()) delete[] (B2dIAOPixel*)pObj; }

	B2dIAOPixel* GetB2dIAOPixel()
		{ if(!pFirst) CreateNewEntries(); B2dIAOPixel* pRet = pFirst; pFirst = (B2dIAOPixel*)pFirst->pNext; return pRet; }
	void PutB2dIAOPixel(B2dIAOPixel* pOld)
		{ pOld->pNext = pFirst; pFirst = pOld; }
};

//************************************************************
//   Geometric Bitmap Object provider
//************************************************************

class B2dIAOBitmapProvider
{
	friend class				B2dIAOManager;

	// List of allocated memory blocks
	List						aMemList;

	// chained list of free entries
	B2dIAOBitmap*				pFirst;

	// Entry creator
	void CreateNewEntries();

	// called on manager destruction
	void TryToReleaseSomeMemory();

public:
	B2dIAOBitmapProvider() 
	:	aMemList(64, 4, 4), 
		pFirst(NULL)
	{}
	~B2dIAOBitmapProvider() 
		{ for(void* pObj = aMemList.First(); pObj; pObj = aMemList.Next()) delete[] (B2dIAOBitmap*)pObj; }

	B2dIAOBitmap* GetB2dIAOBitmap() 
		{ if(!pFirst) CreateNewEntries(); B2dIAOBitmap* pRet = pFirst; pFirst = (B2dIAOBitmap*)pFirst->pNext; return pRet; }
	void PutB2dIAOBitmap(B2dIAOBitmap* pOld) 
		{ pOld->aBitmap = Bitmap(); pOld->pNext = pFirst; pFirst = pOld; }
};

//************************************************************
//   Geometric BitmapReference Object provider
//************************************************************

class B2dIAOBmpRefProvider
{
	friend class				B2dIAOManager;

	// List of allocated memory blocks
	List						aMemList;

	// chained list of free entries
	B2dIAOBmpRef*				pFirst;

	// Entry creator
	void CreateNewEntries();

	// called on manager destruction
	void TryToReleaseSomeMemory();

public:
	B2dIAOBmpRefProvider() 
	:	aMemList(64, 4, 4), 
		pFirst(NULL)
	{}
	~B2dIAOBmpRefProvider() 
		{ for(void* pObj = aMemList.First(); pObj; pObj = aMemList.Next()) delete[] (B2dIAOBmpRef*)pObj; }

	B2dIAOBmpRef* GetB2dIAOBmpRef() 
		{ if(!pFirst) CreateNewEntries(); B2dIAOBmpRef* pRet = pFirst; pFirst = (B2dIAOBmpRef*)pFirst->pNext; return pRet; }
	void PutB2dIAOBmpRef(B2dIAOBmpRef* pOld) 
		{ pOld->pBitmap = NULL; pOld->pNext = pFirst; pFirst = pOld; }
};

//************************************************************
//   Geometric BmpVDev Object provider
//************************************************************

class B2dIAOBmpVDevProvider
{
	friend class				B2dIAOManager;

	// List of allocated memory blocks
	List						aMemList;

	// chained list of free entries
	B2dIAOBmpVDev*				pFirst;

	// Entry creator
	void CreateNewEntries();

	// called on manager destruction
	void TryToReleaseSomeMemory();

public:
	B2dIAOBmpVDevProvider() 
	:	aMemList(64, 4, 4), 
		pFirst(NULL)
	{}
	~B2dIAOBmpVDevProvider() 
		{ for(void* pObj = aMemList.First(); pObj; pObj = aMemList.Next()) delete[] (B2dIAOBmpVDev*)pObj; }

	B2dIAOBmpVDev* GetB2dIAOBmpVDev() 
		{ if(!pFirst) CreateNewEntries(); B2dIAOBmpVDev* pRet = pFirst; pFirst = (B2dIAOBmpVDev*)pFirst->pNext; return pRet; }
	void PutB2dIAOBmpVDev(B2dIAOBmpVDev* pOld) 
		{ pOld->pEntry = NULL; pOld->pNext = pFirst; pFirst = pOld; }
};

//************************************************************
//   Position entity with chaining
//************************************************************

class B2dPositionEntity
{
	B2dPositionEntity*			pNext;
	Point						aPosition;
	Point						aPositionPixel;

public:
	B2dPositionEntity(B2dPositionEntity*& rpList, Point aPos = Point(0, 0))
		{ pNext = rpList; rpList = this; aPosition = aPos; }

	const Point& GetPosition() const { return aPosition; }
	void SetPosition(const Point& rNew) { aPosition = rNew; }

	const Point& GetPositionPixel() const { return aPositionPixel; }
	void SetPositionPixel(const Point& rNew) { aPositionPixel = rNew; }

	B2dPositionEntity* GetNext() const { return pNext; }
};

//************************************************************
//   Basis-InterActionObject (IAO)
//
// Baseclass for all kinds of InterActionObjects (IAO's).
//
//************************************************************

class B2dIAObject
{
	// Manager is allowed access to private Members
	friend class				B2dIAOManager;

	// Pointer to Manager
	B2dIAOManager*				pManager;

	// Chaining of IAO's
	B2dIAObject*				pNext;
	B2dIAObject*				pPrev;

	// The Display Geometry of the Object
	B2dIAOElement*				pGeometry;

	// start of geometric positions
	B2dPositionEntity*			pGeomPositions;

	// Base position of this IAO (logic and pixel)
	B2dPositionEntity			aBasePosition;

	// Local region
	Rectangle					aBaseRect;

	// Base color of IAO
	Color						aBaseColor;

	// Visibility of IAO
	unsigned					bVisible : 1;

	// Validity of geometry
	unsigned					bGeometryValid : 1;

	// Validity of BaseRect
	unsigned					bBaseRectValid : 1;

	// Animation switch
	unsigned					bAnimationOn : 1;
	unsigned					bAnimRegisteredAtManager : 1;

	// Hittable switch
	unsigned					bIsHittable : 1;

	// Throw away Geometry
	void FreeGeometry();

	// test if this needs to be told to the manager
	void CheckAnimationState();

protected:
	// Create the Geometry - this is the pixel creator
	// use AddPixel() or AddBitmap() to describe full display geometry
	virtual void CreateGeometry() = 0;

	// Create the BaseRect
	virtual void CreateBaseRect() = 0;

	// React on animation (optional)
	virtual void AnimationStep(UINT32 nAnimCounter);

	// Apply mapping, calc pixel positions
	void ApplyDevice(OutputDevice *pOut);

	// Get/Set the BaseRect
	const Rectangle& GetBaseRect() const;
	void SetBaseRect(const Rectangle& rNew) { aBaseRect = rNew; }

	// Get the Geometry
	B2dIAOElement* GetGeometry();

	// React on geometry change
	void GeometryChange() { if(bGeometryValid) FreeGeometry(); }
	void BaseRectChange() { bBaseRectValid = FALSE; }

	// for usage in CreateGeometry: Fill a new pixel and add it
	// to the geometry list
	BOOL AddPixel(const Point& rPos, const Color& rCol);

	// same with Bitmaps and BitmapReferences and VDevs
	BOOL AddBitmap(const Point& rPos, const BitmapEx& rBmp);
	BOOL AddBmpRef(const Point& rPos, BitmapEx* pBmp);

	// create a whole PixelLine, the virtual function AddLinePixel()
	// gets all the coordinates and can create the Pixels
	virtual BOOL AddLinePixel(const Point& rPos, UINT32 nPixelNum);
	BOOL AddLine(const Point& rPos1, const Point& rPos2);

	// create a whole PixelTriangle, the virtual function AddTrianglePixel()
	// gets all the coordinates and can create the Pixels
	virtual BOOL AddTrianglePixel(const Point& rPos);
	BOOL AddTriangle(const Point& rPos1, const Point& rPos2, const Point& rPos3);

	// Access to BasePosition
	const Point& GetBasePositionPixel() const { return aBasePosition.GetPositionPixel(); }

	// access to pGeomPositions for derived classes
	B2dPositionEntity*& GetGeomPositions() { return pGeomPositions; }

public:
    TYPEINFO();
	B2dIAObject(B2dIAOManager* pMan, Point aBasPos = Point(0,0), Color aBasCol = Color(COL_LIGHTGREEN));
	virtual ~B2dIAObject();

	// Transform IAO
	void Transform(const Matrix3D& rMat);

	// Access to Manager
	B2dIAOManager* GetManager() const { return pManager; }

	// Access to next IAO
	B2dIAObject* GetNext() const { return pNext; }

	// Access to BasePosition
	const Point& GetBasePosition() const { return aBasePosition.GetPosition(); }
	void SetBasePosition(Point aNew);

	// Access to visibility state
	BOOL IsVisible() const { return bVisible; }
	void SetVisible(BOOL bNew);

	// Access to hitability state
	BOOL IsHittable() const { return bIsHittable; }
	void SetHittable(BOOL bNew) { bIsHittable = bNew; }

	// Access to BaseColor
	const Color& GetBaseColor() const { return aBaseColor; }
	void SetBaseColor(Color aNew);

	// Animation
	BOOL IsAnimation() const { return bAnimationOn; }
	void SetAnimation(BOOL bNew);

	// Hittest
	virtual BOOL IsHit(const Point& rPixelPos, UINT16 nTol = 0) const;

	// Invalidate
	inline void InvalidateRectangle();
};

//************************************************************
//   IAOGroup
//
// groups some IAOs to make handling more easy for the
// user. Destructor deletes all contained IAOs(!). To
// destruct without deleting Clear() group before.
//
//************************************************************

class B2dIAOGroup
{
	B2dIAObject*				pIAO;
	Container*					pIAOList;

public:
	B2dIAOGroup();
	~B2dIAOGroup();

	// Clear group, delete no elements
	void Clear();

	// Delete all IAO's and Clear group for new usage
	void Delete();

	// Add/remove objects
	BOOL InsertIAO(B2dIAObject* pNew);
	BOOL RemoveIAO(B2dIAObject* pOld);

	// access to objects
	UINT32 GetIAOCount() const;
	B2dIAObject* GetIAObject(UINT32 nNum) const;

	// Hittest
	BOOL IsHit(const Point& rPixelPos, UINT16 nTol = 0) const;
};

//************************************************************
//   InterActionObject Manager
//
// Manages a whole bunch of IAO's, their common data, 
// visibility, redraw et cetera. Every IAO needs to be
// constructed with a IAOManager which is responsible for
// the IAO from this moment on.
//
//************************************************************

class B2dIAOManager
{
	// Manager is allowed access to private Members
	friend class				B2dIAObject;

	// the window to work on
	Window*						pWindow;

	// the source for all IAOPixels and IAORectangles
	// static to make this providers appear only ONCE
	// so they are global for ALL existing managers.
	// When more multithreading ist used, the providers
	// need to be protected by a semaphore!!
	static B2dIAOPixelProvider	aPixelProvider;
	static B2dIAOBitmapProvider	aBitmapProvider;
	static B2dIAOBmpRefProvider	aBmpRefProvider;
	static B2dIAOBmpVDevProvider aBmpVDevProvider;

	// VDev cache for B2dIAOBackground Objects
	VDevCache					aVDevCache;

	// Chain of IAO's in this Manager
	B2dIAObject*				pIAObjectList;
	B2dIAObject*				pIAObjectListEnd;
	UINT32						nIAONumber;

	// Chain of IAOElements with saved background
	B2dIAOElement*				pSaveList;

	// MapMode to measure scrolling and zooming changes
	MapMode						maLastMapMode;

	// mechanism for using Array-accesses for Read/WritePixel
	Polygon						aTmpPoly;
	Color*						pTmpColor;
	UINT16						nNextFree;

	// Local remembered ClipRegion
	Region						aClipRegion;

	// Local invalidate region
	Rectangle					aInvalidateRectangle;

	// Timer to allow animation and counter of time state
    AutoTimer					aAnimator;
	UINT32						nAnimatorCount;
	List						aAnimatedObjectList;

	// changes done in added objects?
	unsigned					bChanged : 1;

	// Visibility of whole marker objects
	unsigned					bVisible : 1;

	// Animation main switch
	unsigned					bAnimationOn : 1;
	unsigned					bTimerIsOn : 1;

	// interface for getting/putting B2dIAOPixel's and B2dIAOBitmaps
	B2dIAOPixel* GetB2dIAOPixel() { return aPixelProvider.GetB2dIAOPixel(); }
	B2dIAOBitmap* GetB2dIAOBitmap() { return aBitmapProvider.GetB2dIAOBitmap(); }
	B2dIAOBmpRef* GetB2dIAOBmpRef() { return aBmpRefProvider.GetB2dIAOBmpRef(); }
	B2dIAOBmpVDev* GetB2dIAOBmpVDev() { return aBmpVDevProvider.GetB2dIAOBmpVDev(); }
	void PutB2dIAOElement(B2dIAOElement* pOld) 
		{ if(pOld->IsPixel()) aPixelProvider.PutB2dIAOPixel((B2dIAOPixel*)pOld);
		  else if(pOld->IsBitmap()) aBitmapProvider.PutB2dIAOBitmap((B2dIAOBitmap*)pOld);
		  else if(pOld->IsBmpRef()) aBmpRefProvider.PutB2dIAOBmpRef((B2dIAOBmpRef*)pOld); 
		  else aBmpVDevProvider.PutB2dIAOBmpVDev((B2dIAOBmpVDev*)pOld); }

	void RestoreBackground(const Region& rClipRegion, const Region& rWindowRegion, BOOL bInPaint);
	BOOL SaveBackground(const Region& rClipRegion);
	void ForgetBackground();
	void Paint(const Region& rClipRegion);

	// mechanism for using Array-accesses for Read/WritePixel
	void PixelArrayAdd(B2dIAOPixel* pNew);
	void PixelArrayFlushWrite();

	// Link for Animation
    DECL_LINK(AnimatorHdl, AutoTimer*);

	// VDev cache for B2dIAOBackground Objects
	VDevCache& GetVDevCache() { return aVDevCache; }

protected:
	void ApplyClipRegion(const Region& rClipRegion);
	void ApplyDevice(OutputDevice *pOut, BOOL bInPaint);
	BOOL InsertIAO(B2dIAObject* pNew);
	BOOL RemoveIAO(B2dIAObject* pOld);
	B2dIAOElement* GetSave() const { return pSaveList; }
	void SetSave(B2dIAOElement* pNew) { pSaveList = pNew; }
	void MoveSavedElementsPixel(const Point& rDelta);
	void CheckTimerState();
	void RegisterAnimatedObject(B2dIAObject* pNew);
	void UnregisterAnimatedObject(B2dIAObject* pOld);

public:
	B2dIAOManager(Window* pTarget);
	virtual ~B2dIAOManager();

	// Access to Window
	Window* GetWindow() const { return pWindow; }

	// Transform all IAOs
	void Transform(const Matrix3D& rMat);

	// Get the local ClipRegion of last ApplyDevice()
	const Region& GetClipRegion() const { return aClipRegion; }

	// Access to list of IAO's
	B2dIAObject* GetIAObjectList() const { return pIAObjectList; }
	UINT32 GetIAOCount() const { return nIAONumber; }
	B2dIAObject* GetIAObject(UINT32 nNum) const;

	// Access to visibility state
	BOOL IsVisible() const;
	void SetVisible(BOOL bNew); 

	// Invalidate (add to) a region of an IAObject
	void InvalidateRectangle(const Rectangle& rRect);

	// Paint
	BOOL UpdateDisplay();

	// UpdateDisplay() in force-remove-saved-parts mode
	void ForceHide();

	// Animation
	BOOL IsAnimation() const { return bAnimationOn; }
	void SetAnimation(BOOL bNew);
};

#endif          // _B2D_MBASE_HXX
