#include "stdafx.h"
#include "cspcfd.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

UINT CALLBACK OFN_SpcHookProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);

UINT CALLBACK OFN_SpcHookProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    HWND hParent;

#ifdef _DEBUG
    if ((uMsg == WM_NOTIFY) || (uMsg == WM_COMMAND)) {
        int a = WM_COMMAND;
        uMsg++;
        uMsg--;
    }
#endif
    hParent = ::GetParent(hDlg);
    if (hParent) {
        CSpcFileDialog& DLG = (uMsg == WM_INITDIALOG) ? *(CSpcFileDialog*)((OPENFILENAME*)lParam)->lCustData: *(CSpcFileDialog*)CWnd::FromHandlePermanent(hDlg);
        if (&DLG) {
            if (uMsg == WM_INITDIALOG)
                DLG.m_bWM_INITDIALOG = TRUE;
            if (DLG.m_bWM_INITDIALOG && !DLG.m_bWM_DESTROY) {
                if (uMsg == WM_DESTROY)
                    DLG.m_bWM_DESTROY = TRUE;
                BOOL bRet = FALSE;
                if (DLG.DoMessage(hParent, uMsg, wParam, lParam, bRet))
                    return bRet;
            }
        }
    }

    return CSpcFileDialog::DoOldProc(hDlg, uMsg, wParam, lParam);
}

UINT CSpcFileDialog::DoOldProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    static CFileDialog s_FD(FALSE, NULL, NULL);

    return (*s_FD.m_ofn.lpfnHook)(hDlg, uMsg, wParam, lParam);
}

CSpcFileDialog::CSpcFileDialog(BOOL bOpenFileDialog, LPCTSTR lpszDefExt/* = NULL*/, LPCTSTR lpszFileName/* = NULL*/, DWORD dwFlags/* = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT*/, LPCTSTR lpszFilter/* = NULL*/, CWnd* pParentWnd/* = NULL*/)
    : CFileDialog(bOpenFileDialog, lpszDefExt, lpszFileName, dwFlags, lpszFilter, pParentWnd),
    m_dwStyle(0), m_uID(SPCHOOK_CONTROL_ID), m_hInstance(NULL)
{
    m_bWM_INITDIALOG = FALSE;
    m_bWM_DESTROY = FALSE;
}

void CSpcFileDialog::SetTitle(const char* pcszTitle)
{
    m_ofn.lpstrTitle = pcszTitle;
}

void CSpcFileDialog::SetWorkingDir(const char* pcszWorkingDir)
{
    m_ofn.lpstrInitialDir = pcszWorkingDir;
}

void CSpcFileDialog::SetFilterIndex(int nFilterIndex)
{
    m_ofn.nFilterIndex = nFilterIndex;
}

int CSpcFileDialog::GetFilterIndex() const
{
    return m_ofn.nFilterIndex;
}

void CSpcFileDialog::SetCustomFilter(const char* pcszName/* = NULL*/, const char* pcszExt/* = NULL*/)
{
    char* p = m_strCustFilter.GetBuffer(m_ofn.nMaxCustFilter = 512);
    m_ofn.lpstrCustomFilter = p;

    if (!pcszName) {
        pcszName = "User-defined file";
    }
    strcpy(p, pcszName);
    p = &p[strlen(pcszName)];
    p++; // skip '\0';
    if (!pcszExt) {
        pcszExt = "*.*";
    }
    strcpy(p, pcszExt);
    p = &p[strlen(pcszExt)];
    p++; // skip '\0';
    *p = '\0';
}

void CSpcFileDialog::EnableHook(const char* pcszWindowText, DWORD dwStyle/* = (DWORD)(-1)*/)
{
    m_strWindowText.Assign(pcszWindowText);
    ASSERT(dwStyle);
    m_dwStyle = dwStyle;

    m_ofn.Flags |= (OFN_ENABLEHOOK | OFN_EXPLORER);
    m_ofn.Flags &= ~OFN_HIDEREADONLY;
    m_ofn.lpfnHook = OFN_SpcHookProc;
    m_ofn.lCustData = (DWORD)this;
}

BOOL CSpcFileDialog::DoMessage(HWND hParent, UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bRet)
{
    switch(uMsg) {
    case WM_INITDIALOG:
        if (m_dwStyle) {
            //0x480 // File Name Edit
            HWND hReadOnly = ::GetDlgItem(hParent, 0x0410); //  Read Only
            if (hReadOnly) {
                if (m_dwStyle == (DWORD)(-1)) {
                    ::SetWindowText(hReadOnly, m_strWindowText);
                } else {
                    CRect r;

                    ::GetWindowRect(hReadOnly, &r);
                    ::ShowWindow(hReadOnly, SW_HIDE);
                    ::ScreenToClient(hParent, &r.TopLeft());
                    ::ScreenToClient(hParent, &r.BottomRight());

                    int nRet = DoOveride(hParent, r);
                    if (nRet != 0)
                        EndDialog(nRet);
                }
            }
        }
        break;
    case WM_DESTROY:
        DoDestroy();
        break;
    }

    return FALSE;
}

int CSpcFileDialog::DoOveride(HWND hParent, CRect& r)
{
    return 0; // ok!
}

void CSpcFileDialog::DoDestroy()
{
}

CSelFileDialog::CSelFileDialog(BOOL bOpenFileDialog, LPCTSTR lpszDefExt/* = NULL*/, LPCTSTR lpszFileName/* = NULL*/, DWORD dwFlags/* = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT*/, LPCTSTR lpszFilter/* = NULL*/, CWnd* pParentWnd/* = NULL*/)
    : CSpcFileDialog(bOpenFileDialog, lpszDefExt, lpszFileName, dwFlags, lpszFilter, pParentWnd)
{
    EnableHook(NULL, WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST | CBS_HASSTRINGS);
    m_nSEL = -1;
}

int CSelFileDialog::GetSEL() const
{
    ASSERT(m_dwStyle && (m_dwStyle != (DWORD)(-1)));
    return m_nSEL;
}

BOOL CSelFileDialog::OnFileNameOK()
{
    ASSERT(::IsWindow(m_Combo));
    m_nSEL = m_Combo.GetCurSel();

    return CSpcFileDialog::OnFileNameOK();
}

int CSelFileDialog::DoOveride(HWND hParent, CRect& r)
{
    r.bottom = r.top + 300;

    if (!m_hInstance) {
        m_hInstance = AfxGetApp()->m_hInstance;
    }
    HWND hWndCombo = ::CreateWindow("ComboBox", m_strWindowText, m_dwStyle, r.left, r.top, r.Width(), r.Height(), hParent, (HMENU)m_uID, m_hInstance, NULL);
    if (hWndCombo) {
        m_Combo.Attach(hWndCombo);
        m_Combo.ResetContent();

        int i, nSize = m_aSELs.GetSize();
        ASSERT(nSize > 0);

        CStr* p = &m_aSELs.GetAt(0);
        for(i = 0; i < nSize; i++) {
            m_Combo.AddString(p->String());
            p++;
        }
        m_Combo.SetCurSel(m_nSEL);

        return 0;
    }

    return -2;
}

void CSelFileDialog::DoDestroy()
{
    if (::IsWindow(m_Combo)) {
        m_Combo.Detach();
    }
}
