/*****************************************************************************\
    FILE: ftpdrop.h - IDropTarget interface

    Remarks:

    Note that you cannot create a shortcut on an FTP site.  Although
    there's nothing technically preventing it, it's not done because
    the shortcut won't be of much use on an FTP site.  (It points to
    your local machine, which doesn't help much for people not on the
    same network!)

    If you really want to put a shortcut file on an FTP site, create
    it on the desktop, then drag the shortcut onto the FTP site.

    The default verb for FTP sites is always "Copy".  This is true
    even if an intra-site drag-drop is being done.

    DESCRIPTION:
        DefView will cache the IDropTarget pointer (CFtpDrop) for a shell extension.
    When it calls CFtpDrop::Drop(), the work needs to be done on a background
    thread in order to not block the UI thread.  The problem is that if the user
    does another drag to the same Ftp Window, CFtpDrop::Drop() will be called again.
    For this reasons, CFtpDrop::Drop() cannot have any state after it returns.
    In order to accomplish this with the asynch background thread, we have
    CFtpDrop::Drop() call CDropOperation_Create(), and then CDropOperation->DoOperation().
    And then it will orphan (call Release()) the CDropOperation.  The CDropOperation
    will then destroy itself when the copy is finishes.  This enables subsequent calls
    to CFtpDrop::Drop() to spawn separate CDropOperation objects so each can maintain
    the state for that specifc operation and CFtpDrop remains stateless.
\*****************************************************************************/

#ifndef _FTPDROP_H
#define _FTPDROP_H

#include "util.h"

typedef enum OPS
{                           // Overwrite prompt status
    opsPrompt,              // Prompt each collision
    opsYesToAll,            // Overwrite unconditionally
    opsNoToAll,             // Never overwrite
    opsCancel,              // Stop the operation
} OPS;

#define COHDI_FILESIZE_COUNT            5
#define COHDI_COPY_FILES                6

typedef struct tagCOPYONEHDROPINFO
{
    CFtpFolder * pff;
    LPCWSTR pszFSSource;
    LPCWSTR pszFtpDest;
    LPCWSTR pszDir;
    DWORD dwOperation;                  // COHDI_FILESIZE_COUNT, COHDI_COPY_FILES, etc.
    OPS ops;
    BOOL fIsRoot;
    CMultiLanguageCache * pmlc;
    LPITEMIDLIST pidlServer;
    BOOL fFireChangeNotify;     // Don't fire change notify on BrowserOnly when replacing a file.
    PROGRESSINFO progInfo;
} COPYONEHDROPINFO, * LPCOPYONEHDROPINFO;

typedef HRESULT (*STREAMCOPYPROC)(IStream * pstm, DWORD dwFlags, DWORD dwFileSizeHigh, DWORD dwFileSizeLow, LPVOID pv, ULARGE_INTEGER *pqw);

#ifdef UNICODE
#define _EnumOneHdrop          _EnumOneHdropW
#else // UNICODE
#define _EnumOneHdrop          _EnumOneHdropA
#endif // UNICODE


/*****************************************************************************\

    CFtpDrop

    de and pde are rather gnarly.

    pde is where the output drop effect is kept.  A drop handler
    can force the effect to be DROPEFFECT_COPY if it encounters a
    situation that indicates that the source shouldn't be deleted.
    (E.g., if a file is not copied due to an illegal file name.)

    de is where the current effect is kept.  A drop handler
    should consult de to decide whether or not the source
    should be deleted.  (Used by the HDROP handler, because it is
    the drop target's responsibility to delete the source of an
    HDROP if applicable.)

    You should read from de and write to *pde.  Don't
    write to de or read from *pde.

    The overwrite prompting state tells us how to handle
    the case where an incoming file collides with an existing file.

    DESCRIPTION:
        DefView will cache the IDropTarget pointer (CFtpDrop) for a shell extension.
    When it calls CFtpDrop::Drop(), the work needs to be done on a background
    thread in order to not block the UI thread.  The problem is that if the user
    does another drag to the same Ftp Window, CFtpDrop::Drop() will be called again.
    For this reasons, CFtpDrop::Drop() cannot have any state after it returns.
    In order to accomplish this with the asynch background thread, we have
    CFtpDrop::Drop() call CDropOperation_Create(), and then CDropOperation->DoOperation().
    And then it will orphan (call Release()) the CDropOperation.  The CDropOperation
    will then destroy itself when the copy is finishes.  This enables subsequent calls
    to CFtpDrop::Drop() to spawn separate CDropOperation objects so each can maintain
    the state for that specifc operation and CFtpDrop remains stateless.
\*****************************************************************************/
class CFtpDrop          : public IDropTarget
{
public:
    //////////////////////////////////////////////////////
    // Public Interfaces
    //////////////////////////////////////////////////////
    
    // *** IUnknown ***
    virtual STDMETHODIMP_(ULONG) AddRef(void);
    virtual STDMETHODIMP_(ULONG) Release(void);
    virtual STDMETHODIMP QueryInterface(REFIID riid, LPVOID * ppvObj);
    
    // *** IDropTarget ***
    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);

public:
    CFtpDrop();
    ~CFtpDrop(void);

    // Public Member Functions
    DWORD GetEffectsAvail(IDataObject * pdto);
    STDMETHODIMP EnumHdrop(HGLOBAL hdrop, HGLOBAL hmap, BOOL fCopy);

    static HRESULT _CopyHglobal(IStream * pstm, DWORD dwFlags, DWORD dwFileSizeHigh, DWORD dwFileSizeLow, LPVOID pvSrc, ULARGE_INTEGER *pqw);
    static HRESULT CopyStream(IStream * pstm, DWORD dwFlags, DWORD dwFileSizeHigh, DWORD dwFileSizeLow, LPVOID pvSrc, ULARGE_INTEGER *pqw);
    

    // Friend Functions
    friend HRESULT CFtpDrop_Create(CFtpFolder * pff, HWND hwnd, CFtpDrop ** ppfm);

protected:
    // Protected Member Variables
    int                     m_cRef;

    CFtpFolder *            m_pff;          // The owner
    CFtpDir *               m_pfd;          // The FtpDir of the owner
    HWND                    m_hwnd;         // The window being drug over

    DWORD                   m_grfks;        // Last grfKeyState seen
    DWORD                   m_grfksAvail;   // Effects available
    DROPEFFECT              m_de;           // Effect being performed
    DROPEFFECT *            m_pde;          // Output effect
    OPS                     m_ops;          // Overwrite prompting state
    int                     m_cobj;         // Number of objects being dropped

    // Private Member Functions
    HRESULT SetEffect(DROPEFFECT * pde);
    HRESULT _InvokePaste(LPCMINVOKECOMMANDINFO pici);
    BOOL _HasData(IDataObject * pdto, FORMATETC * pformatetc) { return (S_OK == pdto->QueryGetData(pformatetc)); };
    DROPEFFECT GetEffect(POINTL pt);
    HRESULT CopyStorage(LPCTSTR pszFile, IStorage * pstgIn);
    HRESULT CopyHdrop(IDataObject * pdto, STGMEDIUM *psm);
    HRESULT CopyAsStream(LPCTSTR pszName, DWORD dwFileAttributes, DWORD dwFlags, DWORD dwFileSizeHigh, DWORD dwFileSizeLow, STREAMCOPYPROC pfn, LPVOID pv);
    HRESULT CopyFCont(LPCTSTR pszName, DWORD dwFileAttributes, DWORD dwFlags, DWORD dwFileSizeHigh, DWORD dwFileSizeLow, STGMEDIUM *psm);
    HRESULT CopyFGD(IDataObject * pdto, STGMEDIUM *psm, BOOL fUnicode);
    HRESULT _Copy(IDataObject * pdto);
    HRESULT _CopyOneHdrop(LPCTSTR pszFSSource, LPCTSTR pszFtpDest, IProgressDialog * ppd);

    HRESULT _StartBackgroundInteration(void);
    HRESULT _DoCountIteration(void);
    HRESULT _GetFSSourcePaths(HGLOBAL hdrop, BOOL * pfAnsi);
    HRESULT _GetFtpDestPaths(HGLOBAL hmap, BOOL fAnsi);

private:
    // Private Member Variables
    LPCTSTR                 m_pszzFSSource;         // Paths
    LPCTSTR                 m_pszzFtpDest;              // Map


    HRESULT _CalcSizeOneHdrop(LPCWSTR pszFSSource, LPCWSTR pszFtpDest, IProgressDialog * ppd);
    HRESULT _GetFileDescriptor(LONG nIndex, LPFILEGROUPDESCRIPTORW pfgdW, LPFILEGROUPDESCRIPTORA pfgdA, BOOL fUnicode, LPFILEDESCRIPTOR pfd);
    HRESULT _CreateFGDDirectory(LPFILEDESCRIPTOR pfd);
    BOOL _IsFTPOperationAllowed(IDataObject * pdto);
    CFtpDir * _GetRelativePidl(LPCWSTR pszFullPath, DWORD dwFileAttributes, DWORD dwFileSizeHigh, DWORD dwFileSizeLow, LPITEMIDLIST * ppidl);
};

#endif // _FTPDROP_H