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

    /* global define */
    define(["jquery",
            "underscore",
            "backbone",
            "models/portals/PortalImage",
            "models/metadata/eml220/EMLText"
        ],
        function($, _, Backbone, PortalImage, EMLText) {

          /**
           * @class PortalSectionModel
           * @classdesc A Portal Section model represents the ContentSectionType from the portal schema
           * @classcategory Models/Portals
           * @extends Backbone.Model
           */
          var PortalSectionModel = Backbone.Model.extend(
            /** @lends PortalSectionModel.prototype */{
            defaults: function(){
              return {
                label: "Untitled",
                image: "",
                title: "",
                introduction: "",
                content: new EMLText({
                              type: "content",
                              parentModel: this
                          }),
                literatureCited: null,
                objectDOM: null,
                sectionType: "",
                portalModel: null
              }
            },

            /**
             * Parses a <section> element from a portal document
             *
             *  @param {XMLElement} objectDOM - A ContentSectionType 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){
                return {};
              }

              var $objectDOM = $(objectDOM),
                  modelJSON = {};

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

              //Parse the image URL or identifier
              var image = $objectDOM.children("image");
              if( image.length ){
                var portImageModel = new PortalImage({
                  objectDOM: image[0],
                  portalModel: this.get("portalModel")
                });
                portImageModel.set(portImageModel.parse());
                modelJSON.image = portImageModel;
              }

              //Create an EMLText model for the section content
              modelJSON.content = new EMLText({
                objectDOM: $objectDOM.children("content")[0]
              });
              modelJSON.content.set(modelJSON.content.parse($objectDOM.children("content")));

              return modelJSON;

            },

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

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

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

              // Get and update the simple text strings (everything but content)
              var sectionTextData = {
                label: this.get("label"),
                title: this.get("title"),
                introduction: this.get("introduction")
              };

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

                // Don't serialize default values, except for default label strings, since labels are required
                if(value && (value != this.defaults()[nodeName] || (nodeName == "label" && typeof value == "string")) ){
                  // Make new sub-node
                  var sectionSubnodeSerialized = objectDOM.ownerDocument.createElement(nodeName);
                  $(sectionSubnodeSerialized).text(value);

                  this.addUpdatedXMLNode(objectDOM, sectionSubnodeSerialized);
                }
                //If the value was removed from the model, then remove the element from the XML
                else{
                  $(objectDOM).children(nodeName).remove();
                }

              }, this);

              //Update the image element
              if( this.get("image") && typeof this.get("image").updateDOM == "function" ){

                var imageSerialized = this.get("image").updateDOM();

                this.addUpdatedXMLNode(objectDOM, imageSerialized);
              }
              else{
                $(objectDOM).children("image").remove();
              }

              // Get markdown which is a child of content
              var content = this.get("content");

              if(content){
                var contentSerialized = content.updateDOM("content");

                this.addUpdatedXMLNode(objectDOM, contentSerialized);

              }
              else{
                $(objectDOM).children("content").remove();
              }

              //If nothing was serialized, return an empty string
              if( !$(objectDOM).children().length ){
                return "";
              }

              return objectDOM;

            },

            /**
            * Takes the updated XML node and inserts it into the given object DOM in
            * the correct position.
            * @param {Element} objectDOM - The full object DOM for this model
            * @param {Element} newElement - The updated element to insert into the object DOM
            */
            addUpdatedXMLNode: function(objectDOM, newElement){

              //If a parameter is missing, don't do anything
              if( !objectDOM || !newElement ){
                return;
              }

              try{
                //Get the node name of the new element
                var nodeName = $(newElement)[0].nodeName;

                if( nodeName ){

                  //Only insert the new element if there is content in it
                  if( $(newElement).children().length || $(newElement).text().length ){

                    //Add the new element to the owner Document
                    objectDOM.ownerDocument.adoptNode(newElement);

                    //Get the existing node
                    var existingNodes = $(objectDOM).children(nodeName);

                    //Get the position that the image should be
                    var insertAfter = this.getXMLPosition(objectDOM, nodeName);

                    if( insertAfter ){
                      //Insert it into that position
                      $(insertAfter).after(newElement);
                    } else {
                      objectDOM.appendChild(newElement);
                    }

                    existingNodes.remove();
                  }
                }
              }
              catch(e){
                console.log(e);
                return;
              }

            },

            /**
             * Finds the node in the given portal XML document afterwhich the
             * given node type should be inserted
             *
             * @param {Element} parentNode - The parent XML element
             * @param {string} nodeName - The name of the node to be inserted
             *                             into xml
             * @return {(jQuery|boolean)} A jQuery object indicating a position,
             *                            or false when nodeName is not in the
             *                            portal schema
            */
            getXMLPosition: function(parentNode, nodeName){

              var nodeOrder = [ "label", "title", "introduction", "image", "content", "option"];

              var position = _.indexOf(nodeOrder, nodeName);

              // First check that nodeName is in the list of nodes
              if ( position == -1 ) {
                  return false;
              };

              // If there's already an occurence of nodeName...
              if($(parentNode).children(nodeName).length > 0){
                // ...insert it after the last occurence
                return $(parentNode).children(nodeName).last();
              } else {
                // Go through each node in the node list and find the position
                // after which this node will be inserted
                for (var i = position - 1; i >= 0; i--) {
                  if ( $(parentNode).children(nodeOrder[i]).length ) {
                    return $(parentNode).children(nodeOrder[i]).last();
                  }
                }
              }

              return false;
            },

            /**
             * Overrides the default Backbone.Model.validate.function() to
             * check if this PortalSection 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");

                //--Validate the label--
                //Labels are always required
                if( !this.get("label") ){
                  errors.label = "Please provide a page name.";
                }

                //---Validate the title---
                //If section titles are required and there isn't one, set an error message
                if( requiredFields.sectionTitle &&
                    typeof this.get("title") == "string" &&
                    !this.get("title").length ){
                  errors.title = "Please provide a title for this page.";
                }

                //---Validate the introduction---
                //If section introductions are required and there isn't one, set an error message
                if( requiredFields.sectionIntroduction &&
                    typeof this.get("introduction") == "string" &&
                    !this.get("introduction").length ){
                  errors.introduction = "Please provide some a sub-title or some introductory text for this page.";
                }

                //---Validate the section content---
                //Content is always required
                if( !this.get("content") ){
                  errors.markdown = "Please provide content for this page.";
                }
                //Check if there is either markdown or an array of strings in the text attribute
                else if( !this.get("content").get("markdown") && !this.get("content").get("text").length ){
                  errors.markdown = "Please provide content for this page.";
                }
                //Check if the markdown hasn't been changed from the example markdown
                else if( this.get("content").get("markdown") == this.get("content").get("markdownExample") ){
                  errors.markdown = "Please provide content for this page.";
                }

                //---Validate the section image---

                if(requiredFields.sectionImage && (!this.get("image") || this.get("image").isEmpty())){
                  errors.sectionImage = "A section image is required."
                }

                //Return the errors object
                if( Object.keys(errors).length )
                  return errors;
                else{
                  return;
                }

              }
              catch(e){
                console.error(e);
                return;
              }

            }

          });

          return PortalSectionModel;
    });