# Source: js/views/portals/PortalView.js

    define(["jquery",
            "underscore",
            "backbone",
            "models/portals/PortalModel",
            "text!templates/alert.html",
            "text!templates/loading.html",
            "text!templates/portals/portal.html",
            "text!templates/portals/editPortals.html",
            "views/portals/PortalHeaderView",
            "views/portals/PortalDataView",
            "views/portals/PortalSectionView",
            "views/portals/PortalMetricsView",
            "views/portals/PortalMembersView",
            "views/portals/PortalLogosView"
        ],
        function($, _, Backbone, Portal, AlertTemplate, LoadingTemplate, PortalTemplate, EditPortalsTemplate, PortalHeaderView,
            PortalDataView, PortalSectionView, PortalMetricsView, PortalMembersView, PortalLogosView) {
            "use_strict";

            /**
            * @class PortalView
            * @classdesc The PortalView is a generic view to render
             * portals, it will hold portal sections
             * @extends Backbone.View
             * @constructor
             */
            var PortalView = Backbone.View.extend(
                /** @lends PortalView.prototype */{

                /**
                 * The Portal element
                 * @type {string}
                 */
                el: "#Content",

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

                /**
                 * The currently active section view
                 * @type {PortalSectionView}
                 */
                activeSection: undefined,

                /**
                * The currently active section label. e.g. Data, Metrics, Settings, etc.
                * @type {string}
                */
                activeSectionLabel: "",

                /**
                 * The names of all sections in this portal editor
                 * @type {Array}
                 */
                sectionNames: [],

                /**
                 * The seriesId of the portal document
                 * @type {string}
                 */
                portalId: "",

                /**
                 * The unique short name of the portal
                 * @type {string}
                 */
                label: "",

                /**
                * Flag to add section name to URL. Enabled by default.
                * @type {boolean}
                */
                displaySectionInUrl: true,

                /**
                 * The subviews contained within this view to be removed with onClose
                 * @type {Array}
                 */
                subviews: new Array(), // Could be a literal object {} */

                /**
                 * A Portal Model is associated with this view and gets created during render()
                 * @type {Portal}
                 */
                model: null,

                /* Renders the compiled template into HTML */
                template: _.template(PortalTemplate),
                //A template to display a notification message
                alertTemplate: _.template(AlertTemplate),
                //A template for displaying a loading message
                loadingTemplate: _.template(LoadingTemplate),
                // Template for the 'edit portal' button
                editPortalsTemplate: _.template(EditPortalsTemplate),

                /**
                * A jQuery selector for the element that a single section link will be inserted into
                * @type {string}
                */
                sectionLinkContainer: ".section-link-container",
                /**
                * A jQuery selector for the elements that are links to the individual sections
                * @type {string}
                */
                sectionLinks: ".portal-section-link",
                /**
                * A jQuery selector for the section elements
                * @type {string}
                */
                sectionEls: ".portal-section-view",
                /**
                 * The events this view will listen to and the associated function to call.
                 * @type {Object}
                 */
                events: {
                  "click .portal-section-link"   : "handleSwitchSection",
                  "click .section-links-container" : "toggleSectionLinks"
                },

                /**
                 * Is executed when a new PortalView is created
                 */
                initialize: function(options) {
                    // Set the current PortalView properties
                    this.portalId = options.portalId ? options.portalId : undefined;
                    this.label = options.label ? options.label : undefined;
                    this.activeSection = options.activeSection ? options.activeSection : undefined;
                    this.activeSectionLabel = options.activeSectionLabel ? options.activeSectionLabel : undefined;
                },

                /**
                 * Initial render of the PortalView
                 *
                 * @return {PortalView} Returns itself for easy function stacking in the app
                 */
                render: function() {

                    //Make sure the subviews array is reset
                    this.subviews = new Array();

                    // Add the overall class immediately so the navbar is styled correctly right away
                    $("body").addClass("PortalView");

                    this.$el.html(this.loadingTemplate({
                      msg: "Loading..."
                    }));

                    // Create a new Portal model
                    this.model = new Portal({
                        seriesId: this.portalId,
                        label: this.label
                    });

                    // When the model has been synced, render the results
                    this.stopListening();
                    this.listenToOnce(this.model, "sync", this.renderPortal);

                    //If the portal isn't found, display a 404 message
                    this.listenTo(this.model, "notFound", this.handleNotFound);

                    //Listen to errors that might occur during fetch()
                    this.listenToOnce(this.model, "error", this.showError);

                    //Fetch the model
                    this.model.fetch({ objectOnly: true });

                    return this;
                },

                /**
                 * Render the Portal view
                 */
                renderPortal: function() {

                  // Add edit button if user is authorized
                  this.insertOwnerControls();

                  // Getting the correct portal label and seriesID
                  this.label = this.model.get("label");
                  this.portalId = this.model.get("seriesId");

                  // Remove the listeners that were set during the fetch() process
                  this.stopListening(this.model, "notFound", this.handleNotFound);
                  this.stopListening(this.model, "error", this.showError);

                    // Insert the overall portal template
                    this.$el.html(this.template(this.model.toJSON()));

                    // Render the header view
                    this.headerView = new PortalHeaderView({
                        model: this.model
                    });
                    this.headerView.render();
                    this.subviews.push(this.headerView);

                    // Render the content sections
                    _.each(this.model.get("sections"), function(section){
                      this.addSection(section);
                    }, this);

                    // Render the Data section
                    if( this.model.get("hideData") !== true ) {
                        this.sectionDataView = new PortalDataView({
                            model: this.model,
                            id: "Data",
                            sectionName: "Data"
                        });
                        this.subviews.push(this.sectionDataView);

                        this.$("#portal-sections").append(this.sectionDataView.el);

                        //Render the section view and add it to the page
                        this.sectionDataView.render();

                        this.addSectionLink( this.sectionDataView );
                    }

                    //Render the metrics section link
                    if ( this.model.get("hideMetrics") !== true ) {

                      //Create a PortalMetricsView
                      this.metricsView = new PortalMetricsView({
                        model: this.model,
                        id: this.model.get("metricsLabel"),
                        uniqueSectionName: this.model.get("metricsLabel")
                      });

                      this.subviews.push(this.metricsView);
                      this.$("#portal-sections").append(this.metricsView.el);

                      this.metricsView.render();

                      this.addSectionLink( this.metricsView );

                    }

                    // Render the members section
                    if ( this.model.get("hideMembers") !== true &&
                         (this.model.get("associatedParties").length || this.model.get("acknowledgments"))){

                        this.sectionMembersView = new PortalMembersView({
                            model: this.model,
                            id: "Members",
                            sectionName: "Members"
                        });
                        this.subviews.push(this.sectionMembersView);

                        this.$("#portal-sections").append(this.sectionMembersView.el);

                        //Render the section view and add it to the page
                        this.sectionMembersView.render();

                        this.addSectionLink( this.sectionMembersView );
                    }

                    //Switch to the active section
                    this.switchSection();

                    //Render the logos at the bottom of the portal page
                    var ackLogos = this.model.get("acknowledgmentsLogos") || [];
                    this.logosView = new PortalLogosView();
                    this.logosView.logos = ackLogos;
                    this.subviews.push(this.logosView);
                    this.logosView.render();
                    this.$(".portal-view").append(this.logosView.el);

                    //Scroll to an inner-page link if there is one specified
                    if( window.location.hash && this.$(window.location.hash).length ){
                      MetacatUI.appView.scrollTo(this.$(window.location.hash));
                    }

                    // Save reference to this view
                    var view = this;

                    // On mobile, hide section tabs a moment after page loads so
                    // users notice where they are
                    setTimeout(function () {
                      view.toggleSectionLinks();
                    }, 700);

                    // On mobile where the section-links-container is set to fixed,
                    // hide the portal navigation element when user scrolls down,
                    // show again when the user scrolls up.
                    MetacatUI.appView.prevScrollpos = window.pageYOffset;
                    $(window).on("scroll", "", undefined, this.handleScroll);

                },

                /**
                 * toggleSectionLinks - show or hide the section links nav. Used for
                 * mobile/small screens only.
                 */
                toggleSectionLinks: function(){
                  try{
                    // Only toggle the section links on mobile. On mobile, the
                    // ".show-sections-toggle" is visible.
                    if(this.$(".show-sections-toggle").is(":visible")){
                      this.$("#portal-section-tabs").slideToggle();
                    }
                  } catch(e){
                    console.log("Failed to toggle section links, error message: " + e);
                  }
                },

                /*
                 * Checks the authority for the logged in user for this portal and
                 * inserts control elements onto the page for the user to interact
                 * with the portal. So far, this is just an 'edit portal' button.
                 */
                insertOwnerControls: function(){

                  // Insert the button into the navbar
                  var container = $(".edit-portal-link-container");

                  var model = this.model;

                  this.listenToOnce(this.model, "change:isAuthorized", function(){
                    if(!model.get("isAuthorized")){
                      return false;
                    } else {
                      container.html(
                        this.editPortalsTemplate({
                          editButtonText: "Edit " + MetacatUI.appModel.get('portalTermSingular'),
                          pathToEdit: MetacatUI.root + "/edit/"+ MetacatUI.appModel.get("portalTermPlural") +"/" + model.get("label")
                        })
                      );
                    }
                  });

                  this.model.checkAuthority("write");
                },

                /**
                 * Update the window location path with the active section name
                 * @param {boolean} [showSectionLabel] - If true, the section label will be added to the path
                */
                updatePath: function(showSectionLabel){

                  var label         = this.model.get("label") || this.newPortalTempName,
                      originalLabel = this.model.get("originalLabel") || this.newPortalTempName,
                      pathName      = decodeURIComponent(window.location.pathname)
                                      .substring(MetacatUI.root.length)
                                      // remove trailing forward slash if one exists in path
                                      .replace(/\/$/, "");

                  // Add or replace the label and section part of the path with updated values.
                  // pathRE matches "/label/section", where the "/section" part is optional
                  var pathRE = new RegExp("\\/(" + label + "|" + originalLabel + ")(\\/[^\\/]*)?$", "i");
                  newPathName = pathName.replace(pathRE, "") + "/" + label;

                  if( showSectionLabel && this.activeSection ){
                    newPathName += "/" + this.activeSection.uniqueSectionLabel;
                  }

                  // Update the window location
                  MetacatUI.uiRouter.navigate( newPathName, { trigger: false } );

                },

                /**
                 * Gets a list of section names from tab elements and updates the
                 * sectionNames attribute on this view.
                 */
                updateSectionNames: function() {

                  // Get the section names from the tab elements
                  var sectionNames = [];
                  this.$(this.sectionLinks)
                    .each(function(i, anchorEl){
                      sectionNames[i] = $(anchorEl)
                                          .attr("href")
                                          .substring(1)
                    });

                  // Set the array of sectionNames on the view
                  this.sectionNames = sectionNames
                },

                /**
                * Manually switch to a section subview by making the tab and tab panel active.
                * Navigation between sections is usually handled automatically by the Bootstrap
                * library, but a manual switch may be necessary sometimes
                * @param {PortalSectionView} [sectionView] - The section view to switch to. If not given, defaults to the activeSection set on the view.
                */
                switchSection: function(sectionView){

                  //Create a flag for whether the section label should be shown in the URL
                  var showSectionLabelInURL = true;

                  // If no section view is given, use the active section in the view.
                  if( !sectionView ){
                    //Use the sectionView set already
                    if( this.activeSection ){
                      var sectionView = this.activeSection;
                    }
                    //Or find the section view by name, which may have been passed through the URL
                    else if( this.activeSectionLabel ){
                      var sectionView = this.getSectionByLabel(this.activeSectionLabel);
                    }
                  }

                  //If no section view was indicated, just default to the first visible one
                  if( !sectionView ){
                    var sectionView = this.$(this.sectionLinkContainer).first().data("view");

                    //If we are defaulting to the first section, don't show the section label in the URL
                    showSectionLabelInURL = false;

                    //If there are no section views on the page at all, exit now
                    if( !sectionView ){
                      return;
                    }
                  }

                  // Update the activeSection set on the view
                  this.activeSection = sectionView;

                  // Activate the section content
                  this.$(this.sectionEls).each(function(i, contentEl){
                    if($(contentEl).data("view") == sectionView){
                      $(contentEl).addClass("active");
                    } else {
                      // make sure no other sections are active
                      $(contentEl).removeClass("active");
                    }
                  });

                  // Activate the link to the content
                  this.$(this.sectionLinkContainer).each(function(i, linkEl){
                    if( $(linkEl).data("view") == sectionView ){
                      $(linkEl).addClass("active")
                    } else {
                      // make sure no other sections are active
                      $(linkEl).removeClass("active")
                    };
                  });

                  //If the section view has post-render functionality, execute it now
                  if( typeof sectionView.postRender == "function" ){
                    sectionView.postRender();
                  }

                  //Update the location path with the new section name
                  this.updatePath(showSectionLabelInURL);

                },

                /**
                * When a section link has been clicked, switch to that section
                * @param {Event} e - The click event on the section link
                */
                handleSwitchSection: function(e){

                  e.preventDefault();

                  var sectionView = $(e.target).parents(this.sectionLinkContainer).first().data("view");

                  if( sectionView ){
                    this.switchSection(sectionView);

                    // If the user clicks a link and is not near the top of the page
                    // (i.e. on mobile), scroll to the top of the section content.
                    // Otherwise it might look like the page hasn't changed (e.g.
                    // when focus is on the footer)
                    if(window.pageYOffset > this.$("#portal-sections").offset().top){
                      MetacatUI.appView.scrollTo(this.$("#portal-sections"));
                    }

                  }

                },

                /**
                * Returns the section view that has a label matching the one given.
                * @param {string} label - The label for the section
                * @return {PortalSectionView|false} - Returns false if a matching section view isn't found
                */
                getSectionByLabel: function(label){

                  //If no label is given, exit
                  if(!label){
                    return;
                  }

                  //Find the section view whose unique label matches the given label. Case-insensitive matching.
                  return _.find( this.subviews, function(view){
                    if( typeof view.uniqueSectionLabel == "string" ){
                      return view.uniqueSectionLabel.toLowerCase() == label.toLowerCase();
                    }
                    else{
                      return false;
                    }
                  });
                },

                /**
                * Creates and returns a unique label for the given section. This label is just used in the view,
                * because portal sections can have duplicate labels. But unique labels need to be used for navigation in the view.
                * @param {PortEditorSection} sectionModel - The section for which to create a unique label
                * @return {string} The unique label string
                */
                getUniqueSectionLabel: function(sectionModel){
                  //Get the label for this section
                  var sectionLabel = sectionModel.get("label").replace(/[^a-zA-Z0-9 ]/g, "").replace(/ /g, "-"),
                      unalteredLabel = sectionLabel,
                      sectionLabels = this.sectionLabels || [],
                      i = 2;

                  //Concatenate a number to the label if this one already exists
                  while( sectionLabels.includes(sectionLabel) ){
                    sectionLabel = unalteredLabel + i;
                    i++;
                  }

                  return sectionLabel;
                },

                /**
                 * Creates a PortalSectionView to display the content in the given portal
                 * section. Also creates a navigation link to the section.
                 *
                 * @param {PortalSectionModel} sectionModel - The section to render in this view
                 */
                addSection: function(sectionModel){

                  //Create a new PortalSectionView
                  var sectionView = new PortalSectionView({
                    model: sectionModel
                  });

                  //Render the section
                  sectionView.render();

                  //Add the section view to this portal view
                  this.$("#portal-sections").append(sectionView.el);

                  this.addSectionLink( sectionView );

                  //Create a unique label for this section and save it
                  var uniqueLabel = this.getUniqueSectionLabel(sectionModel);
                  //Set the unique section label for this view
                  sectionView.uniqueSectionLabel = uniqueLabel;

                  this.subviews.push(sectionView);

                },

                /**
                 * Add a link to a section of this portal page
                 * @param {PortalSectionView} sectionView - The view to add a link to
                 */
                addSectionLink: function(sectionView){

                  var label = sectionView.getName();
                  var hrefLabel = sectionView.getName({ linkFriendly: true });

                  //Create a navigation link
                  this.$("#portal-section-tabs").append(
                    $(document.createElement("li"))
                      .addClass("section-link-container")
                      .data("view", sectionView)
                      .append( $(document.createElement("a"))
                                 .text(label)
                                 .attr("href", "#" + hrefLabel )
                                 .attr("data-toggle", "tab")
                                 .addClass("portal-section-link")
                                 .data("view", sectionView)));

                },

                /**
                * Handles the case where the PortalModel is fetched and nothing is found.
                */
                handleNotFound: function(){

                  //If the user is NOT logged in OR
                  // if the suer is logged in, and the last fetch was done with user credentials, then this Portal is either not accessible or non-existent
                  if( MetacatUI.appUserModel.get("checked") && !MetacatUI.appUserModel.get("loggedIn") ||
                      (MetacatUI.appUserModel.get("checked") && MetacatUI.appUserModel.get("loggedIn") && this.model.get("fetchedWithAuth")) ){

                    var view = this;

                    //Check if there is an indexing queue, because this model may still be indexing
                    var onError = function(){
                        //If the request to the monitor/status API fails, then show the not-found message
                        view.showNotFound.call(view);
                      },
                      onSuccess = function(sizeOfQueue){

                        if( sizeOfQueue > 0 ){
                          //Show a warning message about the index queue
                          MetacatUI.appView.showAlert(
                            "<p>We couldn't find a data portal named \"" + (view.label || view.portalId) +
                              "\".</p><p><i class='icon icon-exclamation-sign'></i> If this portal was created in the last few minutes, it may still be processing, since there are currently <b>" + sizeOfQueue +
                              "</b> submissions in the queue.</p>",
                            "alert-warning",
                            view.$el
                          );
                          view.$(".loading").remove();
                        }
                        else{
                          //If the size of the queue is 0, then show the not-found message
                          view.showNotFound.call(view);
                        }

                      }

                    //Get the size of the index queue
                    MetacatUI.appLookupModel.getSizeOfIndexQueue(onSuccess, onError);

                  }
                  //If the user IS logged in and we haven't fetched the model with user authentication yet
                  else if( MetacatUI.appUserModel.get("checked") && MetacatUI.appUserModel.get("loggedIn") ){
                    //Fetch again now that the user is logged in
                    this.model.fetch();
                  }
                  //If the user login status is unknown, because authentication is still pending
                  else if( !MetacatUI.appUserModel.get("checked") ){
                    //Wait for the authentication to be checked, and then start this function over again
                    this.listenToOnce(MetacatUI.appUserModel, "change:checked", this.handleNotFound);
                  }

                },

                /**
                 * If the given portal doesn't exist, display a Not Found message.
                 */
                showNotFound: function(){

                  var notFoundMessage = "The data portal \"" + (this.label || this.portalId) +
                                        "\" doesn't exist.",
                      notification = this.alertTemplate({
                        classes: "alert-error",
                        msg: notFoundMessage,
                        includeEmail: true
                      });

                  this.$el.html(notification);

                },

                /**
                * Show an error message in this view
                * @param {SolrResult} model
                * @param {XMLHttpRequest.response} response
                */
                showError: function(model, response){

                  var errorMsg = "";
                  if( response && response.responseText ){
                    errorMsg = "<p>Error details: " + $(response.responseText).text() + "</p>";
                  }

                  //Show the error message
                  MetacatUI.appView.showAlert(
                    "<h4><i class='icon icon-frown'></i>Something went wrong while displaying this portal.</h4>" + errorMsg,
                    "alert-error",
                    this.$el
                  );

                  //Remove the loading message from this view
                  this.$el.find(".loading").remove();

                },

                /**
                * This function is called whenever the window is scrolled.
                */
                handleScroll: function() {
                  var menu = $(".section-links-container")[0],
                      menuHeight = $(menu).height(),
                      hiddenHeight = (menuHeight * -1);
                  var currentScrollPos = window.pageYOffset;
                  if(MetacatUI.appView.prevScrollpos > currentScrollPos) {
                    menu.style.bottom = "0px";
                  } else {
                    menu.style.bottom = hiddenHeight +"px";
                  }
                  MetacatUI.appView.prevScrollpos = currentScrollPos;
                },

                /**
                 * This function is called when the app navigates away from this view.
                 * Any clean-up or housekeeping happens at this time.
                 */
                onClose: function() {
                    //Remove each subview from the DOM and remove listeners
                    _.invoke(this.subviews, "remove");

                    this.subviews = new Array();

                    //Remove all listeners
                    this.stopListening();

                    //Delete the metrics view from this view
                    delete this.sectionMetricsView;
                    //Delete the model from this view
                    delete this.model;

                    //Remove the scroll listener
                    $(window).off("scroll", "", this.handleScroll);

                    $("body").removeClass("PortalView");

                    $("#editPortal").remove();

                    this.undelegateEvents();
                }
            });

            return PortalView;
        });