import React from 'react';
import PropTypes from 'prop-types';
import get from 'lodash/get';
import isEqual from 'lodash/isEqual';
import cloneDeep from 'lodash/cloneDeep';
import size from 'lodash/size';
import isMatch from 'lodash/isMatch';
import containerConnect from 'Framework/ComponentContainer';
import { t } from 'Framework/i18n';
import { Services } from 'App/ServiceLocator';
import {
    getColorPalettes,
    getDesignDataUsedColors,
    getMaxUploadSize,
    getSelectedDesignProductionMethod,
    hasPlaceHolderImagesForActiveDesignArea,
    isColoringDisabled,
} from 'App/Reducers/DesignArea/Selectors';
import {
    getInitialMaxColorAmount,
    getColorKeysForAggregatedColor,
    getAggregatedColors,
    getAggregatedColorCount,
} from 'App/Reducers/DesignData/Selectors';

import {
    getPreviewUrlFromImageData,
    isAddMode,
    isColorMappingCompatible,
    isEditableVectorImage,
    isEditMode,
    isImageCompatible,
    isColorPreviewCompatible,
    isImageReadyToBeAdded,
    showVectorizeImageQuality,
} from 'App/Reducers/ImageGallery/Selectors';
import { createBackgroundWorkStateSelector } from 'App/Reducers/UI/Selectors';
import {
    addGalleryImageToUserImages,
    setSelectedImageByIdentifier,
    WN_UPLOAD_IMAGE,
} from 'App/Reducers/ImageGallery/Actions';
import ImageEditDialog from '../Components/ImageEditDialog';
import ImageUpload from '../Components/ImageEditDialog/ImageUpload';
import ImageColorize from '../Components/ImageColorize';
import Feedback from '../Components/FeedbackNotice';
import Progress from 'App/Shared/Components/Progress/Progress';
import { applySvgContentOperations, getSvgContent } from 'App/Services/DesignDataService';
import AddGalleryImage from './AddGalleryImage';
import createSelector from 'Utils/Function/createSelector';
import { getConf } from 'App/configuration';
import { getUrl } from 'App/Utils/getUrl';
import { EventTypes } from 'App/Constant';
import { expandVectorizeColorsMap, getClosestColorFromMap } from '../Utils/ImageEditUtils';
import { isOriginalVector } from '../Utils/Transformers';
import { getClient, getConfigurator } from '../../../Reducers/Configurator/Selectors';

const getOperationsFromState = state => {
    const { clipping, clippingColor, vectorize, vectorizeThreshold, vectorizeColorsMap } = state;

    return {
        clipping,
        clippingColor,
        vectorize,
        vectorizeThreshold,
        vectorizeColorsMap,
    };
};

const getLoadingState = createBackgroundWorkStateSelector(WN_UPLOAD_IMAGE);

const isVectorizableGalleryImage = imageData =>
    Boolean(
        imageData &&
            !get(imageData, 'operations.vectorize') &&
            imageData.gallery &&
            isEditableVectorImage(imageData.preview)
    );

const getDerivedOperationStateFromImageData = imageData => ({
    clipping: get(imageData, 'operations.clipping', null),
    clippingColor: get(imageData, 'operations.clippingColor', null),
    vectorize: !!get(imageData, 'operations.vectorize', false),
    vectorizeThreshold: get(imageData, 'operations.vectorizeThreshold', 0),
    vectorizeColorsMap: get(imageData, 'operations.vectorizeColorsMap', {}),
    vectorizeOriginalColorsMap: get(imageData, 'operations.vectorizeOriginalColorsMap', {}),
    vectorizeMaxColorAmount: get(imageData, 'operations.vectorizeMaxColorAmount', undefined),
});

const isImageInvalidatedByChange = (imageData1, imageData2) =>
    ['operations.clipping', 'operations.clippingColor', 'displayColorPreview'].some(
        key => get(imageData1, key, null) !== get(imageData2, key, null)
    );

export class ImageEditDialogContainer extends React.Component {
    static propTypes = {
        image: PropTypes.object,
        open: PropTypes.bool,
        editMode: PropTypes.bool,
        vectorsRequired: PropTypes.bool,
        vectorizedLogoMandatory: PropTypes.bool,
        colorDisabled: PropTypes.bool,
        loading: PropTypes.bool,
        errorCode: PropTypes.string,
        colorPalettes: PropTypes.array,
        galleryHasImages: PropTypes.bool,
        hasPlaceHolderImage: PropTypes.bool,
        displayColorPreview: PropTypes.bool,
        imageColorsWereEdited: PropTypes.bool,
        initialColorMaxAmount: PropTypes.number,
        originalColorsMap: PropTypes.object,
        colorPreviewRequirementFulfilled: PropTypes.bool,
        colorPreviewEnabled: PropTypes.bool,
        userImages: PropTypes.array.isRequired,
        editFile: PropTypes.func.isRequired,
        ProgressComponent: PropTypes.elementType.isRequired,
        maxColorAmount: PropTypes.number.isRequired,
        usedColors: PropTypes.array.isRequired,
        addGalleryImageToUserImages: PropTypes.func.isRequired,
        setSelectedImage: PropTypes.func.isRequired,
        shouldAddImageImmediately: PropTypes.func.isRequired,
        isImageCompatible: PropTypes.func.isRequired,
        isColorMappingCompatible: PropTypes.func.isRequired,
        resetColorizing: PropTypes.func.isRequired,
        uploadSize: PropTypes.number,
        ImageColorizeComponent: PropTypes.elementType,
        ImageUploadComponent: PropTypes.elementType,
        customControlElements: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node]),
        checkOwnership: PropTypes.bool,
        client: PropTypes.object,
        designProductionMethod: PropTypes.object,
        uploadDelayed: PropTypes.bool,
        loopIcon: PropTypes.element,
        colorizeIcon: PropTypes.element,
        formatPaintIcon: PropTypes.element,
        photoLibraryIcon: PropTypes.element,
        addIcon: PropTypes.element,
        imageIcon: PropTypes.element,
        checkIcon: PropTypes.element,
        errorIcon: PropTypes.element,
    };

    static defaultProps = {
        colorPreviewRequirementFulfilled: false,
        colorPreviewEnabled: false,
        checkOwnership: true,
    };

    colorAmountNoticeRef = React.createRef();
    embroideryNoticeRef = React.createRef();
    imageUploadRef = React.createRef();

    state = {
        preview: null,
        clipping: null,
        clippingColor: null,
        vectorize: false,
        vectorizeThreshold: 0,
        vectorizeMaxColorAmount: undefined,
        vectorizeColorsMap: {},
        vectorizeOriginalColorsMap: {},
        activeTabIndex: 0,
        showAddImagePanel: false,
        colorAmount: 0,
        continueButtonDisabled: false,
        originalImagePreview: null,
        upload: null,
    };

    lastImageUpdateData = null;

    componentDidMount() {
        this.updatePreview(null);

        const { image, editMode, hasPlaceHolderImage, colorDisabled } = this.props;

        const initialState = getDerivedOperationStateFromImageData(image);

        if (editMode && image && !hasPlaceHolderImage) {
            initialState.activeTabIndex = initialState.vectorize && !colorDisabled ? 2 : 1;
        }
        this.setState(initialState);
    }

    componentDidUpdate(prevProps, prevState) {
        const {
            image,
            open,
            maxColorAmount,
            editMode,
            hasPlaceHolderImage,
            isImageCompatible,
            isColorMappingCompatible,
            vectorsRequired,
            vectorizedLogoMandatory,
        } = this.props;

        const { vectorize, vectorizeColorsMap, activeTabIndex, originalImagePreview } = this.state;

        const newState = {};

        const justOpened = open !== prevProps.open && open;

        const imageChanged = !!image && image !== prevProps.image;

        const prevOperationData = getDerivedOperationStateFromImageData(prevProps.image);
        const operationData = getDerivedOperationStateFromImageData(image);
        const operationsChanged = !!image && !isEqual(prevOperationData, operationData);

        if (
            image &&
            image.preview &&
            image.preview.url &&
            activeTabIndex === 2 &&
            originalImagePreview === null &&
            !isOriginalVector(image)
        ) {
            this.updateOriginalPreview();
        }

        if (operationsChanged) {
            Object.assign(newState, operationData);
        }

        if (justOpened) {
            let activeTabIndex = 0;

            if (image && editMode && !hasPlaceHolderImage) {
                activeTabIndex = isEditableVectorImage(image.preview) ? 2 : 1;
            }

            Object.assign(newState, { activeTabIndex });
        }

        if (
            maxColorAmount !== prevProps.maxColorAmount ||
            vectorize !== prevState.vectorize ||
            vectorizeColorsMap !== prevState.vectorizeColorsMap ||
            activeTabIndex !== prevState.activeTabIndex
        ) {
            const colorAmount = getAggregatedColorCount(vectorizeColorsMap);
            const continueButtonDisabled =
                activeTabIndex === 2 && vectorize && !!maxColorAmount && colorAmount > maxColorAmount;

            this.setState({
                colorAmount,
                continueButtonDisabled,
            });
        }

        if (
            activeTabIndex === 2 &&
            isVectorizableGalleryImage(image) &&
            (!vectorize ||
                // if the user comes from the background removal tab vectorizing should be performed again
                prevState.activeTabIndex === 1)
        ) {
            Object.assign(newState, {
                vectorize: true,
            });
        }

        // when switching to the colorizing tab the color has to be made compatible
        if (
            activeTabIndex === 2 &&
            activeTabIndex !== prevState.activeTabIndex &&
            (!isImageCompatible(image) || !isColorMappingCompatible(vectorizeColorsMap))
        ) {
            Object.assign(newState, { vectorizeColorsMap });
        }

        if (
            activeTabIndex === 2 &&
            (vectorsRequired || vectorizedLogoMandatory) &&
            !vectorize &&
            !image.gallery
        ) {
            Object.assign(newState, {
                vectorize: true,
            });
        }

        let options;
        if (
            activeTabIndex === 2 &&
            !image.gallery &&
            vectorizedLogoMandatory &&
            !image.displayColorPreview &&
            !this.state.displayColorPreview
        ) {
            options = { displayColorPreview: true };
            Object.assign(newState, {
                displayColorPreview: true,
            });
        }

        (!isMatch(this.state, newState) || options) && this.handleStateChange(newState, options);

        if ((justOpened || imageChanged) && !image.incomplete) {
            this.updatePreview(null, { forceFetch: operationsChanged });
        } else if (activeTabIndex !== prevState.activeTabIndex && vectorize) {
            this.updatePreview(null, { forceFetch: true });
        }

        // update upload state if it is just opened
        if (justOpened) {
            const { userImages, galleryHasImages } = this.props;

            let upload = null;

            // if no gallery images, default to user upload
            if (!image && !userImages.length && !galleryHasImages) {
                upload = { disabled: true };
            }

            this.setUpload(upload);
        }
    }

    updateOriginalPreview = async () => {
        const { image } = this.props;
        const url = get(image, 'preview.url', '');
        const previewUrl = getUrl(url);
        const isSvg = previewUrl && /\.svg$/.test(previewUrl);
        if (isSvg) {
            const svgContent = await getSvgContent(previewUrl, true);
            const preview = applySvgContentOperations(image.original, image.preview, null, svgContent);

            this.setState({
                originalImagePreview: preview,
            });
        } else {
            this.setState({
                originalImagePreview: previewUrl,
            });
        }
    };

    setUpload = upload => {
        this.setState({ upload });
    };

    resetDerivedImageState = () => {
        this.setState({
            originalImagePreview: null,
            ...getDerivedOperationStateFromImageData(),
        });
    };

    changeSelectedBackground = value => {
        const partialState = { clipping: value };

        if (value !== null && this.state.clippingColor === null) {
            partialState.clippingColor = '#ffffff';
        }

        // remove the threshold value to trigger the re-creation of the color map
        if (this.state.vectorizeThreshold) {
            partialState.vectorizeThreshold = null;
        }

        this.handleStateChange(partialState);
    };

    changeColor = color => {
        const partialState = { clippingColor: color.hex };

        if (this.state.clipping === null) {
            partialState.clipping = 'replace';
        }

        // remove the threshold value to trigger the re-creation of the color map
        if (this.state.vectorizeThreshold) {
            partialState.vectorizeThreshold = null;
        }

        this.handleStateChange(partialState);
    };

    handleStateChange = async (partialState, options = {}) => {
        const { displayColorPreview } = options;
        const { image } = this.props;

        const nextState = {
            ...this.state,
            ...partialState,
        };

        this.setState(nextState);

        const operations = getOperationsFromState(nextState);

        if (
            !image ||
            (isMatch(image.operations, operations) && image.displayColorPreview === displayColorPreview)
        ) {
            return;
        }

        this.continueBlocked = true;
        try {
            const result = await this.props.editFile(
                operations,
                image,
                displayColorPreview !== undefined && {
                    displayColorPreview,
                }
            );

            const {
                vectorizeColorsMap,
                vectorizeThreshold,
                vectorizeMaxColorAmount,
                vectorizeOriginalColorsMap,
            } = result;

            this.setState({
                vectorizeColorsMap,
                vectorizeThreshold,
                vectorizeMaxColorAmount,
                vectorizeOriginalColorsMap,
            });
        } finally {
            this.continueBlocked = false;
        }
    };

    onVectorizeToggleChange = value => {
        this.handleStateChange({
            vectorize: value,
        });
    };

    onVectorizeThresholdChange = threshold => {
        const { image } = this.props;

        // skip if the threshold is the same as the color count
        const colorCount = getAggregatedColorCount(this.state.vectorizeColorsMap);
        if (threshold === colorCount) {
            return;
        }

        if (threshold !== this.state.vectorizeThreshold && !image.gallery) {
            return this.handleStateChange({
                vectorizeThreshold: threshold,
            });
        }

        // if the threshold value is the same, there might be some aggregated colors to restore
        return this.handleStateChange({
            vectorizeColorsMap: expandVectorizeColorsMap(
                this.state.vectorizeColorsMap,
                this.props.colorPalettes,
                threshold
            ),
            ...(image.gallery && { vectorizeThreshold: threshold }),
        });
    };

    onColorImageStateReset = async () => {
        await this.props.resetColorizing();
    };

    selectColor = async (colorKey, newColor) => {
        const vectorizeColorsMap = cloneDeep(this.state.vectorizeColorsMap);
        const colorKeys = getColorKeysForAggregatedColor(vectorizeColorsMap, colorKey);

        if (Services.designData.changeAllColorsNeeded()) {
            for (const colorKey in vectorizeColorsMap) {
                if (!vectorizeColorsMap.hasOwnProperty(colorKey)) {
                    continue;
                }

                vectorizeColorsMap[colorKey] = newColor;
            }
        } else {
            for (const colorKey of colorKeys) {
                vectorizeColorsMap[colorKey] = {
                    ...newColor,
                    isUserColor: true,
                };
            }
        }

        await this.handleStateChange({ vectorizeColorsMap });

        Services.designData.setImageAndTextColor(newColor);
        Services.analytics.triggerEvent(
            EventTypes.image_edit_colorize_color,
            newColor.value.replace('#', '')
        );
    };

    removeColor = async colorKey => {
        const { vectorizeColorsMap } = this.state;
        if (!vectorizeColorsMap[colorKey]) {
            throw new Error('Color key does not exist!');
        }
        const closestColor = getClosestColorFromMap(vectorizeColorsMap, vectorizeColorsMap[colorKey].value);
        await this.selectColor(colorKey, closestColor);
    };

    onActiveTabChange = activeTabIndex => {
        const { image } = this.props;
        const { upload } = this.state;

        if (upload !== null) {
            return;
        }

        if (!image && [1, 2].indexOf(activeTabIndex) !== -1) {
            return;
        }
        this.setState({ activeTabIndex });
    };

    updatePreview = async (svgContent, options = {}) => {
        const { forceFetch = false } = options;
        const { image } = this.props;

        let preview = null;
        let originalImagePreview = null;

        let previewUrl = image?.preview?.url;

        const isSvg = previewUrl && /\.svg$/.test(previewUrl);

        if (image) {
            const updateSVG = isSvg;

            if (updateSVG) {
                if (!svgContent) {
                    svgContent = await getSvgContent(
                        image.preview.url,
                        image.preview.url.startsWith('http'),
                        forceFetch
                    );
                }

                preview = applySvgContentOperations(
                    image.original,
                    image.preview,
                    image.displayColorPreview ? image.operations : null,
                    svgContent
                );
            } else {
                const forceUpdate = isImageInvalidatedByChange(this.lastImageUpdateData, image);
                if (forceUpdate) {
                    this.previewVersion = Math.random();
                }
                if (previewUrl) {
                    preview =
                        getPreviewUrlFromImageData(previewUrl) +
                        (this.previewVersion ? `?${this.previewVersion}` : '');
                    originalImagePreview = preview;
                }
            }
        }

        this.lastImageUpdateData = image;

        this.setState({ preview, originalImagePreview });
    };

    closeAddImagePanel = () => this.setState({ showAddImagePanel: false });

    onSelectImage = async file => {
        const { addGalleryImageToUserImages } = this.props;

        const { imageUrl, thumbUrl } = file;

        const fileName = imageUrl
            .replace(/^.*[\\/]/, '') // get filename
            .replace(/\.[^.$]+$/, ''); // remove extension

        const vectorizeColorsMap = await Services.designData.getGalleryImageColors(imageUrl);

        const svgImageSize = await Services.designData.getSVGImageSize(imageUrl);

        addGalleryImageToUserImages(imageUrl, thumbUrl, fileName, vectorizeColorsMap, svgImageSize);

        // exit image upload if a gallery image is selected
        this.setUpload(null);
    };

    continueClick = async () => {
        // block until finishing the previous action to prevent multiple image additions
        if (this.continueBlocked) {
            return;
        }

        const {
            colorDisabled,
            image,
            shouldAddImageImmediately,
            colorPreviewRequirementFulfilled,
        } = this.props;
        const { activeTabIndex, continueButtonDisabled } = this.state;

        if (activeTabIndex === 0 && shouldAddImageImmediately(image)) {
            this.continueBlocked = true;
            try {
                await Services.designer.imageEditDialogContinueClickHandler();
            } finally {
                this.continueBlocked = false;
            }
            return;
        }

        if (activeTabIndex === 0 && !(image.gallery && colorDisabled)) {
            this.setState({ activeTabIndex: image.gallery ? 2 : 1 });
            return;
        }

        // first go to the color replace step, if it's required and the color replacement is not disabled
        if (activeTabIndex === 1 && !colorDisabled) {
            this.setState({ activeTabIndex: 2 });
            return;
        }

        if (activeTabIndex === 2 && !colorPreviewRequirementFulfilled) {
            if (this.embroideryNoticeRef && this.embroideryNoticeRef.current) {
                this.embroideryNoticeRef.current.scrollIntoView();
                return;
            }
        }

        if (continueButtonDisabled) {
            if (this.colorAmountNoticeRef && this.colorAmountNoticeRef.current) {
                this.colorAmountNoticeRef.current.scrollIntoView();
                return;
            }
        }

        this.continueBlocked = true;
        try {
            await Services.designer.imageEditDialogContinueClickHandler();
        } finally {
            this.continueBlocked = false;
        }
    };

    onGalleryClick = () => {
        this.setState({ showAddImagePanel: true });
    };

    closePreviewDialog = () => {
        Services.designer.imageEditDialogCloseHandler();
    };

    onOriginalImageAndColorPreviewToggleClick = () => {
        this.handleStateChange(
            {},
            {
                displayColorPreview: !this.props.displayColorPreview,
            }
        );
    };

    uploadImage = () => this.imageUploadRef.current.uploadFile();

    onNewUploadClick = () => {
        this.setUpload({ disabled: true });
        this.resetDerivedImageState();
    };

    selectUserImage = imageIndex => {
        const { userImages, setSelectedImage } = this.props;
        setSelectedImage(userImages[imageIndex].identifier);
        this.resetDerivedImageState();
    };

    render() {
        const {
            loading,
            ProgressComponent,
            errorCode,
            colorPalettes,
            maxColorAmount,
            colorDisabled,
            vectorsRequired,
            vectorizedLogoMandatory,
            image,
            usedColors,
            imageColorsWereEdited,
            colorPreviewEnabled,
            colorPreviewRequirementFulfilled,
            uploadSize,
            ImageColorizeComponent,
            ImageUploadComponent,
            customControlElements,
            checkOwnership,
            designProductionMethod,
            client,
            uploadDelayed,
            loopIcon,
            colorizeIcon,
            formatPaintIcon,
            photoLibraryIcon,
            addIcon,
            imageIcon,
            checkIcon,
            errorIcon,
        } = this.props;
        const {
            preview,
            clipping,
            vectorize,
            vectorizeColorsMap,
            activeTabIndex,
            colorAmount,
            continueButtonDisabled,
            originalImagePreview,
            upload,
        } = this.state;

        const isGalleryImage = image && !!image.gallery;
        const showWarningMessage = showVectorizeImageQuality(image);
        const aggregatedColors = getAggregatedColors(vectorizeColorsMap);

        const colorAmountList = Array(maxColorAmount)
            .fill(null)
            .map((_, i) => i + 1);

        const colorCount = size(aggregatedColors);

        const colorPreviewBlockActive =
            activeTabIndex === 2 &&
            colorCount > 0 &&
            !isGalleryImage &&
            !vectorizedLogoMandatory &&
            (colorPreviewEnabled || !colorPreviewRequirementFulfilled);

        return (
            <React.Fragment>
                <ImageEditDialog
                    {...this.props}
                    loaderComponent={<ProgressComponent loading={loading} />}
                    errorFeedback={
                        errorCode && <Feedback errorNotice={t(`fileUpload.errors.${errorCode}`)} />
                    }
                    changeSelectedBackground={this.changeSelectedBackground}
                    onChangeColor={this.changeColor}
                    closePreviewDialog={this.closePreviewDialog}
                    backgroundSelected={clipping}
                    preview={preview}
                    uploadDelayed={uploadDelayed}
                    continueButtonDisabled={continueButtonDisabled}
                    continueClick={this.continueClick}
                    showWarningMessage={showWarningMessage}
                    imageColorizeElement={
                        <ImageColorizeComponent
                            inputRef={this.colorAmountNoticeRef}
                            colorPalettes={colorPalettes}
                            usedColors={usedColors}
                            vectorizeThreshold={colorCount > maxColorAmount ? 0 : colorCount}
                            onVectorizeThresholdChange={this.onVectorizeThresholdChange}
                            vectorizeColorsMap={vectorizeColorsMap}
                            onColorSelectClick={this.selectColor}
                            onColorRemoveClick={this.removeColor}
                            aggregatedColors={aggregatedColors}
                            disableInputs={(!vectorize && !isGalleryImage) || colorDisabled}
                            maxColorAmount={maxColorAmount}
                            colorAmount={colorAmount}
                            vectorize={vectorize}
                            onVectorizeToggleChange={this.onVectorizeToggleChange}
                            vectorizeToggleDisabled={vectorsRequired || (isGalleryImage && vectorize)}
                            onColorImageStateReset={this.onColorImageStateReset}
                            isLoading={loading}
                            imageColorsWereEdited={imageColorsWereEdited}
                            vectorsRequired={vectorsRequired}
                            colorAmountList={colorAmountList}
                            customControlElements={customControlElements}
                            designProductionMethodName={designProductionMethod?.title}
                        />
                    }
                    activeTabIndex={activeTabIndex}
                    onActiveTabChange={this.onActiveTabChange}
                    onGalleryClick={this.onGalleryClick}
                    onOriginalImageAndColorPreviewToggleClick={this.onOriginalImageAndColorPreviewToggleClick}
                    originalImagePreview={originalImagePreview}
                    embroideryNoticeRef={this.embroideryNoticeRef}
                    colorPreviewBlockActive={colorPreviewBlockActive}
                    onNewUploadClick={this.onNewUploadClick}
                    showUploadPanel={upload !== null}
                    uploadDisabled={!!(upload && upload.disabled)}
                    uploadImage={this.uploadImage}
                    selectUserImage={this.selectUserImage}
                    imageUploadElement={
                        <ImageUploadComponent
                            innerRef={this.imageUploadRef}
                            uploadSize={uploadSize}
                            onValidate={({ isValid }) => this.setUpload({ disabled: !isValid })}
                            onUploadFinished={() => {
                                this.setUpload(null);
                                this.onActiveTabChange(1);
                            }}
                            checkOwnership={checkOwnership}
                            imageIcon={imageIcon}
                            checkIcon={checkIcon}
                            errorIcon={errorIcon}
                            loopIcon={loopIcon}
                        />
                    }
                    loopIcon={loopIcon}
                    colorizeIcon={colorizeIcon}
                    formatPaintIcon={formatPaintIcon}
                    photoLibraryIcon={photoLibraryIcon}
                    addIcon={addIcon}
                />
                <AddGalleryImage
                    open={this.state.showAddImagePanel}
                    onClose={this.closeAddImagePanel}
                    onSelectImage={this.onSelectImage}
                    client={client}
                />
            </React.Fragment>
        );
    }
}

const getUserImages = createSelector(
    imageGalleryState => imageGalleryState.userImages,
    images => {
        const userImages = images.filter(image => !image.isPlaceHolderImage);
        return userImages.map(image => {
            return {
                ...image,
                url: getUrl(image.thumbnail.url),
            };
        });
    }
);
const mapStateToProps = state => {
    const { ui, imageGallery } = state;
    const colorPalettes = getColorPalettes(state);
    const designProductionMethod = getSelectedDesignProductionMethod(state);
    const vectorsRequired = !!get(designProductionMethod, 'options.vectorsRequired');
    const vectorizedLogoMandatory = !!get(designProductionMethod, 'options.vectorizedLogoMandatory');
    const colorDisabled = isColoringDisabled(state);
    const userImages = getUserImages(imageGallery);
    const hasPlaceHolderImage = hasPlaceHolderImagesForActiveDesignArea(state);
    const firstUserImageToPreSelect = userImages.length > 0 ? userImages[0] : null;
    const userImage = imageGallery.selectedImage || firstUserImageToPreSelect;
    const defaultMaxColorAmount = getConf('designer.maxColorAmount', 10);
    const maxColorAmount = Math.min(
        +get(designProductionMethod, 'options.maxColorAmount') || defaultMaxColorAmount,
        +get(userImage, 'operations.vectorizeMaxColorAmount', defaultMaxColorAmount)
    );
    const editMode = isEditMode(state);
    const galleryHasImages = imageGallery.gallery.length !== 0;
    const uploadSize = getMaxUploadSize(state);
    const open = !!ui.visibilityMap.imageEditDialog;
    const usedColors = getDesignDataUsedColors(state);
    const displayColorPreview = userImage && !!userImage.displayColorPreview;
    const colorPreviewEnabled = userImage && !!userImage.colorPreviewEnabled;
    const imageColorsWereEdited = userImage && !!userImage.imageColorsWereEdited;
    const initialColorMaxAmount = getInitialMaxColorAmount(state);
    const colorPreviewRequirementFulfilled = isColorPreviewCompatible(state, userImage);
    const client = getClient(getConfigurator(state));
    const uploadDelayed = imageGallery.uploadDelayed;

    return {
        Component: open ? ImageEditDialogContainer : () => null,
        ProgressComponent: Progress,
        ImageColorizeComponent: ImageColorize,
        ImageUploadComponent: ImageUpload,
        errorCode: imageGallery.lastErrorCode,
        loading: getLoadingState(ui) || !!(userImage && userImage.incomplete),
        image: userImage,
        maxColorAmount,
        displayColorPreview,
        colorPreviewEnabled,
        imageColorsWereEdited,
        editMode,
        open,
        userImages,
        colorPalettes,
        vectorsRequired,
        vectorizedLogoMandatory,
        colorDisabled,
        uploadSize,
        galleryHasImages,
        usedColors,
        hasPlaceHolderImage,
        initialColorMaxAmount,
        colorPreviewRequirementFulfilled,
        designProductionMethod,
        client,
        uploadDelayed,
    };
};

const mapDispatchToProps = dispatch => ({
    editFile: (operations, image, options = {}) =>
        Services.designData.editFileQueued(operations, image, {
            addMode: isAddMode(Services.store.state),
            ...options,
        }),
    setSelectedImage: identifier => dispatch(setSelectedImageByIdentifier(identifier)),
    addGalleryImageToUserImages: (imageUrl, thumbUrl, fileName, vectorizeColorsMap, svgImageSize) =>
        dispatch(addGalleryImageToUserImages(imageUrl, thumbUrl, fileName, vectorizeColorsMap, svgImageSize)),
    shouldAddImageImmediately: imageData => isImageReadyToBeAdded(Services.store.state, imageData),
    isColorMappingCompatible: vectorizeColorsMap =>
        isColorMappingCompatible(
            getSelectedDesignProductionMethod(Services.store.state).colorPalettes,
            vectorizeColorsMap
        ),
    isImageCompatible: imageData => isImageCompatible(Services.store.state, imageData),
    resetColorizing: () => Services.designData.resetEditedFile(),
});

export default containerConnect(mapStateToProps, mapDispatchToProps);
