# Source: src/js/views/filters/SemanticFilterView.js

    /*global define */
    define(['jquery',
      'underscore',
      'backbone',
      'models/filters/Filter',
      'views/filters/FilterView',
      'views/searchSelect/AnnotationFilterView'],
      function ($, _, Backbone, Filter, FilterView, AnnotationFilterView) {
        'use strict';

        /**
        * @class SemanticFilterView
        * @classdesc Render a specialized view of a single Filter model using the
        *   AnnotationFilterView.
        * @classcategory Views/Filters
        * @extends FilterView
        * @screenshot views/filters/SemanticFilterView.png
        * @since 2.22.0
        */
        var SemanticFilterView = FilterView.extend(
        /** @lends SemanticFilterView.prototype */{

            /**
             * @inheritdoc
             */
            model: null,

            /**
             * @inheritdoc
             */
            modelClass: Filter,

            className: "filter semantic",

            // Template is an empty function because this view delegates to the
            // AnnotationFilterView. See render() method.
            template: function () { },

            /**
            * Render an instance of a Semantic Filter View.
            *
            * Note that this View doesn't have a template and instead delegates to
            * the AnnotationFilterView which renders a SearchableSelectView which
            * renders an NCBOTree.
            * @since 2.22.0
            */
            render: function () {

              try {
                var templateVars = this.model.toJSON();
                templateVars.id = this.model.cid;

                // Renders the template and inserts the FilterEditorView if the mode is uiBuilder
                FilterView.prototype.render.call(this, templateVars);

                var viewOpts = {
                  "useSearchableSelect": true,
                  "placeholderText": templateVars.placeholder,
                  "inputLabel": null, // Hides label and uses FilterView label
                  "ontology": this.model.get("ontology"),
                  "startingRoot": this.model.get("startingRoot")
                };

                var subView = new AnnotationFilterView(viewOpts);

                this.$el.append(subView.el);
                subView.render();

                var view = this;
                subView.on("annotationSelected", function (event, item) {
                  // Get the value of the associated input
                  var term = (!item || !item.value) ? input.val() : item.value;
                  var label = (!item || !item.filterLabel) ? null : item.filterLabel;

                  // Set up a label mapping for the term so we can display a
                  // human-readable label for it in the UI
                  view.setLabelMapping(term, label);

                  // Set the value, supports multiple values
                  var currentValue = view.model.get("values");
                  var newValuesArray = _.flatten(new Array(currentValue, term));
                  view.model.set("values", newValuesArray);

                  view.defocus()
                });
              }
              catch (error) {
                console.log('There was an error rendering a SemanticFilterView.' +
                  ' Error details: ' + error);
              }
            },

            /**
             * Helper function which defocuses the dropdown portion of the
             * SearchableSelectView used by this View's AnnotationFilterView. When the
             * user clicks an item in the NCBOTree widget, we want the
             * SearchableSelectView's dropdown to go away and I couldn't find any API
             * to do that so we have this code. See the render() method to see how it's
             * called.
             *
             * Note: This isn't really a stable API and is really something we might
             * remove in the future if we refactor the NCBOTree widget.
             * @since 2.22.0
             */
            defocus: function () {
              this.$el.find("div.menu").removeClass("visible").addClass("hidden")
              this.$el.find("div.fluid.ui.dropdown").removeClass("active").removeClass("visible")
              this.$el.find("input").blur()
            },

            /**
             * Set the human-readable label for a term URI.
             *
             * For most uses of the Filter model, the value(s) set on the model can
             * be shown directly in the UI. But for Semantic searches, we need to
             * be able to display a human-readable label for the value because the
             * value is likely an opaque URI.
             *
             * Rather than fetch and/or store all the possible labels for all
             * possible URIs, we store a label for whichever terms the user chooses
             * and keep that around until we need it in the UI.
             *
             * @param {string} term The term URI to set a label for
             * @param {string} label The label to set
             * @since 2.22.0
             */
            setLabelMapping: function (term, label) {
              var newMappings;

              if (this.model.get("valueLabels")) {
                newMappings = _.clone(this.model.get("valueLabels"));
              }
              else {
                newMappings = new Object();
              }

              newMappings[term] = label;
              this.model.set("valueLabels", newMappings);
            }
          });

        return SemanticFilterView;
      });