//=========================================================================================================
function RemoteDataProvider(sUrl) {
    this.iActiveRequests = 0;
    this.sUrl = sUrl;
}

//-------------------------------------------------------------------------------------------------------------
RemoteDataProvider.prototype.GetHttpObj = function() {
    var oHttpObj = null;
    try {
        oHttpObj = new ActiveXObject("Msxml2.XMLHTTP");
    } catch(e) {
        try {
            oHttpObj = new ActiveXObject("Microsoft.XMLHTTP")
        } catch(oc) {
            oHttpObj = null;
        }
    }
    if (!oHttpObj && typeof XMLHttpRequest != "undefined") {
        oHttpObj = new XMLHttpRequest();
    }
    return oHttpObj; 
}

//-------------------------------------------------------------------------------------------------------------
RemoteDataProvider.prototype.Request = function(sRequest) {
    var oHttpObj = this.GetHttpObj();
    if (null == oHttpObj) return;

    
    var sURL = this.sUrl + "?" + sRequest;        //alert(sURL);
    this.iActiveRequests++;
    var oThis = this;
    oHttpObj.onreadystatechange = function () {
        if (oHttpObj.readyState == 4 && oHttpObj.status == 200) {
            oThis.onSuccess(oHttpObj);
            oThis.iActiveRequests--;    
            oThis.onStop();    
        } else if(oHttpObj.readyState == 4 && oHttpObj.status != 200) {
            oThis.onError(oHttpObj);
            oThis.iActiveRequests--;    
            oThis.onStop();    
        }
    };
    
    if (oHttpObj.readyState != 0) oHttpObj.abort();
    this.onStart();
    oHttpObj.open("get", sURL, true);
//    oHttpObj.setRequestHeader('Cache-Control', 'no-cache'); 
    oHttpObj.send(null);
}

//-------------------------------------------------------------------------------------------------------------
RemoteDataProvider.prototype.onSuccess = function(obj) {
    alert(["success:", this.iActiveRequests, obj.responseText]);
}

//-------------------------------------------------------------------------------------------------------------
RemoteDataProvider.prototype.onStart = function() {
//    alert(["start:", this.iActiveRequests]);
}

//-------------------------------------------------------------------------------------------------------------
RemoteDataProvider.prototype.onStop = function() {
//    alert(["start:", this.iActiveRequests]);
}

//-------------------------------------------------------------------------------------------------------------
RemoteDataProvider.prototype.onError = function(obj) {
    //alert(["error:", this.iActiveRequests, obj.status]);
}

//
// AccnLookup binds together three UI elements:
//  - db: an input whose value is the sequence type (nucleotide or protein)
//  - seq: a textarea whose value contains the accession to look up 
//  - title: an input whose value is *set* to the appropriate title text
//          when the server returns it
//
// Each time seq loses focus, the AccnLookup object tries to identify a title for the
// sequence in seq:
//  [1] If there's a defline (starting with ">"), then its content is the title
//  [2] If there's an accession or gi (defined by the regular expressions in AccnLookup), the
//      AccnLookup issues a call to the server-side CGI "seqdesc.cgi", passing the database
//      name and the accession or gi.  seqdesc.cgi must be in the same directory as
//      the original file (or CGI) from which the current request came. (The
//      URL is relative to ".")
//  [3] No title was found (FIXME: add code to count residues and use residue count)
//
// seqdesc.cgi returns a JSON object that contains either:
//    A successful title fetch; the JSON object contains the results of an esummary
//    call for the requested accessions; for example:
//        {
//             'caption': 'X65215',
//             'title': 'B.taurus microsatellite DNA (624bp)',
//             'extra': 'gi|555|emb|X65215.1|BTMISATN[555]',
//             'gi': '555',
//             'createdate': '1992/06/15',
//             'updatedate': '1992/06/15',
//             'flags': '0',
//             'taxid': '9913',
//             'status': 'live',
//             'replacedby': '',
//             'comment': ''
//        }
//
//    An error object, indicated by the presence of a property "err":
//        {
//             'err': 'AccessionNotFound',
//             'msg': '123123: No such accession in database nucleotide'
//        }
//
// In either case, when the callback from the server arrives, AccnLookup calls
// its receive() method, passing the received JavaScript object (reconstituted
// from JSON notation) to the method.
//

AccnLookup = function(seq, title, db) {
   var oThis = this;
   this.seq = seq;
   this.title = title;
   this.db = db;
   this.prevTitle = title.value;

   // Lookup title when user leaves field
   utils.addEvent(this.seq, "blur", function(e) {
      oThis.sync();
   }, false);

   // Create remote data provider for seqdesc.cgi
   this.rdp = new RemoteDataProvider("seqdesc.cgi");

   this.rdp.onSuccess = function(obj) {
      oThis.receive(eval("(" + obj.responseText + ")"));
   };

   this.rdp.onFailure = function(obj) {
      //debug("XMLHTTP failure: " + obj.responseText);
   }
}

AccnLookup.prototype = {

   receive: function(obj) {     
     if (obj.title) {
        this.setTitle(obj.caption + ":" + obj.title);
     }
     if (obj.err) {
		//Do not show error message
        //alert(obj.msg);
     }
   },
   getSeqLength: function() {     
     var lwalpha = "abcdefghijklmnopqrstuvwxyz";
     var upalpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
     var length = 0;
     for(i=0;i < this.seq.value.length; i++) {
        var ch = this.seq.value.charAt(i);
        if(upalpha.indexOf(ch,0) != -1 || lwalpha.indexOf(ch,0) != -1) {
            length++;
        }
     }
     return length;
     
   }, 
   setTitle: function(s) {
   //Limit title to not more than 40 chars
	if(s.length > 40) {
		var words = s.split(" ");
		s = "";
		for(i=0;i < words.length;i++) {		
			if(i) {
				s += " ";
			}
			s += words[i];
			if(s.length > 40) {
				if(i != words.length -1) {
					s += "..."
				}
				break;
			}
		}
	  }
      this.title.value = s;
   },

   // Figure out title and assign it.
   sync: function() {

      // Ignore if seq is blank
      if (!/[^\s]/mi.exec(this.seq.value)) { return; }

      // Defline?      	      
      var match = /^\s*\>\s*(.[^$]*)$/mi.exec(this.seq.value);
      if (match) {		 		 
		 var seqList = match[1].split(">");		 
		 if(seqList.length > 0) {
		    var firstSeq = seqList[0].split("\n");						
			if(firstSeq.length > 1) {//nothing after ">" if length =1			
			    var defline = firstSeq[0];
			    //if more than one sequnce
			    title = (seqList.length > 1) ? seqList.length + " sequences (" + defline + ")" : defline;
			    this.setTitle(title);
			    return;				
			}
		}		
      }

      // OK, get first word that looks like a gi or an accession
      // This is three alternate RE's:
      // ^\s*[a-z]+\|([0-9]+|[A-Za-z][A-Za-z0-9_.]+[0-9]+): a line that starts with foo|(gi or accession)
      // ^\s*([A-Za-z][A-Za-z0-9_.]+[0-9]+): a line that starts with an accession
      // ^\s*(\d+)\b: a line that starts with an integer (probably gi)
      //if (match = /^\s*[a-z]+\|([0-9]+|[A-Za-z][A-Za-z0-9_.]+[0-9]+)|^\s*([A-Za-z][A-Za-z0-9_.]+[0-9]+)|^\s*(\d+)\b/mi.exec(this.seq.value)) {
      var accnTerm = "";
      
      match = /^\s*([A-Za-z][A-Za-z0-9_.]+[0-9]+)/mi.exec(this.seq.value);
      if(match) {
         accnTerm = " [accn]";         
      }
      else match = /^\s*[a-z]+\|([0-9]+|[A-Za-z][A-Za-z0-9_.]+[0-9]+)|^\s*(\d+)\b/mi.exec(this.seq.value);
      if(match) {
         var firstWord = match[1] ? match[1] : match[0];
         this.rdp.Request("db=" + this.db.value + "&term=" + firstWord + accnTerm);
         return;
      }
         
      //debug("No title");      
      /*var length = this.getSeqLength();      
      var res = this.db.value + " " + "sequence " + " " + length;
      res += this.db.value == "nucleotide" ? " bp" : " aa";
      
      this.setTitle(res);*/      
   }
}

