#ifndef WXSDRAGWINDOW_H
#define WXSDRAGWINDOW_H

#include <wx/control.h>
#include <wx/timer.h>
#include <wx/bitmap.h>
#include <vector>
#include "wxsevent.h"

class wxsWidget;
/** This class is used as an additional layer between window's preview
 *  and user input.
 *
 * Main task for this class is to process all mouse and keyboard events
 * processed by preview window and adding additional features like
 * mouse-dragging boxes.
 */
class wxsDragWindow : public wxControl
{
	public:

        /** Ctor */
		wxsDragWindow(wxWindow* Parent,wxsWidget* RootWidget,const wxSize& Size);

		/** Dctor */
		virtual ~wxsDragWindow();

		/** Function changing root widget */
		void SetWidget(wxsWidget* RootWidget);

        /** Used to notify that this widget is transparent */
		virtual bool HasTransparentBackground() const { return true; }

		/** Function notifying about size change */
		void NotifySizeChange(const wxSize& NewSize);

		/** Getting currently selected widget or NULL if there's no such widget inside this resource */
		wxsWidget* GetSelection();

		/** Getting count of widgets in multiple selection */
		int GetMultipleSelCount();

		/** Getting widget frrom multiple selection */
		wxsWidget* GetMultipleSelWidget(int Index);

        /** Getting vector of selected widges. If any-level parent of widget
         *  is also selected, widget is skipped.
         */
		void GetSelectionNoChildren(std::vector<wxsWidget*>& Vector);

		/** Checking if given widget is inside current selection */
		bool IsSelected(wxsWidget* Widget);

	private:

        /** Size of boxes used to drag borders of widgets */
        static const int DragBoxSize = 6;

        /** Minimal distace which must be done to apply dragging */
        static const int MinDragDistance = 8;

        /** Enum type describing placement of drag box */
        enum DragBoxType
        {
            LeftTop = 0,
            Top,
            RightTop,
            Left,
            Right,
            LeftBtm,
            Btm,
            RightBtm,
            /*************/
            DragBoxTypeCnt
        };

        /** Structure describing one dragging point */
        struct DragPointData
        {
        	wxsWidget* Widget;                              ///< Widget associated with this box
        	DragBoxType Type;                               ///< Type of this drag box
        	//bool Invisible;                                 ///< If true, this point is hidden
        	bool Inactive;                                  ///< If true, this drag point will be drawn gray
        	bool NoAction;                                  ///< If true, thiss drag point is used to show placement of object only, not for moving or sizing
        	int PosX;                                       ///< X position of this drag point
        	int PosY;                                       ///< Y position of this drag point
        	int DragInitPosX;                               ///< X position before dragging
        	int DragInitPosY;                               ///< Y position before dragging
        	bool KillMe;                                    ///< Used while refreshing drag points list to find invalid points
        	DragPointData* WidgetPoints[DragBoxTypeCnt];    ///< Pointers to all drag points for this widget
        };

        /** Declaration of vector containing all drag points */
        typedef std::vector<DragPointData*> DragPointsT;
        typedef DragPointsT::iterator DragPointsI;

        /** Painting event - currently do nothing, all drawing is done inside timer event */
        void OnPaint(wxPaintEvent& evt);

        /** Function drawing all additional graphic items */
        void AddGraphics(wxDC& DC);

        /** Erasing background will do nothing */
        void OnEraseBack(wxEraseEvent& event);

        /** Event handler for all mouse events */
        void OnMouse(wxMouseEvent& event);

        /** Forwarding mouse event to preview widget */
        void ForwardMouseEventToPreview(wxMouseEvent& event,wxsWidget* Widget);

        /** Searching for drag point under cursor */
        DragPointData* FindCoveredPoint(int PosX,int PosY);

        /** Searching for drag point attached to widget edge under cursor */
        DragPointData* FindCoveredEdge(int PosX,int PosY);

        /** Searching for left-top drag point for given widget */
        DragPointData* FindLeftTop(wxsWidget* Widget);

        /** Returning left-top drag point from other one */
        inline DragPointData* FindLeftTop(DragPointData* Point) { return Point->WidgetPoints[LeftTop]; }

        /** Initializing drag sequence */
        void DragInit(DragPointData* NewDragPoint,wxsWidget* NewDragWidget,bool MultipleSel,int MouseX,int MouseY);

        /** Processing mouse while dragging */
        void DragProcess(int MouseX,int MouseY,wxsWidget* UnderCursor);

        /** Finalizing dragging sequence */
        void DragFinish(wxsWidget* UnderCursor);

        /** Updating cursor */
        void UpdateCursor(bool Dragging,DragPointData* NewDragPoint,wxsWidget* NewDragWidget);

        /** Updating drag assist */
        void UpdateAssist(bool Dragging,wxsWidget* UnderCursor);

        /** Size event */
        void OnSize(wxSizeEvent& event);

        /** Additional event fetching background bitmap */
        void OnFetchBackground(wxTimerEvent& event);

        /** Event handler for EVT_SELECT_WIDGET event */
        void OnSelectWidget(wxsEvent& event);

        /** Event handler for EVT_UNSELECT_WIDGET event */
        void OnUnselectWidget(wxsEvent& event);

        /** TiMakefile.unixmer function refreshing additional graphics */
        void TimerRefresh(wxTimerEvent& event);

        /** Removing all drag points */
        void ClearDragPoints();

        /** Adding drag points for given widget
         *  \return first drag point for this widget
         */
        DragPointData* BuildDragPoints(wxsWidget* Widget);

        /** Updating drag points for given widget */
        void UpdateDragPointData(wxsWidget* Widget,DragPointData** WidgetPoints);

        /** Updating content of current drag points
         *
         * This functions updates coordinates for drag points and removes
         * points for widgets which were removed.
         */
        void RecalculateDragPoints();

        /** Additional function used inside RecalculateDragPoints()  */
        void RecalculateDragPointsReq(wxsWidget* Widget,int& HintIndex);

        /** Changing cursor to one of defaults */
        inline void SetCur(int Cur);

        /** Finding absolute (screen-related) position of given widget */
        void FindAbsolutePosition(wxsWidget* Widget,int* X,int* Y);

        /** Searching for widget at given position */
        wxsWidget* FindWidgetAtPos(int PosX,int PosY,wxsWidget* Widget);

        /** Setting all current drag points to inactive (gray) */
        void GrayDragPoints();

        /** Setting drag points for given widget to active (black) */
        void BlackDragPoints(wxsWidget* Widget);

        /** Checking if given widget is inside widget tree */
        bool IsInside(wxsWidget* What,wxsWidget* Where);

        /** Checking if widget is truthly visible (it and all of it's parents must be shown) */
        bool IsVisible(wxsWidget* Wdg);

        /** Notifying outside about widget change */
        void SelectWidget(wxsWidget* Widget);

        /** Refreshing everything from outside wxPaint */
        void UpdateGraphics();

        /** Function used inside GetSelectionNoChildren to iterate through
            all widgets */
        void GetSelectionNoChildrenReq(wxsWidget* Widget,std::vector<wxsWidget*>& Vector);

        /** Function rebuilding drag points on edges of widgets from other points */
        void RebuildEdgePoints(DragPointData** WidgetPoints);

    /*******************************************/
    /* Variables                               */
    /*******************************************/
        /** All drag points used inside this drag window */
        DragPointsT DragPoints;

        /** Root widget for this resource */
        wxsWidget* RootWidget;

        /** Drag Point which is currently dragged */
        DragPointData* CurDragPoint;

        /** Widget which is currently dragged */
        wxsWidget* CurDragWidget;

        /** Mouse position at the beginning of dragging */
        int DragMouseBegX, DragMouseBegY;

        /** Set to true if distance while dragging was too small and will be discarded */
        bool DragDistanceSmall;

        /** Timer responsible for refreshing additional data */
        wxTimer RefreshTimer;

        /** Timer used inside background-fetching system */
        wxTimer BackFetchTimer;

        /** Bitmap keeping preview of edited window as background */
        wxBitmap* Background;

        /** If set to true, drag window will first fetch background and then
         *  paint content
         */
        bool BackFetchMode;

        /** Flag set when repainting control after fetching background */
        bool PaintAfterFetch;

        /** Flag blocking adding graphic when waiting for background fetch */
        bool BlockTimerRefresh;

        /** Flag blocking incomming widget select events */
        bool BlockWidgetSelect;

        /** Updated region - will be used to fetch background */
        wxRegion FetchArea;

        /** Target container where dragged widgets will be thrown (used while painting) */
        wxsWidget* DragParent;

        /** Changed background bitmap for DragParent */
        wxBitmap* DragParentBitmap;

        /** Highlighted widget which is under cursor when dragging (used while painting) */
        wxsWidget* DragTarget;

        /** Changed background bitmap for DragTarget */
        wxBitmap* DragTargetBitmap;

        DECLARE_EVENT_TABLE()
};

#endif


syntax highlighted by Code2HTML, v. 0.9.1