define(['jquery', 'lodash', 'async', 'i18n', 'core/mimetype', 'handlebars', 'lib/handlebars/helpers', 'ui/feedback', 'context', 'ui/uploader', 'core/logger'], function ($$1, _, async, __, mimeType, Handlebars, Helpers0, feedback, context, uploader, loggerFactory) { 'use strict';

    $$1 = $$1 && Object.prototype.hasOwnProperty.call($$1, 'default') ? $$1['default'] : $$1;
    _ = _ && Object.prototype.hasOwnProperty.call(_, 'default') ? _['default'] : _;
    async = async && Object.prototype.hasOwnProperty.call(async, 'default') ? async['default'] : async;
    __ = __ && Object.prototype.hasOwnProperty.call(__, 'default') ? __['default'] : __;
    mimeType = mimeType && Object.prototype.hasOwnProperty.call(mimeType, 'default') ? mimeType['default'] : mimeType;
    Handlebars = Handlebars && Object.prototype.hasOwnProperty.call(Handlebars, 'default') ? Handlebars['default'] : Handlebars;
    Helpers0 = Helpers0 && Object.prototype.hasOwnProperty.call(Helpers0, 'default') ? Helpers0['default'] : Helpers0;
    feedback = feedback && Object.prototype.hasOwnProperty.call(feedback, 'default') ? feedback['default'] : feedback;
    context = context && Object.prototype.hasOwnProperty.call(context, 'default') ? context['default'] : context;
    loggerFactory = loggerFactory && Object.prototype.hasOwnProperty.call(loggerFactory, 'default') ? loggerFactory['default'] : loggerFactory;

    if (!Helpers0.__initialized) {
      Helpers0(Handlebars);
      Helpers0.__initialized = true;
    }
    var Template = Handlebars.template(function (Handlebars,depth0,helpers,partials,data) {
      this.compilerInfo = [4,'>= 1.0.0'];
    helpers = this.merge(helpers, Handlebars.helpers); data = data || {};
      var buffer = "", stack1, helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression, functionType="function", self=this;

    function program1(depth0,data) {
      
      var buffer = "", stack1, helper;
      buffer += "\n    <li data-type=\"";
      if (helper = helpers.type) { stack1 = helper.call(depth0, {hash:{},data:data}); }
      else { helper = (depth0 && depth0.type); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; }
      buffer += escapeExpression(stack1)
        + "\"\n        data-file=\"";
      if (helper = helpers.uri) { stack1 = helper.call(depth0, {hash:{},data:data}); }
      else { helper = (depth0 && depth0.uri); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; }
      buffer += escapeExpression(stack1)
        + "\"\n        data-display=\"";
      if (helper = helpers.display) { stack1 = helper.call(depth0, {hash:{},data:data}); }
      else { helper = (depth0 && depth0.display); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; }
      buffer += escapeExpression(stack1)
        + "\"\n        data-mime=\"";
      if (helper = helpers.mime) { stack1 = helper.call(depth0, {hash:{},data:data}); }
      else { helper = (depth0 && depth0.mime); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; }
      buffer += escapeExpression(stack1)
        + "\"\n        data-size=\"";
      if (helper = helpers.size) { stack1 = helper.call(depth0, {hash:{},data:data}); }
      else { helper = (depth0 && depth0.size); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; }
      buffer += escapeExpression(stack1)
        + "\"\n        data-url=\"";
      if (helper = helpers.viewUrl) { stack1 = helper.call(depth0, {hash:{},data:data}); }
      else { helper = (depth0 && depth0.viewUrl); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; }
      buffer += escapeExpression(stack1)
        + "\"\n        ";
      stack1 = helpers['if'].call(depth0, ((stack1 = (depth0 && depth0.permissions)),stack1 == null || stack1 === false ? stack1 : stack1.download), {hash:{},inverse:self.noop,fn:self.program(2, program2, data),data:data});
      if(stack1 || stack1 === 0) { buffer += stack1; }
      buffer += "\n        ";
      stack1 = helpers['if'].call(depth0, ((stack1 = (depth0 && depth0.permissions)),stack1 == null || stack1 === false ? stack1 : stack1.preview), {hash:{},inverse:self.noop,fn:self.program(4, program4, data),data:data});
      if(stack1 || stack1 === 0) { buffer += stack1; }
      buffer += "\n        ";
      stack1 = helpers['if'].call(depth0, ((stack1 = (depth0 && depth0.permissions)),stack1 == null || stack1 === false ? stack1 : stack1.read), {hash:{},inverse:self.noop,fn:self.program(6, program6, data),data:data});
      if(stack1 || stack1 === 0) { buffer += stack1; }
      buffer += "\n        data-alt=\"";
      if (helper = helpers.alt) { stack1 = helper.call(depth0, {hash:{},data:data}); }
      else { helper = (depth0 && depth0.alt); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; }
      buffer += escapeExpression(stack1)
        + "\">\n        <span class=\"desc truncate\">";
      if (helper = helpers.name) { stack1 = helper.call(depth0, {hash:{},data:data}); }
      else { helper = (depth0 && depth0.name); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; }
      buffer += escapeExpression(stack1)
        + "</span>\n        <div class=\"actions\">\n            <div class=\"tlb\">\n                <div class=\"tlb-top\">\n                    <span class=\"tlb-box\">\n                        <span class=\"tlb-bar\">\n                            <span class=\"tlb-start\"></span>\n                            ";
      stack1 = helpers['if'].call(depth0, ((stack1 = (depth0 && depth0.permissions)),stack1 == null || stack1 === false ? stack1 : stack1.read), {hash:{},inverse:self.noop,fn:self.program(8, program8, data),data:data});
      if(stack1 || stack1 === 0) { buffer += stack1; }
      buffer += "\n                            <span class=\"tlb-end\"></span>\n                        </span>\n                    </span>\n                </div>\n            </div>\n        </div>\n    </li>\n";
      return buffer;
      }
    function program2(depth0,data) {
      
      
      return " data-download=\"true\" ";
      }

    function program4(depth0,data) {
      
      
      return " data-preview=\"true\" ";
      }

    function program6(depth0,data) {
      
      
      return " data-select=\"true\" ";
      }

    function program8(depth0,data) {
      
      var buffer = "", stack1;
      buffer += "\n                                <span class=\"tlb-group\">\n                                    ";
      stack1 = helpers['if'].call(depth0, ((stack1 = (depth0 && depth0.permissions)),stack1 == null || stack1 === false ? stack1 : stack1.read), {hash:{},inverse:self.noop,fn:self.program(9, program9, data),data:data});
      if(stack1 || stack1 === 0) { buffer += stack1; }
      buffer += "\n                                    ";
      stack1 = helpers['if'].call(depth0, ((stack1 = (depth0 && depth0.permissions)),stack1 == null || stack1 === false ? stack1 : stack1.download), {hash:{},inverse:self.noop,fn:self.program(11, program11, data),data:data});
      if(stack1 || stack1 === 0) { buffer += stack1; }
      buffer += "\n                                    ";
      stack1 = helpers['if'].call(depth0, ((stack1 = (depth0 && depth0.permissions)),stack1 == null || stack1 === false ? stack1 : stack1['delete']), {hash:{},inverse:self.noop,fn:self.program(13, program13, data),data:data});
      if(stack1 || stack1 === 0) { buffer += stack1; }
      buffer += "\n                                </span>\n                            ";
      return buffer;
      }
    function program9(depth0,data) {
      
      var buffer = "", helper, options;
      buffer += "\n                                        <a href=\"#\" class=\"tlb-button-off select\" title=\""
        + escapeExpression((helper = helpers.__ || (depth0 && depth0.__),options={hash:{},data:data},helper ? helper.call(depth0, "Select this file", options) : helperMissing.call(depth0, "__", "Select this file", options)))
        + "\"><span class=\"icon-move-item\"></span></a>\n                                    ";
      return buffer;
      }

    function program11(depth0,data) {
      
      var buffer = "", stack1, helper, options;
      buffer += "\n                                        <a href=\"";
      if (helper = helpers.downloadUrl) { stack1 = helper.call(depth0, {hash:{},data:data}); }
      else { helper = (depth0 && depth0.downloadUrl); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; }
      buffer += escapeExpression(stack1)
        + "\" download=\"";
      if (helper = helpers.name) { stack1 = helper.call(depth0, {hash:{},data:data}); }
      else { helper = (depth0 && depth0.name); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; }
      buffer += escapeExpression(stack1)
        + "\" target=\"_blank\" class=\"tlb-button-off download\" title=\""
        + escapeExpression((helper = helpers.__ || (depth0 && depth0.__),options={hash:{},data:data},helper ? helper.call(depth0, "Download this file", options) : helperMissing.call(depth0, "__", "Download this file", options)))
        + "\"><span class=\"icon-download\"></span></a>\n                                    ";
      return buffer;
      }

    function program13(depth0,data) {
      
      var buffer = "", helper, options;
      buffer += "\n                                        <a href=\"#\" class=\"tlb-button-off delete\" title=\""
        + escapeExpression((helper = helpers.__ || (depth0 && depth0.__),options={hash:{},data:data},helper ? helper.call(depth0, "Remove this file", options) : helperMissing.call(depth0, "__", "Remove this file", options)))
        + "\"><span class=\"icon-bin\"></span></a>\n                                    ";
      return buffer;
      }

      stack1 = helpers.each.call(depth0, (depth0 && depth0.files), {hash:{},inverse:self.noop,fn:self.program(1, program1, data),data:data});
      if(stack1 || stack1 === 0) { buffer += stack1; }
      buffer += "\n";
      return buffer;
      });
    function fileSelectTpl(data, options, asString) {
      var html = Template(data, options);
      return (asString || true) ? html : $(html);
    }

    /**
     * Update the permissions in HTML Tree
     * @param {Object} item - the tree item
     * @return {Object} - item with permissions
     */
    function updatePermissions(item) {
      const isAssets = (item.uri || item.path || '').includes('mediamanager');
      let permissions = {
        read: true,
        write: true,
        preview: true,
        download: true,
        upload: true,
        delete: true
      };
      if (item.permissions) {
        if (!item.permissions.includes('READ')) {
          permissions.read = false;
        }
        if (!item.permissions.includes('WRITE')) {
          permissions.write = false;
        }
        // Atomic permissions for Assets
        if (isAssets) {
          if (!item.permissions.includes('PREVIEW')) {
            permissions.preview = false;
          }
          if (!item.permissions.includes('DOWNLOAD')) {
            permissions.download = false;
          }
          if (!item.permissions.includes('UPLOAD')) {
            permissions.upload = false;
          }
          if (!item.permissions.includes('DELETE')) {
            permissions.delete = false;
          }
          // Generic permissions for item gallery media
        } else {
          if (!permissions.read) {
            permissions.preview = false;
            permissions.download = false;
          }
          if (!permissions.write) {
            permissions.delete = false;
            permissions.upload = false;
          }
        }
      }
      item.permissions = permissions;
      return item;
    }

    /*
     * This program is free software; you can redistribute it and/or
     * modify it under the terms of the GNU General Public License
     * as published by the Free Software Foundation; under version 2
     * of the License (non-upgradable).
     *
     * This program is distributed in the hope that it will be useful,
     * but WITHOUT ANY WARRANTY; without even the implied warranty of
     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     * GNU General Public License for more details.
     *
     * You should have received a copy of the GNU General Public License
     * along with this program; if not, write to the Free Software
     * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
     *
     * Copyright (c) 2015-2024 (original work) Open Assessment Technologies SA;
     *
     */
    const ns = 'resourcemgr';
    const logger = loggerFactory(`ui/${ns}`);
    function shortenPath(path) {
      let tokens = path.replace(/\/$/, '').split('/');
      let start = tokens.length - 3;
      let end = tokens.length - 1;
      let title = _.map(tokens, function (token, index) {
        return index > start && token ? index < end ? token[0] : token : void 0;
      });
      title = title.filter(Boolean);
      return title.join('/');
    }
    function isTextLarger($element, text) {
      let $dummy = $element.clone().detach().css({
        position: 'absolute',
        visibility: 'hidden',
        'text-overflow': 'clip',
        width: 'auto'
      }).text(text).insertAfter($element);
      let textSize = $dummy.width();
      $dummy.remove();
      return textSize > $element.width();
    }
    function fileSelector (options) {
      let root = options.root || '/';
      let disableUpload = options.disableUpload || false;
      let $container = options.$target;
      let $fileSelector = $$1('.file-selector', $container);
      let $fileContainer = $$1('.files', $fileSelector);
      let $placeholder = $$1('.empty', $fileSelector);
      let $uploader = $$1('.file-upload-container', $fileSelector);
      let parentSelector = `#${$container.attr('id')} .file-selector`;
      let $pathTitle = $fileSelector.find('h1 > .title');
      let $browserTitle = $$1('.file-browser > h1', $container);

      //set up the uploader
      if (disableUpload) {
        let $switcher = $$1('.upload-switcher', $fileSelector);
        $switcher.remove();
      } else {
        setUpUploader(root);
      }
      //update current folder
      $container.on(`folderselect.${ns}`, function (e, fullPath, data, activePath, content) {
        let files;
        data = data.map(function (dataItem) {
          if (Array.isArray(dataItem.permissions)) {
            updatePermissions(dataItem);
          }
          return dataItem;
        });

        //update title
        if ($container[0].querySelector('.upload')) {
          if (content && content.permissions && content.permissions.upload) {
            $container[0].querySelector('.upload').classList.remove('hidden');
          } else {
            $container[0].querySelector('.upload').classList.add('hidden');
          }
        }
        $pathTitle.text(isTextLarger($pathTitle, fullPath) ? shortenPath(fullPath) : fullPath);

        //update content here
        if (_.isArray(data)) {
          files = _.filter(data, function (item) {
            return !!item.uri;
          }).map(function (file) {
            file.type = mimeType.getFileType(file);
            if (typeof file.identifier === 'undefined') {
              file.display = `${fullPath}/${file.name}`.replace('//', '/');
            } else {
              file.display = file.identifier + file.name;
            }
            file.viewUrl = `${options.downloadUrl}?${$$1.param(options.params)}&${options.pathParam}=${encodeURIComponent(file.uri)}`;
            file.downloadUrl = `${file.viewUrl}&svgzsupport=true`;
            return file;
          });
          updateFiles(fullPath, files);
          if (activePath) {
            $$1(`li[data-file="${activePath}"]`).trigger('click');
          }
        }
      });
      function injectTranscriptionMetadata(transcriptionUrl, metadataUri, resourceUri) {
        return `${transcriptionUrl}?metadataUri=${encodeURIComponent(metadataUri)}&resourceUri=${resourceUri.replace('taomedia://mediamanager/', '')}`;
      }

      //listen for file activation
      $$1(parentSelector).off('click', '.files li').on('click', '.files li', function (e) {
        const clickedItem = e.target;
        if (clickedItem.hasAttribute('data-delete') || $$1(clickedItem).hasClass('icon-bin')) {
          return;
        }
        let $selected = $$1(this);
        let $files = $$1('.files > li', $fileSelector);
        let data = _.clone($selected.data());
        if (options.resourceMetadataUrl && options.transcriptionMetadata && data.file.includes('taomedia://mediamanager/')) {
          data.transcriptionUrl = injectTranscriptionMetadata(options.resourceMetadataUrl, options.transcriptionMetadata, data.file);
        }
        $files.removeClass('active');
        $selected.addClass('active');
        $container.trigger(`fileselect.${ns}`, [data]);
      });

      //select a file
      $$1(parentSelector).off('click', '.files li a.select').on('click', '.files li a.select', function (e) {
        e.preventDefault();
        let data = _.pick($$1(this).parents('li').data(), ['file', 'type', 'mime', 'size', 'alt']);
        if (context.mediaSources && context.mediaSources.length === 0 && data.file.indexOf('local/') > -1) {
          data.file = data.file.substring(6);
        }
        $container.trigger(`select.${ns}`, [[data]]);
      });

      //delete a file
      $$1(parentSelector).off('click', '.files li a.delete').on('click', '.files li a.delete', function (e) {
        // This function replaces ui/deleter and must follow the same logic.
        // The main difference is that it insert a confirmation dialog before deleting the file.
        e.preventDefault();
        const $elt = $$1(e.target);
        if ($elt.hasClass(options.disableClass)) {
          return;
        }
        const $target = $elt.closest('li');
        const path = $target.data('file');
        const hooks = [];
        if (options.hooks && 'function' === typeof options.hooks.deleteFile) {
          hooks.push(options.hooks.deleteFile(path));
        }
        Promise.all(hooks).then(() => {
          $$1(this).trigger('delete.deleter', [$target]);
          $target.trigger('delete', [false]);
          $target.detach();
          $target.remove();
          $fileContainer.trigger('deleted.deleter', [$target]);
        }).catch(err => {
          if (err instanceof Error) {
            logger.error(err);
          }
        });
      });
      $fileContainer.on('delete.deleter', function (e, $target) {
        let path,
          params = {};
        if (e.namespace === 'deleter' && $target.length) {
          path = $target.data('file');
          params[options.pathParam] = path;
          $$1.getJSON(options.deleteUrl, _.merge(params, options.params), function (response) {
            if (response.deleted) {
              $container.trigger(`filedelete.${ns}`, [path]);
            }
          });
        }
      });
      function setUpUploader(currentPath) {
        let errors = [];
        let $switcher = $$1('.upload-switcher a', $fileSelector);
        $uploader.on('upload.uploader', function (e, file, result) {
          let path = $$1(`[data-display="${currentPath}"]`).data('path') || $$1(`[data-display="/${currentPath}"]`).data('path');
          if (!path) {
            path = currentPath;
          }
          $container.trigger(`filenew.${ns}`, [result, path]);
        });
        $uploader.on('fail.uploader', function (e, file, err) {
          errors.push(__('Unable to upload file %s : %s', file.name, err.message));
        });
        $uploader.on('end.uploader', function () {
          if (errors.length === 0) {
            _.delay(switchUpload, 500);
          } else {
            feedback().error(`<ul><li>${errors.join('</li><li>')}</li></ul>`, {
              encodeHtml: false
            });
          }
          //reset errors
          errors = [];
        });
        $uploader.uploader({
          upload: true,
          multiple: true,
          uploadUrl: `${options.uploadUrl}?${$$1.param(options.params)}&${options.pathParam}=${currentPath}`,
          fileSelect: function (files, done) {
            let givenLength = files.length;
            let fileNames = [];
            $fileContainer.find('li > .desc').each(function () {
              fileNames.push($$1(this).text().toLowerCase());
            });

            //check the mime-type
            if (options.params.filters) {
              let filters = [],
                i;
              if (!_.isString(options.params.filters)) {
                for (i in options.params.filters) {
                  filters.push(options.params.filters[i]['mime']);
                }
              } else {
                filters = options.params.filters.split(',');
              }
              //TODO check stars
              files = _.filter(files, function (file) {
                // Under rare circumstances a browser may report the mime type
                // with quotes (e.g. "application/foo" instead of application/foo)
                let checkType = file.type.replace(/^["']+|['"]+$/g, '');
                return _.includes(filters, checkType);
              });
              if (files.length !== givenLength) {
                //TODO use a feedback popup
                feedback().error('Unauthorized files have been removed');
              }
            }
            async.filter(files, function (file, cb) {
              let result = true;

              //try to call a server side service to check whether the selected files exists or not.
              if (options.fileExistsUrl) {
                let pathParam = `${currentPath}/${file.name}`;
                pathParam.replace('//', '/');
                $$1.getJSON(`${options.fileExistsUrl}?${$$1.param(options.params)}&${options.pathParam}=${pathParam}`, function (response) {
                  if (response && response.exists === true) {
                    //eslint-disable-next-line no-alert
                    result = window.confirm(__('Do you want to override "%s"?', file.name));
                  }
                  cb(result);
                });
              } else {
                //fallback on client side check
                if (_.includes(fileNames, file.name.toLowerCase())) {
                  //eslint-disable-next-line no-alert
                  result = window.confirm(__('Do you want to override "%s"?', file.name));
                }
                cb(result);
              }
            }, done);
          }
        });
        $container.on(`folderselect.${ns}`, function (e, fullPath, data, uri) {
          currentPath = uri;
          $uploader.uploader('options', {
            uploadUrl: `${options.uploadUrl}?${$$1.param(options.params)}&${options.pathParam}=${currentPath}&relPath=${currentPath}`
          });
        });
        function switchUpload() {
          if ($fileContainer.css('display') === 'none') {
            $uploader.hide();
            $fileContainer.show();
            // Note: show() would display as inline, not inline-block!
            $switcher.filter('.upload').css({
              display: 'inline-block'
            });
            $switcher.filter('.listing').hide();
            $browserTitle.text(__('Browse folders:'));
          } else {
            $fileContainer.hide();
            $placeholder.hide();
            $uploader.show();
            $switcher.filter('.upload').hide();
            $switcher.filter('.listing').css({
              display: 'inline-block'
            });
            $browserTitle.text(__('Upload into:'));
            $uploader.uploader('reset');
          }
        }

        //switch to upload mode
        $switcher.click(function (e) {
          e.preventDefault();
          switchUpload();
        });
      }
      function updateFiles(path, files) {
        $fileContainer.empty();
        if (files.length) {
          $placeholder.hide();
          $fileContainer.append(fileSelectTpl({
            files: files
          }));
        } else if ($fileContainer.css('display') !== 'none') {
          $placeholder.show();
        }
      }
    }

    return fileSelector;

});
