# Source: src/js/views/searchSelect/AccountSelectView.js

    define([
        "jquery",
        "underscore",
        "backbone",
        "views/searchSelect/SearchableSelectView",
        "models/LookupModel"
      ],
      function($, _, Backbone,  SearchableSelect, LookupModel) {

        /**
         * @class AccountSelectView
         * @classdesc A select interface that allows the user to search for and select one or
         * more accountIDs
         * @classcategory Views/SearchSelect
         * @extends SearchableSelect
         * @constructor
         * @since 2.15.0
         * @screenshot views/searchSelect/AccountSelectViewView.png
         */
        var AccountSelectView = SearchableSelect.extend(
          /** @lends AccountSelectViewView.prototype */
          {
            /**
             * The type of View this is
             * @type {string}
             * @since 2.15.0
             */
            type: "AccountSelect",

            /**
             * The HTML class names for this view element
             * @type {string}
             * @since 2.15.0
             */
            className: SearchableSelect.prototype.className + " account-select",

            /**
             * Text to show in the input field before any value has been entered
             * @type {string}
             * @default "Start typing a name"
             * @since 2.15.0
             */
            placeholderText: "Start typing a name",

            /**
             * Label for the input element
             * @type {string}
             * @default "Search for a person or group"
             * @since 2.15.0
             */
            inputLabel: "Search for a person or group",

            /**
             * Whether to allow users to select more than one value
             * @type {boolean}
             * @default true
             * @since 2.15.0
             */
            allowMulti: true,

            /**
             * Setting to true gives users the ability to add their own options that
             * are not listed in this.options. This can work with either single
             * or multiple search select dropdowns
             * @type {boolean}
             * @default true
             */
            allowAdditions: true,

            /**
             * Can be set to an object to specify API settings for retrieving remote selection
             * menu content from an API endpoint. Details of what can be set here are
             * specified by the Semantic-UI / Fomantic-UI package. Set to false if not
             * retrieving remote content.
             * @type {Object|booealn}
             * @since 2.15.0
             * @see {@link https://fomantic-ui.com/modules/dropdown.html#remote-settings}
             * @see {@link https://fomantic-ui.com/behaviors/api.html#/settings}
             */
            apiSettings: {

              // Use the Accounts lookup to search for a person or group when the user types
              // something into the input
              responseAsync: function(settings, callback){

                var view = $(this).data("view");

                // The search term that the user has typed into the input
                var searchTerm = settings.urlData.query

                // Only use the account lookup service is the user has typed at least two
                // characters. Otherwise, the callback function is never called.
                if(searchTerm.length < 2){
                  callback({
                    success: false,
                  })
                  return
                }

                // For search terms at least 2 characters long, use the Lookup Model
                MetacatUI.appLookupModel.getAccountsAutocomplete({ term: searchTerm }, function(results){

                  // If no match was found to the search term
                  if(results && results.length < 1){
                    callback({
                      success: false,
                    })
                    return
                  }

                  // If there were results, format for the semantic UI dropdown function
                  results = view.formatResults(results);

                  callback({
                    success: true,
                    results: results
                  })

                })
              }

            },

            /**
             * Creates a new SearchableSelectView
             * @param {Object} options - A literal object with options to pass to the view
             * @since 2.15.0
             */
            initialize: function(options) {

              try {

                var view = this;

                // Ensure there is a lookup model ready for this view to use.
                if(MetacatUI.appLookupModel === "undefined"){
                  MetacatUI.appLookupModel = new LookupModel();
                }

                SearchableSelect.prototype.initialize.call(view, options);

              } catch (e) {
                console.log("Failed to initialize an Account Select view, error message:",
                e);
              }
            },

            /**
             * Takes the results returned from from
             * {@link LookupModel#getAccountsAutocomplete} and re-formats them for other
             * functions. When the forTemplate argument is false, the results are formatted as
             * a list mapping dropdown content specifically for the FomanticUI API. When
             * forTemplate is true, then the results are formatted for use in the
             * SearchableSelectView template: {@link SearchableSelectView#template}.
             *
             * @param  {Object[]} results The response from
             * {@link LookupModel#getAccountsAutocomplete}
             * @param  {boolean} forTemplate=false Whether or not to format the results for
             * the {@link SearchableSelectView#template}
             * @return {Object[]} The re-formatted results
             *
             * @see {@link https://fomantic-ui.com/modules/dropdown.html#remote-settings}
             * @since 2.15.0
             */
            formatResults: function(results, forTemplate = false){

              results = _.map(results, function(result){

                if(forTemplate){
                  // Get the ID which is saved in the parentheses
                  var regExp = /\(([^)]+)\)$/;
                  var matches = regExp.exec(result.label);
                  //matches[1] contains the value between the parentheses
                  result.description = "Account ID: " + matches[1];
                  result.label = result.label.replace(regExp, "")
                  result.label = result.label.trim()

                } else {
                  result.label = result.label.replace("(", '<span class="description">')
                  result.label = result.label.replace(")", '</span>')
                }

                var icon = ""

                if(result.type === "person"){
                  icon = "user"
                }
                if(result.type === "group"){
                  icon = "group"
                }

                if(icon){
                  if(forTemplate){
                    result.icon = icon;
                  } else {
                    result.label = '<i class="icon icon-on-left icon-' + icon + '"></i>' + result.label
                  }
                }

                if(!forTemplate) {
                  result = {
                    name: result.label,
                    value: result.value,
                  }
                }
                return result

              })

              return results
            },

            /**
             * Render the view
             *
             * @return {AccountSelectView}  Returns the view
             * @since 2.15.0
             */
            render: function(){

              var view = this;

              // Use the account lookup service to match the pre-selected values to
              // the account holder's name to use as a label.

              // If we haven't started looking up user/organization names yet...
              if(typeof view.labelsToFetch === "undefined"){

                // Keep a count of the number of accounts we need to lookup
                view.labelsToFetch = this.selected ? this.selected.length : 0;

                if(view.labelsToFetch > 0){

                  view.options = [];

                  view.selected.forEach(function(accountId){
                    MetacatUI.appLookupModel.getAccountsAutocomplete({ term: accountId }, function(results){

                      // The value should match only one account (since the value is an
                      // account ID). If we found the match, format it for the
                      // SearchableSelectView, and the icon and tooltip will automatically be
                      // added to the pre-selected labels.
                      if(results && results.length === 1){
                        results = view.formatResults(results, true);
                        view.options.push(results[0])
                      }
                      // Whether or not we found a match, count this lookup as complete
                      --view.labelsToFetch

                      // Once we've looked up all of the accounts, call this render function
                      // again
                      if(view.labelsToFetch === 0 ){
                        view.render();
                      }

                    })
                  })

                  return

                }

              }

              // Once we've fetched the labels for any pre-selected account IDs,
              // render as usual
              SearchableSelect.prototype.render.call(view);

            },

            /**
             * addTooltip - Add a tooltip to a given element using the description in the
             * options object that's set on the view.
             *
             * @param  {HTMLElement} element The HTML element a tooltip should be added
             * @param  {string} position how to position the tooltip - top | bottom | left |
             * right
             * @return {jQuery} The element with a tooltip wrapped by jQuery
             * @since 2.15.0
             */
            addTooltip: function(element, position = "bottom"){

              try {
                if(!element){
                  return
                }

                // The account ID is saved in a <span> element in the label with the
                // description class when the label is added from the list of search results
                var descEl = $(element).find(".description");
                var id = descEl.text();
                descEl.remove();

                // Otherwise, the ID is always saved as a data attribute
                if(!id){
                  id = $(element).attr("data-value")
                }

                // Show the account ID as a tooltip rather than in the label. Otherwise
                // the input gets too crowded.
                $(element).tooltip({
                  title: id ? "Account ID: " + id : "",
                  placement: position,
                  container: "body",
                  delay: {
                    show: 900,
                    hide: 50
                  }
                })
                .on("show.bs.popover",
                  function(){
                    var $el = $(this);
                    // Allow time for the popup to be added to the DOM
                    setTimeout(function () {
                      // Then add a special class to identify
                      // these popups if they need to be removed.
                      $el.data('tooltip').$tip.addClass("search-select-tooltip")
                    }, 10);
                });

                return $(element)
              } catch (e) {
                console.log("Failed to add tooltips in a searchable select view, error message: " + e);
              }

            },

            // TODO: We may want to add a custom is valid option to warn the user when
            // a value entered cannot be found in the accounts lookup service.

            // /**
            //  * isValidOption - Checks if a value is one of the values given in view.options
            //  *
            //  * @param  {string} value The value to check
            //  * @return {boolean}      returns true if the value is one of the values given in
            //  * view.options
            //  */
            // isValidOption: function(value){
            // },

          });

          return AccountSelectView
      });