# Source: js/models/LookupModel.js

    /*global define */
    define(['jquery', 'jqueryui', 'underscore', 'backbone'],
    	function($, $ui, _, Backbone) {
    	'use strict';

    	/**
      * @class LookupModel
      * @classdesc A uttility model that contains functions for looking up values from various services
      */
    	var LookupModel = Backbone.Model.extend(
        /** @lends LookupModel.prototype */{
    		defaults: {
    			concepts: {}
    		},

    		initialize: function() {

    		},

    		bioportalSearch: function(request, response, localValues, allValues) {

    			// make sure we have something to lookup
    			if (!MetacatUI.appModel.get('bioportalAPIKey')) {
    				response(localValues);
    				return;
    			}

    			var query = MetacatUI.appModel.get('bioportalSearchUrl') +
                      "?q=" + request.term +
                      "&apikey=" + MetacatUI.appModel.get("bioportalAPIKey") +
                      "&ontologies=ECSO&pagesize=1000&suggest=true";
    			var availableTags = [];
    			$.get(query, function(data, textStatus, xhr) {

    				_.each(data.collection, function(obj) {
    					var choice = {};
    					choice.label = obj['prefLabel'];
    					var synonyms = obj['synonym'];
    					if (synonyms) {
    						choice.synonyms = [];
    						_.each(synonyms, function(synonym) {
    							choice.synonyms.push(synonym);
    						});
    					}
    					choice.filterLabel = obj['prefLabel'];
    					choice.value = obj['@id'];
    					if (obj['definition']) {
    						choice.desc = obj['definition'][0];
    					}

    					// mark items that we know we have matches for
    					if (allValues) {
    						var matchingChoice = _.findWhere(allValues, {value: choice.value});
    						if (matchingChoice) {
    							//choice.label = "*" + choice.label;
    							choice.match = true;

    							// remove it from the local value - why have two?
    							if (localValues) {
    								localValues = _.reject(localValues, function(obj) {
    									return obj.value == matchingChoice.value;
    								});
    							}
    							//availableTags.push(choice);
    						}
    					}

    					availableTags.push(choice);

    				});

    				// combine the lists if called that way
    				if (localValues) {
    					availableTags = localValues.concat(availableTags);
    				}

    				response(availableTags);

    			});
    		},

    		bioportalExpand: function(term) {

    			// make sure we have something to lookup
    			if (!MetacatUI.appModel.get('bioportalAPIKey')) {
    				response(null);
    				return;
    			}

    			var terms = [];
    			var countdown = 0;

    			var query = MetacatUI.appModel.get('bioportalSearchUrl') +
                      "?q=" + term +
                      "&apikey=" + MetacatUI.appModel.get("bioportalAPIKey") +
                      "&ontologies=ECSO&pagesize=1000&suggest=true";;
    			$.ajax(
    			{
    				url: query,
    				method: "GET",
    				async: false, // we want to wait for the response!
    				success: function(data, textStatus, xhr) {

    				_.each(data.collection, function(obj) {
    					// use the preferred label
    					var prefLabel = obj['prefLabel'];
    					terms.push(prefLabel);

    					// add the synonyms
    					var synonyms = obj['synonym'];
    					if (synonyms) {
    						_.each(synonyms, function(synonym) {
    							terms.push(synonym);
    						});
    					}
    					// process the descendants
    					var descendantsUrl = obj['links']['descendants'];
    					//if (false) {
    					if (descendantsUrl && countdown > 0) {

    						countdown--;

    						$.ajax(
    						{
    						url: descendantsUrl + "?apikey=" + MetacatUI.appModel.get("bioportalAPIKey"),
    						method: "GET",
    						async: false,
    						success: function(data, textStatus, xhr) {
    							_.each(data.collection, function(obj) {
    								var prefLabel = obj['prefLabel'];
    								var synonyms = obj['synonym'];
    								if (synonyms) {
    									_.each(synonyms, function(synonym) {
    										terms.push(synonym);
    									});
    								}
    							});
    						}
    							});
    					}
    				});
    			}
    			});
    			return terms;
    		},

    		bioportalGetConcepts: function(uri, callback) {

    			var concepts = this.get('concepts')[uri];

    			if (concepts) {
    				callback(concepts);
    				return;
    			} else {
    				concepts = [];
    			}

    			// make sure we have something to lookup
    			if (!MetacatUI.appModel.get('bioportalAPIKey')) {
    				return;
    			}

    			var query = MetacatUI.appModel.get('bioportalSearchUrl') +
                      "?q=" + encodeURIComponent(uri) +
                      "&apikey=" + MetacatUI.appModel.get("bioportalAPIKey") +
                      "&ontologies=ECSO&pagesize=1000&suggest=true";
    			var availableTags = [];
    			var model = this;
    			$.get(query, function(data, textStatus, xhr) {

    				_.each(data.collection, function(obj) {
    					var concept = {};
    					concept.label = obj['prefLabel'];
    					concept.value = obj['@id'];
    					if (obj['definition']) {
    						concept.desc = obj['definition'][0];
    					}
    					// add the synonyms
    					var synonyms = obj['synonym'];
    					if (synonyms) {
    						concept.synonyms = [];
    						_.each(synonyms, function(synonym) {
    							concept.synonyms.push(synonym);
    						});
    					}

    					concepts.push(concept);

    				});
    				model.get('concepts')[uri] = concepts;

    				callback(concepts);
    			});
    		},

    		bioportalGetConceptsBatch: function(uris, callback) {

    			// make sure we have something to lookup
    			if (!MetacatUI.appModel.get('bioportalBatchUrl')) {
    				return;
    			}
    			// prepare the request JSON
    			var batchData = {};
    			batchData["http://www.w3.org/2002/07/owl#Class"] = {};
    			batchData["http://www.w3.org/2002/07/owl#Class"]["display"] = "prefLabel,synonym,definition";
    			batchData["http://www.w3.org/2002/07/owl#Class"]["collection"] = [];
    			_.each(uris, function(uri) {
    				var item = {};
    				item["class"] = uri;
    				item["ontology"] = "http://data.bioontology.org/ontologies/ECSO";
    				batchData["http://www.w3.org/2002/07/owl#Class"]["collection"].push(item);
    			});

    			var url = MetacatUI.appModel.get('bioportalBatchUrl');
    			var model = this;
    			$.ajax(url,
    					{
    					method: "POST",
    					//url: url,
    					data: JSON.stringify(batchData),
    					contentType: "application/json",
    					headers: {
    						"Authorization": "apikey token="+ MetacatUI.appModel.get("bioportalAPIKey")
    					},
    					error: function(e) {
    						console.log(e);
    					},
    					success: function(data, textStatus, xhr) {

    						_.each(data["http://www.w3.org/2002/07/owl#Class"], function(obj) {
    							var concept = {};
    							concept.label = obj['prefLabel'];
    							concept.value = obj['@id'];
    							if (obj['definition']) {
    								concept.desc = obj['definition'][0];
    							}
    							// add the synonyms
    							var synonyms = obj['synonym'];
    							if (synonyms) {
    								concept.synonyms = [];
    								_.each(synonyms, function(synonym) {
    									concept.synonyms.push(synonym);
    								});
    							}

    							var conceptList = [];
    							conceptList.push(concept);
    							model.get('concepts')[concept.value] = conceptList;

    						});

    						callback.apply();
    					}
    				});

    		},

    		orcidGetConcepts: function(uri, callback) {

    			var people = this.get('concepts')[uri];

    			if (people) {
    				callback(people);
    				return;
    			} else {
    				people = [];
    			}

    			var query = MetacatUI.appModel.get('orcidBaseUrl')  + uri.substring(uri.lastIndexOf("/"));
    			var model = this;
    			$.get(query, function(data, status, xhr) {
    				// get the orcid info
    				var profile = $(data).find("orcid-profile");

    				_.each(profile, function(obj) {
    					var choice = {};
    					choice.label = $(obj).find("orcid-bio > personal-details > given-names").text() + " " + $(obj).find("orcid-bio > personal-details > family-name").text();
    					choice.value = $(obj).find("orcid-identifier > uri").text();
    					choice.desc = $(obj).find("orcid-bio > personal-details").text();
    					people.push(choice);
    				});

    				model.get('concepts')[uri] = people;

    				// callback with answers
    				callback(people);
    			})
    		},

    		/*
    		 * Supplies search results for ORCiDs to autocomplete UI elements
    		 */
    		orcidSearch: function(request, response, more, ignore) {

    			var people = [];

    			if(!ignore) var ignore = [];

    			var query = MetacatUI.appModel.get('orcidSearchUrl') + request.term;
    			$.get(query, function(data, status, xhr) {
    				// get the orcid info
    				var profile = $(data).find("orcid-profile");

    				_.each(profile, function(obj) {
    					var choice = {};
    					choice.value = $(obj).find("orcid-identifier > uri").text();

    					if(_.contains(ignore, choice.value.toLowerCase())) return;

    					choice.label = $(obj).find("orcid-bio > personal-details > given-names").text() + " " + $(obj).find("orcid-bio > personal-details > family-name").text();
    					choice.desc = $(obj).find("orcid-bio > personal-details").text();
    					people.push(choice);
    				});

    				// add more if called that way
    				if (more) {
    					people = more.concat(people);
    				}

    				// callback with answers
    				response(people);
    			});
    		},

    		/*
    		 * Gets the bio of a person given an ORCID
    		 * Updates the given user model with the bio info from ORCID
    		 */
    		orcidGetBio: function(options){
    			if(!options || !options.userModel) return;

    			var orcid     = options.userModel.get("username"),
    				onSuccess = options.success || function(){},
    				onError   = options.error   || function(){};

    			$.ajax({
    				url: MetacatUI.appModel.get("orcidSearchUrl") + orcid,
    				type: "GET",
    				//accepts: "application/orcid+json",
    				success: function(data, textStatus, xhr){
    					// get the orcid info
    					var orcidNode = $(data).find("path:contains(" + orcid + ")"),
    						profile = orcidNode.length? $(orcidNode).parents("orcid-profile") : [];

    					if(!profile.length) return;

    					var fullName = $(profile).find("orcid-bio > personal-details > given-names").text() + " " + $(profile).find("orcid-bio > personal-details > family-name").text();
    					options.userModel.set("fullName", fullName);

    					onSuccess(data, textStatus, xhr);
    				},
    				error: function(xhr, textStatus, error){
    					onError(xhr, textStatus, error);
    				}
    			});
    		},

    		getGrantAutocomplete: function(request, response){
                var term = $.ui.autocomplete.escapeRegex(request.term),
                	filterBy = "";

                //Only search after 3 characters or more
                if(term.length < 3) return;
                else if(term.match(/\d/)) return; //Don't search for digit only since it's most likely a user just entering the grant number directy
                else filterBy = "keyword";

                var url = MetacatUI.appModel.get("grantsUrl") + "?"  + filterBy + "=" + term + "&printFields=title,id";

    						// Send the AJAX request as a JSONP data type since it will be cross-origin
    						var requestSettings = {
    							url: url,
    							dataType: "jsonp",
    							success: function(data, textStatus, xhr) {

    								// Handle the response from the NSF Award Search API and
    								//transform each award query result into a jQueryUI autocomplete item

    								if(!data || !data.response || !data.response.award) return [];

    								var list = [];

    								_.each(data.response.award, function(award, i){
    									list.push({
    										value: award.id,
    										label: award.title
    									});
    								});

    								var term = $.ui.autocomplete.escapeRegex(request.term)
    									, startsWithMatcher = new RegExp("^" + term, "i")
    									, startsWith = $.grep(list, function(value) {
    											return startsWithMatcher.test(value.label || value.value || value);
    									})
    									, containsMatcher = new RegExp(term, "i")
    									, contains = $.grep(list, function (value) {
    											return $.inArray(value, startsWith) < 0 &&
    													containsMatcher.test(value.label || value.value || value);
    									});

    								response(startsWith.concat(contains));
    							}
    						}

    						//Send the query
    						$.ajax(requestSettings);
    		},

    		getGrant: function(id, onSuccess, onError){
    			if(!id || !onSuccess || !MetacatUI.appModel.get("useNSFAwardAPI") || !MetacatUI.appModel.get("grantsUrl")) return;

    			var requestSettings = {
    					url: MetacatUI.appModel.get("grantsUrl") + "?id=" + id,
    					success: function(data, textStatus, xhr){
    						if(!data || !data.response || !data.response.award || !data.response.award.length){
    							if(onError) onError();
    							return;
    						}

    						onSuccess(data.response.award[0]);
    					},
    					error: function(){
    						if(onError) onError();
    					}
    			}

    			//Send the query
    			$.ajax(requestSettings);
    		},

        getAccountsAutocomplete: function(request, response){
          var searchTerm = $.ui.autocomplete.escapeRegex(request.term);

          //Only search after 2 characters or more
          if(searchTerm.length < 2)
            return;

          var url = MetacatUI.appModel.get("accountsUrl") + "?query=" + searchTerm;

          // Send the AJAX request as a JSONP data type since it will be cross-origin
          var requestSettings = {
            url: url,
            success: function(data, textStatus, xhr) {

              if(!data)
                return [];

              //If an XML doc was not returned from the server, then try to parse the response as XML
              if( !XMLDocument.prototype.isPrototypeOf(data) ){
                try{
                  data = $.parseXML(data);
                }
                catch(e){
                  //If the parsing XML failed, exit now
                  console.error("The accounts service did not return valid XML.", e);
                  return;
                }
              }

              var list = [];

              _.each($(data).children(/.+subjectInfo/).children(), function(accountNode, i){

                var name = "";

                if( $(accountNode).children("givenName").length ){
                  name = $(accountNode).children("givenName").text() + " " + $(accountNode).children("familyName").text()
                }
                else{
                  name = $(accountNode).children("groupName").text();
                }

                if( !name ){
                  name = $(accountNode).children("subject").text();
                }

                list.push({
                  value: $(accountNode).children("subject").text(),
                  label: name + "  (" + $(accountNode).children("subject").text() + ")"
                });
              });

              var term = $.ui.autocomplete.escapeRegex(request.term)
                , startsWithMatcher = new RegExp("^" + term, "i")
                , startsWith = $.grep(list, function(value) {
                    return startsWithMatcher.test(value.label || value.value || value);
                })
                , containsMatcher = new RegExp(term, "i")
                , contains = $.grep(list, function (value) {
                    return $.inArray(value, startsWith) < 0 &&
                        containsMatcher.test(value.label || value.value || value);
                });

              response(startsWith.concat(contains));
            }
          }

          //Send the query
          $.ajax(requestSettings);
        },

        /**
        * Calls the monitor/status DataONE MN API and gets the size of the index queue.
        * @param {function} [onSuccess]
        * @param {function} [onError]
        */
        getSizeOfIndexQueue: function(onSuccess, onError){

          try{

            if( !MetacatUI.appModel.get("monitorStatusUrl") ){
              if( typeof onSuccess == "function" ){
                onSuccess();
              }
              else{
                //Trigger a custom event for the size of the index queue.
                this.trigger("sizeOfQueue", -1);
              }

              return false;
            }

            var model = this;

            //Check if there is an indexing queue, because this model may still be indexing
            var requestSettings = {
              url: MetacatUI.appModel.get("monitorStatusUrl"),
              type: "GET",
              error: function(){
                if( typeof onError == "function" ){
                  onError();
                }
              },
              success: function(data){

                var sizeOfQueue = parseInt($(data).find("status > index > sizeOfQueue").text());

                if(sizeOfQueue > 0 || sizeOfQueue == 0){
                  //Trigger a custom event for the size of the index queue.
                  model.trigger("sizeOfQueue", sizeOfQueue);

                  if( typeof onSuccess == "function" ){
                    onSuccess(sizeOfQueue);
                  }
                }
                else{
                  if( typeof onError == "function" ){
                    onError();
                  }
                }
              }
            }

            $.ajax(_.extend(requestSettings, MetacatUI.appUserModel.createAjaxSettings()));
          }
          catch(e){
            console.error(e);

            if( typeof onError == "function" ){
              onError();
            }

          }
        }

    	});
    	return LookupModel;
    });