// ==UserScript==
// @name          Alexa rank/google pagerank
// @namespace     http://iescripts.org
// @description	  Display the website' Alexa and Google Page Rank. (Thanks to SearchStatus of FireFox)
// @statussize    160
// ==/UserScript==

(function()
 {
 var plugin = PRO_plugin(@name);
 plugin.onpagechange = handlePageChange;
 plugin.registerContextMenu("Show Google results from this site", menuShowGoogleResult);
 plugin.registerContextMenu("Show Google Related Site", menuShowGoogleRelated);
 plugin.registerContextMenu("Show Alexa Overview", menuShowAlexaOverview);
 plugin.registerContextMenu("Show Alexa Traffic Detail", menuShowAlexaTraffic);

 var gCookie = "";
 var gAlexaRank = "";
 var gGoogleRank = "";

 var reqObj = new Object();
 reqObj.request = function(callback, cookie, url, userAgent, lastModify) {
 var req;
 req = PRO_xmlhttpRequest();
 req.onreadystatechange = function() {
 if (req.readyState == 4) {// completed
 if (req.status < 400) {// only if "OK"
 try {
	 callback(true, req, cookie);
 } catch(err) {
 }
 } else {
	 // PRO_log("There was a problem loading data :\n" + req.status+ "/" + req.statusText);
	 callback(false, req, cookie);
 }
 setTimeout(function() {req.forceClean();req = null;}, 1000);
 }
 }
 try {
	 req.open("GET", url);
	 req.setRequestHeader( "User-Agent", userAgent);
	 if(lastModify.length > 0)
		 req.setRequestHeader( "If-Modified-Since", lastModify);
	 req.send(null);

 } catch(err){ 
 }
 return req;
 }

 // escape the url
 function encodeURL(url)
 {
	 return escape(url).replace(/\+/g, '%2B').replace(/\"/g, '%22').replace(/\'/g, '%27');
 }

 function menuShowGoogleResult(cookie,url) {
	 PRO_openInTab("http://google.com/search?&q=site:"+url,1);
 }

 function menuShowGoogleRelated(cookie,url) {
	 PRO_openInTab("http://www.google.com/search?q=related:"+url,1);
 }

 function menuShowAlexaOverview(cookie,url) {
	 var urlhost = url.split("/");
	 var qhost = urlhost[2];
	 PRO_openInTab("http://www.alexa.com/data/details/main?q=&url="+qhost,1);
 }

 function menuShowAlexaTraffic(cookie,url) {
	 var urlhost = url.split("/");
	 var qhost = urlhost[2];
	 PRO_openInTab("http://www.alexa.com/data/details/traffic_details?q=&url="+qhost,1);
 }


 function handlePageChange(cookie, url, state) {
	 if(state == 1) {// page loading
		 var re = /http:\/\/(.*)/i;
		 var urlhost = url.split("/");

		 var qhost = urlhost[2];
		 gCookie = cookie;
		 gAlexaRank = "";
		 gGoogleRank = "";
		 var encodeurl = encodeURL(qhost);
		 var queryurl = "http://xml.alexa.com/data?cli=10&dat=nsa&ver=quirk-searchstatus&uid=20060101000000&userip=126.12.3.4&url=" + encodeurl;
		 reqObj.request(processAlexaData, cookie, queryurl, "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; Alexa Toolbar)", "Thu, 26 Aug 2002 08:24:16 GMT");

		 var encodeurl2 = encodeURL(url);
		 var reqgr = "info:" + url;
		 var reqgre = "info:" + encodeurl2.replace( "_", "%5F" );
		 var gGoogleCHCalc = new googlechcalc();  
		 var mGoogleCH = gGoogleCHCalc.googleCH( gGoogleCHCalc.strord( reqgr ) );
		 mGoogleCH = "6" + gGoogleCHCalc.googleNewCh( mGoogleCH );
		 queryurl = "http://toolbarqueries.google.com/search?client=navclient-auto&ch=" + mGoogleCH + "&ie=UTF-8&oe=UTF-8&features=Rank&q=" + reqgre;
		 // PRO_log(queryurl);
		 reqObj.request(processGoogleData, cookie, queryurl, "User-Agent", "Mozilla/4.0 (compatible; GoogleToolbar 2.0.114-big; Windows XP 5.1)");

	 } else if(state == 2) {// page loaded
	 }
 }

 function processAlexaData(isOK, req, cookie) {
	 if(gCookie == cookie) {
		gAlexaRank = "0";
		 if(isOK) {
			try {
				var re = /POPULARITY.*TEXT=\"(\d+)\"\/\>/i;
				var alexaRank = req.responseText.match(re);
				gAlexaRank = alexaRank[1];
			} catch(e) {}
		 }
		 if(gGoogleRank.length > 0) {
			 processResult();
		 }
	 }
 }

 function processGoogleData(isOK, req, cookie) {
	if(gCookie == cookie) {
		gGoogleRank = "0";
		 if(isOK) {
			try {
				 var re = /Rank_.*?:.*?:(\d+)/i;
				 var googleRank = req.responseText.match(re);
				 gGoogleRank = googleRank[1];
			} catch(e) {}
		 }
		 if(gAlexaRank.length > 0) {
			 processResult();
		 }
	 }
 }

 function processResult()
 {
	plugin.setStatusInfo("", "Alexa:"+FormatInteger(gAlexaRank)+"  Google:" + gGoogleRank + "/10", "", gCookie);
 }

 function googlechcalc() {
	 return this; 
 }

 googlechcalc.prototype =
 {
googleNewCh: function( ch )
	     {
		     ch = ( ( ( ch / 7 ) << 2 ) | ( ( this.myfmod( ch,13 ) ) & 7 ) );

		     prbuf = new Array();
		     prbuf[0] = ch;
		     for( i = 1; i < 20; i++ ) 
		     {
			     prbuf[i] = prbuf[i-1] - 9;
		     }
		     ch = this.googleCH( this.c32to8bit( prbuf ), 80 );

		     return ch;		
	     },

googleCH: function( url ) 
	  {
		  var init = 0xE6359A60;

		  var length = url.length;

		  var a = 0x9E3779B9;
		  var b = 0x9E3779B9;
		  var c = 0xE6359A60;
		  var k = 0;
		  var len = length;
		  var mixo = new Array(); 

		  while( len >= 12 ) 
		  {
			  a += (url[k+0] +(url[k+1]<<8) +(url[k+2]<<16) +(url[k+3]<<24));
			  b += (url[k+4] +(url[k+5]<<8) +(url[k+6]<<16) +(url[k+7]<<24));
			  c += (url[k+8] +(url[k+9]<<8) +(url[k+10]<<16)+(url[k+11]<<24));
			  mixo = this.mix(a,b,c);
			  a = mixo[0]; b = mixo[1]; c = mixo[2];
			  k += 12;
			  len -= 12;
		  }

		  c += length;

		  switch( len ) 
		  {
			  case 11:
				  c += url[k+10]<<24;

			  case 10: 
				  c+=url[k+9]<<16;

			  case 9 : 
				  c+=url[k+8]<<8;

			  case 8 : 
				  b+=(url[k+7]<<24);

			  case 7 : 
				  b+=(url[k+6]<<16);

			  case 6 : 
				  b+=(url[k+5]<<8);

			  case 5 : 
				  b+=(url[k+4]);

			  case 4 : 
				  a+=(url[k+3]<<24);

			  case 3 : 
				  a+=(url[k+2]<<16);

			  case 2 : 
				  a+=(url[k+1]<<8);

			  case 1 : 
				  a+=(url[k+0]);
		  }

		  mixo = this.mix( a, b, c );

		  if( mixo[2] < 0 )
		  {
			  return ( 0x100000000 + mixo[2] );
		  }
		  else
		  {
			  return mixo[2];
		  }
	  },

hexdec: function( str )
	{
		return parseInt( str, 16 );
	},

zeroFill: function( a, b )
	  {
		  var z = this.hexdec( 80000000 );

		  if( z & a )
		  {
			  a = a >> 1;
			  a &= ~z;
			  a |= 0x40000000;
			  a = a >> ( b - 1 );
		  } 
		  else
		  {
			  a = a >> b;
		  }

		  return (a);
	  },

mix: function( a, b, c ) 
     {
	     a -= b; a -= c; a ^= ( this.zeroFill( c, 13 ) );
	     b -= c; b -= a; b ^= ( a << 8 );
	     c -= a; c -= b; c ^= ( this.zeroFill( b, 13 ) );
	     a -= b; a -= c; a ^= ( this.zeroFill( c, 12 ) );
	     b -= c; b -= a; b ^= ( a << 16);
	     c -= a; c -= b; c ^= ( this.zeroFill( b, 5 ) );
	     a -= b; a -= c; a ^= ( this.zeroFill( c, 3 ) ); 
	     b -= c; b -= a; b ^= ( a << 10);
	     c -= a; c -= b; c ^= ( this.zeroFill( b, 15 ) );

	     var ret = new Array( (a), (b), (c) );

	     return ret;
     },

strord: function( string ) 
	{
		var result = new Array();

		for( i = 0; i < string.length; i++ ) 
		{
			result[i] = string.charCodeAt( i);	
		}

		return result;
	},

c32to8bit: function( arr32 ) 
	   {
		   var arr8 = new Array();	

		   for( i = 0; i < arr32.length; i++ ) 
		   {
			   for( bitOrder = i * 4; bitOrder <= i * 4 + 3; bitOrder++ ) 
			   {
				   arr8[bitOrder] = arr32[i] & 255;
				   arr32[i] = this.zeroFill( arr32[i], 8 );
			   }
		   }

		   return arr8;
	   },

myfmod: function( x, y )
	{
		var i = Math.floor( x / y );
		return ( x - i * y );
	}
 };
 function FormatInteger( integer )
 {
	 var pattern = "###,###,###,###";
	 var result = '';

	 integerIndex = integer.length - 1;
	 patternIndex = pattern.length - 1;

	 while( ( integerIndex >= 0 ) && ( patternIndex >= 0 ) )
	 {
		 var digit = integer.charAt( integerIndex );
		 integerIndex--;

		 // Skip non-digits from the source integer (eradicate current formatting).
		 if( ( digit < '0' ) || ( digit > '9') )  continue;

		 // Got a digit from the integer, now plug it into the pattern.
		 while( patternIndex >= 0 )
		 {
			 var patternChar = pattern.charAt( patternIndex );
			 patternIndex--;

			 // Substitute digits for '#' chars, treat other chars literally.
			 if( patternChar == '#' )
			 {
				 result = digit + result;
				 break;
			 }
			 else
			 {
				 result = patternChar + result;
			 }
		 }
	 }

	 return result;
 }
 }
)();


