/**
 * Create an drag and drop uploader.
 *
 * The `.presentationUiDnduploader()` method creates a drag and drop uploader.
 *
 * Only applicable to <input type="file"> nodes.
 *
 * ### Examples
 * Explanation for example,
 *
 * JavaScript:
 *
 *
 *     <input type="file" name="NewFile" class="ep-js" data-js="de_epages.presentationUiDnduploader({
 *       multiple:false,
 *       accept:'image/*',
 *       data:{
 *         ChangeAction:'SaveImage',
 *         ObjectID:#ObjectID,
 *         SCALE_WIDTH_l:#Shop.ProductImageLargeWidth,
 *         SCALE_HEIGHT_l:#Shop.ProductImageLargeHeight,
 *         SCALE_WIDTH_m:200,
 *         SCALE_WIDTH_s:100,
 *         SCALE_HEIGHT_s:100,
 *         SCALE_WIDTH_h:150,
 *         SCALE_HEIGHT_h:150,
 *         SCALE_WIDTH_xs:50,
 *         SCALE_HEIGHT_xs:33,
 *         SCALE_NAME_m:'ImageMedium',
 *         SCALE_NAME_s:'ImageSmall',
 *         SCALE_NAME_h:'ImageHotDeal'
 *       },
 *       callback:'?ViewAction='+ep.config.viewAction+'&ObjectID='+ep.config.objectId+'&DialogArea=ViewArea'
 *     })"/>
 *
 *
 * @class jQuery.ui.presentationUiDnduploader
 * @extends jQuery.widget
 *
 * @uses jQuery.dict
 * @uses jQuery.tmpl
 * @uses jQuery.i18n
 * @uses jQuery.expr
 * @uses jQuery.fn.form
 * @uses jQuery.ui.widget
 * @uses jQuery.ui.progressbar
 * @uses de_epages
 * @uses ep.ajaxTransport
 * @uses ep.ui.dialog
 * @since 6.17.38
 */

/**
 * @cfg {String} [accept] A string of MIME types and/or MIME type groups.
 */

/**
 * @cfg {String} [url] A string containing the URL to which the request is sent.
 */

/**
 * @cfg {String} [buttonText] A string for the upload button
 */

/**
 * @cfg {Object} [data] A map of additional data to send with the request.
 */

/**
 * @cfg {Function,String} [callback] A url to open or method to call when upload process is finished. The callback method receives data and statusText as arguments.
 */

/**
 * @cfg {Boolean} [multiple] A boolean indication whether to allow muplitple files to upload.
 */

/**
 * @cfg {Boolean} [big] A boolean boolean short handle set style big.
 */

/**
 * @cfg {String} [style] One of the available styles: normal,big,icon.
 */

/**
 * @cfg {Array} [exists] An array including already existing files.
 */

/**
 * See `jQuery.ui.presentationUiDnduploader` for details.
 *
 * @param {Object} [options] A map of additional options pass to the method.
 * @param {String} [accept] A string of MIME types and/or MIME type groups.
 * @param {String} [url] A string containing the URL to which the request is sent.
 * @param {String} [buttonText] A string for the upload button
 * @param {Object} [data] A map of additional data to send with the request.
 * @param {Function,String} [callback] A url to open or method to call when upload process is finished. The callback method receives data and statusText as arguments.
 * @param {Boolean} [multiple] A boolean indication whether to allow muplitple files to upload.
 * @param {Boolean} [big] A boolean boolean short handle set style big.
 * @param {String} [style] One of the available styles: normal,big,icon.
 * @param {Array} [exists] An array including already existing files.
 *
 * @method presentationUiDnduploader
 * @member jQuery
 *
 * @since 6.12.0
 */

/*
 * @copyright       © Copyright 2006-2010, epages GmbH, All Rights Reserved.
 *
 * @module          de_epages.presentation.ui.dnduploader
 */

define( "de_epages/presentation/ui/dnduploader", [
    "jquery",
    "ep",
    "de_epages",
    "util/mime",
    "$dict!../dictionary",
    "$tmpl!./dnduploader",
    "$tmpl!./dnduploader-inputs",
    "$tmpl!./dnduploader-sortable_item",
    "$tmpl!./dnduploader-mainplaceholder",
    "$tmpl!./dnduploader-alert",

    "jquery/ui/widget",
    "jquery/tmpl",
    "jquery/ui/sortable",
    "ep/alert"
], function ($, ep, de_epages, mime, presentationDict, tmplDndUploader, tmplDndUploaderInputs, tmplDndUploaderSortableItem, tmplDndUploaderMainPlaceholder, tmplDndUploaderAlert) {

    /*
     * @dictionary      ep.dict
     *
     * @translation     {Cancel}
     *                  {Ignore}
     *                  {Replace}
     *                  {AddImages}
     *                  {Notification}
     *
     * @dictionary      de_epages.presentation.dictionary
     *
     * @translation     {FileUploadSingle}
     *                  {FileUploadMultiple}
     *                  {UploaderError}
     *                  {UploaderReplace}
     *                  {FixErrors}
     *                  {FilesUploaded}
     *                  {FileSizeLimitError}
     *                  {InternalServerError}
     *                  {FontLicenseRestricted}
     *                  {MimetypeNotAcceptError}
     *                  {UnknownError}
     *                  {FeatureLimitExceeded}
     *                  {InvalidMP3File}
     *                  {InvalidImageFile}
     *                  {ImageExceedsMegapixels}
     *                  {VirusFoundError}
     *                  {FileAlreadyExistsOnServer}
     *                  {InvalidImageSize}
     */

    var translationsDnduploader = {
        addImages: presentationDict.translate('AddImages'),
        invalidImageFile: presentationDict.translate('InvalidImageFile'),
        notification: presentationDict.translate('Notification')
    };

    $.widget('ui.presentationUiDnduploader', {
        files: {
            order: [],
            exist: [],
            upload: [],
            mime_error: []
        },

        // fileCount,

        options: {
        //    files :{exist: [], order: []},
            mime: 'image.*',
            multiple: true,
            // callback: $.noop,
            // url: '?',
            // data: {
            //     'ViewAction': 'JSONViewResponse'
            // },

            dimensions: {
                width: 150,
                height: 100
            }
        },

        _create: function () {
            var self = this,
                elem = self.element,
                o = self.options,
                renderedTmpl;


            renderedTmpl = tmplDndUploader([{
                multiple: o.multiple,
                order: JSON.stringify((o.files && o.files.order) ? o.files.order : []),
                tAddImages: translationsDnduploader.addImages
            }]);

            // initialize object for dropZone elements
            self.dropZone = {};

            // load template and push named tmpl elements to current instance
            $.extend(self.dropZone, renderedTmpl.tmplItem('elements'));

            elem.append(renderedTmpl);

            // register handler for drag and drop and file input
            // DragOver-Handler
            self.dropZone.area.on('dragover', $.proxy(function (e) {
                self._handleDragOver(e);
            }, self));
            // Drop-Handler
            self.dropZone.area.on('drop', $.proxy(function (e) {
                self._handleDrop(e);
            }, self));
            // fileInput-Handler
            self.dropZone.fileInput.on('change', $.proxy(function (e) {
                self._handleFile(e);
            }, self));

            // initialize sortable list
            self._initSortable();

            if (o.files) {
                $.extend(self.files, o.files);

                // inserts already existing files
                if (self.files.exist.length) {
                    // insert regular images
                    // and hand over a callback that will be executed after all regular images are loaded
                    self._insertExistingImages(self._handleUploadDataUrlImages);
                }

                // inserts files handed over as DataURL (only if no regular images exist)
                if (self.files.exist.length===0 && self.files.upload.length) {
                    self._handleUploadDataUrlImages();
                }
            }

            self._setMainImage();


            // init options
            // self._setOptions({
            //     'accept': mime.mime(o.accept || self.elem.attr('accept') || '*/*'),
            //     'multiple': o.multiple || self.elem.attr('multiple') || false
            // });
        },

        _insertExistingImages: function (callback) {
            var self = this,
                // o = self.options,
                $img,
                i;

            self.fileCount = self.files.exist.length;

            for (i=0; i<self.files.exist.length; i++) {

                $img = $('<img />');

                // write dataUrl to image source
                $img
                    .attr('src', self.files.exist[i].src)
                    .data('id', self.files.exist[i].id);

                // load handler for image
                $img.on('load', function(evt) {
                    var $img = $(this),
                        id = $img.data('id');

                    // insert item with image to sortable list
                    self._insertSortableItem($img, id);

                    // decrease file counter
                    self.fileCount--;

                    // an error occurs after the last uploaded element
                    if (self.fileCount === 0) {
                        // sort items by order array
                        self._sortListByArray();
                        self.dropZone.sortable.sortable('refresh');
                        self._setMainImage();

                        // execute callback after all regular images are loaded
                        if (callback) {
                            callback.call(self);
                        }
                    }

                });

            }
        },

        _handleUploadDataUrlImages: function () {
            var self = this;

            self.fileCount = self.files.upload.length;

            if (self.files.upload_order && self.files.upload_order.length) {
                // concatinate order and upload order arrays
                self.files.order = self.files.order.concat(self.files.upload_order);
            }

            // loop over upload images
            for (var i=0; i<self.files.upload.length; i++) {
                // insert image
                self._insertDataUrlImage(self.files.upload[i]);
            }
        },

        _initSortable: function () {
            var self = this,
                o = self.options;

            // initialize sortable list
            self.dropZone.sortable.sortable({
                placeholder: "ep-dropzone-state-highlight AlignCenter col-xs-12 col-md-6 col-lg-4",
                items: "li:not(.ep-dropzone-placeholder)",
                stop: function(event, ui) {
                    // rebuild order array
                    self._sortOrder(self.dropZone.sortable.find('li.ep-dropzone-sortable-item'));
                }
            });
            self.dropZone.sortable.disableSelection();
        },

        _insertSortableItem: function ($img, id) {
            var self = this,
                $body = $('body'),
                elements = {},
                dimensions = {},
                itemTmpl;

            itemTmpl = tmplDndUploaderSortableItem([{
                id: id
            }]);
            // load template and push named tmpl elements to object
            $.extend(elements, itemTmpl.tmplItem('elements'));

            // register click handler for delete button
            elements.deleteButton.on('click', $.proxy(function (evt) {
                self._deleteItemById($(evt.target).data('id'));
            }, self));

            elements.itemHolder.append($img);
            self.dropZone.placeholder.before(itemTmpl);
        },

        _sortOrder: function (list) {
            var self = this,
                o = self.options,
                uploadOrder = [],
                id;

            // reset order array
            self.files.order.length = 0;
            // rebuild order array
            list.each(function(key, item){
                id = $(item).data('id');
                self.files.order.push(id);

                // add id of upload image to array
                if(ep('#ep-dropzone-inputs-' + id).length) {
                    uploadOrder.push(id);
                }
            });

            self.dropZone.orderInput.val(JSON.stringify(self.files.order));
            self.dropZone.uploadedDataUrlImages.val(JSON.stringify(self.files.upload));
            self.dropZone.uploadedDataUrlImagesOrder.val(JSON.stringify(uploadOrder));

            self._setMainImage();
        },

        // sorts sortable list items by order of corresponding order array
        // necessary e.g. if depending to the loading duration the order of the sortable list
        // is not equal the order of the files.order array
        _sortListByArray: function () {
            var self = this,
                i;

            if (self.files && self.files.order && self.files.order.length) {
                for (i=0; i<self.files.order.length; i++) {
                    self.dropZone.placeholder.before($('#ep-dropzone-sortable-item-' + self.files.order[i]));
                }
            }
        },

        _setMainImage: function () {
            var self = this,
                list = self.dropZone.sortable.find('li.ep-dropzone-sortable-item'),
                renderedMain,
                elements = {};

            self.dropZone.mainImage.empty();

            if (list.length > 0) {
                self.dropZone.mainImage.addClass('with-content');
                self.dropZone.mainImage.append($('<img src=' + list.eq(0).find('img').attr('src') + ' />'));
            } else {
                renderedMain = tmplDndUploaderMainPlaceholder();
                // load template and push named tmpl elements to current instance
                $.extend(elements, renderedMain.tmplItem('elements'));
                self.dropZone.mainImage.append(elements.mainImagePlaceholder);
                self.dropZone.mainImage.removeClass('with-content');
            }
        },

        // DnD
        _handleDragOver: function(evt) {
            evt.stopPropagation();
            evt.preventDefault();

            // set effect to copy
            evt.originalEvent.dataTransfer.dropEffect = 'copy';
        },

        // Drop-Handler
        _handleDrop: function(evt) {
            evt.stopPropagation();
            evt.preventDefault();

            var self = this;

            self._manageFiles(evt.originalEvent.dataTransfer.files);
        },

        _handleFile: function(evt) {
            var self = this;

            self._manageFiles(evt.originalTarget.files);
        },

        _manageFiles: function (files) {
            var self = this,
                o = self.options,
                len = o.multiple ? files.length : 1,
                i;

            // clear error array
            self.files.mime_error.length = 0;
            self.fileCount = len;
            self.imageLength = 0;

            for (i=0; i<len; i++) {
                self._fileReader(files[i]);
            }
        },

        // FileReader
        _fileReader: function(file) {
            var self = this,
                reader = new FileReader();

            reader.onload = function (evt) {
                var fileReader = this;

                // Handler aufrufen, um die Datei weiter zu verarbeiten
                self._readerSuccessHandler(fileReader, file, evt);
            };

            reader.onloadstart = function (evt) {
                if (!file.type.match(self.options.mime)) {
                    self.files.mime_error.push({
                        id: "id_" + file.size + new Date().getTime(),
                        name: file.name
                    });

                    self.fileCount--;

                    // an error occurs and only one element should be uploaded
                    if (self.fileCount === 0 && self.imageLength === 0) {
                        var list = [];

                        for(var j=0; j<self.files.mime_error.length; j++) {
                            list.push(self.files.mime_error[j].name);
                        }

                        // reset file input
                        self.dropZone.fileInput.val("");

                        // open message dialog
                        self._messageDialog(translationsDnduploader.invalidImageFile, list);
                    }

                    reader.abort();

                    return;
                }
            };

            // reader.onprogress = readerProgressHandler;
            // reader.onerror = readerErrorHandler;

            // read file as dataUrl
            reader.readAsDataURL(file);

        },

        _readerSuccessHandler: function(fileReader, file, evt) {
            var self = this,
                o = self.options,
                id = "id_" + file.size + new Date().getTime(),
                fileData;

            self.imageLength++;

            fileData = {
                id: id,
                name: file.name.replace(/_/g, "-"),
                dataUrl: fileReader.result
            };

            // write informations for file on object
            self.files.upload.push(fileData);

            self._insertDataUrlImage(fileData);
        },

        _insertDataUrlImage: function (fileData) {
            var self = this,
                o = self.options,
                $img = $('<img />');

            // write dataUrl to image source
            $img.attr('src', fileData.dataUrl);

            // load handler for image
            $img.on('load', function(evt) {
                var $img = $(this),
                    inputTmpl;

                // insert item with image to sortable list
                self._insertSortableItem($img, fileData.id);

                // insert input template for image information
                inputTmpl = tmplDndUploaderInputs([fileData]);
                self.dropZone.holder.append(inputTmpl);

                self.fileCount--;
                // an error occurs after the last uploaded element
                if (self.fileCount === 0) {
                    // if an upload array is handed over initially
                    if (self.files.upload_order && self.files.upload_order.length) {
                        self._sortListByArray();

                        // delete order property for upload array to avoid sorting more than one time
                        delete self.files.upload_order;
                    }

                    self.dropZone.sortable.sortable('refresh');
                    // rebuild order array
                    self._sortOrder(self.dropZone.sortable.find('li.ep-dropzone-sortable-item'));
                    // reset file input
                    self.dropZone.fileInput.val("");


                    self._setMainImage();

                    // if an error occurs during the readAsDataUrl method
                    if (self.files.mime_error.length > 0) {
                        var list = [],
                            alertTmpl;

                        for(var j=0; j<self.files.mime_error.length; j++) {
                            list.push(self.files.mime_error[j].name);
                        }

                        // open message dialog
                        self._messageDialog(translationsDnduploader.invalidImageFile, list);
                    }
                }

            });
        },

        _messageDialog: function(info, messages) {
            var self = this,
                alertTmpl;

            // render alert template
            alertTmpl = tmplDndUploaderAlert([{
                messages: messages,
                info: info
            }]);

            // if already an alert dialog exists
            if (self.alert) {
                // clean up previous dialog and append new message
                self.alert.find('.Message')
                    .empty()
                    .append(alertTmpl);
                // open alert dialog
                self.alert.uiDialog('open');
            } else {
                // show alert
                self.alert = ep.alert({
                    title:  translationsDnduploader.notification,
                    type:   'notification',
                    size:   'l',
                    content: alertTmpl,
                    close:  function( event ){
                        // do something on close
                    },
                    ok:     function( event ){
                        // do something on confirm
                    }
                });
            }
        },

        _readerProgressHandler: function() {
            // ToDo: Handler für die Fortschrittsanzeige
            //console.log("readerProgressHandler: ", arguments);
        },

        _readerErrorHandler: function() {
            // ToDo: Handler für den Fehlerfall
            //console.log("readerErrorHandler: ", arguments);
        },

        // Helper
        _recalcDimensions: function(dimensions) {
            var self = this,
                o = self.options,
                factor;

            dimensions.origWidth = dimensions.width;
            dimensions.origHeight = dimensions.height;

            if (dimensions.width > o.dimensions.width) {
                factor = o.dimensions.width / dimensions.width;

                dimensions.width = o.dimensions.width;
                dimensions.height = dimensions.height * factor;
            }

            if (dimensions.height > o.dimensions.height) {
                factor = o.dimensions.height / dimensions.height;

                dimensions.height = o.dimensions.height;
                dimensions.width = dimensions.width * factor;
            }

            dimensions.width = Math.floor(dimensions.width);
            dimensions.height = Math.floor(dimensions.height);

            return dimensions;
        },

        // _setOption: function (name, value) {
        //     var o = this.options;

        //     if (value !== undef) {
        //         switch (name) {
        //         case 'accept':
        //             this.elem.attr(name, mime.mime(value));
        //             break;
        //         case 'multiple':
        //             this.elem.attr(name, value);
        //             this._setOption('style', o.style);
        //             break;
        //         }
        //     }

        //     return this._superApply(arguments);
        // },

        _upload: function (event, doReplace) {
            var self = this,
                o = self.options;
        },

        _getItemById: function (id) {
            var self = this,
                i;

            // loop over already existing images
            for (i=0; i<self.files.exist.length; i++) {
                if (self.files.exist[i].id === id){
                    // return self.files.exist[i];
                    return {array: self.files.exist, index: i};
                }
            }

            // loop over new images
            for (i=0; i<self.files.upload.length; i++) {
                if (self.files.upload[i].id === id){
                    // return self.files.upload[i];
                    return {array: self.files.upload, index: i};
                }
            }

            return false;
        },

        _deleteItemById: function (id) {
            var self = this,
                item,
                i;

            // remove container for image information input from DOM
            $('#ep-dropzone-inputs-' + id).remove();

            // delete item from files array
            item = self._getItemById(id);
            item.array.splice(item.index, 1);

            // remove item from sortable list
            $('#ep-dropzone-sortable-item-' + id).remove();
            // refresh sortable list
            self.dropZone.sortable.sortable('refresh');
            // rebuild order array
            self._sortOrder(self.dropZone.sortable.find('li.ep-dropzone-sortable-item'));

            // ToDo: initiate AJAX request by sending file id to remove image from server
            // ! Only if image is in exits array
        },

        /**
         * This method removes the container on which the Uploader has been appended to.
         *
         * @method destroy
         * @member jQuery.ui.presentationUiUploader
         *
         * @since 6.12.0
         */
        destroy: function () {
            var self = this;

            self.elem.off('.presentationUiDnduploader');

            self._superApply(arguments);
        }

    });

    return de_epages;

});