/* global define */
define(['jquery', 'underscore', 'backbone', 'models/filters/Filter'],
    function($, _, Backbone, Filter) {

  /**
  * @class ToggleFilter
  * @classdesc A search filter whose search term is only one of two opposing choices
  * @classcategory Models/Filters
  * @constructs ToggleFilter
  * @extends Filter
  */
	var ToggleFilter = Filter.extend(
    /** @lends ToggleFilter.prototype */{

    type: "ToggleFilter",

    /**
    * The Backbone Model attributes set on this ToggleFilter
    * @type {object}
    * @extends Filter#defaultts
    * @property {string}         trueLabel - A human-readable label for the first search term
    * @property {string}         falseLabel - A human-readable label for the second search term
    * @property {string|boolean} trueValue - The exact search value to use for search term one
    * @property {string|boolean} falseValue - The exact search value to use for search term two
    * @property {string}         nodeName - The XML node name to use when serializing this model into XML
    */
    defaults: function(){
      return _.extend(Filter.prototype.defaults(), {
        trueLabel: "On",
        trueValue: null,
        falseLabel: "Off",
        falseValue: null,
        nodeName: "toggleFilter"
      });
    },

    /*
    * Parses the ToggleFilter XML node into JSON
    *
    * @param {Element} xml - The XML Element that contains all the ToggleFilter elements
    * @return {JSON} - The JSON object literal to be set on the model
    */
    parse: function(xml){

      var modelJSON = Filter.prototype.parse.call(this, xml);

      //Parse the trueLabel and falseLabels
      modelJSON.trueLabel = this.parseTextNode(xml, "trueLabel");
      modelJSON.trueValue = this.parseTextNode(xml, "trueValue");
      modelJSON.falseLabel = this.parseTextNode(xml, "falseLabel");
      modelJSON.falseValue = this.parseTextNode(xml, "falseValue");

      //Delete any attributes from the JSON that don't exist in the XML
      if( !modelJSON.trueLabel ){
        delete modelJSON.trueLabel;
      }
      if( !modelJSON.falseLabel ){
        delete modelJSON.falseLabel;
      }
      if( !modelJSON.trueValue && modelJSON.trueValue !== false ){
        delete modelJSON.trueValue;
      }
      if( !modelJSON.falseValue && modelJSON.falseValue !== false ){
        delete modelJSON.falseValue;
      }

      return modelJSON;
    },

    /**
     * Updates the XML DOM with the new values from the model
     *  @inheritdoc
     *  @return {XMLElement} An updated toggleFilter XML element from a portal document
    */
    updateDOM: function(options){

      try{
        var objectDOM = Filter.prototype.updateDOM.call(this, options);

        if( (typeof options == "undefined") || (typeof options == "object" && this.get("isUIFilterType")) ){

          var toggleData = {
            trueValue: this.get("trueValue"),
            trueLabel: this.get("trueLabel"),
            falseValue: this.get("falseValue"),
            falseLabel: this.get("falseLabel")
          }

          // Make and append new subnodes
          _.map(toggleData, function(value, nodeName){

            // Remove the node if it exists in the DOM already
            $(objectDOM).find(nodeName).remove();

            // Don't serialize falsey or default values
            if((value || value === false) && value != this.defaults()[nodeName]){

              var nodeSerialized = objectDOM.ownerDocument.createElement(nodeName);
              $(nodeSerialized).text(value);
              $(objectDOM).append(nodeSerialized);
            }

          }, this);

          //Move the filterOptions node to the end of the filter node
        /*  var filterOptionsNode = $(objectDOM).find("filterOptions");
          filterOptionsNode.detach();
          $(objectDOM).append(filterOptionsNode);*/

        }
        //For collection definitions, serialize the filter differently
        else{
          //Remove the filterOptions
          $(objectDOM).find("filterOptions").remove();

          //Change the root element into a <filter> element
          var newFilterEl = objectDOM.ownerDocument.createElement("filter");
          $(newFilterEl).html( $(objectDOM).children() );

          //Return this node
          return newFilterEl;
        }

        return objectDOM;
      }
      //If there's an error, return the original DOM or an empty string
      catch(e){
        console.log("error updating the toggle filter object DOM, returning un-updated object DOM instead. Error message: " + e);
        return this.get("objectDOM") || "";
      }
      },
    
      /**
      * Checks if the values set on this model are valid and expected
      * @return {object} - Returns a literal object with the invalid attributes and their
      * corresponding error message
      */
      validate: function () {
        try {

          // Validate most of the ToggleFilter attributes using the parent validate
          // function
          var errors = Filter.prototype.validate.call(this);

          // If everything is valid so far, then we have to create a new object to store
          // errors
          if (typeof errors != "object") {
            errors = {};
          }

          // Delete error messages for the attributes that are going to be validated
          // specially for the ToggleFilter
          ["trueLabel", "trueValue", "falseLabel", "falseValue"].forEach(function (attr) {
            delete errors[attr]
          });

          // At least one trueValue required
          var trueValue = this.get("trueValue")
          if (!trueValue) {
            errors.trueValue = "The filter requires a term to search for when the toggle is on"
          }

          // Return the errors, if there are any
          if (Object.keys(errors).length)
            return errors;
          else {
            return;
          }
        }
        catch (error) {
          console.log(
            'There was an error validating a ToggleFilter' +
            '. Error details: ' + error
          );
        }
      },

  });

  return ToggleFilter;
});
