#ifndef _DROPTGT_H_
#define _DROPTGT_H_

// There are two drag-drop support objects:
//
//  CDropTargetWrap -       This object takes a collection of drop-target
//                          objects and wraps them as one drop-target
//                          handler.  The first drop-target wins over the
//                          the last one if there is a conflict in who
//                          will take the drop.
//
//  CDelegateDropTarget -   This class implements IDropTarget given an 
//                          IDelegateDropTargetCB interface.  It handles 
//                          all hit testing, caching, and scrolling for you.
//                          Use this class by inheriting it in your derived
//                          class; it is not intended to be instantiated alone.
//

// Event notifications for HitTestDDT
#define HTDDT_ENTER     0
#define HTDDT_OVER      1
#define HTDDT_LEAVE     2

class CDelegateDropTarget : public IDropTarget
{        
public:
    // *** IDropTarget methods ***
    virtual STDMETHODIMP DragEnter(IDataObject *pdtobj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect);
    virtual STDMETHODIMP DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect);
    virtual STDMETHODIMP DragLeave(void);
    virtual STDMETHODIMP Drop(IDataObject *pdtobj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect);

    // *** Other methods to be implemented by derived class ***

    virtual HRESULT GetWindowsDDT (HWND * phwndLock, HWND * phwndScroll) PURE;
    virtual HRESULT HitTestDDT (UINT nEvent, LPPOINT ppt, DWORD_PTR * pdwId, DWORD *pdwEffect) PURE;
    virtual HRESULT GetObjectDDT (DWORD_PTR dwId, REFIID riid, LPVOID * ppvObj) PURE;
    virtual HRESULT OnDropDDT (IDropTarget *pdt, IDataObject *pdtobj, 
                            DWORD * pgrfKeyState, POINTL pt, DWORD *pdwEffect) PURE;

    friend IDropTarget* DropTargetWrap_CreateInstance(IDropTarget* pdtPrimary, 
                                           IDropTarget* pdtSecondary,
                                           HWND hwnd, IDropTarget* pdt3 = NULL);
protected:
    CDelegateDropTarget();
    virtual ~CDelegateDropTarget();

    BOOL IsValid() { return (_hwndLock && _hwndScroll); }
    void SetCallback(IDelegateDropTargetCB* pdtcb);
    HRESULT Init(); // init lock + scroll windows
    friend IDropTarget* DelegateDropTarget_CreateInstance(IDelegateDropTargetCB* pdtcb);

private:
    void _ReleaseCurrentDropTarget();

    // the below are parameters we use to implement this IDropTarget
    HWND                    _hwndLock;
    HWND                    _hwndScroll;

    // the object we are dragging
    LPDATAOBJECT            _pDataObj;      // from DragEnter()/Drop()

    // the below indicate the current drag state
    BITBOOL                 _fPrime:1;      // TRUE iff _itemOver/_grfKeyState is valid
    DWORD_PTR               _itemOver;      // item we are visually dragging over
    IDropTarget*            _pdtCur;        // drop target for _itemOver
    DWORD                   _grfKeyState;   // cached key state
    DWORD                   _dwEffectOut;   // last *pdwEffect out
    POINT                   _ptLast;        // last dragged position

    // for scrolling
    RECT                    _rcLockWindow;  // WindowRect of hwnd for DAD_ENTER
    AUTO_SCROLL_DATA        _asd;           // for auto scrolling
    
} ;

// dummy drop target to only call DAD_DragEnterEx() on DragEnter();

class CDropDummy : public IDropTarget
{
public:
    // *** IUnknown ***
    virtual STDMETHODIMP_(ULONG) AddRef(void);
    virtual STDMETHODIMP_(ULONG) Release(void);
    virtual STDMETHODIMP QueryInterface(REFIID riid, LPVOID * ppvObj);

    // *** IDropTarget methods ***
    virtual STDMETHODIMP DragEnter(IDataObject *pdtobj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect);
    virtual STDMETHODIMP DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect);
    virtual STDMETHODIMP DragLeave(void)   
    { 
        DAD_DragLeave();  
        return(S_OK); 
    };
    virtual STDMETHODIMP Drop(IDataObject *pdtobj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)   
    { 
        DragLeave();
        return(S_OK); 
    };

    CDropDummy(HWND hwndLock) : _hwndLock(hwndLock), _cRef(1)  { return; };
protected:
    ~CDropDummy()    { return; };
private:
    HWND _hwndLock;         // window for dummy drop target.
    int  _cRef;

};


#endif // _DROPTGT_H_
