# Source: src/js/views/metadata/EMLPartyView.js

    /* global define */
    define(['underscore', 'jquery', 'backbone', 'models/metadata/eml211/EMLParty',
            'text!templates/metadata/EMLParty.html'],
        function(_, $, Backbone, EMLParty, EMLPartyTemplate){

            /**
              @class EMLPartyView
              @classdesc  The EMLParty renders the content of an EMLParty model
              @classcategory Views/Metadata
              @extends Backbone.View
            */
            var EMLPartyView = Backbone.View.extend(
              /** @lends EMLPartyView.prototype */{

              type: "EMLPartyView",

              tagName: "div",

              className: "row-fluid eml-party",

              editTemplate: _.template(EMLPartyTemplate),

              initialize: function(options){
                if(!options)
                  var options = {};

                this.isNew = options.isNew || (options.model? false : true);
                this.model = options.model || new EMLParty();
                this.edit  = options.edit  || false;

                this.$el.data({ model: this.model });

              },

              events: {
                "change"             : "updateModel",
                "focusout"          : "showValidation",
                "keyup .phone"      : "formatPhone",
                "mouseover .remove" : "previewRemove",
                "mouseout .remove"  : "previewRemove"
              },

              render: function(){

                //Format the given names
                var name = this.model.get("individualName") || {},
                  fullGivenName = "";

                //Take multiple given names and combine into one given name.
                //TODO: Support multiple given names as an array
                if (Array.isArray(name.givenName)) {
              fullGivenName = _.map(name.givenName, function(name) {
                  if(typeof name != "undefined" && name)
                    return name.trim();
                  else
                    return "";
                }).join(' ');
            }
                else
                  fullGivenName = name.givenName;

                //Get the address object
                var address = Array.isArray(this.model.get("address"))?
                        (this.model.get("address")[0] || {}) : (this.model.get("address") || {});

                //Use the template with the editing elements if this view has the "edit" flag on
                if(this.edit){

                  //Send all the EMLParty info to the template
                  this.$el.html(this.editTemplate({
                    uniqueId   : this.model.cid
                  }));

                  //Populate the form with all the EMLParty values
                  this.$("#" + this.model.cid + "-givenName").val(fullGivenName || "");
                  this.$("#" + this.model.cid + "-surName").val(name.surName || "");
                  this.$("#" + this.model.cid + "-position").val(this.model.get("positionName") || "");
                  this.$("#" + this.model.cid + "-organizationName").val(this.model.get("organizationName") || "");
                  this.$("#" + this.model.cid + "-email").val(this.model.get("email").length? this.model.get("email")[0] : "");
                  this.$("#" + this.model.cid + "-website").val(this.model.get("onlineUrl").length? this.model.get("onlineUrl")[0] : "");
                  this.$("#" + this.model.cid + "-phone").val(this.model.get("phone").length? this.model.get("phone")[0] : "");
                  this.$("#" + this.model.cid + "-fax").val(this.model.get("fax").length? this.model.get("fax")[0] : "");
                  this.$("#" + this.model.cid + "-orcid").val(Array.isArray(this.model.get("userId"))? this.model.get("userId")[0] : this.model.get("userId") || "");
                  this.$("#" + this.model.cid + "-address").val(address.deliveryPoint && address.deliveryPoint.length? address.deliveryPoint[0] : "");
                  this.$("#" + this.model.cid + "-address2").val(address.deliveryPoint && address.deliveryPoint.length > 1? address.deliveryPoint[1] : "");
                  this.$("#" + this.model.cid + "-city").val(address.city || "");
                  this.$("#" + this.model.cid + "-state").val(address.administrativeArea || "");
                  this.$("#" + this.model.cid + "-zip").val(address.postalCode || "");
                  this.$("#" + this.model.cid + "-country").val(address.country || "");
                }

                //If this EML Party is new/empty, then add the new class
                if(this.isNew){
                  this.$el.addClass("new");
                }

                //Save the view and model on the element
                this.$el.data({
                  model: this.model,
                  view: this
                });

                this.$el.attr("data-category", this.model.get("type"));

                return this;
              },

              updateModel: function(e){
                if(!e) return false;

                //Get the attribute that was changed
                var changedAttr = $(e.target).attr("data-attribute");
                if(!changedAttr) return false;

                //Get the current value
                var currentValue = this.model.get(changedAttr);

                //Addresses and Names have special rules for updating
                switch(changedAttr){
                  case "deliveryPoint":
                    this.updateAddress(e);
                    return;
                  case "city":
                    this.updateAddress(e);
                    return;
                  case "administrativeArea":
                    this.updateAddress(e);
                    return;
                  case "country":
                    this.updateAddress(e);
                    return;
                  case "postalCode":
                    this.updateAddress(e);
                    return;
                  case "surName":
                    this.updateName(e);
                    return;
                  case "givenName":
                    this.updateName(e);
                    return;
                  case "salutation":
                    this.updateName(e);
                    return;
                }

                //Update the EMLParty model with the new value
                if(Array.isArray(currentValue)){
                  //Get the position that this new value should go in
                  var position = this.$("[data-attribute='" + changedAttr + "']").index(e.target);

                  if( $(e.target).val() == "" ){
                    //Remove the current value from the array if there is no value in the input field
                    currentValue.splice(position, 1);
                  }
                  else{

                    var emlModel = this.model.getParentEML(),
                        value = $(e.target).val();

                    if( emlModel ){
                      value = emlModel.cleanXMLText(value);
                    }

                    //Put the new value in the array at the correct position
                    currentValue[position] = value;
                  }

                  this.model.set(changedAttr, currentValue);

                  this.model.trigger("change:" + changedAttr);
                  this.model.trigger("change");
                }
                else{
                  //If the value of the input field is nothing, then reset the field
                  if( $(e.target).val() == "" ){
                    this.model.set(changedAttr, this.model.defaults()[changedAttr]);
                  }
                  else{

                    var emlModel = this.model.getParentEML(),
                        value = $(e.target).val();

                    if( emlModel ){
                      value = emlModel.cleanXMLText(value);
                    }

                    this.model.set(changedAttr, value);
                  }
                }

                //If this is a new EML Party, add it to the parent EML211 model
                if(this.isNew){
                  var mergeSuccess = this.model.mergeIntoParent();

                  //If the merge was sucessfull, mark this as not new
                  if( mergeSuccess  )
                     this.notNew();
                }

                //If this EMLParty model has been removed from the parent EML model,
                //then add it back
                if( this.model.get("removed") ){
                  var position = this.$el.parent().children(".eml-party").index(this.$el);
                  this.model.get("parentModel").addParty(this.model);
                  this.model.set("removed", false);
                }

                this.model.trickleUpChange();

              },

              updateAddress: function(e){
                if(!e) return false;

                //Get the address part that was changed
                var changedAttr = $(e.target).attr("data-attribute");
                if(!changedAttr) return false;

                //TODO: Allow multiple addresses - right now we only support editing the first address
                var address = this.model.get("address")[0] || {},
                  currentValue = address[changedAttr];

                //Get the parent EML model and the value from the input element
                var emlModel = this.model.getParentEML(),
                    value = $(e.target).val();

                //If there is a parent EML model, clean up the text for XML
                if( emlModel ){
                  value = emlModel.cleanXMLText(value);
                }

                //Update the address
                if(Array.isArray(currentValue)){
                  //Get the position that this new value should go in
                  var position = this.$("[data-attribute='" + changedAttr + "']").index(e.target);

                  //Put the new value in the array at the correct position
                  currentValue[position] = value;
                }
                //Make sure delivery points are saved as arrays
                else if(changedAttr == "deliveryPoint"){
                  address[changedAttr] = [value];
                }
                else
                  address[changedAttr] = value;

                //Update the model
              var allAddresses = this.model.get("address");
              allAddresses[0] = address;
              this.model.set("address", allAddresses);

              //If this is a new EML Party, add it to the parent EML211 model
              if(this.isNew){
                var mergeSuccess = this.model.mergeIntoParent();

                //If the merge was sucessfull, mark this as not new
                if( mergeSuccess  )
                   this.notNew();
              }

              //If this EMLParty model has been removed from the parent EML model,
              //then add it back
              if( this.model.get("removed") ){
                var position = this.$el.parent().children(".eml-party").index(this.$el);
                this.model.get("parentModel").addParty(this.model);
                this.model.set("removed", false);
              }

              //Manually trigger the change event since it's an object
                this.model.trigger("change:address");
                this.model.trigger("change");

                this.model.trickleUpChange();
              },

              updateName: function(e){
                if(!e) return false;

                //Get the address part that was changed
                var changedAttr = $(e.target).attr("data-attribute");
                if(!changedAttr) return false;

                //TODO: Allow multiple given names - right now we only support editing the first given name
                var name = this.model.get("individualName") || {},
                currentValue = String.prototype.trim(name[changedAttr]);

                //Get the parent EML model and the value from the input element
                var emlModel = this.model.getParentEML(),
                    value = $(e.target).val().trim();

                //If there is a parent EML model, clean up the text for XML
                if( emlModel ){
                  value = emlModel.cleanXMLText(value);
                }

                //Update the name
                if(Array.isArray(currentValue)){

                  //Get the position that this new value should go in
                  var position = this.$("[data-attribute='" + changedAttr + "']").index(e.target);

                  //Put the new value in the array at the correct position
                  currentValue[position] = value;

                }
                else if(changedAttr == "givenName"){
                  name.givenName = value;
                }
                else
                  name[changedAttr] = value;

                //Update the value on the model
                this.model.set("individualName", name);

                //If this is a new EML Party, add it to the parent EML211 model
                if(this.isNew){
                  var mergeSuccess = this.model.mergeIntoParent();

                  //If the merge was sucessfull, mark this as not new
                  if( mergeSuccess  )
                     this.notNew();
                }

                //If this EMLParty model has been removed from the parent EML model,
                //then add it back
                if( this.model.get("removed") ){
                  var position = this.$el.parent().children(".eml-party").index(this.$el);
                  this.model.get("parentModel").addParty(this.model);
                  this.model.set("removed", false);
                }

                //Manually trigger a change on the name attribute
                this.model.trigger("change:individualName");
                this.model.trigger("change");

                this.model.trickleUpChange();
              },

                /**
                 * Validates and displays error messages for the persons' name, position
                 * and organization name.
                 *
                 */
              showValidation: function() {

                //Remove the error styling
                this.$(".notification").empty();
                    this.$(".error").removeClass("error");

                    // Check if there are values to validate
                    if( this.isEmpty() ) {

                        //Remove this EMLParty model from it's parent model instead
                        //of showing a validation error, since it's completely empty
                        this.model.removeFromParent();

                        return;

                    }
                    //If the model is valid, exit
                    else if (this.model.isValid()) {
                        return;
                    }
                    else{
                      //Start the full error message string for all the EMLParty errors
                      var errorMessages = "";

                      //Iterate over each field that has a validation error
                      _.mapObject( this.model.validationError, function(errorMsg, attribute){

                        //Find the input element for this attribute and add the error styling
                        this.$("[data-attribute='" + attribute + "']").addClass("error");

                        //Add this error message to the full error messages string
                        errorMessages += errorMsg + " ";

                      }, this);

                    //Add the full error message text to the notification area and add the error styling
                    this.$(".notification").text(errorMessages).addClass("error");

                   }
                },

                /**
                 * Checks if the user has entered any data in the fields.
                 *
                 * @return {bool} True if the user hasn't entered any party info, otherwise returns false
                 */
                isEmpty: function() {

                    // If we add any new fields, be sure to add the data-attribute here.
                    var attributes = ["country", "city", "administrativeArea", "postalCode", "deliveryPoint","userId",
                                      "fax", "phone", "onlineUrl", "email", "givenName", "surName", "positionName", "organizationName"];

                     for(var i in attributes) {
                        var attribute = "[data-attribute='"+attributes[i]+"']";
                        if(this.$(attribute).val() != "")
                            return false;
                     }

                     return true;
                },

              // A function to format text to look like a phone number
              formatPhone: function(e){
                      // Strip all characters from the input except digits
                      var input = $(e.target).val().replace(/\D/g,'');

                      // Trim the remaining input to ten characters, to preserve phone number format
                      input = input.substring(0,10);

                      // Based upon the length of the string, we add formatting as necessary
                      var size = input.length;
                      if(size == 0){
                              input = input;
                      }else if(size < 4){
                              input = '('+input;
                      }else if(size < 7){
                              input = '('+input.substring(0,3)+') '+input.substring(3,6);
                      }else{
                              input = '('+input.substring(0,3)+') '+input.substring(3,6)+' - '+input.substring(6,10);
                      }

                      $(e.target).val(input);
              },

              previewRemove: function(){
                this.$("input, img, label").toggleClass("remove-preview");
              },

              /**
               * Changes this view and its model from -new- to -not new-
               * "New" means this EMLParty model is not referenced or stored on a
               * parent model, and this view is being displayed to the user so they can
               * add a new party to their EML (versus edit an existing one).
               */
              notNew: function(){
                this.isNew = false;

                this.$el.removeClass("new");
                this.$el.find(".new").removeClass("new");
              }
            });

            return EMLPartyView;
        });