# Source: src/js/views/search/CatalogSearchView.js

    /*global define */
    define(["jquery",
            "backbone",
            "collections/maps/MapAssets",
            "models/filters/FilterGroup",
            "models/connectors/Filters-Search",
            "models/connectors/Geohash-Search",
            "models/maps/assets/CesiumGeohash",
            "models/maps/Map",
            "views/search/SearchResultsView",
            "views/filters/FilterGroupsView",
            "views/maps/MapView",
            "views/search/SearchResultsPagerView",
            "views/search/SorterView"
        ],
    function($, Backbone, MapAssets, FilterGroup, FiltersSearchConnector, GeohashSearchConnector, CesiumGeohash, Map, SearchResultsView, FilterGroupsView, MapView, PagerView, SorterView){

        "use strict";

        /**
        * @class CatalogSearchView
        * @name CatalogSearchView
        * @classcategory Views
        * @extends Backbone.View
        * @constructor
        * @since 2.22.0
        */
        return Backbone.View.extend(
          /** @lends CatalogSearchView.prototype */ {

        /**
        * The type of View this is
        * @type {string}
        */
        type: "CatalogSearch",

        /**
        * The HTML tag to use for this view's element
        * @type {string}
        */
        tagName: "section",

        /**
        * The HTML classes to use for this view's element
        * @type {string}
        */
        className: "catalog-search-view",

        template: `
            <section class="catalog-search-inner">
                <div class="filter-groups-container"></div>
                <div class="search-results-panel-container">
                    <div class="map-toggle-container"><a class="toggle-map"><i class="icon icon-double-angle-left"></i> Show Map</a></div>
                    <div class="title-container"></div>
                    <div class="pager-container"></div>
                    <div class="sorter-container"></div>
                    <div class="search-results-container"></div>
                </div>
                <div class="map-panel-container">
                    <div class="map-toggle-container"><a class="toggle-map">Hide Map <i class="icon icon-double-angle-right"></i></a></div>
                    <div class="map-container"></div>
                </div>
            </section>
        `,

        /**
         * The search mode to use. This can be set to either `map` or `list`. List mode will hide all map features.
         * @type string
         * @since 2.22.0
         * @default "map"
         */
        mode: "map",

        searchResults: null,

        filterGroupsView: null,

        /**
         * @type {PagerView}
         */
        pagerView: null,

        /**
         * @type {SorterView}
         */
        sorterView: null,

        searchModel: null,

        allFilters: null,

        filterGroups: null,

        /**
         * An array of literal objects to transform into FilterGroup models. These FilterGroups will be displayed in this view and used for searching. If not provided, the {@link AppConfig#defaultFilterGroups} will be used.
        * @type {FilterGroup#defaults[]}
         */
        filterGroupsJSON: null,

        /**
        * The jQuery selector for the FilterGroupsView container
        * @type {string}
        */
        filterGroupsContainer: ".filter-groups-container",

        /**
        * The query selector for the SearchResultsView container
        * @type {string}
        */
        searchResultsContainer: ".search-results-container",

        /**
        * The query selector for the CesiumWidgetView container
        * @type {string}
        */
        mapContainer: ".map-container",

        /**
        * The query selector for the PagerView container
        * @type {string}
        */
        pagerContainer: ".pager-container",

        /**
        * The query selector for the SorterView container
        * @type {string}
        */
        sorterContainer: ".sorter-container",

        /**
         * The query selector for the title container
         * @type {string}
         */
        titleContainer: ".title-container",

         /**
        * The events this view will listen to and the associated function to call.
        * @type {Object}
        */
        events: {
            "click .map-toggle-container" : "toggleMode"
        },

        render: function(){

            //Set the search mode - either map or list
            this.setMode();

            //Set up the view for styling and layout
            this.setupView();

            //Set up the search and search result models
            this.setupSearch();

            //Render the search components
            this.renderComponents();

        },

        /**
         * Sets up the basic components of this view
         */
        setupView: function(){
            document.querySelector("body").classList.add(`catalog-search-body`, `${this.mode}Mode`);

            //Add LinkedData to the page
            this.addLinkedData();

            this.$el.html(this.template);
        },

        /**
         * Sets the search mode (map or list)
         * @since 2.22.0
         */
        setMode: function(){
            //Get the search mode - either "map" or "list"
            if (((typeof this.mode === "undefined") || !this.mode) && (MetacatUI.appModel.get("enableCesium"))) {
                this.mode = "map";
            }

            // Use map mode on tablets and browsers only
            if ($(window).outerWidth() <= 600) {
                this.mode = "list";
            }
        },

        renderComponents: function(){
            this.renderFilters();

            //Render the list of search results
            this.renderSearchResults();

            //Render the Title
            this.renderTitle();
            this.listenTo(this.searchResultsView.searchResults, "reset", this.renderTitle);

            //Render Pager
            this.renderPager();

            //Render Sorter
            this.renderSorter();

            //Render Cesium
            this.renderMap();
        },

        /**
         * Renders the search filters
         * @since 2.22.0
         */
        renderFilters: function(){
            //Render FilterGroups
            this.filterGroupsView = new FilterGroupsView({
                filterGroups: this.filterGroups,
                filters: this.connector?.get("filters"),
                vertical: true,
                parentView: this
            });

            //Add the FilterGroupsView element to this view
            this.$(this.filterGroupsContainer).html(this.filterGroupsView.el);

            //Render the FilterGroupsView
            this.filterGroupsView.render();
        },

        /**
         * Creates the SearchResultsView and saves a reference to the SolrResults collection
         * @since 2.22.0
         */
        createSearchResults: function(){
            this.searchResultsView = new SearchResultsView();

            if( this.connector ){
                this.searchResultsView.searchResults = this.connector.get("searchResults");
            }
        },

        /**
         * Renders the search result list
         * @since 2.22.0
         */
        renderSearchResults: function(){
            if(!this.searchResultsView) return;

            //Add the view element to this view
            this.$(this.searchResultsContainer).html(this.searchResultsView.el);

            //Render the view
            this.searchResultsView.render();
        },

        /**
         * Creates a PagerView and adds it to the page.
         * @since 2.22.0
         */
        renderPager: function(){
            this.pagerView = new PagerView();

            //Give the PagerView the SearchResults to listen to and update
            this.pagerView.searchResults = this.searchResultsView.searchResults;

            //Add the pager view to the page
            this.el.querySelector(this.pagerContainer).replaceChildren(this.pagerView.el);

            //Render the pager view
            this.pagerView.render();
        },

        /**
         * Creates a SorterView and adds it to the page.
         * @since 2.22.0
         */
        renderSorter: function(){
            this.sorterView = new SorterView();

            //Give the SorterView the SearchResults to listen to and update
            this.sorterView.searchResults = this.searchResultsView.searchResults;

            //Add the sorter view to the page
            this.el.querySelector(this.sorterContainer).replaceChildren(this.sorterView.el);

            //Render the sorter view
            this.sorterView.render();
        },

        /**
        * Constructs an HTML string of the title of this view
        * @param {number} start
        * @param {number} end
        * @param {number} numFound
        * @returns {string}
        * @since 2.22.0
        */
        titleTemplate: function(start, end, numFound){
            let html = `<div id="statcounts"><h5 class="result-header-count bold-header" id="countstats"><span>${MetacatUI.appView.commaSeparateNumber(start)}</span> to <span>${MetacatUI.appView.commaSeparateNumber(end)}</span>`;

            if(typeof numFound == "number"){
                html += ` of <span>${MetacatUI.appView.commaSeparateNumber(numFound)}</span>`;
            }

            html += `</h5></div>`;
            return html;
        },

        /**
         * Updates the view title using the {@link CatalogSearchView#searchResults} data.
         * @since 2.22.0
         */
        renderTitle: function(){
            let titleEl = this.el.querySelector(this.titleContainer);

            if(!titleEl){
                titleEl = document.createElement("div");
                titleEl.classList.add("title-container");
                this.el.prepend(titleEl);
            }

            titleEl.innerHTML="";

            let title = this.titleTemplate(this.searchResultsView.searchResults.getStart()+1, this.searchResultsView.searchResults.getEnd()+1, this.searchResultsView.searchResults.getNumFound());

            titleEl.insertAdjacentHTML("beforeend", title);

        },

        /**
         * Creates the Filter models and SolrResults that will be used for searches
         * @since 2.22.0
         */
        setupSearch: function(){

            //Get an array of all Filter models
            let allFilters = [];
            this.filterGroups = this.createFilterGroups();
            this.filterGroups.forEach(group => {
                allFilters = allFilters.concat(group.get("filters")?.models);
            });

            //Connect the filters to the search and search results
            let connector = new FiltersSearchConnector({ filtersList: allFilters });
            this.connector = connector;
            connector.startListening();

            this.createSearchResults();

            this.createMap();
        },

        /**
        * Creates UI Filter Groups. UI Filter Groups
        * are custom, interactive search filter elements, grouped together in one
        * panel, section, tab, etc.
        * @param {FilterGroup#defaults[]} filterGroupsJSON An array of literal objects to transform into FilterGroup models. These FilterGroups will be displayed in this view and used for searching. If not provided, the {@link AppConfig#defaultFilterGroups} will be used.
        * @since 2.22.0
        */
        createFilterGroups: function(filterGroupsJSON=this.filterGroupsJSON){

            try{
                //Start an array for the FilterGroups and the individual Filter models
                let filterGroups = [];

                //Iterate over each default FilterGroup in the app config and create a FilterGroup model
                (filterGroupsJSON || MetacatUI.appModel.get("defaultFilterGroups")).forEach( filterGroupJSON => {

                    //Create the FilterGroup model
                    //Add to the array
                    filterGroups.push(new FilterGroup(filterGroupJSON));

                });

                return filterGroups;
            }
            catch(e){
                console.error("Couldn't create Filter Groups in search. ", e)
            }

        },

        /**
         * Create the models and views associated with the map and map search
         * @since 2.22.0
         */
        createMap: function(){
            let mapOptions = Object.assign({}, MetacatUI.appModel.get("catalogSearchMapOptions") || {});
            let map = new Map(mapOptions);

            //Add a CesiumGeohash layer to the map
           /* let geohashLayer = new CesiumGeohash();
            geohashLayer.
            let assets = map.get("layers");
            assets.add(geohashLayer);
    */

            let geohashLayer = map.get("layers").findWhere({type: "CesiumGeohash"})

            //Connect the CesiumGeohash to the SolrResults
            let connector = new GeohashSearchConnector({
                cesiumGeohash: geohashLayer,
                searchResults: this.searchResultsView.searchResults
            });
            connector.startListening();
            this.geohashSearchConnector = connector;

            //Set the geohash level for the search
            if( Array.isArray(this.searchResultsView.searchResults.facet) )
                this.searchResultsView.searchResults.facet.push("geohash_" + geohashLayer.get("geohashLevel"));
            else
                this.searchResultsView.searchResults.facet = "geohash_" + geohashLayer.get("geohashLevel");

            //Create the Map model and view
            this.mapView = new MapView({ model: map });
        },

        /**
         * Renders the Cesium map with a geohash layer
         * @since 2.22.0
         */
        renderMap: function(){
            //Add the map to the page and render it
            this.$(this.mapContainer).empty().append(this.mapView.el);
            this.mapView.render();
        },

         /**
          * Linked Data Object for appending the jsonld into the browser DOM
          * @since 2.22.0
          * */
         addLinkedData: function() {

            // JSON Linked Data Object
            let elJSON = {
                "@context": {
                    "@vocab": "http://schema.org/"
                },
                "@type": "DataCatalog",
            }

            // Find the MN info from the CN Node list
            let members = MetacatUI.nodeModel.get("members"),
                nodeModelObject;

            for (let i = 0; i < members.length; i++) {
                if (members[i].identifier == MetacatUI.nodeModel.get("currentMemberNode")) {
                    nodeModelObject = members[i];
                }
            }
            if (nodeModelObject) {
                // "keywords": "",
                // "provider": "",
                let conditionalData = {
                    "description": nodeModelObject.description,
                    "identifier": nodeModelObject.identifier,
                    "image": nodeModelObject.logo,
                    "name": nodeModelObject.name,
                    "url": nodeModelObject.url
                }
                $.extend(elJSON, conditionalData);
            }

            // Check if the jsonld already exists from the previous data view
            // If not create a new script tag and append otherwise replace the text for the script
            if (!document.getElementById("jsonld")) {
                var el = document.createElement("script");
                el.type = "application/ld+json";
                el.id = "jsonld";
                el.text = JSON.stringify(elJSON);
                document.querySelector("head").appendChild(el);
            } else {
                var script = document.getElementById("jsonld");
                script.text = JSON.stringify(elJSON);
            }
        },

        /**
         * Toggles between map and list search mode
         * @since 2.22.0
         */
        toggleMode: function(){

            let classList = document.querySelector("body").classList;

            if(this.mode == "map"){
                this.mode = "list";
                classList.remove("mapMode");
                classList.add("listMode")
            }
            else{
                this.mode = "map";
                classList.remove("listMode");
                classList.add("mapMode")
            }

        },

        onClose: function(){
            document.querySelector("body").classList.remove(`catalog-search-body`, `${this.mode}Mode`);

            //Remove the JSON-LD from the page
            document.getElementById("jsonld")?.remove();
        }

    });

    });