/*
 * PROJECT:     ReactOS Applications Manager
 * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
 * PURPOSE:     Settings Dialog
 * COPYRIGHT:   Copyright 2009 Dmitry Chapyshev (dmitry@reactos.org)
 *              Copyright 2017 Alexander Shaposhnikov (sanchaez@reactos.org)
 */
#include "rapps.h"

SETTINGS_INFO *g_pNewSettingsInfo;

static int CALLBACK
BrowseFolderCallback(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
{
    switch (uMsg)
    {
        case BFFM_INITIALIZED:
            SendMessageW(hwnd, BFFM_SETSELECTIONW, TRUE, lpData);
            break;
        case BFFM_VALIDATEFAILED:
            return TRUE;
    }
    return 0;
}

static BOOL
ChooseFolder(HWND hwnd)
{
    BOOL bRet = FALSE;
    BROWSEINFOW bi;
    CStringW szChooseFolderText;

    szChooseFolderText.LoadStringW(IDS_CHOOSE_FOLDER_TEXT);

    ZeroMemory(&bi, sizeof(bi));
    bi.hwndOwner = hwnd;
    bi.pidlRoot = NULL;
    bi.lpszTitle = szChooseFolderText;
    bi.ulFlags =
        BIF_USENEWUI | BIF_DONTGOBELOWDOMAIN | BIF_RETURNONLYFSDIRS | /* BIF_BROWSEFILEJUNCTIONS | */ BIF_VALIDATE;

    if (SUCCEEDED(CoInitialize(NULL)))
    {
        WCHAR szDir[MAX_PATH];
        if (GetWindowTextW(GetDlgItem(hwnd, IDC_DOWNLOAD_DIR_EDIT), szDir, _countof(szDir)))
        {
            bi.lpfn = BrowseFolderCallback;
            bi.lParam = (LPARAM)szDir;
        }

        LPITEMIDLIST lpItemList = SHBrowseForFolderW(&bi);
        if (lpItemList && SHGetPathFromIDListW(lpItemList, szDir))
        {
            if (*szDir)
            {
                SetDlgItemTextW(hwnd, IDC_DOWNLOAD_DIR_EDIT, szDir);
                bRet = TRUE;
            }
        }

        CoTaskMemFree(lpItemList);
        CoUninitialize();
    }

    return bRet;
}

static BOOL
IsUrlValid(const WCHAR *Url)
{
    URL_COMPONENTSW UrlComponmentInfo = {0};
    UrlComponmentInfo.dwStructSize = sizeof(UrlComponmentInfo);
    UrlComponmentInfo.dwSchemeLength = 1;

    BOOL bSuccess = InternetCrackUrlW(Url, wcslen(Url), 0, &UrlComponmentInfo);
    if (!bSuccess)
    {
        return FALSE;
    }

    switch (UrlComponmentInfo.nScheme)
    {
        case INTERNET_SCHEME_HTTP:
        case INTERNET_SCHEME_HTTPS:
        case INTERNET_SCHEME_FTP:
        case INTERNET_SCHEME_FILE:
            // supported
            return TRUE;

        default:
            return FALSE;
    }
}

namespace
{
static inline BOOL
IsCheckedDlgItem(HWND hDlg, INT nIDDlgItem)
{
    return SendDlgItemMessageW(hDlg, nIDDlgItem, BM_GETCHECK, 0, 0) == BST_CHECKED;
}

static inline void
AdjustListViewHeader(HWND hWndList)
{
    ListView_SetColumnWidth(hWndList, 0, LVSCW_AUTOSIZE_USEHEADER);
}

static void
HandleGeneralListItems(HWND hWndList, PSETTINGS_INFO Load, PSETTINGS_INFO Save)
{
    PSETTINGS_INFO Info = Load ? Load : Save;
    const struct {
        WORD Id;
        BOOL *Setting;
    } Map[] = {
        { IDS_CFG_SAVE_WINDOW_POS, &Info->bSaveWndPos },
        { IDS_CFG_UPDATE_AVLIST, &Info->bUpdateAtStart },
        { IDS_CFG_LOG_ENABLED, &Info->bLogEnabled },
        { IDS_CFG_SMALL_ICONS, &Info->bSmallIcons },
    };

    if (ListView_GetItemCount(hWndList) == 0)
    {
        UINT ExStyle = LVS_EX_CHECKBOXES | LVS_EX_LABELTIP;
        ListView_SetExtendedListViewStyleEx(hWndList, ExStyle, ExStyle);
        LVCOLUMN lvc;
        lvc.mask = LVCF_TEXT | LVCF_SUBITEM;
        lvc.iSubItem = 0;
        lvc.pszText = const_cast<PWSTR>(L"");
        ListView_InsertColumn(hWndList, 0, &lvc);

        CStringW Name;
        for (SIZE_T i = 0; i < _countof(Map); ++i)
        {
            LVITEMW Item;
            Item.mask = LVIF_TEXT | LVIF_PARAM;
            Item.iItem = 0x7fff;
            Item.iSubItem = 0;
            Item.lParam = Map[i].Id;
            Name.LoadStringW(Map[i].Id);
            Item.pszText = const_cast<PWSTR>(Name.GetString());
            Item.iItem = ListView_InsertItem(hWndList, &Item);
        }
        ListView_SetItemState(hWndList, 0, -1, LVIS_FOCUSED | LVIS_SELECTED);
        AdjustListViewHeader(hWndList);
    }

    for (SIZE_T i = 0; i < _countof(Map); ++i)
    {
        LVFINDINFOW FindInfo = { LVFI_PARAM, NULL, Map[i].Id };
        int Idx = ListView_FindItem(hWndList, -1, &FindInfo);
        if (Idx >= 0)
        {
            if (Load)
            {
                ListView_SetCheckState(hWndList, Idx, *Map[i].Setting);
            }
            else
            {
                *Map[i].Setting = ListView_GetCheckState(hWndList, Idx);
            }
        }
    }
}

static VOID
InitSettingsControls(HWND hDlg, PSETTINGS_INFO Info)
{
    HandleGeneralListItems(GetDlgItem(hDlg, IDC_GENERALLIST), Info, NULL);
    SendDlgItemMessageW(hDlg, IDC_DEL_AFTER_INSTALL, BM_SETCHECK, Info->bDelInstaller, 0);

    HWND hCtl = GetDlgItem(hDlg, IDC_DOWNLOAD_DIR_EDIT);
    SetWindowTextW(hCtl, Info->szDownloadDir);
    SendMessageW(hCtl, EM_LIMITTEXT, MAX_PATH - 1, 0);

    CheckRadioButton(hDlg, IDC_PROXY_DEFAULT, IDC_USE_PROXY, IDC_PROXY_DEFAULT + Info->Proxy);

    if (Info->Proxy == 2)
    {
        EnableWindow(GetDlgItem(hDlg, IDC_PROXY_SERVER), TRUE);
        EnableWindow(GetDlgItem(hDlg, IDC_NO_PROXY_FOR), TRUE);
    }
    else
    {
        EnableWindow(GetDlgItem(hDlg, IDC_PROXY_SERVER), FALSE);
        EnableWindow(GetDlgItem(hDlg, IDC_NO_PROXY_FOR), FALSE);
    }

    CheckRadioButton(hDlg, IDC_SOURCE_DEFAULT, IDC_USE_SOURCE, Info->bUseSource ? IDC_USE_SOURCE : IDC_SOURCE_DEFAULT);

    EnableWindow(GetDlgItem(hDlg, IDC_SOURCE_URL), Info->bUseSource);

    SetWindowTextW(GetDlgItem(hDlg, IDC_SOURCE_URL), Info->szSourceURL);
    SetWindowTextW(GetDlgItem(hDlg, IDC_PROXY_SERVER), Info->szProxyServer);
    SetWindowTextW(GetDlgItem(hDlg, IDC_NO_PROXY_FOR), Info->szNoProxyFor);
}

static INT_PTR CALLBACK
SettingsDlgProc(HWND hDlg, UINT Msg, WPARAM wParam, LPARAM lParam)
{
    SETTINGS_INFO &NewSettingsInfo = *g_pNewSettingsInfo;

    switch (Msg)
    {
        case WM_INITDIALOG:
            InitSettingsControls(hDlg, &SettingsInfo);
            return TRUE;

        case WM_SETTINGCHANGE:
        case WM_THEMECHANGED:
        case WM_SYSCOLORCHANGE:
            SendMessage(GetDlgItem(hDlg, IDC_GENERALLIST), Msg, wParam, lParam);
            AdjustListViewHeader(GetDlgItem(hDlg, IDC_GENERALLIST));
            break;

        case WM_COMMAND:
        {
            switch (LOWORD(wParam))
            {
                case IDC_CHOOSE:
                    ChooseFolder(hDlg);
                    break;

                case IDC_DEL_AFTER_INSTALL:
                    NewSettingsInfo.bDelInstaller = IsCheckedDlgItem(hDlg, IDC_DEL_AFTER_INSTALL);
                    break;

                case IDC_SOURCE_DEFAULT:
                    NewSettingsInfo.bUseSource = FALSE;
                    EnableWindow(GetDlgItem(hDlg, IDC_SOURCE_URL), NewSettingsInfo.bUseSource);
                    break;

                case IDC_USE_SOURCE:
                    NewSettingsInfo.bUseSource = TRUE;
                    EnableWindow(GetDlgItem(hDlg, IDC_SOURCE_URL), NewSettingsInfo.bUseSource);
                    break;

                case IDC_PROXY_DEFAULT:
                    NewSettingsInfo.Proxy = 0;
                    EnableWindow(GetDlgItem(hDlg, IDC_PROXY_SERVER), FALSE);
                    EnableWindow(GetDlgItem(hDlg, IDC_NO_PROXY_FOR), FALSE);
                    break;

                case IDC_NO_PROXY:
                    NewSettingsInfo.Proxy = 1;
                    EnableWindow(GetDlgItem(hDlg, IDC_PROXY_SERVER), FALSE);
                    EnableWindow(GetDlgItem(hDlg, IDC_NO_PROXY_FOR), FALSE);
                    break;

                case IDC_USE_PROXY:
                    NewSettingsInfo.Proxy = 2;
                    EnableWindow(GetDlgItem(hDlg, IDC_PROXY_SERVER), TRUE);
                    EnableWindow(GetDlgItem(hDlg, IDC_NO_PROXY_FOR), TRUE);
                    break;

                case IDC_DEFAULT_SETTINGS:
                    FillDefaultSettings(&NewSettingsInfo);
                    InitSettingsControls(hDlg, &NewSettingsInfo);
                    break;

                case IDOK:
                {
                    HandleGeneralListItems(GetDlgItem(hDlg, IDC_GENERALLIST), NULL, &NewSettingsInfo);

                    CStringW szDir;
                    CStringW szSource;
                    CStringW szProxy;
                    CStringW szNoProxy;
                    DWORD dwAttr;

                    GetWindowTextW(GetDlgItem(hDlg, IDC_DOWNLOAD_DIR_EDIT), szDir.GetBuffer(MAX_PATH), MAX_PATH);
                    szDir.ReleaseBuffer();

                    GetWindowTextW(
                        GetDlgItem(hDlg, IDC_SOURCE_URL), szSource.GetBuffer(INTERNET_MAX_URL_LENGTH),
                        INTERNET_MAX_URL_LENGTH);
                    szSource.ReleaseBuffer();

                    GetWindowTextW(GetDlgItem(hDlg, IDC_PROXY_SERVER), szProxy.GetBuffer(MAX_PATH), MAX_PATH);
                    szProxy.ReleaseBuffer();
                    CStringW::CopyChars(
                        NewSettingsInfo.szProxyServer, _countof(NewSettingsInfo.szProxyServer), szProxy,
                        szProxy.GetLength() + 1);

                    GetWindowTextW(GetDlgItem(hDlg, IDC_NO_PROXY_FOR), szNoProxy.GetBuffer(MAX_PATH), MAX_PATH);
                    szNoProxy.ReleaseBuffer();
                    CStringW::CopyChars(
                        NewSettingsInfo.szNoProxyFor, _countof(NewSettingsInfo.szNoProxyFor), szNoProxy,
                        szNoProxy.GetLength() + 1);

                    CStringW::CopyChars(
                        NewSettingsInfo.szDownloadDir, _countof(NewSettingsInfo.szDownloadDir), szDir,
                        szDir.GetLength() + 1);
                    dwAttr = GetFileAttributesW(szDir);
                    if (dwAttr == INVALID_FILE_ATTRIBUTES || !(dwAttr & FILE_ATTRIBUTE_DIRECTORY))
                    {
                        CStringW szMsgText;
                        szMsgText.LoadStringW(IDS_CHOOSE_FOLDER_ERROR);

                        if (MessageBoxW(hDlg, szMsgText, NULL, MB_YESNO) == IDYES)
                        {
                            if (!CreateDirectoryW(szDir, NULL))
                            {
                                ErrorBox(hDlg);
                                break;
                            }
                        }
                        else
                        {
                            SetFocus(GetDlgItem(hDlg, IDC_DOWNLOAD_DIR_EDIT));
                            break;
                        }
                    }

                    if (NewSettingsInfo.bUseSource && !IsUrlValid(szSource))
                    {
                        CStringW szMsgText;
                        szMsgText.LoadStringW(IDS_URL_INVALID);

                        MessageBoxW(hDlg, szMsgText, NULL, MB_OK);
                        SetFocus(GetDlgItem(hDlg, IDC_SOURCE_URL));
                        break;
                    }
                    else
                    {
                        CStringW::CopyChars(
                            NewSettingsInfo.szSourceURL, _countof(NewSettingsInfo.szSourceURL), szSource,
                            szSource.GetLength() + 1);
                    }

                    if (SettingsInfo.bSmallIcons != NewSettingsInfo.bSmallIcons)
                    {
                        SendMessageW(hMainWnd, WM_SETTINGCHANGE, SPI_SETICONMETRICS, 0); // Note: WM_SETTINGCHANGE cannot be posted
                        PostMessageW(hMainWnd, WM_COMMAND, ID_REFRESH, 0);
                    }
                    SettingsInfo = NewSettingsInfo;
                    SaveSettings(GetParent(hDlg), &SettingsInfo);
                    EndDialog(hDlg, LOWORD(wParam));
                }
                break;

                case IDCANCEL:
                    EndDialog(hDlg, LOWORD(wParam));
                    break;
            }
            break;
        }

        case WM_NOTIFY:
        {
            NMITEMACTIVATE &nmia = *(NMITEMACTIVATE*)lParam;
            if (wParam == IDC_GENERALLIST && nmia.hdr.code == NM_CLICK)
            {
                LVHITTESTINFO lvhti;
                lvhti.pt = nmia.ptAction;
                if (nmia.iItem != -1 && ListView_HitTest(nmia.hdr.hwndFrom, &lvhti) != -1)
                {
                    if (lvhti.flags & (LVHT_ONITEMICON | LVHT_ONITEMLABEL))
                        ListView_SetCheckState(nmia.hdr.hwndFrom, nmia.iItem,
                                               !ListView_GetCheckState(nmia.hdr.hwndFrom, nmia.iItem));
                }
            }
            break;
        }
    }

    return FALSE;
}
} // namespace

VOID
CreateSettingsDlg(HWND hwnd)
{
    SETTINGS_INFO NewSettingsInfo = SettingsInfo;
    g_pNewSettingsInfo = &NewSettingsInfo;

    DialogBoxW(hInst, MAKEINTRESOURCEW(IDD_SETTINGS_DIALOG), hwnd, SettingsDlgProc);
}