/**************************************************************
 * 
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 * 
 *************************************************************/


/***************************************************************************
**
**       Von StatementList werden alle Statements abgeleitet.
**   Es gibt immer nur eine Statementliste, die verpointert ist.
**       jederzeit kann das der Anfang der Kette abgefragt werden.
**
**
**
**
**
**
**
***************************************************************************/
#ifndef _STATEMNT_HXX
#define _STATEMNT_HXX

#include <tools/wintypes.hxx>
#include <tools/string.hxx>
#include <tools/debug.hxx>
#include <tools/time.hxx>
#ifndef _SV_DRAG_HXX //autogen
//#include <vcl/drag.hxx>
#endif
#include <vcl/menu.hxx>
#include <vcl/svapp.hxx>
#include <tools/fsys.hxx>
#include <sot/storage.hxx>
#include <basic/sbstar.hxx>
#include <vcl/event.hxx>
#include <com/sun/star/beans/PropertyValue.hpp>
#include <automation/commtypes.hxx>

class Window;
class SystemWindow;
class Point;
class SfxPoolItem;

class ScrollBar;

class SCmdStream;
class RetStream;
class ImplRemoteControl;

class TTProfiler;
class TTProperties;

class Dir;

class CommunicationLink;

#if OSL_DEBUG_LEVEL > 1
class EditWindow;
#endif

#ifdef __cplusplus
extern "C"
{
#endif
    void SAL_CALL osl_TestToolDebugPrint( const sal_Char *pString );
#ifdef __cplusplus
}
#endif


#define IsVisible IsReallyVisible
#define GET_REAL_PARENT() GetWindow( WINDOW_REALPARENT )

// switch behaviour of ImplMouse* and ImplKeyInput
#define FORCE_DIRECT_CALL   sal_True

typedef sal_uInt16 SearchFlags;
#define SEARCH_NOOVERLAP			((SearchFlags) 0x0001)
#define SEARCH_NO_TOPLEVEL_WIN		((SearchFlags) 0x0002)
#define SEARCH_FOCUS_FIRST      	((SearchFlags) 0x0004)
#define SEARCH_FIND_DISABLED      	((SearchFlags) 0x0008)

class Search
{
	SearchFlags nmSearchFlags;
public:
	Search( SearchFlags nSearchFlags = 0): nmSearchFlags(nSearchFlags) {}
	virtual ~Search() {}

	virtual sal_Bool IsWinOK( Window *pWin ) = 0;
	SearchFlags GetSearchFlags() { return nmSearchFlags; }
    void AddSearchFlags( SearchFlags aNewFlags ) { nmSearchFlags |= aNewFlags; }
	void RemoveSearchFlags( SearchFlags aRemoveFlags ) { nmSearchFlags &= ( ~aRemoveFlags ); }
	sal_Bool HasSearchFlag( SearchFlags aQueryFlag ) { return (nmSearchFlags & aQueryFlag) == aQueryFlag; }
};

sal_Bool IsDialog(Window *pWin);		// Ist *pWin von SystemWindow abgeleitet (Kann es Active sein)
sal_Bool IsAccessable(Window *pWin);	// Ist *pWin Zugreifbar (über IsEnabled und Parents geprüft)


//class SafePointer : CriticalSection
class SafePointer
{
	SafePointer *pSelf;
public:
	SafePointer()   { pSelf = this; }
	virtual ~SafePointer()  { DBG_ASSERT(pSelf==this,"Destructor von Nicht existierendem Objekt aufgerufen");
							  pSelf = NULL; }
//	static sal_Bool IsValid( SafePointer *pThis ) { return pThis == pThis->pSelf; }
// virtual      operator -> (); { DBG_ASSERT(pMyself == this,"-> von Nicht existierendem Objekt aufgerufen"); }
};


class DisplayHidWin;
class StatementCommand;
class TranslateWin;

struct TTSettings
{
    // DisplayHID
   	StatementCommand *pDisplayInstance;
	DisplayHidWin *pDisplayHidWin;
	Window *Old;
    Window *Act;
	String aOriginalCaption;

    // Translate
	TranslateWin *pTranslateWin;
	sal_Bool bToTop;
};


TTSettings* GetTTSettings();


#define MAX_RETRIES 9
class StatementList : public SafePointer
{
private:
    StatementList(const StatementList&);
    StatementList & operator=(const StatementList&);

protected:
	StatementList();
	sal_uInt16 nRetryCount;
	void QueStatement(StatementList *pAfterThis);
	sal_Bool bStatementInQue;
	static sal_uInt16 nUseBindings;

	static TTProfiler *pProfiler;
	void InitProfile();
	void SendProfile( String aText );
	static StatementList *pCurrentProfileStatement;

	static sal_Bool bIsInReschedule;
        static sal_uInt16 nModalCount;
	static Window *pLastFocusWindow;		// Wenn dieses sich ändert wird Safe Reschedule abgebrochen
	static sal_Bool bWasDragManager;			// Wenn dieses sich ändert wird Safe Reschedule abgebrochen
	static sal_Bool bWasPopupMenu;				// Wenn dieses sich ändert wird Safe Reschedule abgebrochen
   	static sal_Bool bBasicWasRunning;

	static sal_uInt16 nMinTypeKeysDelay;				/// Verzögerung der einzelnen Anschläge für TypeKeys
	static sal_uInt16 nMaxTypeKeysDelay;
	static sal_Bool bDoTypeKeysDelay;

	static Window* pFirstDocFrame;

    static sal_Bool bIsSlotInExecute;

public:
	static sal_Bool IsInReschedule() { return bIsInReschedule; }
	void SafeReschedule( sal_Bool bYield = sal_False )	// Setzt Flag, so daß nicht schon der nächste Befehl ausgeführt wird
	{
		nModalCount = Application::GetModalModeCount();
		bIsInReschedule = sal_True;
		pLastFocusWindow = GetpApp()->GetFocusWindow();
		bWasDragManager = false /*!= DragManager::GetDragManager()*/;
		bWasPopupMenu = NULL != PopupMenu::GetActivePopupMenu();
        bBasicWasRunning = StarBASIC::IsRunning();
		bWasExecuting = bExecuting;
		if ( bYield )
			GetpApp()->Yield();
		else
			GetpApp()->Reschedule();
		bExecuting = bWasExecuting;
        bBasicWasRunning = sal_False;
		bWasPopupMenu = sal_False;
		bWasDragManager = sal_False;
		pLastFocusWindow = NULL;
		bIsInReschedule = sal_False;
		nModalCount = 0;
	}
	static sal_Bool MaybeResetSafeReschedule()
	{		// Implementierung muß hier zwar nicht sein, ist aber übersichtlicher so
		if ( !bIsInReschedule )
			return sal_False;

		if ( pLastFocusWindow != GetpApp()->GetFocusWindow()
			|| ( Application::GetModalModeCount() > nModalCount )
//			|| ( DragManager::GetDragManager() && !bWasDragManager )
			|| ( PopupMenu::GetActivePopupMenu() && !bWasPopupMenu )
			|| ( StarBASIC::IsRunning() && !bBasicWasRunning ) )
		{
			bIsInReschedule = sal_False;
			pLastFocusWindow = NULL;
			return sal_True;
		}
		else
			return sal_False;
	}
	static void NormalReschedule()	// Setzt das flag nicht
	{
		GetpApp()->Reschedule();
	}
#define Reschedule RescheduleNichtBenutzen_StattdessenSafeRescheduleAnStatementList

	static Window* GetMouseWin();
	static sal_Bool WinPtrValid(Window *pTest);
	static Window* SearchAllWin( Window *pBase, Search &aSearch, sal_Bool MaybeBase = sal_True );
protected:
	static Window* SearchClientWin( Window *pBase, Search &aSearch, sal_Bool MaybeBase = sal_True );

	Window* SearchTree( rtl::OString aUId, sal_Bool bSearchButtonOnToolbox = sal_False );
	Window* GetActive( WindowType nRT, sal_Bool MaybeBase = sal_True );
	Window* GetFocus( WindowType nRT, sal_Bool MaybeBase = sal_True );
	Window* GetAnyActive( sal_Bool MaybeBase = sal_True );
    ScrollBar* GetScrollBar( Window *pBase, sal_uInt16 nDirection, sal_Bool MaybeBase = sal_True );
	Window* GetPopupFloatingWin( sal_Bool MaybeBase = sal_True );
    Menu* GetMatchingMenu( Window* pWin, Menu* pBaseMenu = NULL );
	Window* GetWinByRT( Window *pBase, WindowType nRT, sal_Bool MaybeBase = sal_True, sal_uInt16 nSkip = 0, sal_Bool bSearchAll = sal_False );
	sal_uInt16 CountWinByRT( Window *pBase, WindowType nRT, sal_Bool MaybeBase = sal_True );
    Window* GetDocWin( sal_uInt16 nNr );
    sal_uInt16 GetDocWinCount();
	Window* GetFadeSplitWin( Window *pBase, WindowAlign nAlign, sal_Bool MaybeBase = sal_True );
	sal_Bool ValueOK(rtl::OString nId, String aBezeichnung, sal_uLong nValue, sal_uLong nMax);

    sal_uInt16 GetCurrentMenues( PopupMenu *&pPopup, MenuBar *&pMenuBar, Menu *&pMenu );

public:
//  void AddStatement( StatementList *pNewStatement );

	virtual ~StatementList();
	void Advance();
	virtual sal_Bool Execute() = 0;
/***************************************************************************
** Bestimmt erst den nächsten Befehl, setzt Current
** und führt dann aus.
** Returnwert gibt an, ob Befehl nochmal ausgeführt
** werden soll. Dann muß auch der UserEvent verlassen werden, um der Applikation
** normales Arbeiten zu ermöglichen (Dialog schliessen)
** sal_True bedeutet, dass alles klar gegangen ist
** sal_False bedeutet nochmal Bitte
***************************************************************************/

	void ReportError(String aMessage);
	void ReportError(rtl::OString aUId, String aMessage);
	void ReportError(String aMessage, sal_uLong nWhatever);

	static void DirectLog( sal_uLong nType, String aString );

	String Tree(Window *pBase, int Indent);
	String ClientTree(Window *pBase, int Indent);

	StatementList *pNext;
	static StatementList /**pCurrent,*/ *pFirst;
	static sal_Bool bReadingCommands;
	static rtl::OString aWindowWaitUId;
	static Window *pWindowWaitPointer;
	static rtl::OString aWindowWaitOldHelpId;
	static rtl::OString aWindowWaitOldUniqueId;
	static RetStream *pRet;
	static sal_Bool IsError;
	static sal_Bool bDying;
	static sal_Bool bExecuting;				// Gesetzt, wenn ein Befehl rescheduled ohne einen neuen Befehl zu erlauben
	sal_Bool bWasExecuting;	        		// Wurde bei einem MaybeResetSafeReschedule resettet, so wird der Zustand danach wiederhergestellt
	static sal_uInt16 aSubMenuId1;			// Untermenüs bei PopupMenus
	static sal_uInt16 aSubMenuId2;			// erstmal 2-Stufig
	static sal_uInt16 aSubMenuId3;			// and now even 3 levels #i31512#
    static SystemWindow *pMenuWindow;   // when using MenuBar as base for MenuCommands
	static TTProperties *pTTProperties;	// Hier stehen die SlotIDs aus dem SFX drin

	sal_Bool CheckWindowWait();			//True heisst, dass Window noch existiert
									//False -> Window weg;
	static void SetFirstDocFrame( Window* pWin );
	static Window* GetFirstDocFrame();
	static sal_Bool IsFirstDocFrame( Window* pWin );
	static sal_Bool IsDocWin( Window* pWin );
	static sal_Bool IsIMEWin( Window* pWin );    // Input Window for CJK under Solaris
    static sal_Bool IsDocFrame( Window* pWin );
    static MenuBar* GetDocFrameMenuBar( Window* pWin );
    static sal_uInt16 GetDocFrameCount();

    static sal_Bool bCatchGPF;

	static sal_Bool bUsePostEvents;         // use Application::Post*Event or own impl to handle key and mouseevents

#if OSL_DEBUG_LEVEL > 1
	static EditWindow *m_pDbgWin;
#endif
};

class StatementSlot : public StatementList	//Slots aufrufen
{
protected:
	sal_uInt16 nAnzahl;
	SfxPoolItem **pItemArr;
    ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue> aArgs;
	sal_uInt16 nFunctionId;     // can get removed when the old (numeric) slothandling is removed
    String aUnoUrl;
    sal_Bool bMenuClosed;

    StatementSlot();
    void AddReferer();
public:
	StatementSlot( SCmdStream *pIn );
	StatementSlot( sal_uLong nSlot, SfxPoolItem* pItem = NULL );
	virtual ~StatementSlot();
	virtual sal_Bool Execute();
};

class StatementUnoSlot : public StatementSlot	//Uno Slots aufrufen
{
public:
	StatementUnoSlot(SCmdStream *pIn);
};

class StatementCommand : public StatementList	// Befehl ausführen (wintree, resetaplication ...)
{
	friend class ImplRemoteControl;
protected:
	sal_uInt16 nMethodId;
	sal_uInt16 nParams;
	comm_USHORT nNr1,nNr2,nNr3,nNr4;
	comm_ULONG nLNr1;
	String aString1,aString2;
	sal_Bool bBool1,bBool2;

	Window* GetNextOverlap( Window* pBase );
	Window* GetNextRecoverWin();

	static sal_uInt16 nDirPos;
	static Dir *pDir;
	static pfunc_osl_printDebugMessage pOriginal_osl_DebugMessageFunc;


	sal_Bool UnpackStorage( SotStorageRef xStorage, DirEntry &aBaseDir );

    void HandleSAXParser();

public:
	StatementCommand( SCmdStream *pIn );
	StatementCommand( StatementList *pAfterThis, sal_uInt16 MethodId, sal_uInt16 Params, sal_uInt16 Nr1 );
	virtual sal_Bool Execute();
	sal_Bool DisplayHID();
	void Translate();
	void WriteControlData( Window *pBase, sal_uLong nConf, sal_Bool bFirst = sal_True );

};


enum TTHotSpots  { MitteLinks, Mitte, MitteOben };

class StatementControl : public StatementList
{
protected:
	rtl::OString aUId;
	sal_uInt16 nMethodId;
	sal_uInt16 nParams;
	comm_USHORT nNr1,nNr2,nNr3,nNr4;
	comm_ULONG nLNr1;
	String aString1,aString2;
	sal_Bool bBool1,bBool2;
	sal_Bool ControlOK( Window *pControl, const sal_Char* aBezeichnung );
	void AnimateMouse( Window *pControl, TTHotSpots aWohin );
	void AnimateMouse( Window *pControl, Point aWohin );

	sal_Bool MaybeDoTypeKeysDelay( Window *pTestWindow );

	sal_Bool HandleVisibleControls( Window *pControl );
	sal_Bool HandleCommonMethods( Window *pControl );

public:
	StatementControl( SCmdStream *pIn, sal_uInt16 nControlType );
	virtual sal_Bool Execute();

};

class StatementFlow : public StatementList		// Kommunikation mit Sequence
{
	sal_uInt16 nArt;

	sal_uInt16 nParams;
	comm_USHORT nSNr1;
	comm_ULONG nLNr1;
	String aString1;
	sal_Bool bBool1;


public:
	StatementFlow (sal_uLong nServiceId, SCmdStream *pIn, ImplRemoteControl *pRC );
	StatementFlow( StatementList *pAfterThis, sal_uInt16 nArtP );
	virtual sal_Bool Execute();
	static CommunicationLink *pCommLink;
	static sal_Bool bSending;

	static sal_Bool bUseIPC;	// Soll zur rückmeldung IPC verwendet werden?
	static ImplRemoteControl *pRemoteControl;	// Static für 2. Constructor

private:
	void SendViaSocket();
};

class SearchUID : public Search
{
	Window *pMaybeResult;
	Window *pAlternateResult;
	rtl::OString aUId;
	sal_Bool bSearchButtonOnToolbox;
public:
	SearchUID( rtl::OString aUIdP, sal_Bool bSearchButtonOnToolboxP ): Search( SEARCH_FOCUS_FIRST ), pMaybeResult(NULL), pAlternateResult(NULL), aUId(aUIdP), bSearchButtonOnToolbox(bSearchButtonOnToolboxP) {}
	virtual sal_Bool IsWinOK( Window *pWin );
	Window* GetMaybeWin() { return pMaybeResult; }
	Window* GetAlternateResultWin() { return pAlternateResult; }
};
class SearchActive : public Search
{
	WindowType nRT;
public:
	SearchActive( WindowType nRTP ): nRT(nRTP) {}
	virtual sal_Bool IsWinOK( Window *pWin );
};
class SearchPopupFloatingWin : public Search
{
public:
	SearchPopupFloatingWin(): Search( SEARCH_FOCUS_FIRST ) {}
	virtual sal_Bool IsWinOK( Window *pWin );
};
class SearchRT : public Search
{
	WindowType mnRT;
    sal_uInt16 mnSkip;
    sal_uInt16 mnCount;
public:
	SearchRT( WindowType nRTP, SearchFlags nSearchFlags, sal_uInt16 nSkip = 0 ): Search(nSearchFlags), mnRT(nRTP), mnSkip( nSkip ), mnCount( 0 ) {}
	virtual sal_Bool IsWinOK( Window *pWin );
    sal_uInt16 GetCount(){ return mnCount; }
};
class SearchScroll : public SearchRT
{
	sal_uInt16 nDirection;
public:
	SearchScroll( sal_uInt16 nDir, SearchFlags nSearchFlags ): SearchRT(WINDOW_SCROLLBAR, nSearchFlags), nDirection(nDir) {}
	virtual sal_Bool IsWinOK( Window *pWin );
};
class SearchWinPtr : public Search
{
	Window *pTest;
public:
	SearchWinPtr( Window *pTestP ): pTest(pTestP) {}
	virtual sal_Bool IsWinOK( Window *pWin );
};
class SearchFadeSplitWin : public Search
{
	WindowAlign nAlign;
public:
	SearchFadeSplitWin( WindowAlign nAlignP ): nAlign(nAlignP) {}
	virtual sal_Bool IsWinOK( Window *pWin );
};


void ImplKeyInput( Window* pWin, KeyEvent &aKEvnt, sal_Bool bForceDirect=sal_False );
void ImplMouseMove( Window* pWin, MouseEvent &aMEvnt, sal_Bool bForceDirect=sal_False );
void ImplMouseButtonDown( Window* pWin, MouseEvent &aMEvnt, sal_Bool bForceDirect=sal_False );
void ImplMouseButtonUp( Window* pWin, MouseEvent &aMEvnt, sal_Bool bForceDirect=sal_False );
void ImplCommand( Window* pWin, CommandEvent &aCmdEvnt );
void ImplEventWait( sal_uLong nID );

#endif
