(function ($) {
    var mediaViewerOpenInNewWindow = openInWindow();
    var mediaViewerDownloadAttachment = download();
    var mediaViewerOpenForPrint = openInWindow(true);
    var mediaViewerOpenForPrintPrev = null;
    var mediaViewerOpenForPrintNext = null;
    var displayNavigation = false;
    var currentZoom = 1;
    var zoomIncrement = 0.25;
    var audioFileExtensions = ["mp3", "wav", "wma", "aif", "aiff", "flac", "alac"];

    $.fn.mediaViewer = function (data) {
        if (typeof data === 'string') {
            switch (data) {
                case 'displayLoader':
                    $(this).find('.media-viewer-loader').removeClass("hidden");
                    break;
            }

            return;
        }

        $(this).addClass("media-viewer");
        
        data = data === undefined ? {} : data;
        mediaViewerOpenInNewWindow = data.onOpenInNewWindow ? data.onOpenInNewWindow : mediaViewerOpenInNewWindow;
        mediaViewerDownloadAttachment = data.onDownloadAttachment ? data.onDownloadAttachment : mediaViewerDownloadAttachment;
        mediaViewerOpenForPrint = data.onOpenForPrint ? data.onOpenForPrint : mediaViewerOpenForPrint;
        mediaViewerOpenForPrintPrev = data.onNavigationPrevious ? data.onNavigationPrevious : mediaViewerOpenForPrintPrev;
        mediaViewerOpenForPrintNext = data.onNavigationNext ? data.onNavigationNext : mediaViewerOpenForPrintNext;
        displayNavigation = data.displayNavigation !== undefined ? data.displayNavigation : displayNavigation;
        currentZoom = 1;
        zoomIncrement = data.zoomIncrement ? data.zoomIncrement : zoomIncrement;
        data.dataType = data.dataType === undefined ? getDataType(data.fileName) : data.dataType;
        var translations = paw.lang.append({}, data.translations || {});

        if (data.dataType === "pdf" || data.dataType === "PDF") {
            if (data.dataUrl) {
                $(this).html(generatePdfViewer(data.dataUrl));
            }
            else if (data.dataByte) {
                if (typeof data.dataByte === 'string') {
                    data.dataByte = base64ToArrayBuffer(data.dataByte);
                }
                var blob = new Blob([data.dataByte], { type: 'application/pdf' });
                var objectURL = URL.createObjectURL(blob);
                $(this).html(generatePdfViewer(objectURL));
            }
        }
        else if (data.dataType === "img") {
            if (data.dataUrl) {
                $(this).html("<div class='media-viewer-zoom-wrapper'><img class='max-size media-viewer-data' src='" + data.dataUrl + "' /></div>");
            }
            else if (data.dataByte) {
                $(this).html("<div class='media-viewer-zoom-wrapper'><img class='max-size media-viewer-data' src='data:image/png;base64," + data.dataByte + "' /></div>");
            }

            AppendToolbar($(this), data.fileName);
            AppendZoom($(this));
        }
        else if (data.dataType === 'docx') {
            let $elt = $(this);
            $elt.html('<div class="paw-media-viewer-preview"><div id="docx-media-viewer-preview" class="paw-media-viewer-docx"></div></div>');
            $elt.find('#docx-media-viewer-preview').docx({
                blob: paw.utils.value.base64toBlob(data.dataByte),
                controls: true,
                downloadUrl: $('[data-file-id=' + data.fileId + ']').val(),
                recalcHeight: true,
                previewNotAvailableLabel: translations.previewNotAvailable
            });
        }
        else if (data.dataType === 'xlsx') {
            let $elt = $(this);
            $elt.html('<div class="paw-media-viewer-preview"><div id="xlsx-media-viewer-preview"></div></div>');
            $elt.find('#xlsx-media-viewer-preview').xlsx({
                blob: paw.utils.value.base64toBlob(data.dataByte),
                controls: true,
                downloadUrl: $('[data-file-id=' + data.fileId + ']').val(),
                scaling: false,
                previewNotAvailableLabel: translations.previewNotAvailable
            });
        }
        else if (data.dataType === 'csv') {
            let $elt = $(this);
            $elt.html('<div class="paw-media-viewer-preview"><div id="csv-media-viewer-preview"></div></div>');
            $elt.find('#csv-media-viewer-preview').csv({
                blob: paw.utils.value.base64toBlob(data.dataByte),
                controls: true,
                downloadUrl: $('[data-file-id=' + data.fileId + ']').val(),
                previewNotAvailableLabel: translations.previewNotAvailable
            });
        }
        else if (audioFileExtensions.indexOf(data.dataType) > -1) {
            let $elt = $(this);
            $elt.html('<div class="paw-media-viewer-preview"><div id="audio-file-media-viewer-preview"></div></div>');
            $elt.find('#audio-file-media-viewer-preview').audioFile({
                //blob: paw.utils.value.base64toBlob(data.dataByte),
                controls: true,
                downloadUrl: $('[data-file-id=' + data.fileId + ']').val(),
                previewNotAvailableLabel: translations.previewNotAvailable,
                extension: data.dataType
            });
        }

        appendNavigation($(this));
        appendLoader($(this));
    };

    function generatePdfViewer(url) {
        var pdfViewer = '<div>';
        pdfViewer += '<i class="fa fa-spinner fa-spin fa-2x icon-absolute-center text-muted pdfSpinner"></i>';
        pdfViewer += '<div id="preview-wrapper">';
        pdfViewer += '<object class="pdf-viewer media-viewer-data" data="' + url + '" type="application/pdf">';
        pdfViewer += '<p>' + $("#mediaViewer-noPDF").val();
        pdfViewer += '<a href="' + url + '">' + $("#mediaViewer-downloadPDF").val() + '</a>.';
        pdfViewer += '<a href="http://get.adobe.com/reader/" target="_blank">' + $("#mediaViewer-installAdobeReader").val() + '</a>.';
        pdfViewer += '</p>';
        pdfViewer += '<embed src="' + url + '" type="application/pdf" />';
        pdfViewer += '</object>';
        pdfViewer += '</div>';
        pdfViewer += '</div>';

        return pdfViewer;
    }

    function base64ToArrayBuffer(base64String) {
        var binaryString = window.atob(base64String);
        var bytes = new Uint8Array(binaryString.length);
        for (var i = 0; i < binaryString.length; i++) {
            bytes[i] = binaryString.charCodeAt(i);
        }
        return bytes.buffer;
    }

    function getDataType(fileName) {
        if (!fileName) return undefined;

        var ext = fileName.split('.').pop().toLowerCase();
        if (audioFileExtensions.indexOf(ext) > -1) {
            return ext;
        }

        switch (ext) {
            case 'jpg':
            case 'jpeg':
            case 'png':
                return "img";
            case 'pdf':
                return "pdf";
            case 'docx':
                return 'docx';
            case 'xlsx':
                return 'xlsx';
            case 'csv':
                return 'csv';
        }
    }

    function AppendToolbar($element, fileName) {
        var toolbar = $("<div class='media-viewer-toolbar'></div>");
        toolbar.append('<a class="text-default mediaViewerOpen" title="Open"><i class="far fa-window-restore"></i></a>');
        toolbar.append('<a class="text-default mediaViewerDownload" title="Save"><i class="fa fa-save"></i></a>');
        toolbar.append('<a class="text-default mediaViewerPrint" title="Print"><i class="far fa-print"></i></a>');

        $element.append(toolbar);

        $element.off("click", ".mediaViewerOpen");
        $element.on("click", ".mediaViewerOpen", function () {
            mediaViewerOpenInNewWindow($(this));
        });

        $element.off("click", ".mediaViewerDownload");
        $element.on("click", ".mediaViewerDownload", function () {
            mediaViewerDownloadAttachment($(this), fileName);
        });

        $element.off("click", ".mediaViewerPrint");
        $element.on("click", ".mediaViewerPrint", function () {
            mediaViewerOpenForPrint($(this));
        });
    }

    function AppendZoom($element) {
        var buttons = $("<div class='media-viewer-zoom'></div>");
        buttons.append('<div class="text-default mediaViewerResize" title="Resize"><i class="fas fa-expand"></i></div>');
        buttons.append('<div class="text-default mediaViewerZoomIn" title="Zoom in"><i class="fa fa-plus"></i></div>');
        buttons.append('<div class="text-default mediaViewerZoomOut" title="Zoom out"><i class="fa fa-minus"></i></div>');

        $element.append(buttons);

        $element.off("click", ".mediaViewerResize");
        $element.on("click", ".mediaViewerResize", function () {
            currentZoom = 1;
            $(this).closest(".media-viewer").find(".media-viewer-data").css("transform", "scale(" + currentZoom + ")");
        });

        $element.off("click", ".mediaViewerZoomIn");
        $element.on("click", ".mediaViewerZoomIn", function () {
            currentZoom = Math.min(5, currentZoom + zoomIncrement);
            $(this).closest(".media-viewer").find(".media-viewer-data").css("transform", "scale(" + currentZoom + ")");
        });

        $element.off("click", ".mediaViewerZoomOut");
        $element.on("click", ".mediaViewerZoomOut", function () {
            currentZoom = Math.max(0.3, currentZoom - zoomIncrement);
            $(this).closest(".media-viewer").find(".media-viewer-data").css("transform", "scale(" + currentZoom + ")");
        });
    }

    function appendNavigation($element) {
        if (!displayNavigation) return;

        $element.append('<div class="text-default media-viewer-navigation media-viewer-navigation-prev mediaViewerPrev" title="Previous"><i class="fal fa-chevron-double-left"></i></div>');
        $element.append('<div class="text-default media-viewer-navigation media-viewer-navigation-next mediaViewerNext" title="Next"><i class="fal fa-chevron-double-right"></i></div>');

        $element.off("click", ".mediaViewerPrev");
        $element.on("click", ".mediaViewerPrev", function () {
            $element.trigger("mediaViewer-prev");
            mediaViewerOpenForPrintPrev();
        });

        $element.off("click", ".mediaViewerNext");
        $element.on("click", ".mediaViewerNext", function () {
            $element.trigger("mediaViewer-next");
            mediaViewerOpenForPrintNext();
        });
    }

    function appendLoader($element) {
        var loader = $("<div class='media-viewer-loader hidden'></div>");
        loader.append('<i class="fa fa-spinner fa-spin fa-2x fa-fw text-muted"></i>');

        $element.append(loader);
    }

    function openInWindow(print) {
        return function (element) {
            let $dataElement = $($(element).closest(".media-viewer").find('.media-viewer-data')[0]);

            var popupWin = window.open();
            popupWin.document.open();
            popupWin.document.write('<html><head></head><body ' + (print ? 'onload="window.print()' : '') + '">' + jQuery('<div />').append($dataElement.clone()).html() + '</html>');
            popupWin.document.close();
        };
    }

    function download() {
        return function (element, fileName) {
            let $dataElement = $($(element).closest(".media-viewer").find('.media-viewer-data')[0]);
            fileName = !fileName ?
                "undefined." + $dataElement.attr("src").substring($dataElement.attr("src").indexOf('/') + 1, $dataElement.attr("src").indexOf(';')) :
                fileName;

            if (navigator.msSaveBlob) {
                let blob = new Blob([base64ToArrayBuffer($dataElement.attr("src").substring($dataElement.attr("src").indexOf(',') + 1))]);
                return navigator.msSaveBlob(blob, fileName);
            }
            else {
                $("body").append('<a id="mediaViewerDownloader" class="hidden" download="' + fileName + '" href="' + $dataElement.attr("src") + '"></a>');
                $("#mediaViewerDownloader")[0].click();

                $("#mediaViewerDownloader").remove();
            }
        };
    }
}(jQuery));