/*!
 * FilePondPluginFilePoster 2.5.1
 * Licensed under MIT, https://opensource.org/licenses/MIT/
 * Please visit https://pqina.nl/filepond/ for details.
 */

/* eslint-disable */

(function (global, factory) {
    typeof exports === 'object' && typeof module !== 'undefined'
        ? (module.exports = factory())
        : typeof define === 'function' && define.amd
        ? define(factory)
        : ((global = global || self), (global.FilePondPluginFilePoster = factory()));
})(this, function () {
    'use strict';

    var IMAGE_SCALE_SPRING_PROPS = {
        type: 'spring',
        stiffness: 0.5,
        damping: 0.45,
        mass: 10,
    };

    var createPosterView = function createPosterView(_) {
        return _.utils.createView({
            name: 'file-poster',
            tag: 'div',
            ignoreRect: true,
            create: function create(_ref) {
                var root = _ref.root;
                root.ref.image = document.createElement('img');
                root.element.appendChild(root.ref.image);
            },
            write: _.utils.createRoute({
                DID_FILE_POSTER_LOAD: function DID_FILE_POSTER_LOAD(_ref2) {
                    var root = _ref2.root,
                        props = _ref2.props;
                    var id = props.id;

                    // get item
                    var item = root.query('GET_ITEM', { id: props.id });
                    if (!item) return;

                    // get poster
                    var poster = item.getMetadata('poster');
                    root.ref.image.src = poster;

                    // let others know of our fabulous achievement (so the image can be faded in)
                    root.dispatch('DID_FILE_POSTER_DRAW', { id: id });
                },
            }),

            mixins: {
                styles: ['scaleX', 'scaleY', 'opacity'],
                animations: {
                    scaleX: IMAGE_SCALE_SPRING_PROPS,
                    scaleY: IMAGE_SCALE_SPRING_PROPS,
                    opacity: { type: 'tween', duration: 750 },
                },
            },
        });
    };

    var applyTemplate = function applyTemplate(source, target) {
        // copy width and height
        target.width = source.width;
        target.height = source.height;

        // draw the template
        var ctx = target.getContext('2d');
        ctx.drawImage(source, 0, 0);
    };

    var createPosterOverlayView = function createPosterOverlayView(fpAPI) {
        return fpAPI.utils.createView({
            name: 'file-poster-overlay',
            tag: 'canvas',
            ignoreRect: true,
            create: function create(_ref) {
                var root = _ref.root,
                    props = _ref.props;
                applyTemplate(props.template, root.element);
            },
            mixins: {
                styles: ['opacity'],
                animations: {
                    opacity: { type: 'spring', mass: 25 },
                },
            },
        });
    };

    var getImageSize = function getImageSize(url, cb) {
        var image = new Image();
        image.onload = function () {
            var width = image.naturalWidth;
            var height = image.naturalHeight;
            image = null;
            cb(width, height);
        };
        image.src = url;
    };

    var easeInOutSine = function easeInOutSine(t) {
        return -0.5 * (Math.cos(Math.PI * t) - 1);
    };

    var addGradientSteps = function addGradientSteps(gradient, color) {
        var alpha = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 1;
        var easeFn =
            arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : easeInOutSine;
        var steps = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 10;
        var offset = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : 0;
        var range = 1 - offset;
        var rgb = color.join(',');
        for (var i = 0; i <= steps; i++) {
            var p = i / steps;
            var stop = offset + range * p;
            gradient.addColorStop(stop, 'rgba('.concat(rgb, ', ').concat(easeFn(p) * alpha, ')'));
        }
    };

    var MAX_WIDTH = 10;
    var MAX_HEIGHT = 10;

    var calculateAverageColor = function calculateAverageColor(image) {
        var scalar = Math.min(MAX_WIDTH / image.width, MAX_HEIGHT / image.height);

        var canvas = document.createElement('canvas');
        var ctx = canvas.getContext('2d');
        var width = (canvas.width = Math.ceil(image.width * scalar));
        var height = (canvas.height = Math.ceil(image.height * scalar));
        ctx.drawImage(image, 0, 0, width, height);
        var data = null;
        try {
            data = ctx.getImageData(0, 0, width, height).data;
        } catch (e) {
            return null;
        }
        var l = data.length;

        var r = 0;
        var g = 0;
        var b = 0;
        var i = 0;

        for (; i < l; i += 4) {
            r += data[i] * data[i];
            g += data[i + 1] * data[i + 1];
            b += data[i + 2] * data[i + 2];
        }

        r = averageColor(r, l);
        g = averageColor(g, l);
        b = averageColor(b, l);

        return { r: r, g: g, b: b };
    };

    var averageColor = function averageColor(c, l) {
        return Math.floor(Math.sqrt(c / (l / 4)));
    };

    var drawTemplate = function drawTemplate(canvas, width, height, color, alphaTarget) {
        canvas.width = width;
        canvas.height = height;
        var ctx = canvas.getContext('2d');

        var horizontalCenter = width * 0.5;

        var grad = ctx.createRadialGradient(
            horizontalCenter,
            height + 110,
            height - 100,
            horizontalCenter,
            height + 110,
            height + 100
        );

        addGradientSteps(grad, color, alphaTarget, undefined, 8, 0.4);

        ctx.save();
        ctx.translate(-width * 0.5, 0);
        ctx.scale(2, 1);
        ctx.fillStyle = grad;
        ctx.fillRect(0, 0, width, height);
        ctx.restore();
    };

    var hasNavigator = typeof navigator !== 'undefined';

    var width = 500;
    var height = 200;

    var overlayTemplateShadow = hasNavigator && document.createElement('canvas');
    var overlayTemplateError = hasNavigator && document.createElement('canvas');
    var overlayTemplateSuccess = hasNavigator && document.createElement('canvas');

    var itemShadowColor = [40, 40, 40];
    var itemErrorColor = [196, 78, 71];
    var itemSuccessColor = [54, 151, 99];

    if (hasNavigator) {
        drawTemplate(overlayTemplateShadow, width, height, itemShadowColor, 0.85);
        drawTemplate(overlayTemplateError, width, height, itemErrorColor, 1);
        drawTemplate(overlayTemplateSuccess, width, height, itemSuccessColor, 1);
    }

    var loadImage = function loadImage(url, crossOriginValue) {
        return new Promise(function (resolve, reject) {
            var img = new Image();
            if (typeof crossOrigin === 'string') {
                img.crossOrigin = crossOriginValue;
            }
            img.onload = function () {
                resolve(img);
            };
            img.onerror = function (e) {
                reject(e);
            };
            img.src = url;
        });
    };

    var createPosterWrapperView = function createPosterWrapperView(_) {
        // create overlay view
        var overlay = createPosterOverlayView(_);

        /**
         * Write handler for when preview container has been created
         */
        var didCreatePreviewContainer = function didCreatePreviewContainer(_ref) {
            var root = _ref.root,
                props = _ref.props;
            var id = props.id;

            // we need to get the file data to determine the eventual image size
            var item = root.query('GET_ITEM', id);
            if (!item) return;

            // get url to file
            var fileURL = item.getMetadata('poster');

            // image is now ready
            var previewImageLoaded = function previewImageLoaded(data) {
                // calculate average image color, is in try catch to circumvent any cors errors
                var averageColor = root.query('GET_FILE_POSTER_CALCULATE_AVERAGE_IMAGE_COLOR')
                    ? calculateAverageColor(data)
                    : null;
                item.setMetadata('color', averageColor, true);

                // the preview is now ready to be drawn
                root.dispatch('DID_FILE_POSTER_LOAD', {
                    id: id,
                    data: data,
                });
            };

            // determine image size of this item
            getImageSize(fileURL, function (width, height) {
                // we can now scale the panel to the final size
                root.dispatch('DID_FILE_POSTER_CALCULATE_SIZE', {
                    id: id,
                    width: width,
                    height: height,
                });

                // create fallback preview
                loadImage(fileURL, root.query('GET_FILE_POSTER_CROSS_ORIGIN_ATTRIBUTE_VALUE')).then(
                    previewImageLoaded
                );
            });
        };

        /**
         * Write handler for when the preview has been loaded
         */
        var didLoadPreview = function didLoadPreview(_ref2) {
            var root = _ref2.root;
            root.ref.overlayShadow.opacity = 1;
        };

        /**
         * Write handler for when the preview image is ready to be animated
         */
        var didDrawPreview = function didDrawPreview(_ref3) {
            var root = _ref3.root;
            var image = root.ref.image;

            // reveal image
            image.scaleX = 1.0;
            image.scaleY = 1.0;
            image.opacity = 1;
        };

        /**
         * Write handler for when the preview has been loaded
         */
        var restoreOverlay = function restoreOverlay(_ref4) {
            var root = _ref4.root;
            root.ref.overlayShadow.opacity = 1;
            root.ref.overlayError.opacity = 0;
            root.ref.overlaySuccess.opacity = 0;
        };

        var didThrowError = function didThrowError(_ref5) {
            var root = _ref5.root;
            root.ref.overlayShadow.opacity = 0.25;
            root.ref.overlayError.opacity = 1;
        };

        var didCompleteProcessing = function didCompleteProcessing(_ref6) {
            var root = _ref6.root;
            root.ref.overlayShadow.opacity = 0.25;
            root.ref.overlaySuccess.opacity = 1;
        };

        /**
         * Constructor
         */
        var create = function create(_ref7) {
            var root = _ref7.root,
                props = _ref7.props;
            // test if colors aren't default item overlay colors
            var itemShadowColorProp = root.query('GET_FILE_POSTER_ITEM_OVERLAY_SHADOW_COLOR');

            var itemErrorColorProp = root.query('GET_FILE_POSTER_ITEM_OVERLAY_ERROR_COLOR');

            var itemSuccessColorProp = root.query('GET_FILE_POSTER_ITEM_OVERLAY_SUCCESS_COLOR');

            if (itemShadowColorProp && itemShadowColorProp !== itemShadowColor) {
                itemShadowColor = itemShadowColorProp;
                drawTemplate(overlayTemplateShadow, width, height, itemShadowColor, 0.85);
            }
            if (itemErrorColorProp && itemErrorColorProp !== itemErrorColor) {
                itemErrorColor = itemErrorColorProp;
                drawTemplate(overlayTemplateError, width, height, itemErrorColor, 1);
            }
            if (itemSuccessColorProp && itemSuccessColorProp !== itemSuccessColor) {
                itemSuccessColor = itemSuccessColorProp;
                drawTemplate(overlayTemplateSuccess, width, height, itemSuccessColor, 1);
            }

            // image view
            var image = createPosterView(_);

            // append image presenter
            root.ref.image = root.appendChildView(
                root.createChildView(image, {
                    id: props.id,
                    scaleX: 1.25,
                    scaleY: 1.25,
                    opacity: 0,
                })
            );

            // image overlays
            root.ref.overlayShadow = root.appendChildView(
                root.createChildView(overlay, {
                    template: overlayTemplateShadow,
                    opacity: 0,
                })
            );

            root.ref.overlaySuccess = root.appendChildView(
                root.createChildView(overlay, {
                    template: overlayTemplateSuccess,
                    opacity: 0,
                })
            );

            root.ref.overlayError = root.appendChildView(
                root.createChildView(overlay, {
                    template: overlayTemplateError,
                    opacity: 0,
                })
            );
        };

        return _.utils.createView({
            name: 'file-poster-wrapper',
            create: create,
            write: _.utils.createRoute({
                // image preview stated
                DID_FILE_POSTER_LOAD: didLoadPreview,
                DID_FILE_POSTER_DRAW: didDrawPreview,
                DID_FILE_POSTER_CONTAINER_CREATE: didCreatePreviewContainer,

                // file states
                DID_THROW_ITEM_LOAD_ERROR: didThrowError,
                DID_THROW_ITEM_PROCESSING_ERROR: didThrowError,
                DID_THROW_ITEM_INVALID: didThrowError,
                DID_COMPLETE_ITEM_PROCESSING: didCompleteProcessing,
                DID_START_ITEM_PROCESSING: restoreOverlay,
                DID_REVERT_ITEM_PROCESSING: restoreOverlay,
            }),
        });
    };

    /**
     * File Poster Plugin
     */
    var plugin = function plugin(fpAPI) {
        var addFilter = fpAPI.addFilter,
            utils = fpAPI.utils;
        var Type = utils.Type,
            createRoute = utils.createRoute;

        // filePosterView
        var filePosterView = createPosterWrapperView(fpAPI);

        // called for each view that is created right after the 'create' method
        addFilter('CREATE_VIEW', function (viewAPI) {
            // get reference to created view
            var is = viewAPI.is,
                view = viewAPI.view,
                query = viewAPI.query;

            // only hook up to item view and only if is enabled for this cropper
            if (!is('file') || !query('GET_ALLOW_FILE_POSTER')) return;

            // create the file poster plugin, but only do so if the item is an image
            var didLoadItem = function didLoadItem(_ref) {
                var root = _ref.root,
                    props = _ref.props;
                updateItemPoster(root, props);
            };

            var didUpdateItemMetadata = function didUpdateItemMetadata(_ref2) {
                var root = _ref2.root,
                    props = _ref2.props,
                    action = _ref2.action;
                if (!/poster/.test(action.change.key)) return;
                updateItemPoster(root, props);
            };

            var updateItemPoster = function updateItemPoster(root, props) {
                var id = props.id;
                var item = query('GET_ITEM', id);

                // item could theoretically have been removed in the mean time
                if (!item || !item.getMetadata('poster') || item.archived) return;

                // don't update if is the same poster
                if (root.ref.previousPoster === item.getMetadata('poster')) return;
                root.ref.previousPoster = item.getMetadata('poster');

                // test if is filtered
                if (!query('GET_FILE_POSTER_FILTER_ITEM')(item)) return;

                if (root.ref.filePoster) {
                    view.removeChildView(root.ref.filePoster);
                }

                // set preview view
                root.ref.filePoster = view.appendChildView(
                    view.createChildView(filePosterView, { id: id })
                );

                // now ready
                root.dispatch('DID_FILE_POSTER_CONTAINER_CREATE', { id: id });
            };

            var didCalculatePreviewSize = function didCalculatePreviewSize(_ref3) {
                var root = _ref3.root,
                    action = _ref3.action;
                // no poster set
                if (!root.ref.filePoster) return;

                // remember dimensions
                root.ref.imageWidth = action.width;
                root.ref.imageHeight = action.height;

                root.ref.shouldUpdatePanelHeight = true;

                root.dispatch('KICK');
            };

            var getPosterHeight = function getPosterHeight(_ref4) {
                var root = _ref4.root;
                var fixedPosterHeight = root.query('GET_FILE_POSTER_HEIGHT');

                // if fixed height: return fixed immediately
                if (fixedPosterHeight) {
                    return fixedPosterHeight;
                }

                var minPosterHeight = root.query('GET_FILE_POSTER_MIN_HEIGHT');
                var maxPosterHeight = root.query('GET_FILE_POSTER_MAX_HEIGHT');

                // if natural height is smaller than minHeight: return min height
                if (minPosterHeight && root.ref.imageHeight < minPosterHeight) {
                    return minPosterHeight;
                }

                var height = root.rect.element.width * (root.ref.imageHeight / root.ref.imageWidth);

                if (minPosterHeight && height < minPosterHeight) {
                    return minPosterHeight;
                }
                if (maxPosterHeight && height > maxPosterHeight) {
                    return maxPosterHeight;
                }

                return height;
            };

            // start writing
            view.registerWriter(
                createRoute(
                    {
                        DID_LOAD_ITEM: didLoadItem,
                        DID_FILE_POSTER_CALCULATE_SIZE: didCalculatePreviewSize,
                        DID_UPDATE_ITEM_METADATA: didUpdateItemMetadata,
                    },

                    function (_ref5) {
                        var root = _ref5.root,
                            props = _ref5.props;
                        // don't run without poster
                        if (!root.ref.filePoster) return;

                        // don't do anything while hidden
                        if (root.rect.element.hidden) return;

                        // should we redraw
                        if (root.ref.shouldUpdatePanelHeight) {
                            // time to resize the parent panel
                            root.dispatch('DID_UPDATE_PANEL_HEIGHT', {
                                id: props.id,
                                height: getPosterHeight({ root: root }),
                            });

                            // done!
                            root.ref.shouldUpdatePanelHeight = false;
                        }
                    }
                )
            );
        });

        // expose plugin
        return {
            options: {
                // Enable or disable file poster
                allowFilePoster: [true, Type.BOOLEAN],

                // Fixed preview height
                filePosterHeight: [null, Type.INT],

                // Min image height
                filePosterMinHeight: [null, Type.INT],

                // Max image height
                filePosterMaxHeight: [null, Type.INT],

                // filters file items to determine which are shown as poster
                filePosterFilterItem: [
                    function () {
                        return true;
                    },
                    Type.FUNCTION,
                ],

                // Enables or disables reading average image color
                filePosterCalculateAverageImageColor: [false, Type.BOOLEAN],

                // Allows setting the value of the CORS attribute (null is don't set attribute)
                filePosterCrossOriginAttributeValue: ['Anonymous', Type.STRING],

                // Colors used for item overlay gradient
                filePosterItemOverlayShadowColor: [null, Type.ARRAY],
                filePosterItemOverlayErrorColor: [null, Type.ARRAY],
                filePosterItemOverlaySuccessColor: [null, Type.ARRAY],
            },
        };
    };

    // fire pluginloaded event if running in browser, this allows registering the plugin when using async script tags
    var isBrowser = typeof window !== 'undefined' && typeof window.document !== 'undefined';
    if (isBrowser) {
        document.dispatchEvent(new CustomEvent('FilePond:pluginloaded', { detail: plugin }));
    }

    return plugin;
});
