#include "shellprv.h"
#include "ids.h"

#include "apdlg.h"
#include "hwcmmn.h"

#include "mtpt.h"

static const DWORD s_rgdwHelpIDsArray[] =
{
    IDC_AP_TOPTEXT,               IDH_SELECT_CONTENT_TYPE,
    IDC_AP_LIST,                  IDH_SELECT_CONTENT_TYPE,
    IDC_AP_DEFAULTHANDLER,        IDH_SELECT_ACTION,
    IDC_AP_LIST_ACTIONS,          IDH_SELECT_ACTION,
    IDC_AP_PROMPTEACHTIME,        IDH_PROMPT_ME_EACH_TIME,
    IDC_AP_NOACTION,              IDH_TAKE_NO_ACTION,
    0, 0
};

static const DWORD g_rgdwContentTypes[] =
{
    CT_AUTOPLAYMUSIC   ,
    CT_AUTOPLAYPIX     ,
    CT_AUTOPLAYMOVIE   ,
    CT_AUTOPLAYMIXEDCONTENT ,
    CT_CDAUDIO         ,
    CT_DVDMOVIE        ,
    CT_BLANKCDR        , // could also have been: CT_BLANKCDRW
};

#define COL_ACTION      0
#define COL_PROVIDER    1

const UINT c_auTileColumns[] = {COL_ACTION, COL_PROVIDER};
const UINT c_auTileSubItems[] = {COL_PROVIDER};

HRESULT CAutoPlayDlg::_InitListViewActions()
{
    HWND hwndList = GetDlgItem(_hwnd, IDC_AP_LIST_ACTIONS);

    HRESULT hr = _uilListViewActions.Init(hwndList);

    if (SUCCEEDED(hr))
    {
        hr = _uilListViewActions.InitTileInfo(c_auTileSubItems, ARRAYSIZE(c_auTileSubItems));

        if (SUCCEEDED(hr))
        {
            RECT rc = {0};
            LVTILEVIEWINFO lvtvi = {0};
            HIMAGELIST himagelist;

            ListView_SetView(hwndList, LV_VIEW_TILE);

            for (int i = 0; i < ARRAYSIZE(c_auTileColumns); ++i)
            {
                LVCOLUMN lvcolumn = {0};

                lvcolumn.mask = LVCF_SUBITEM;
                lvcolumn.iSubItem = c_auTileColumns[i];
                ListView_InsertColumn(hwndList, i, &lvcolumn);
            }

            GetClientRect(hwndList, &rc);

            lvtvi.cbSize = sizeof(lvtvi);
            lvtvi.dwMask = LVTVIM_TILESIZE | LVTVIM_COLUMNS;
            lvtvi.dwFlags = LVTVIF_FIXEDWIDTH;
    
            // Leave room for the scroll bar when setting tile sizes or listview gets screwed up.
            lvtvi.sizeTile.cx = ((rc.right - rc.left) - GetSystemMetrics(SM_CXVSCROLL));
            lvtvi.cLines = ARRAYSIZE(c_auTileSubItems);
            ListView_SetTileViewInfo(hwndList, &lvtvi);

            Shell_GetImageLists(&himagelist, NULL);

            if (himagelist)
            {
                ListView_SetImageList(hwndList, himagelist, LVSIL_NORMAL);
                hr = S_OK;
            }
        }
    }

    return hr;
}

HRESULT CAutoPlayDlg::_FillListViewActions(CContentTypeData* pdata)
{
    HRESULT hr = _uilListViewActions.ResetContent();
    if (SUCCEEDED(hr))
    {
        int c = pdata->GetHandlerCount();
        if (c)
        {
            for (int i = 0; SUCCEEDED(hr) && (i < c); ++i)
            {
                CHandlerData* phandlerdata = pdata->GetHandlerData(i);

                if (phandlerdata)
                {
                    CHandlerLVItem* puidata = new CHandlerLVItem();

                    if (puidata)
                    {
                        hr = puidata->InitData(phandlerdata);

                        if (SUCCEEDED(hr))
                        {
                            hr = _uilListViewActions.AddItem(puidata);

                            if (FAILED(hr))
                            {
                                delete puidata;
                            }
                        }
                    }
                    else
                    {
                        hr = E_OUTOFMEMORY;
                    }

                    phandlerdata->Release();
                }
            }

            _fAtLeastOneAction = TRUE;
        }
        else
        {
            // disable the listview and its radio button
            _fAtLeastOneAction = FALSE;
        }
    }

    return hr;
}

HRESULT CAutoPlayDlg::_UpdateRestoreButton(BOOL fPromptEachTime)
{
    BOOL fEnable;

    if (fPromptEachTime)
    {
        fEnable = FALSE;
    }
    else
    {
        fEnable = TRUE;
    }

    EnableWindow(GetDlgItem(_hwnd, IDC_AP_RESTOREDEFAULTS), fEnable);

    return fEnable;
}

HRESULT CAutoPlayDlg::_UpdateLowerPane()
{
    CContentTypeData* pdata;
    HRESULT hr = _uilListView.GetSelectedItemData(&pdata);

    _fIgnoreListViewItemStateChanges = TRUE;

    if (SUCCEEDED(hr))
    {
        BOOL fPromptEachTime = !lstrcmpi(pdata->_pszHandlerDefault, TEXT("MSPromptEachTime"));

        if (!fPromptEachTime)
        {
            if (!(pdata->_dwHandlerDefaultFlags & HANDLERDEFAULT_USERCHOSENDEFAULT))
            {
                // There *NO* User Chosen Default
                fPromptEachTime = TRUE;
            }
            else
            {
                // There is a User Chosen Default
                if (pdata->_dwHandlerDefaultFlags &
                    HANDLERDEFAULT_MORERECENTHANDLERSINSTALLED)
                {
                    // But there's also more recent apps
                    fPromptEachTime = TRUE;
                }
            }
        }

        hr = _FillListViewActions(pdata);

        if (SUCCEEDED(hr))
        {
            hr = _SelectListViewActionsItem(pdata->_pszHandlerDefault);
        }

        if (SUCCEEDED(hr))
        {
            hr = _SelectRadioButton(fPromptEachTime);
        }

        if (SUCCEEDED(hr))
        {
            hr = _UpdateRestoreButton(fPromptEachTime);
        }

        pdata->Release();
    }

    _fIgnoreListViewItemStateChanges = FALSE;

    return hr;
}

HRESULT CAutoPlayDlg::_UpdateApplyButton()
{
    if (_dlmanager.IsDirty())
    {
        PropSheet_Changed(GetParent(_hwnd), _hwnd);
    }
    else
    {
        PropSheet_UnChanged(GetParent(_hwnd), _hwnd);
    }

    return S_OK;
}

HRESULT _SetHandlerDefault(LPWSTR* ppszHandlerDefault, LPCWSTR pszHandler)
{
    LPWSTR pszHandlerNew;
    HRESULT hr = SHStrDup(pszHandler, &pszHandlerNew);

    if (SUCCEEDED(hr))
    {
        if (*ppszHandlerDefault)
        {
            CoTaskMemFree(*ppszHandlerDefault);
        }

        *ppszHandlerDefault = pszHandlerNew;
    }

    return hr;
}

HRESULT CAutoPlayDlg::_SelectRadioButton(BOOL fPromptEachTime)
{
    CContentTypeData* pdata;
    HRESULT hr = _uilListView.GetSelectedItemData(&pdata);

    if (SUCCEEDED(hr))
    {
        int iCtrl;
        BOOL fEnableListView = FALSE;

        if (fPromptEachTime)
        {
            _SetHandlerDefault(&(pdata->_pszHandlerDefault), TEXT("MSPromptEachTime"));

            iCtrl = IDC_AP_PROMPTEACHTIME;
        }
        else
        {
            fEnableListView = TRUE;

            CHandlerData* phandlerdata;
            hr = _uilListViewActions.GetSelectedItemData(&phandlerdata);

            if (SUCCEEDED(hr))
            {
                _SetHandlerDefault(&(pdata->_pszHandlerDefault), phandlerdata->_pszHandler);

                phandlerdata->Release();
            }

            iCtrl = IDC_AP_DEFAULTHANDLER;
        }

        Button_SetCheck(GetDlgItem(_hwnd, IDC_AP_DEFAULTHANDLER), (IDC_AP_DEFAULTHANDLER == iCtrl));
        Button_SetCheck(GetDlgItem(_hwnd, IDC_AP_PROMPTEACHTIME), (IDC_AP_PROMPTEACHTIME == iCtrl));

        EnableWindow(GetDlgItem(_hwnd, IDC_AP_LIST_ACTIONS), fEnableListView);

        pdata->Release();

        hr = _UpdateApplyButton();
    }

    return hr;
}

HRESULT CAutoPlayDlg::_SelectListViewActionsItem(LPCWSTR pszHandlerDefault)
{
    HRESULT hr = S_FALSE;
    LVITEM lvitem = {0};
    int iItemToSelect = 0;
    HWND hwndList = GetDlgItem(_hwnd, IDC_AP_LIST_ACTIONS);

    if (pszHandlerDefault)
    {
        int c = ListView_GetItemCount(hwndList);

        if (c)
        {
            int i;

            for (i = 0; i < c; ++i)
            {
                lvitem.mask = LVIF_PARAM;
                lvitem.iItem = i;
        
                if (ListView_GetItem(hwndList, &lvitem))
                {
                    CHandlerLVItem* phandleruidata = (CHandlerLVItem*)lvitem.lParam;

                    if (phandleruidata)
                    {
                        CHandlerData* phandlerdata = phandleruidata->GetData();

                        if (phandlerdata)
                        {
                            if (!lstrcmp(phandlerdata->_pszHandler,
                                pszHandlerDefault))
                            {
                                break;                
                            }

                            phandlerdata->Release();
                        }
                    }
                }
            }

            if (i == c)
            {
                i = 0;
            }
            else
            {
                hr = S_OK;
            }

            iItemToSelect = i;
        }
    }
    else
    {
        // Select first one
        hr = S_OK;
    }

    lvitem.mask = LVIF_STATE;
    lvitem.iItem = iItemToSelect;
    lvitem.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
    lvitem.state = LVIS_SELECTED | LVIS_FOCUSED;

    ListView_SetItem(hwndList, &lvitem);
    ListView_EnsureVisible(hwndList, lvitem.iItem, FALSE);

    return hr;
}

LRESULT CAutoPlayDlg::_OnApply()
{
    if (_dlmanager.IsDirty())
    {
        // Should we get the return value, and if so, why?
        _dlmanager.Commit();
    }

    return PSNRET_NOERROR;
}

// Listview Actions
HRESULT CAutoPlayDlg::_OnListViewActionsSelChange()
{
    CHandlerData* phandlerdata;
    HRESULT hr = _uilListViewActions.GetSelectedItemData(&phandlerdata);

    if (SUCCEEDED(hr))
    {
        CContentTypeData* pdata;
        hr = _uilListView.GetSelectedItemData(&pdata);

        if (SUCCEEDED(hr))
        {
            _SetHandlerDefault(&(pdata->_pszHandlerDefault), phandlerdata->_pszHandler);

            pdata->Release();
        }

        phandlerdata->Release();
    }

    if (SUCCEEDED(hr))
    {
        hr = _UpdateApplyButton();
    }

    return hr;
}

// Radio buttons
HRESULT CAutoPlayDlg::_OnRestoreDefault()
{
    CContentTypeData* pdata;
    HRESULT hr = _uilListView.GetSelectedItemData(&pdata);

    if (SUCCEEDED(hr))
    {
        _SetHandlerDefault(&(pdata->_pszHandlerDefault), TEXT("MSPromptEachTime"));

        _SelectRadioButton(TRUE);

        hr = _UpdateApplyButton();

        if (SUCCEEDED(hr))
        {
            _UpdateRestoreButton(TRUE);
        }

        pdata->Release();

        SetFocus(GetNextDlgTabItem(_hwnd, GetDlgItem(_hwnd, IDC_AP_RESTOREDEFAULTS), FALSE /*next ctrl*/));
    }
    
    return hr;
}

HRESULT CAutoPlayDlg::_OnRadio(int iButton)
{
    CContentTypeData* pdata;
    HRESULT hr = _uilListView.GetSelectedItemData(&pdata);

    if (SUCCEEDED(hr))
    {
        HWND hwndList = GetDlgItem(_hwnd, IDC_AP_LIST_ACTIONS);

        if (IDC_AP_DEFAULTHANDLER == iButton)
        {
            CHandlerData* phandlerdata;

            EnableWindow(hwndList, TRUE);

            hr = _uilListViewActions.GetSelectedItemData(&phandlerdata);

            if (SUCCEEDED(hr))
            {
                _SetHandlerDefault(&(pdata->_pszHandlerDefault), phandlerdata->_pszHandler);

                phandlerdata->Release();
            }
        }
        else
        {
            _SetHandlerDefault(&(pdata->_pszHandlerDefault), TEXT("MSPromptEachTime"));

            EnableWindow(hwndList, FALSE);
        }

        hr = _UpdateApplyButton();

        if (SUCCEEDED(hr))
        {
            _UpdateRestoreButton(!lstrcmpi(pdata->_pszHandlerDefault, TEXT("MSPromptEachTime")));
        }

        pdata->Release();
    }
    
    return hr;
}

LRESULT CAutoPlayDlg::OnInitDialog(WPARAM wParam, LPARAM lParam)
{
    HRESULT hr = _InitDataObjects();

    _fIgnoreListViewItemStateChanges = TRUE;

    if (SUCCEEDED(hr))
    {
        hr = _InitListView();

        if (SUCCEEDED(hr))
        {
            hr = _FillListView();

            if (SUCCEEDED(hr))
            {
                hr = _InitListViewActions();

                if (SUCCEEDED(hr))
                {
                    hr = _uilListView.SelectFirstItem();

                    if (SUCCEEDED(hr))
                    {
                        hr = _UpdateLowerPane();
                    }
                }
            }
        }
    }

    _fIgnoreListViewItemStateChanges = FALSE;

    return TRUE;
}

LRESULT CAutoPlayDlg::OnNotify(WPARAM wParam, LPARAM lParam)
{
    LRESULT lRes = FALSE;
    
    LPNMHDR pNMHDR = (LPNMHDR)lParam;
    UINT_PTR idFrom = pNMHDR->idFrom;
    UINT uCode = pNMHDR->code;
    
    switch (uCode) 
    {
    case PSN_APPLY:
        lRes = _OnApply();
        
        CBaseDlg::OnNotify(wParam, lParam);
        break;
        
    default:
        switch (idFrom)
        {
        case IDC_AP_LIST_ACTIONS:
            
            if (!_fIgnoreListViewItemStateChanges)
            {
                NMLISTVIEW* pNMLV = (NMLISTVIEW*)pNMHDR;
                
                if (LVN_ITEMCHANGED == uCode)
                {
                    // Is a new item being selected?
                    if ((pNMLV->uChanged & LVIF_STATE) &&
                        pNMLV->uNewState & LVIS_SELECTED)
                    {
                        _OnListViewActionsSelChange();
                    }
                }
            }
            
            lRes = CBaseDlg::OnNotify(wParam, lParam);
            break;
            
        default:
            lRes = CBaseDlg::OnNotify(wParam, lParam);
            break;
        }
        break;
    }
    
    return lRes;    
}

LRESULT CAutoPlayDlg::OnCommand(WPARAM wParam, LPARAM lParam)
{
    int iCtl = LOWORD(wParam);
    int iNot = HIWORD(wParam);
    
    switch (iCtl)
    {
    case IDC_AP_DEFAULTHANDLER:
    case IDC_AP_PROMPTEACHTIME:
        if (BN_CLICKED == iNot)
        {
            _OnRadio(iCtl);
        }
        break;
        
    case IDC_AP_LIST:
        if (HIWORD(wParam) == CBN_SELCHANGE)
        {
            _UpdateLowerPane();
        }
        
        break;
        
    case IDC_AP_RESTOREDEFAULTS:
        if (BN_CLICKED == iNot)
        {
            _OnRestoreDefault();
        }
        break;
    }
    
    return CBaseDlg::OnCommand(wParam, lParam);
}

LRESULT CAutoPlayDlg::OnDestroy(WPARAM wParam, LPARAM lParam)
{
    _uilListView.ResetContent();
    _uilListViewActions.ResetContent();

    return CBaseDlg::OnDestroy(wParam, lParam);
}

LRESULT CAutoPlayDlg::OnHelp(WPARAM wParam, LPARAM lParam)
{
    HWND hwndItem = (HWND)((LPHELPINFO)lParam)->hItemHandle;
    BOOL ret = WinHelp(hwndItem, TEXT("filefold.hlp"), HELP_WM_HELP, (ULONG_PTR)(LPTSTR)s_rgdwHelpIDsArray);
    if (!ret)
    {
        return CBaseDlg::OnHelp(wParam, lParam);
    }

    return ret;
}

LRESULT CAutoPlayDlg::OnContextMenu(WPARAM wParam, LPARAM lParam)
{
    BOOL lRes=FALSE;
    
    if (HTCLIENT == (int)SendMessage(_hwnd, WM_NCHITTEST, 0, lParam))
    {
        POINT pt;
        HWND hwndItem = NULL;
        int iCtrlID = 0;
        
        pt.x = GET_X_LPARAM(lParam);
        pt.y = GET_Y_LPARAM(lParam);
        ScreenToClient(_hwnd, &pt);
        
        hwndItem = ChildWindowFromPoint(_hwnd, pt);
        iCtrlID = GetDlgCtrlID(hwndItem);

        lRes = WinHelp((HWND)wParam, TEXT("filefold.hlp"), HELP_CONTEXTMENU, (ULONG_PTR)(LPTSTR)s_rgdwHelpIDsArray);
        if (!lRes)
        {
          return CBaseDlg::OnContextMenu(wParam, lParam);
        }
    }
    else
    {
        lRes = FALSE;
    }

    return lRes;
}

CAutoPlayDlg::CAutoPlayDlg() : CBaseDlg((ULONG_PTR)s_rgdwHelpIDsArray)
{
    ASSERT(ARRAYSIZE(_rgpContentTypeData) >= ARRAYSIZE(g_rgdwContentTypes));
}
      
HRESULT CAutoPlayDlg::Init(LPWSTR pszDrive, int iDriveType)
{
    _iDriveType = iDriveType;

    return StringCchCopy(_szDrive, ARRAYSIZE(_szDrive), pszDrive);
}

HRESULT CAutoPlayDlg::_InitDataObjects()
{
    HRESULT hr = S_FALSE;
    BOOL fIsCDDrive = FALSE;
    DWORD dwDriveCapabilities = HWDDC_CDROM;
    DWORD dwMediaCapabilities = HWDMC_CDROM;

    CMountPoint* pmtpt = CMountPoint::GetMountPoint(_szDrive);

    if (pmtpt)
    {
        fIsCDDrive = pmtpt->IsCDROM();

        if (fIsCDDrive)
        {
            hr = pmtpt->GetCDInfo(&dwDriveCapabilities, &dwMediaCapabilities);
        }

        pmtpt->Release();
    }

    for (DWORD dw = 0; SUCCEEDED(hr) && (dw < ARRAYSIZE(g_rgdwContentTypes));
        ++dw)
    {   
        BOOL fAddOption = TRUE;

        if (fIsCDDrive)
        {
            if ((g_rgdwContentTypes[dw] & CT_DVDMOVIE) &&
                !(dwDriveCapabilities & (HWDDC_DVDROM | HWDDC_DVDRECORDABLE | HWDDC_DVDREWRITABLE)))
            {
                fAddOption = FALSE;
            }
            else if ((g_rgdwContentTypes[dw] & CT_BLANKCDR) &&
                !(dwDriveCapabilities & (HWDDC_CDRECORDABLE | HWDDC_CDREWRITABLE)))
            {
                fAddOption = FALSE;
            }
        }
        else
        {
            if (g_rgdwContentTypes[dw] &
                (CT_CDAUDIO | CT_DVDMOVIE | CT_BLANKCDR))
            {
                fAddOption = FALSE;
            }
        }

        if (fAddOption)
        {
            _rgpContentTypeData[dw] = new CContentTypeData();

            if (_rgpContentTypeData[dw])
            {
                hr = (_rgpContentTypeData[dw])->Init(_szDrive, g_rgdwContentTypes[dw]);
                if (SUCCEEDED(hr))
                {
                    hr = _dlmanager.AddDataObject(_rgpContentTypeData[dw]);
                }
                else
                {
                    // Let's just skip this one, do not go out of the loop and
                    // abort the whole initialization.
                    hr = S_FALSE;
                }
            }
            else
            {
                hr = E_OUTOFMEMORY;
            }
        }
    }

    return hr;
}

HRESULT CAutoPlayDlg::_InitListView()
{    
    HWND hwndList = GetDlgItem(_hwnd, IDC_AP_LIST);
    HRESULT hr = _uilListView.Init(hwndList);

    if (SUCCEEDED(hr))
    {
        Shell_GetImageLists(NULL, &_himagelist);

        if (_himagelist)
        {
            SendMessage(hwndList, CBEM_SETIMAGELIST, 0, (LPARAM)_himagelist);

            hr = S_OK;
        }
    }

    return hr;
}

HRESULT CAutoPlayDlg::_FillListView()
{
    HRESULT hr = S_FALSE;

    for (DWORD dw = 0; SUCCEEDED(hr) && (dw < ARRAYSIZE(_rgpContentTypeData));
        ++dw)
    {
        if (_rgpContentTypeData[dw])
        {
            CContentTypeCBItem* pctlvitem = new CContentTypeCBItem();

            if (pctlvitem)
            {
                hr = pctlvitem->InitData(_rgpContentTypeData[dw]);

                if (SUCCEEDED(hr))
                {
                    hr = _uilListView.AddItem(pctlvitem);
                }

                if (FAILED(hr))
                {
                    delete pctlvitem;
                }
            }
            else
            {
                hr = E_OUTOFMEMORY;
            }
        }
    }

    return hr;
}

CAutoPlayDlg::~CAutoPlayDlg()
{
    for (DWORD dw = 0; dw < ARRAYSIZE(_rgpContentTypeData); ++dw)
    {
        if (_rgpContentTypeData[dw])
        {
            (_rgpContentTypeData[dw])->Release();
        }
    }
    
#ifdef AUTOPLAYDLG_LEAKPARANOIA
    // If this is on, you cannot open two Autoplay dialogs (e.g.: Autoplay
    // proppage and Autoplay prompt) at the same time and then close one.
    // It will assert for sure when you close the first one.
    ASSERT(!_DbgLocalAllocCount);
#endif
}

