text: /**
   * Backbone model denoting the remote Fuseki server.
   */
  
  define(
    function( require ) {
      "use strict";
  
      var Marionette = require( "marionette" ),
          Backbone = require( "backbone" ),
          _ = require( "underscore" ),
          fui = require( "app/fui" ),
          sprintf = require( "sprintf" ),
          Dataset = require( "app/models/dataset" ),
          PageUtils = require( "app/util/page-utils" );
  
      var DATASETS_MANAGEMENT_PATH = "/$/datasets";
  
      /**
       * This model represents the core representation of the remote Fuseki
       * server. Individual datasets have their own model.
       */
      var FusekiServer = Backbone.Model.extend( {
        /** This initializer occurs when the module starts, not when the constructor is invoked */
        init: function( options ) {
          this._baseURL = this.currentRootPath();
          this._managementURL = null;
          this.set( "selectedDatasetName", PageUtils.queryParam( "ds" ) )
        },
  
        baseURL: function() {
          return this._baseURL;
        },
  
        /** Return the URL from which we extract the details of the current server */
        serverDetailsURL: function() {
          return sprintf( "%s/$/server", this.baseURL() );
        },
  
        /** Return the URL for issuing commands to the management API, or null if no API defined */
        managementURL: function() {
          return this._managementURL;
        },
  
        /** Return the URL for getting the stats for all datasets */
        statsURL: function() {
          return sprintf( "%s/$/stats", this.managementURL() );
        },
  
        /** Return the list of datasets that this server knows about. Each dataset will be a Dataset model object */
        datasets: function() {
          return this.get( "datasets" );
        },
  
        /** Return the dataset with the given name */
        dataset: function( dsName ) {
          return _.find( this.datasets(), function( ds ) {return dsName === ds.name();} )
        },
  
        /** Return the name of the currently selected dataset, if known */
        selectedDatasetName: function() {
          return this.get( "selectedDatasetName" );
        },
  
        /** Return the dataset that is currently selected, or null */
        selectedDataset: function() {
          var dsName = this.selectedDatasetName();
          return dsName && this.dataset( dsName );
        },
  
        /** Load and cache the remote server description. Trigger change event when done */
        loadServerDescription: function() {
            var self = this;
            return this.getJSON( this.serverDetailsURL() )
                .done( function( data ) {
                    self.saveServerDescription( data );
                } )
                .then( function() {
                    fui.vent.trigger( "models.fuseki-server.ready" );
                });
        },
  
        /** Store the server description in this model */
        saveServerDescription: function( serverDesc ) {
          // wrap each dataset JSON description as a dataset model
          var bURL = this.baseURL();
          var mgmtURL = bURL;
  
          if (serverDesc.admin) {
  	       // This is too simple.  window.location.port may be empty and matches protocol.
  	       //mgmtURL = bURL.replace( ":" + window.location.port, ":" + serverDesc.admin.port );
             //console.log("managementURL -- s/"+window.location.port+"/"+serverDesc.admin.port+"/") ;
  	       var path = window.location.pathname.replace( /\/[^/]*$/, "" ) ;
   	       mgmtURL = sprintf( "%s//%s:%s%s",  window.location.protocol, window.location.hostname, serverDesc.admin, path );
          }
  	    this._managementURL = mgmtURL ;
  	
          var datasets = _.map( serverDesc.datasets, function( d ) {
            return new Dataset( d, bURL, mgmtURL + DATASETS_MANAGEMENT_PATH );
          } );
  
          datasets.sort( function( ds0, ds1 ) {
            if (ds0.name() > ds1.name()) {
              return 1;
            }
            else if (ds0.name() < ds1.name()) {
              return -1;
            }
            else
              return 0;
          } );
  
          this.set( {
            serverDescription: serverDesc,
            datasets: datasets,
            ready: true
          } );
        },
  
        /**
         * Get the given relative path from the server, and return a promise object which will
         * complete with the JSON object denoted by the path.
         */
        getJSON: function( path, data ) {
          return $.getJSON( path, data );
        },
  
        /** Update or create a dataset by posting to its endpoint */
        updateOrCreateDataset: function( datasetId, data ) {
          var url = sprintf( "%s/$/datasets%s", this.managementURL(),
                             datasetId ? ("/" + datasetId) : ""
                           );
  
          return $.ajax( url,
                         { data: data,
                           method: "post"
                         }
                       );
        },
  
        /** Extract the server root path from the current window href
         * This is the path, from /, without protocol, host or port.
         * Then the browser adds protocol, host or port.
         * Sometimes, the app does not know URL the browser used.
         * For example, in docker, the port may have been remapped,
         * or with a reverse proxy, https may have been terminated.
         */
        currentRootPath: function() {
          var path = window.location.pathname.replace( /\/[^/]*$/, "" );
            /*
              console.log("window.location="+window.location) ;
              console.log("window.location.href="+window.location.href) ;
              
              console.log("window.location.protocol="+window.location.protocol) ;
              console.log("window.location.host="+window.location.host) ;
              console.log("window.location.hostname="+window.location.hostname) ;
              console.log("window.location.port="+window.location.port) ;
              console.log("window.location.pathname="+window.location.pathname) ;
              
              console.log("window.location.origin="+window.location.origin) ;
              console.log("window.location.hash="+window.location.hash) ;
              console.log("window.location.search="+window.location.search) ;
              console.log("path='"+path+"'") ;
            */
          return path ;
        }
      } );
  
      // when the models module starts, automatically load the server description
      fui.models.addInitializer( function( options ) {
        var fusekiServer = new FusekiServer();
        fui.models.fusekiServer = fusekiServer;
  
        fusekiServer.init( options );
        fusekiServer.loadServerDescription();
      } );
  
      return FusekiServer;
    }
  );
  