/*****************************************************************************
 *
 *    ftpicon.cpp - IExtractIcon interface
 *
 *****************************************************************************/

#include "priv.h"
#include "ftpicon.h"
#include "ftpurl.h"




INT GetFtpIcon(UINT uFlags, BOOL fIsRoot)
{
    INT nIcon = (uFlags & GIL_OPENICON) ? IDI_FTPOPENFOLDER : IDI_FTPFOLDER;

    if (fIsRoot)
        nIcon = IDI_FTPSERVER;      // This is an FTP Server Icon.

    return nIcon;
}



#ifndef UNICODE
#define PathFindExtensionA PathFindExtension
#endif

//===========================
// *** IExtractIconA Interface ***
//===========================

/*****************************************************************************\
    FUNCTION: GetIconLocation

    DESCRIPTION:
        Get the icon location from the registry.

    _UNDOCUMENTED_:  Not mentioned is that if you return GIL_NOTFILENAME,
    you should take steps to ensure uniqueness of the non-filename
    return value, to avoid colliding with non-filenames from other
    shell extensions.

    _UNDOCUMENTED_:  The inability of SHGetFileInfo to work properly
    on "magic internal" cached association icons like "*23" is not
    documented.  As a result of this "feature", the SHGFI_ICONLOCATION
    flag is useless.


    Actually, we can still use SHGetFileInfo; we'll use the shell's own
    feature against it.  We'll do a SHGFI_SYSICONINDEX and return that
    as the icon index, with "*" as the GIL_NOTFILENAME.


    We don't handle the cases where we ought to use GIL_SIMULATEDOC.
\*****************************************************************************/
HRESULT CFtpIcon::GetIconLocation(UINT uFlags, LPSTR szIconFile, UINT cchMax, int *piIndex, UINT *pwFlags)
{
    static CHAR szMSIEFTP[MAX_PATH] = "";

    if (0 == szMSIEFTP[0])
        GetModuleFileNameA(HINST_THISDLL, szMSIEFTP, ARRAYSIZE(szMSIEFTP));

    // NOTE: This is negative because it's a resource index.
    *piIndex = (0 - GetFtpIcon(uFlags, m_nRoot));

    if (pwFlags)
        *pwFlags = GIL_PERCLASS; //(uFlags & GIL_OPENICON);

    StrCpyNA(szIconFile, szMSIEFTP, cchMax);

    return S_OK;
}


//===========================
// *** IExtractIconW Interface ***
//===========================
HRESULT CFtpIcon::GetIconLocation(UINT uFlags, LPWSTR wzIconFile, UINT cchMax, int *piIndex, UINT *pwFlags)
{
    HRESULT hres;
    CHAR szIconFile[MAX_PATH];

    ASSERT_SINGLE_THREADED;
    hres = GetIconLocation(uFlags, szIconFile, ARRAYSIZE(szIconFile), piIndex, pwFlags);
    if (EVAL(SUCCEEDED(hres)))
        SHAnsiToUnicode(szIconFile, wzIconFile, cchMax);

    return hres;
}


//===========================
// *** IQueryInfo Interface ***
//===========================
HRESULT CFtpIcon::GetInfoTip(DWORD dwFlags, WCHAR **ppwszTip)
{
    ASSERT_SINGLE_THREADED;
    if (ppwszTip)       // The shell doesn't check the return value
        *ppwszTip = NULL; // so we always have to NULL the output pointer.

//        SHStrDupW(L"", ppwszTip);

    return E_NOTIMPL;

/**************
    // This InfoTip will appear when the user hovers over an item in defview.
    // We don't want to support this now because it isn't needed and looks different
    // than the shell.

    HRESULT hr = E_FAIL;
    LPITEMIDLIST pidl;

    if (!ppwszTip)
        return E_INVALIDARG;

    *ppwszTip = NULL;
    if (m_pflHfpl && (pidl = m_pflHfpl->GetPidl(0)))
    {
        WCHAR wzToolTip[MAX_URL_STRING];

        hr = FtpPidl_GetDisplayName(pidl, wzItemName, ARRAYSIZE(wzItemName));
        if (EVAL(SUCCEEDED(hr)))
            hr = SHStrDupW(wzToolTip, ppwszTip);
    }

    return hr;
***********/
}

HRESULT CFtpIcon::GetInfoFlags(DWORD *pdwFlags)
{
    *pdwFlags = 0;
    return S_OK;
}




/*****************************************************************************
 *    CFtpIcon_Create
 *
 *    We just stash away the pflHfpl; the real work happens on the
 *    GetIconLocation call.
 *
 *    _HACKHACK_: psf = 0 if we are being called by the property sheet code.
 *****************************************************************************/
HRESULT CFtpIcon_Create(CFtpFolder * pff, CFtpPidlList * pflHfpl, REFIID riid, LPVOID * ppvObj)
{
    HRESULT hres;
    CFtpIcon * pfi;

    *ppvObj = NULL;

    hres = CFtpIcon_Create(pff, pflHfpl, &pfi);
    if (SUCCEEDED(hres))
    {
        hres = pfi->QueryInterface(riid, ppvObj);
        pfi->Release();
    }

    return hres;
}


/*****************************************************************************
 *    CFtpIcon_Create
 *
 *    We just stash away the m_pflHfpl; the real work happens on the
 *    GetIconLocation call.
 *
 *    _HACKHACK_: psf = 0 if we are being called by the property sheet code.
 *****************************************************************************/
HRESULT CFtpIcon_Create(CFtpFolder * pff, CFtpPidlList * pflHfpl, CFtpIcon ** ppfi)
{
    HRESULT hres= E_OUTOFMEMORY;

    *ppfi = new CFtpIcon();
    if (*ppfi)
    {
        IUnknown_Set(&(*ppfi)->m_pflHfpl, pflHfpl);
        if (pff && pff->IsRoot())
        {
            (*ppfi)->m_nRoot++;
        }
        hres = S_OK;
    }

    return hres;
}


/****************************************************\
    Constructor
\****************************************************/
CFtpIcon::CFtpIcon() : m_cRef(1)
{
    DllAddRef();

    // This needs to be allocated in Zero Inited Memory.
    // Assert that all Member Variables are inited to Zero.
    ASSERT(!m_pflHfpl);
    ASSERT(!m_nRoot);

    INIT_SINGLE_THREADED_ASSERT;
    LEAK_ADDREF(LEAK_CFtpIcon);
}


/****************************************************\
    Destructor
\****************************************************/
CFtpIcon::~CFtpIcon()
{
    ATOMICRELEASE(m_pflHfpl);

    DllRelease();
    LEAK_DELREF(LEAK_CFtpIcon);
}


//===========================
// *** IUnknown Interface ***
//===========================

ULONG CFtpIcon::AddRef()
{
    m_cRef++;
    return m_cRef;
}

ULONG CFtpIcon::Release()
{
    ASSERT(m_cRef > 0);
    m_cRef--;

    if (m_cRef > 0)
        return m_cRef;

    delete this;
    return 0;
}

HRESULT CFtpIcon::QueryInterface(REFIID riid, void **ppvObj)
{
    static const QITAB qit[] = {
        QITABENT(CFtpIcon, IExtractIconW),
        QITABENT(CFtpIcon, IExtractIconA),
        QITABENT(CFtpIcon, IQueryInfo),
        { 0 },
    };
    
    return QISearch(this, qit, riid, ppvObj);
}