// Copyright (c) 2015-2016 Yuya Ochiai
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.

/* eslint-disable max-lines */

import 'renderer/css/settings.css';

import React from 'react';
import {FormCheck, Col, FormGroup, FormText, Container, Row, Button} from 'react-bootstrap';
import ReactSelect, {ActionMeta, OptionsType} from 'react-select';

import {debounce} from 'underscore';

import {CombinedConfig, LocalConfiguration} from 'types/config';
import {DeepPartial} from 'types/utils';

import {localeTranslations} from 'common/utils/constants';

import {
    GET_LOCAL_CONFIGURATION,
    UPDATE_CONFIGURATION,
    DOUBLE_CLICK_ON_WINDOW,
    GET_DOWNLOAD_LOCATION,
    RELOAD_CONFIGURATION,
    GET_AVAILABLE_SPELL_CHECKER_LANGUAGES,
} from 'common/communication';

import AutoSaveIndicator, {SavingState} from './AutoSaveIndicator';

const CONFIG_TYPE_SERVERS = 'servers';
const CONFIG_TYPE_APP_OPTIONS = 'appOptions';

type ConfigType = typeof CONFIG_TYPE_SERVERS | typeof CONFIG_TYPE_APP_OPTIONS;

type State = DeepPartial<CombinedConfig> & {
    ready: boolean;
    maximized?: boolean;
    savingState: SavingStateItems;
    userOpenedDownloadDialog: boolean;
    allowSaveSpellCheckerURL: boolean;
    availableLanguages: Array<{label: string; value: string}>;
}

type SavingStateItems = {
    appOptions: SavingState;
    servers: SavingState;
};

type SaveQueueItem = {
    configType: ConfigType;
    key: keyof CombinedConfig;
    data: CombinedConfig[keyof CombinedConfig];
}

export default class SettingsPage extends React.PureComponent<Record<string, never>, State> {
    trayIconThemeRef: React.RefObject<HTMLDivElement>;
    downloadLocationRef: React.RefObject<HTMLInputElement>;
    showTrayIconRef: React.RefObject<HTMLInputElement>;
    autostartRef: React.RefObject<HTMLInputElement>;
    hideOnStartRef: React.RefObject<HTMLInputElement>;
    minimizeToTrayRef: React.RefObject<HTMLInputElement>;
    flashWindowRef: React.RefObject<HTMLInputElement>;
    bounceIconRef: React.RefObject<HTMLInputElement>;
    showUnreadBadgeRef: React.RefObject<HTMLInputElement>;
    useSpellCheckerRef: React.RefObject<HTMLInputElement>;
    spellCheckerURLRef: React.RefObject<HTMLInputElement>;
    enableHardwareAccelerationRef: React.RefObject<HTMLInputElement>;

    saveQueue: SaveQueueItem[];

    selectedSpellCheckerLocales: Array<{label: string; value: string}>;

    constructor(props: Record<string, never>) {
        super(props);
        this.state = {
            ready: false,
            savingState: {
                appOptions: SavingState.SAVING_STATE_DONE,
                servers: SavingState.SAVING_STATE_DONE,
            },
            userOpenedDownloadDialog: false,
            allowSaveSpellCheckerURL: false,
            availableLanguages: [],
        };

        this.getConfig();
        this.trayIconThemeRef = React.createRef();
        this.downloadLocationRef = React.createRef();
        this.showTrayIconRef = React.createRef();
        this.autostartRef = React.createRef();
        this.hideOnStartRef = React.createRef();
        this.minimizeToTrayRef = React.createRef();
        this.flashWindowRef = React.createRef();
        this.bounceIconRef = React.createRef();
        this.showUnreadBadgeRef = React.createRef();
        this.useSpellCheckerRef = React.createRef();
        this.enableHardwareAccelerationRef = React.createRef();
        this.spellCheckerURLRef = React.createRef();

        this.saveQueue = [];
        this.selectedSpellCheckerLocales = [];
    }

    componentDidMount() {
        window.ipcRenderer.on(RELOAD_CONFIGURATION, () => {
            this.updateSaveState();
            this.getConfig();
        });

        window.ipcRenderer.invoke(GET_AVAILABLE_SPELL_CHECKER_LANGUAGES).then((languages: string[]) => {
            const availableLanguages = languages.filter((language) => localeTranslations[language]).map((language) => ({label: localeTranslations[language], value: language}));
            availableLanguages.sort((a, b) => a.label.localeCompare(b.label));
            this.setState({availableLanguages});
        });
    }

    getConfig = () => {
        window.ipcRenderer.invoke(GET_LOCAL_CONFIGURATION).then((config) => {
            this.setState({ready: true, maximized: false, ...this.convertConfigDataToState(config) as Omit<State, 'ready'>});
        });
    }

    convertConfigDataToState = (configData: Partial<LocalConfiguration>, currentState: Partial<State> = {}) => {
        const newState = Object.assign({} as State, configData);
        newState.savingState = currentState.savingState || {
            appOptions: SavingState.SAVING_STATE_DONE,
            servers: SavingState.SAVING_STATE_DONE,
        };
        this.selectedSpellCheckerLocales = configData.spellCheckerLocales?.map((language: string) => ({label: localeTranslations[language] || language, value: language})) || [];
        return newState;
    }

    saveSetting = (configType: ConfigType, {key, data}: {key: keyof CombinedConfig; data: CombinedConfig[keyof CombinedConfig]}) => {
        this.saveQueue.push({
            configType,
            key,
            data,
        });
        this.updateSaveState();
        this.processSaveQueue();
    }

    processSaveQueue = debounce(() => {
        window.ipcRenderer.send(UPDATE_CONFIGURATION, this.saveQueue.splice(0, this.saveQueue.length));
    }, 500);

    updateSaveState = () => {
        let queuedUpdateCounts = {
            [CONFIG_TYPE_SERVERS]: 0,
            [CONFIG_TYPE_APP_OPTIONS]: 0,
        };

        queuedUpdateCounts = this.saveQueue.reduce((updateCounts, {configType}) => {
            updateCounts[configType]++;
            return updateCounts;
        }, queuedUpdateCounts);

        const savingState = Object.assign({}, this.state.savingState);

        Object.entries(queuedUpdateCounts).forEach(([configType, count]) => {
            if (count > 0) {
                savingState[configType as keyof SavingStateItems] = SavingState.SAVING_STATE_SAVING;
            } else if (count === 0 && savingState[configType as keyof SavingStateItems] === SavingState.SAVING_STATE_SAVING) {
                savingState[configType as keyof SavingStateItems] = SavingState.SAVING_STATE_SAVED;
                this.resetSaveState(configType as keyof SavingStateItems);
            }
        });

        this.setState({savingState});
    }

    resetSaveState = debounce((configType: keyof SavingStateItems) => {
        if (this.state.savingState[configType] !== SavingState.SAVING_STATE_SAVING) {
            const savingState = Object.assign({}, this.state.savingState);
            savingState[configType] = SavingState.SAVING_STATE_DONE;
            this.setState({savingState});
        }
    }, 2000);

    handleChangeShowTrayIcon = () => {
        const shouldShowTrayIcon = this.showTrayIconRef.current?.checked;
        window.timers.setImmediate(this.saveSetting, CONFIG_TYPE_APP_OPTIONS, {key: 'showTrayIcon', data: shouldShowTrayIcon});
        this.setState({
            showTrayIcon: shouldShowTrayIcon,
        });

        if (window.process.platform === 'darwin' && !shouldShowTrayIcon) {
            this.setState({
                minimizeToTray: false,
            });
        }
    }

    handleChangeTrayIconTheme = (theme: string) => {
        window.timers.setImmediate(this.saveSetting, CONFIG_TYPE_APP_OPTIONS, {key: 'trayIconTheme', data: theme});
        this.setState({
            trayIconTheme: theme,
        });
    }

    handleChangeAutoStart = () => {
        window.timers.setImmediate(this.saveSetting, CONFIG_TYPE_APP_OPTIONS, {key: 'autostart', data: this.autostartRef.current?.checked});
        this.setState({
            autostart: this.autostartRef.current?.checked,
        });
    }

    handleChangeHideOnStart = () => {
        window.timers.setImmediate(this.saveSetting, CONFIG_TYPE_APP_OPTIONS, {key: 'hideOnStart', data: this.hideOnStartRef.current?.checked});
        this.setState({
            hideOnStart: this.hideOnStartRef.current?.checked,
        });
    }

    handleChangeMinimizeToTray = () => {
        const shouldMinimizeToTray = (process.platform === 'win32' || this.state.showTrayIcon) && this.minimizeToTrayRef.current?.checked;

        window.timers.setImmediate(this.saveSetting, CONFIG_TYPE_APP_OPTIONS, {key: 'minimizeToTray', data: shouldMinimizeToTray});
        this.setState({
            minimizeToTray: shouldMinimizeToTray,
        });
    }

    handleFlashWindow = () => {
        window.timers.setImmediate(this.saveSetting, CONFIG_TYPE_APP_OPTIONS, {
            key: 'notifications',
            data: {
                ...this.state.notifications,
                flashWindow: this.flashWindowRef.current?.checked ? 2 : 0,
            },
        });
        this.setState({
            notifications: {
                ...this.state.notifications,
                flashWindow: this.flashWindowRef.current?.checked ? 2 : 0,
            },
        });
    }

    handleBounceIcon = () => {
        window.timers.setImmediate(this.saveSetting, CONFIG_TYPE_APP_OPTIONS, {
            key: 'notifications',
            data: {
                ...this.state.notifications,
                bounceIcon: this.bounceIconRef.current?.checked,
            },
        });
        this.setState({
            notifications: {
                ...this.state.notifications,
                bounceIcon: this.bounceIconRef.current?.checked,
            },
        });
    }

    handleBounceIconType = (event: React.ChangeEvent<HTMLInputElement>) => {
        window.timers.setImmediate(this.saveSetting, CONFIG_TYPE_APP_OPTIONS, {
            key: 'notifications',
            data: {
                ...this.state.notifications,
                bounceIconType: event.target.value,
            },
        });
        this.setState({
            notifications: {
                ...this.state.notifications,
                bounceIconType: event.target.value as 'critical' | 'informational',
            },
        });
    }

    handleShowUnreadBadge = () => {
        window.timers.setImmediate(this.saveSetting, CONFIG_TYPE_APP_OPTIONS, {key: 'showUnreadBadge', data: this.showUnreadBadgeRef.current?.checked});
        this.setState({
            showUnreadBadge: this.showUnreadBadgeRef.current?.checked,
        });
    }

    handleChangeUseSpellChecker = () => {
        window.timers.setImmediate(this.saveSetting, CONFIG_TYPE_APP_OPTIONS, {key: 'useSpellChecker', data: this.useSpellCheckerRef.current?.checked});
        this.setState({
            useSpellChecker: this.useSpellCheckerRef.current?.checked,
        });
    }

    handleChangeSpellCheckerLocales = (value: OptionsType<{label: string; value: string}>, actionMeta: ActionMeta<{label: string; value: string}>) => {
        switch (actionMeta.action) {
        case 'select-option':
            this.selectedSpellCheckerLocales = [...value];
            break;
        case 'remove-value':
            this.selectedSpellCheckerLocales = this.selectedSpellCheckerLocales.filter((language) => language.value !== actionMeta.removedValue.value);
        }

        const values = this.selectedSpellCheckerLocales.map((language) => language.value);
        window.timers.setImmediate(this.saveSetting, CONFIG_TYPE_APP_OPTIONS, {key: 'spellCheckerLocales', data: values});
        this.setState({
            spellCheckerLocales: values,
        });
    }

    handleChangeEnableHardwareAcceleration = () => {
        window.timers.setImmediate(this.saveSetting, CONFIG_TYPE_APP_OPTIONS, {key: 'enableHardwareAcceleration', data: this.enableHardwareAccelerationRef.current?.checked});
        this.setState({
            enableHardwareAcceleration: this.enableHardwareAccelerationRef.current?.checked,
        });
    }

    saveDownloadLocation = (location: string) => {
        if (!location) {
            return;
        }
        this.setState({
            downloadLocation: location,
        });
        window.timers.setImmediate(this.saveSetting, CONFIG_TYPE_APP_OPTIONS, {key: 'downloadLocation', data: location});
    }

    handleChangeDownloadLocation = (e: React.ChangeEvent<HTMLInputElement>) => {
        this.saveDownloadLocation(e.target.value);
    }

    selectDownloadLocation = () => {
        if (!this.state.userOpenedDownloadDialog) {
            window.ipcRenderer.invoke(GET_DOWNLOAD_LOCATION, this.state.downloadLocation).then((result) => this.saveDownloadLocation(result));
            this.setState({userOpenedDownloadDialog: true});
        }
        this.setState({userOpenedDownloadDialog: false});
    }

    saveSpellCheckerURL = (): void => {
        window.timers.setImmediate(this.saveSetting, CONFIG_TYPE_APP_OPTIONS, {key: 'spellCheckerURL', data: this.state.spellCheckerURL});
    }

    resetSpellCheckerURL = (): void => {
        this.setState({spellCheckerURL: undefined, allowSaveSpellCheckerURL: false});
        window.timers.setImmediate(this.saveSetting, CONFIG_TYPE_APP_OPTIONS, {key: 'spellCheckerURL', data: null});
    }

    handleChangeSpellCheckerURL= (e: React.ChangeEvent<HTMLInputElement>): void => {
        const dictionaryURL = e.target.value;
        let allowSaveSpellCheckerURL;
        try {
            // eslint-disable-next-line no-new
            new URL(dictionaryURL);
            allowSaveSpellCheckerURL = true;
        } catch {
            allowSaveSpellCheckerURL = false;
        }
        this.setState({
            spellCheckerURL: dictionaryURL,
            allowSaveSpellCheckerURL,
        });
    }

    handleDoubleClick = () => {
        window.ipcRenderer.send(DOUBLE_CLICK_ON_WINDOW, 'settings');
    }

    render() {
        const settingsPage = {
            close: {
                textDecoration: 'none',
                position: 'absolute',
                right: '0',
                top: '5px',
                fontSize: '35px',
                fontWeight: 'normal',
                color: '#bbb',
            },
            heading: {
                textAlign: 'center' as const,
                fontSize: '24px',
                margin: '0',
                padding: '1em 0',
            },
            sectionHeading: {
                fontSize: '20px',
                margin: '0',
                padding: '1em 0',
                display: 'inline-block',
            },
            sectionHeadingLink: {
                marginTop: '24px',
                display: 'inline-block',
                fontSize: '15px',
            },
            footer: {
                padding: '0.4em 0',
            },
            downloadLocationInput: {
                marginRight: '3px',
                marginTop: '8px',
                width: '320px',
                height: '34px',
                padding: '0 12px',
                borderRadius: '4px',
                border: '1px solid #ccc',
                fontWeight: 500,
            },

            downloadLocationButton: {
                marginBottom: '4px',
            },

            container: {
                paddingBottom: '40px',
            },
        };

        const options = [];

        // MacOS has an option in the Dock, to set the app to autostart, so we choose to not support this option for OSX
        if (window.process.platform === 'win32' || window.process.platform === 'linux') {
            options.push(
                <FormCheck>
                    <FormCheck.Input
                        type='checkbox'
                        key='inputAutoStart'
                        id='inputAutoStart'
                        ref={this.autostartRef}
                        checked={this.state.autostart}
                        onChange={this.handleChangeAutoStart}
                    />
                    {'Start app on login'}
                    <FormText>
                        {'If enabled, the app starts automatically when you log in to your machine.'}
                    </FormText>
                </FormCheck>);

            options.push(
                <FormCheck>
                    <FormCheck.Input
                        type='checkbox'
                        key='inputHideOnStart'
                        id='inputHideOnStart'
                        ref={this.hideOnStartRef}
                        checked={this.state.hideOnStart}
                        onChange={this.handleChangeHideOnStart}
                    />
                    {'Launch app minimized'}
                    <FormText>
                        {'If enabled, the app will start in system tray, and will not show the window on launch.'}
                    </FormText>
                </FormCheck>);
        }

        options.push(
            <>
                <FormCheck>
                    <FormCheck.Input
                        type='checkbox'
                        key='inputSpellChecker'
                        id='inputSpellChecker'
                        ref={this.useSpellCheckerRef}
                        checked={this.state.useSpellChecker}
                        onChange={this.handleChangeUseSpellChecker}
                    />
                    {'Check spelling'}
                    <FormText>
                        {'Highlight misspelled words in your messages based on your system language or language preference. '}
                        {'Setting takes effect after restarting the app.'}
                    </FormText>
                </FormCheck>
                {this.state.useSpellChecker &&
                    <ReactSelect
                        className='SettingsPage__spellCheckerLocalesDropdown'
                        classNamePrefix='SettingsPage__spellCheckerLocalesDropdown'
                        options={this.state.availableLanguages}
                        isMulti={true}
                        isClearable={false}
                        onChange={this.handleChangeSpellCheckerLocales}
                        value={this.selectedSpellCheckerLocales}
                        placeholder={'Select preferred language(s)'}
                    />
                }
            </>,
        );
        if (process.platform !== 'darwin') {
            if (this.state.spellCheckerURL === null || typeof this.state.spellCheckerURL === 'undefined') {
                options.push(
                    <Button
                        id='editSpellcheckerURL'
                        key='editSpellcheckerURL'
                        onClick={() => this.setState({spellCheckerURL: '', allowSaveSpellCheckerURL: false})}
                        variant='link'
                    >{'Use an alternative dictionary URL'}</Button>,
                );
            } else {
                options.push(
                    <div
                        style={settingsPage.container}
                        key='containerInputSpellchekerURL'
                    >
                        <input
                            disabled={!this.state.useSpellChecker}
                            style={settingsPage.downloadLocationInput}
                            key='inputSpellCheckerURL'
                            id='inputSpellCheckerURL'
                            ref={this.spellCheckerURLRef}
                            onChange={this.handleChangeSpellCheckerURL}
                            value={this.state.spellCheckerURL}
                        />
                        <Button
                            disabled={!this.state.allowSaveSpellCheckerURL}
                            key='saveSpellCheckerURL'
                            style={settingsPage.downloadLocationButton}
                            id='saveSpellCheckerURL'
                            onClick={this.saveSpellCheckerURL}
                        >
                            <span>{'Save'}</span>
                        </Button>
                        <FormText>
                            {'Specify the url where dictionary definitions can be retrieved'}
                        </FormText>
                        <Button
                            id='revertSpellcheckerURL'
                            key='revertSpellcheckerURL'
                            onClick={this.resetSpellCheckerURL}
                            variant='link'
                        >{'Revert to default'}</Button>
                    </div>);
            }
        }
        if (window.process.platform === 'darwin' || window.process.platform === 'win32') {
            const TASKBAR = window.process.platform === 'win32' ? 'taskbar' : 'Dock';
            options.push(
                <FormCheck
                    key='showunreadbadge'
                >
                    <FormCheck.Input
                        type='checkbox'
                        key='inputShowUnreadBadge'
                        id='inputShowUnreadBadge'
                        ref={this.showUnreadBadgeRef}
                        checked={this.state.showUnreadBadge}
                        onChange={this.handleShowUnreadBadge}
                    />
                    {`Show red badge on ${TASKBAR} icon to indicate unread messages`}
                    <FormText>
                        {`Regardless of this setting, mentions are always indicated with a red badge and item count on the ${TASKBAR} icon.`}
                    </FormText>
                </FormCheck>);
        }

        if (window.process.platform === 'win32' || window.process.platform === 'linux') {
            options.push(
                <FormCheck>
                    <FormCheck.Input
                        type='checkbox'
                        key='flashWindow'
                        id='inputflashWindow'
                        ref={this.flashWindowRef}
                        checked={!this.state.notifications || this.state.notifications.flashWindow === 2}
                        onChange={this.handleFlashWindow}
                    />
                    {'Flash app window and taskbar icon when a new message is received'}
                    <FormText>
                        {'If enabled, app window and taskbar icon flash for a few seconds when a new message is received.'}
                        {window.process.platform === 'linux' && (
                            <>
                                <br/>
                                <em><strong>{'NOTE: '}</strong>{'This functionality may not work with all Linux window managers.'}</em>
                            </>
                        )}
                    </FormText>
                </FormCheck>);
        }

        if (window.process.platform === 'darwin') {
            options.push(
                <FormGroup
                    key='OptionsForm'
                >
                    <FormCheck
                        type='checkbox'
                        inline={true}
                        key='bounceIcon'
                        id='inputBounceIcon'
                        ref={this.bounceIconRef}
                        checked={this.state.notifications ? this.state.notifications.bounceIcon : false}
                        onChange={this.handleBounceIcon}
                        style={{marginRight: '10px'}}
                        label='Bounce the Dock icon'
                    />
                    <FormCheck
                        type='radio'
                        inline={true}
                        name='bounceIconType'
                        value='informational'
                        disabled={!this.state.notifications || !this.state.notifications.bounceIcon}
                        defaultChecked={
                            !this.state.notifications ||
                !this.state.notifications.bounceIconType ||
                this.state.notifications.bounceIconType === 'informational'
                        }
                        onChange={this.handleBounceIconType}
                        label='once'
                    />
                    {' '}
                    <FormCheck
                        type='radio'
                        inline={true}
                        name='bounceIconType'
                        value='critical'
                        disabled={!this.state.notifications || !this.state.notifications.bounceIcon}
                        defaultChecked={this.state.notifications && this.state.notifications.bounceIconType === 'critical'}
                        onChange={this.handleBounceIconType}
                        label={'until I open the app'}
                    />
                    <FormText
                        style={{marginLeft: '20px'}}
                    >
                        {'If enabled, the Dock icon bounces once or until the user opens the app when a new notification is received.'}
                    </FormText>
                </FormGroup>,
            );
        }

        if (window.process.platform === 'darwin' || window.process.platform === 'linux') {
            options.push(
                <FormCheck
                    key='inputShowTrayIcon'
                >
                    <FormCheck.Input
                        type='checkbox'
                        id='inputShowTrayIcon'
                        ref={this.showTrayIconRef}
                        checked={this.state.showTrayIcon}
                        onChange={this.handleChangeShowTrayIcon}
                    />
                    {window.process.platform === 'darwin' ? `Show ${this.state.appName} icon in the menu bar` : 'Show icon in the notification area'}
                    <FormText>
                        {'Setting takes effect after restarting the app.'}
                    </FormText>
                </FormCheck>);
        }

        if (window.process.platform === 'linux' || window.process.platform === 'win32') {
            options.push(
                <FormGroup
                    key='trayIconTheme'
                    ref={this.trayIconThemeRef}
                    style={{marginLeft: '20px'}}
                >
                    {'Icon theme: '}
                    {window.process.platform === 'win32' &&
                        <>
                            <FormCheck
                                type='radio'
                                inline={true}
                                name='trayIconTheme'
                                value='use_system'
                                defaultChecked={this.state.trayIconTheme === 'use_system' || !this.state.trayIconTheme}
                                onChange={() => this.handleChangeTrayIconTheme('use_system')}
                                label={'Use system default'}
                            />
                            {' '}
                        </>
                    }
                    <FormCheck
                        type='radio'
                        inline={true}
                        name='trayIconTheme'
                        value='light'
                        defaultChecked={this.state.trayIconTheme === 'light' || !this.state.trayIconTheme}
                        onChange={() => this.handleChangeTrayIconTheme('light')}
                        label={'Light'}
                    />
                    {' '}
                    <FormCheck
                        type='radio'
                        inline={true}
                        name='trayIconTheme'
                        value='dark'
                        defaultChecked={this.state.trayIconTheme === 'dark'}
                        onChange={() => this.handleChangeTrayIconTheme('dark')}
                        label={'Dark'}
                    />
                </FormGroup>,
            );
        }

        if (window.process.platform === 'linux' || window.process.platform === 'win32') {
            options.push(
                <FormCheck
                    key='inputMinimizeToTray'
                >
                    <FormCheck.Input
                        type='checkbox'
                        id='inputMinimizeToTray'
                        ref={this.minimizeToTrayRef}
                        disabled={process.platform !== 'win32' && !this.state.showTrayIcon}
                        checked={this.state.minimizeToTray}
                        onChange={this.handleChangeMinimizeToTray}
                    />
                    {'Leave app running in notification area when application window is closed'}
                    <FormText>
                        {'If enabled, the app stays running in the notification area after app window is closed.'}
                        {this.state.showTrayIcon ? ' Setting takes effect after restarting the app.' : ''}
                    </FormText>
                </FormCheck>);
        }

        options.push(
            <FormCheck
                key='inputEnableHardwareAcceleration'
            >
                <FormCheck.Input
                    type='checkbox'
                    id='inputEnableHardwareAcceleration'
                    ref={this.enableHardwareAccelerationRef}
                    checked={this.state.enableHardwareAcceleration}
                    onChange={this.handleChangeEnableHardwareAcceleration}
                />
                {'Use GPU hardware acceleration'}
                <FormText>
                    {'If enabled, Mattermost UI is rendered more efficiently but can lead to decreased stability for some systems.'}
                    {' Setting takes effect after restarting the app.'}
                </FormText>
            </FormCheck>,
        );

        options.push(
            <div
                style={settingsPage.container}
                key='containerDownloadLocation'
            >
                <hr/>
                <div>{'Download Location'}</div>
                <input
                    disabled={true}
                    style={settingsPage.downloadLocationInput}
                    key='inputDownloadLocation'
                    id='inputDownloadLocation'
                    ref={this.downloadLocationRef}
                    onChange={this.handleChangeDownloadLocation}
                    value={this.state.downloadLocation}
                />
                <Button
                    style={settingsPage.downloadLocationButton}
                    id='saveDownloadLocation'
                    onClick={this.selectDownloadLocation}
                >
                    <span>{'Change'}</span>
                </Button>
                <FormText>
                    {'Specify the folder where files will download.'}
                </FormText>
            </div>,
        );

        let optionsRow = null;
        if (options.length > 0) {
            optionsRow = (
                <Row>
                    <Col md={12}>
                        <h2 style={settingsPage.sectionHeading}>{'App Options'}</h2>
                        <div className='IndicatorContainer'>
                            <AutoSaveIndicator
                                id='appOptionsSaveIndicator'
                                savingState={this.state.savingState.appOptions}
                                errorMessage={'Can\'t save your changes. Please try again.'}
                            />
                        </div>
                        { options.map((opt) => (
                            <FormGroup key={opt.key}>
                                {opt}
                            </FormGroup>
                        )) }
                    </Col>
                </Row>
            );
        }

        let waitForIpc;
        if (this.state.ready) {
            waitForIpc = optionsRow;
        } else {
            waitForIpc = (<p>{'Loading configuration...'}</p>);
        }

        return (
            <div
                className='container-fluid'
                style={{
                    height: '100%',
                }}
            >
                <div
                    style={{
                        overflowY: 'auto',
                        height: '100%',
                        margin: '0 -15px',
                    }}
                >
                    <div style={{position: 'relative'}}>
                        <h1 style={settingsPage.heading}>{'Settings'}</h1>
                        <hr/>
                    </div>
                    <Container
                        className='settingsPage'
                    >
                        {waitForIpc}
                    </Container>
                </div>
            </div>
        );
    }
}
