#include "shole.h"
#include "ids.h"

//===========================================================================
// CScrapExt : Class definition
//===========================================================================



class CScrapExt : public IShellExtInit, public IShellPropSheetExt
{
public:
    CScrapExt();
    ~CScrapExt();

    HRESULT GetFileName(LPTSTR pszPath);

    // IUnKnown
    virtual HRESULT __stdcall QueryInterface(REFIID,void **);
    virtual ULONG   __stdcall AddRef(void);
    virtual ULONG   __stdcall Release(void);

    // IShellExtInit
    virtual HRESULT __stdcall Initialize(LPCITEMIDLIST pidlFolder,
		          LPDATAOBJECT lpdobj, HKEY hkeyProgID);

    // IShellPropSheetExt
    virtual HRESULT __stdcall AddPages(LPFNADDPROPSHEETPAGE lpfnAddPage, LPARAM lParam);
    virtual HRESULT __stdcall ReplacePage(UINT uPageID, LPFNADDPROPSHEETPAGE lpfnReplaceWith, LPARAM lParam);


protected:
    UINT         _cRef;
    IDataObject* _pdtobj;
};

HRESULT CScrapExt::GetFileName(LPTSTR pszPath)
{
    STGMEDIUM medium;
    FORMATETC fmte = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
    HRESULT hres = E_FAIL;
    if (_pdtobj)
    {
	hres = _pdtobj->GetData(&fmte, &medium);
	if (hres == S_OK)
	{
	    if (!DragQueryFile((HDROP)medium.hGlobal,0,pszPath,MAX_PATH))
		hres = E_FAIL;
	    ReleaseStgMedium(&medium);
	}
    }
    return hres;
}

HRESULT CScrapExt::QueryInterface(REFIID riid, LPVOID * ppvObj)
{
    if (IsEqualIID(riid, IID_IShellExtInit) || IsEqualIID(riid, IID_IUnknown))
    {
        *ppvObj = (IShellExtInit*)this;
        _cRef++;
        return S_OK;
    }
    else if (IsEqualIID(riid, IID_IShellPropSheetExt))
    {
        *ppvObj = (IShellPropSheetExt *)this;
        _cRef++;
        return S_OK;
    }
    *ppvObj = NULL;

    return E_NOINTERFACE;
}

ULONG CScrapExt::AddRef()
{
    _cRef++;
    return _cRef;
}

ULONG CScrapExt::Release()
{
    _cRef--;
    if (_cRef > 0)
        return _cRef;

    delete this;
    return 0;
}

CScrapExt::CScrapExt() : _cRef(1), _pdtobj(NULL)
{
    g_cRefThisDll++;
    OleInitialize(NULL);
}

CScrapExt::~CScrapExt()
{
    if (_pdtobj) {
	_pdtobj->Release();
    }

    OleUninitialize();
    g_cRefThisDll--;
}

HRESULT CScrapExt::Initialize(LPCITEMIDLIST pidlFolder,
              LPDATAOBJECT pdtobj, HKEY hkeyProgID)
{
    DebugMsg(DM_TRACE, TEXT("sc TR - CScrapExt::Initialize called"));

    if (pdtobj) {
	_pdtobj = pdtobj;
	pdtobj->AddRef();
	return S_OK;
    }
    return E_FAIL;
}

//===========================================================================
// CScrapPropSheetPage: Class definition
//
// Notes: Notice that this class has no destructor. It has no destructor
//  because the lifetime of the object itself does not mean anything
//  -- full contents will be copied by the property sheet code.
//  Instead, it has a _Release function which is explicitly called
//  when the property sheet handle is destroyed.
//===========================================================================

class CScrapPropSheetPage : public PROPSHEETPAGE // spsp
{
public:
    CScrapPropSheetPage(CScrapExt* psext);
protected:
    static INT_PTR CALLBACK _DlgProc(HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
    static UINT CALLBACK _CallBack(HWND hwnd, UINT uMsg, LPPROPSHEETPAGE ppsp);
    void _Release();

    CScrapExt*      _psext;
    HWND            _hdlg;
    IOleClientSite* _pcli;
};


CScrapPropSheetPage::CScrapPropSheetPage(CScrapExt* psext)
		: _psext(psext), _hdlg(NULL), _pcli(NULL)
{
    dwSize = sizeof(CScrapPropSheetPage);
    dwFlags = PSP_DEFAULT|PSP_USECALLBACK;
    hInstance = HINST_THISDLL;
    pszTemplate = MAKEINTRESOURCE(IDD_VIEW);
    // hIcon = NULL; // unused (PSP_USEICON is not set)
    // pszTitle = NULL; // unused (PSP_USETITLE is not set)
    pfnDlgProc = _DlgProc;
    // lParam   = 0;     // unused
    pfnCallback = _CallBack;
    // pcRefParent = NULL;
    _psext->AddRef();
    CShClientSite_RegisterClass();
}

void CScrapPropSheetPage::_Release()
{
    if (_psext) {
	_psext->Release();
    }

    if (_pcli) {
	CShClientSite_Release(_pcli);
    }
};
INT_PTR CALLBACK CScrapPropSheetPage::_DlgProc(HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    HWND hwndView;
    CScrapPropSheetPage* pspsp;
    switch(uMsg)
    {
    case WM_INITDIALOG:
        SetWindowLongPtr(hdlg, DWLP_USER, lParam);
        pspsp = (CScrapPropSheetPage *)lParam;
        pspsp->_hdlg = hdlg;
	hwndView = GetDlgItem(hdlg, IDI_SCRAPVIEW);
	if (hwndView) {
	    SetWindowText(hwndView, TEXT("Not Implemented Yet"));
	    // SetWindowLongPtr(hwndView, sizeof(LPVOID), (LPARAM)pspsp);
	    TCHAR szPath[MAX_PATH];
	    if (SUCCEEDED(pspsp->_psext->GetFileName(szPath)))
	    {
		pspsp->_pcli = CShClientSite_Create(hwndView, szPath);
	    }
	}
	break;
    }
    return FALSE;
}

UINT CALLBACK CScrapPropSheetPage::_CallBack(HWND hwnd, UINT uMsg, LPPROPSHEETPAGE ppsp)
{
    CScrapPropSheetPage * pspsp = (CScrapPropSheetPage*)ppsp;
    switch(uMsg)
    {
    case PSPCB_RELEASE:
	DebugMsg(DM_TRACE, TEXT("sc - TR: _ScrapPageCallBack is releasing _psext"));
	pspsp->_Release();
	break;
    }
    return TRUE;
}


HRESULT CScrapExt::AddPages(LPFNADDPROPSHEETPAGE lpfnAddPage, LPARAM lParam)
{
    DebugMsg(DM_TRACE, TEXT("sc TR - CScrapExt::AddPage called"));

    HPROPSHEETPAGE hpage;
    HRESULT hres = S_OK;
    CScrapPropSheetPage spsp(this);

    hpage = CreatePropertySheetPage(&spsp);
    if (hpage)
    {
	BOOL bResult = lpfnAddPage(hpage, lParam);
	if (!bResult)
	{
	   DestroyPropertySheetPage(hpage);
	   hres = E_FAIL;
	}
    }

    return hres;
}

HRESULT CScrapExt::ReplacePage(UINT uPageID, LPFNADDPROPSHEETPAGE lpfnReplaceWith, LPARAM lParam)
{
    return S_FALSE;
}

HRESULT CScrapExt_CreateInstance(LPUNKNOWN * ppunk)
{
    DebugMsg(DM_TRACE, TEXT("sc TR - CScrapExt_CreateInstance called"));

    CScrapExt* pscd = new CScrapExt();
    if (pscd) {
        *ppunk = (LPDATAOBJECT)pscd;
        return S_OK;
    }
    return E_OUTOFMEMORY;
}