# Source: src/js/models/portals/PortalImage.js

    /* global define */
    define(["jquery",
            "underscore",
            "backbone",
            "models/DataONEObject"
        ],
        function($, _, Backbone, DataONEObject) {

          /**
           * @class PortalImage
           * @classdesc A Portal Image model represents a single image used in a Portal
           * @classcategory Models/Portals
           * @extends Backbone.Model
           */
          var PortalImageModel = DataONEObject.extend(
            /** @lends PortalImage.prototype */{

            /**
            * @inheritdoc
            */
            type: "PortalImage",

            defaults: function(){
              return _.extend(DataONEObject.prototype.defaults(), {
                identifier: "",
                imageURL: "",
                label: "",
                associatedURL: "",
                objectDOM: null,
                nodeName: "image",
                portalModel: null
              });
            },

            initialize: function(attrs){

              // Call the super class initialize function
              DataONEObject.prototype.initialize.call(this, attrs);

              // If the image model is initialized with an identifier but no image URL,
              // create the full image URL
              if(this.get("identifier") && !this.get("imageURL")){

                var baseURL = this.getBaseURL(),
                    imageURL = baseURL + this.get("identifier");
                    this.set("imageURL", imageURL);
              }

            },

            /**
             * Parses an ImageType XML element from a portal document
             *
             *  @param {XMLElement} objectDOM - An ImageType XML element from a portal document
             *  @return {JSON} The result of the parsed XML, in JSON. To be set directly on the model.
            */
            parse: function(objectDOM){

              if(!objectDOM){
                objectDOM = this.get("objectDOM");

                if(!objectDOM){
                  return {};
                }
              }

              var portalModel = this.get("portalModel"),
                  $objectDOM = $(objectDOM),
                  modelJSON = {};

              if( portalModel ){
                modelJSON.datasource = portalModel.get("datasource");
                modelJSON.submitter  = portalModel.get("submitter");
                modelJSON.rightsHolder = portalModel.get("rightsHolder");
                modelJSON.originMemberNode = portalModel.get("originMemberNode");
                modelJSON.authoritativeMemberNode = portalModel.get("authoritativeMemberNode");
              }

              modelJSON.nodeName = objectDOM.nodeName;

              //Parse all the simple string elements
              modelJSON.label = $objectDOM.children("label").text();
              modelJSON.associatedURL = $objectDOM.children("associatedURL").text();

              // Parse the image URL or identifier
              modelJSON.identifier = $objectDOM.children("identifier").text();
              if( modelJSON.identifier ){
                if( modelJSON.identifier.substring(0, 4) !== "http" ){

                  var baseURL = this.getBaseURL();
                  modelJSON.imageURL = baseURL + modelJSON.identifier;

                }
                else{
                  modelJSON.imageURL = modelJSON.identifier;
                }
              }

              return modelJSON;

            },

            /**
             * imageExists - Check if an image exists with the given
             * url, or if no url provided, with the baseURL + identifier
             *
             * @param  {string} imageURL  The image URL to check
             * @return {boolean}          Returns true if an HTTP request returns anything but 404
             */
            imageExists: function (imageURL){

              if(!imageURL){
                this.get("imageURL")
              }

              if(!imageURL && this.get("identifier")){
                var baseURL = this.getBaseURL(),
                    imageURL = baseURL + this.get("identifier");
              }

              if(!imageURL){
                return false
              }

              var http = new XMLHttpRequest();
              http.open('HEAD', imageURL, false);
              http.send();

              return http.status != 404;

            },

            /**
             * getBaseURL - Get the base URL to use with an image identifier
             *
             * @return {string}  The image base URL, or an empty string if not found
             */
            getBaseURL: function(){

              var url = "",
                  portalModel = this.get("portalModel"),
                  // datasource = portalModel ? portalModel.get("datasource") : false;
                  datasource = this.get("datasource"),
                  datasource = (portalModel && !datasource) ? portalModel.get("datasource") : datasource;

              if( MetacatUI.appModel.get("isCN") ){
                var sourceRepo;

                //Use the object service URL from the origin MN/datasource
                if( datasource ){
                  sourceRepo = MetacatUI.nodeModel.getMember(datasource);
                }
                // Use the object service URL from the alt repo
                if( !sourceRepo ){
                  sourceRepo = MetacatUI.appModel.getActiveAltRepo();
                }
                if( sourceRepo ){
                  url = sourceRepo.objectServiceUrl;
                }
              }

              if(!url && datasource){
                var imageMN = _.findWhere(MetacatUI.appModel.get("alternateRepositories"), { identifier: datasource });
                if(imageMN){
                  url = imageMN.objectServiceUrl;
                }
              }

              //If this MetacatUI deployment is pointing to a MN, use the meta service URL from the AppModel
              if( !url ){
                url = MetacatUI.appModel.get("objectServiceUrl") || MetacatUI.appModel.get("resolveServiceUrl");
              }
              return url;
            },

            /**
        		 * Makes a copy of the original XML DOM and updates it with the new values from the model
             *
             *  @return {XMLElement} An updated ImageType XML element from a portal document
        		 */
            updateDOM: function() {

              //If there is no identifier, don't serialize anything
              if( !this.get("identifier") ){
                return "";
              }

              var objectDOM = this.get("objectDOM");

              if (objectDOM) {
                objectDOM = objectDOM.cloneNode(true);
                $(objectDOM).empty();
              } else {
                // create an XML image element from scratch
                var xmlText = "<" + this.get("nodeName") + "></" + this.get("nodeName") + ">",
                    objectDOM = new DOMParser().parseFromString(xmlText, "text/xml"),
                    objectDOM = $(objectDOM).children()[0];
             }

              // get new image data
              var imageData = {
                identifier: this.get("identifier"),
                label: this.get("label"),
                associatedURL: this.get("associatedURL")
              }

              _.map(imageData, function(value, nodeName){

                // Don't serialize falsey values
                if(value){
                  // Make new sub-node
                  var imageSubnodeSerialized = objectDOM.ownerDocument.createElement(nodeName);
                  $(imageSubnodeSerialized).text(value);
                  // Append new sub-node to objectDOM
                  $(objectDOM).append(imageSubnodeSerialized);

                }

              });

              return objectDOM;
            },

            /**
             * Overrides the default Backbone.Model.validate.function() to
             * check if this PortalImage model has all the required values necessary
             * to save to the server.
             *
             * @return {Object} If there are errors, an object comprising error
             *                   messages. If no errors, returns nothing.
            */
            validate: function(){
              try {

                var errors          = {},
                    requiredFields = MetacatUI.appModel.get("portalEditorRequiredFields"),
                    label           = this.get("label"),
                    url             = this.get("associatedURL"),
                    id              = this.get("identifier"),
                    genericLabels   = ["logo", "image"], // not set by the user
                    hasLabel        = (label && typeof label == "string" && !genericLabels.includes(label)) ? true : false,
                    hasURL          = (url && typeof url == "string") ? true : false,
                    hasId           = (id && typeof id == "string") ? true : false,
                    urlRegex        = new RegExp(/^(http:\/\/www\.|https:\/\/www\.|http:\/\/|https:\/\/)?[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(:[0-9]{1,5})?(\/.*)?$/);

                // If it's a logo, check whether it's a required image
                if(this.get("nodeName") === "logo" && requiredFields.logo && !hasId){
                  errors["identifier"] = "An image is required."
                  return errors
                }
                // If it's a section image, check whether it's a required image
                else if(this.get("nodeName") === "image" && requiredFields.sectionImage && !hasId){
                  errors["identifier"] = "An image is required."
                  return errors
                }
                // If none of the fields have values, the portalImage won't be serialized
                else if(!hasId && !hasURL && !hasLabel){
                  return
                }

                // If the URL isn't a valid format, add an error message
                if(hasURL && !urlRegex.test(url)){
                  errors["associatedURL"] = "Enter a valid URL."
                }
                //If the URL is valid, check if there is an http or https protocol
                else if(hasURL && url.substring(0,4) != "http"){
                  //If not, add the https protocol
                  this.set("associatedURL", "https://" + url);
                }

                return errors;

              }
              catch(e){
                console.error("Error validating a portal image. Error message:" + e);
                return;
              }
            },

            /**
             * isEmpty - Returns true if the PortalImage model has no label, no associatedURL, and no identifier
             *
             * @return {boolean}  true if the model is empty, false if it has at least a label, url, or id
             */
            isEmpty: function(){
              return (
                !this.get("label")          &&
                !this.get("associatedURL")  &&
                !this.get("identifier")
              ) ;
            },

            /**
            * Returns true if this PortalImage hasn't been saved to a Portal yet, so it is a new object.
            * For now, all PortalImages will be considered new objects since we will not be performing updates on them.
            * @return {boolean}
            */
            isNew: function(){
              if( this.get("identifier") ){
                return false;
              }
              else{
                return true;
              }
            }

          });

          return PortalImageModel;
    });