/* global define */
define(["jquery",
        "underscore",
        "backbone",
  "models/portals/PortalSectionModel",
  "models/maps/Map"
    ],
  function ($, _, Backbone, PortalSectionModel, Map) {

      /**
       * @class PortalVizSectionModel
       * @classdesc A Portal Section for Data Visualizations. This is still an experimental feature and not recommended for general use.
       * @classcategory Models/Portals
       * @extends PortalSectionModel
       * @private
       */
      var PortalVizSectionModel = PortalSectionModel.extend(
        /** @lends PortalVizSectionModel.prototype */{

        type: "PortalVizSection",

        defaults: function(){
          return _.extend(PortalSectionModel.prototype.defaults(), {
            sectionType: "visualization",
            visualizationType: "",
            supportedVisualizationTypes: ["fever", "cesium"]
          });
        },

        /**
         * 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 {};
          }

          //Create a jQuery object of the XML DOM
          var $objectDOM = $(objectDOM),
          //Parse the XML using the parent class, PortalSectionModel.parse()
              modelJSON  = this.constructor.__super__.parse(objectDOM);

          //Parse the visualization type
          var allOptions = $objectDOM.children("option"),
              vizType = "";

          var vizTypeNode = allOptions.find("optionName:contains(visualizationType)");
          if( vizTypeNode.length ){
            vizType = vizTypeNode.first().siblings("optionValue").text();

            //Right now, only support "fever" as a visualization type, until this feature is expanded.
            if(vizType == "fever"){
            //  modelJSON.visualizationType = "fever";
            }

            var vizTypes = this.get("supportedVisualizationTypes");
            if( Array.isArray(vizTypes) && vizTypes.includes(vizType) ){
              modelJSON.visualizationType = vizType;
            }

            // Find the map configuration JSON in the section option, if there is one.
            if (vizType == "cesium") {
              var mapConfigNode = allOptions.find("optionName:contains(mapConfig)");
              var mapConfig = {};
              if (mapConfigNode.length) {
                mapConfig = mapConfigNode.first().siblings("optionValue").text();
                if (mapConfig && mapConfig.length) {
                  mapConfig = JSON.parse(mapConfig)
                }
              }
              modelJSON.mapModel = new Map(mapConfig)
            }

          }

          return modelJSON;

        },

        /**
         *  Makes a copy of the original XML DOM and updates it with the new values from the model.
         *  For now, this function only updates the label. All other parts of Viz sections are not editable
         * in MetacatUI, since this is still an experimental feature.
         *
         *  @return {XMLElement} An updated ContentSectionType XML element from a portal document
         */
        updateDOM: function(){

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

          //Clone the DOM if it exists already
          if (objectDOM) {
            objectDOM = objectDOM.cloneNode(true);
          //Or create a new DOM
          } else {
            // create an XML section element from scratch
            var xmlText = "<section>  <content>FEVer visualization</content><option><optionName>sectionType</optionName><optionValue>visualization</optionValue>" +
                          "</option><option><optionName>visualizationType</optionName><optionValue>fever</optionValue></option></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")
          };

          _.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);

          //Make sure the content element is valid
          var contentEl = $(objectDOM).children("content");
          if( contentEl.length ){
              //If there is content in the content element
              if( contentEl[0].childNodes.length ){
                //If there is only text in the <content> element, we need to wrap it in a <markdown> element so it's schema valid
                if( contentEl[0].childNodes[0].nodeType == 3 ){
                  $(contentEl[0]).html("<markdown>" + contentEl[0].childNodes[0].textContent + "</markdown>");
                }
              }
          }

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

          return objectDOM;

        },

        /**
         * 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 = {};

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

            //---Validate the section content---
            //Content is always required, but for visualizations, we can just input dummy content
            if( !this.get("content") ){
              this.set("content", "visualization");
            }

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

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

        }


      });

      return PortalVizSectionModel;
});
