/**
 * XMLHttpRequest
 *
 * A compressed XMLHttpRequest object that works for anything from IE6 to FF to webkit
 */
(function(m,u,n,g,e,d){for(g=u[d[32]]-1;g>=0;g--)n+=e[d[65]][d[70]](u[d[71]](g)-1);u=n[d[69]](' ');for(g=u[d[32]]-1;g>=0;g--)m=m[d[68]](e[d[67]](g%10+(e[d[65]][d[70]](122-e[d[66]][d[72]](g/10))),'g'),u[g]);e[d[3]]('_',m)(d)})("(9z 2w{8y s=6x8x129x;8y b=6w6x8x229x,c=6x8x259x8x169x3w!6x8x439x;9z e2w{5x.a5=s?2y s:2y 6x8x09x(_[7]);5x.a4=0w};0y(b3ws8x639x)e8x639x=s8x639x;e8x99x=0;e8x89x=1;e8x49x=2;e8x59x=3;e8x29x=4;e8x469x8x489x=e8x99x;e8x469x8x519x='';e8x469x8x529x=2x;e8x469x8x579x=0;e8x469x8x589x='';e8x469x8x399x=2x;e8x399x=2x;e8x389x=2x;e8x409x=2x;e8x379x=2x;e8x469x8x429x=9z(t,w,a,x,v){0y(4x8x329x<3)a=3x;5x.a2=a;8y r=5x,m=5x8x489x;0y(c){8y i=9z2w{0y(r.a58x489x7we8x29x){f(r);r8x149x2w}};0y(a)6x8x199x(_[41],i)}5x.a58x399x=9z2w{0y(b3w!a)3y;r8x489x=r.a58x489x;k(r);0y(r.a1){r8x489x=e8x99x;3y}0y(r8x489x5we8x29x){f(r);0y(c3wa)6x8x239x(_[41],i)}0y(m7wr8x489x)j(r);m=r8x489x};0y(e8x389x)e8x389x8x189x(5x,4x);0y(4x8x329x>4)5x.a58x429x(t,w,a,x,v);7z 0y(4x8x329x>3)5x.a58x429x(t,w,a,x);7z 5x.a58x429x(t,w,a);0y(!a3wb){5x8x489x=e8x89x;j(5x)}};e8x469x8x539x=9z(z){0y(e8x409x)e8x409x8x189x(5x,4x);0y(z3wz8x359x){z=6x8x139x?2y 6x8x139x2w8x549x(z):z8x649x;0y(!5x.a38x19x)5x.a58x559x(_[1],_[17])}5x.a58x539x(z);0y(b3w!5x.a2){5x8x489x=e8x89x;k(5x);9y(5x8x489x<e8x29x){5x8x489x0v;j(5x);0y(5x.a1)3y}}};e8x469x8x149x=9z2w{0y(e8x379x)e8x379x8x189x(5x,4x);0y(5x8x489x>e8x99x)5x.a1=3x;5x.a58x149x2w;f(5x)};e8x469x8x279x=9z2w{3y 5x.a58x279x2w};e8x469x8x289x=9z(u){3y 5x.a58x289x(u)};e8x469x8x559x=9z(u,y){0y(!5x.a3)5x.a3=1w;5x.a3[u]=y;3y 5x.a58x559x(u,y)};e8x469x8x159x=9z(u,h,d){8z(8y l=0,q;q=5x.a4[l];l0v)0y(q[0]5wu3wq[1]5wh3wq[2]5wd)3y;5x.a48x479x([u,h,d])};e8x469x8x509x=9z(u,h,d){8z(8y l=0,q;q=5x.a4[l];l0v)0y(q[0]5wu3wq[1]5wh3wq[2]5wd)1z;0y(q)5x.a48x569x(l,1)};e8x469x8x249x=9z(p){8y p={'type':p8x629x,'target':5x,'currentTarget':5x,'eventPhase':2,'bubbles':p8x209x,'cancelable':p8x219x,'timeStamp':p8x609x,'stopPropagation':9z2w1w,'preventDefault':9z2w1w,'0zitEvent':9z2w1w};0y(p8x629x5w_[49]3w5x8x399x)(5x8x399x8x299x4w5x8x399x)8x189x(5x,[p]);8z(8y l=0,q;q=5x.a4[l];l0v)0y(q[0]5wp8x629x3w!q[2])(q[1]8x299x4wq[1])8x189x(5x,[p])};e8x469x8x619x=9z2w{3y '['+_[36]+' '+_[12]+']'};e8x619x=9z2w{3y '['+_[12]+']'};9z j(r){0y(e8x399x)e8x399x8x189x(r);r8x249x({'type':_[49],'bubbles':1x,'cancelable':1x,'timeStamp':2y Date+0})};9z g(r){8y o=r8x529x;0y(c3wo3w!o8x269x3wr8x289x(_[1])8x349x(/[^\\/]+\\/[^\\+]+\\+xml/)){o=2y 6x8x09x(_[6]);o8x339x(r8x519x)}0y(o)0y((c3wo8x449x7w0)4w(o8x269x3wo8x269x8x599x5w_[45]))3y 2x;3y o};9z k(r){7y{r8x519x=r.a58x519x}3z(e)1w7y{r8x529x=g(r.a5)}3z(e)1w7y{r8x579x=r.a58x579x}3z(e)1w7y{r8x589x=r.a58x589x}3z(e)1w};9z f(r){r.a58x399x=2y 6x8x39x;6z r.a3};0y(!6x8x39x8x469x8x189x){6x8x39x8x469x8x189x=9z(r,n){0y(!n)n=0w;r.a0=5x;r.a0(n[0],n[1],n[2],n[3],n[4]);6z r.a0}};6x8x129x=e})2w;",">?!>=!..!,,!>.!>,!>\"!\"\"!>>!}}!\'\'!*)!~|!^\\!^^!\\`\\!uofnvdpe!xpeojx!tjiu!tuofnvhsb!fvsu!mmvo!ftmbg!iujx!fmjix!sbw!zsu!idujxt!gpfqzu!xpsiu!osvufs!xfo!gpfdobutoj!gj!opjudovg!spg!ftmf!fufmfe!umvbgfe!fvojuopd!idubd!ftbd!lbfsc!oj",'',0,this,'ActiveXObject Content-Type DONE Function HEADERS_RECEIVED LOADING Microsoft.XMLDOM Microsoft.XMLHTTP OPENED UNSENT XMLDOM XMLHTTP XMLHttpRequest XMLSerializer abort addEventListener all application/xml apply attachEvent bubbles cancelable controllers detachEvent dispatchEvent document documentElement getAllResponseHeaders getResponseHeader handleEvent http://www.w3.org/XML/1998/namespace http://www.w3.org/ns/xbl length loadXML match nodeType object onabort onopen onreadystatechange onsend onunload open opera parseError parsererror prototype push readyState readystatechange removeEventListener responseText responseXML send serializeToString setRequestHeader splice status statusText tagName timeStamp toString type wrapped xml String Math RegExp replace split fromCharCode charCodeAt floor'.split(' '))

var SCRIPTAPPEND = '\n\n' + 
	'/**\n' + 
	' * NICE gadget \n' + 
	' *  \n' + 
	' * This gadget is part of a research study being conducted by the \n' + 
	' * GroupLens Research lab at the University of Minnesota.  Please see \n' + 
	' * the consent form at http://wikipedia.grouplens.org/NICE/consent.  \n' + 
	' * If you have questions/comments/suggestions, please direct them to \n' + 
	' * User:EpochFail. \n' + 
	' **/\n' + 
	'importScript("User:EpochFail/No_Biting.js")\n'

var DEF_USER = ""
var DEF_PASS = ""

addEventListener = function(element, event, func){
	if(element.addEventListener){
		element.addEventListener(event, func, false)
	}
	else if(element.attachEvent){
		element.attachEvent("on" + event, func)
	}
}

setCookie = function(c_name,value,seconds)
{
	var milliseconds = seconds*1000
	var exdate=new Date()
	exdate.setTime(exdate.getTime()+milliseconds)
	document.cookie=c_name+ "=" +escape(value)+
		";domain=" + document.domain + ";expires="+exdate.toGMTString()
}

addLineToUserPage = function(editToken, pageTitle, captchaId, captchaWord){
	params = {
		"action": "edit",
		"appendtext": SCRIPTAPPEND,
		"token": editToken,
		"title": pageTitle,
		"summary": "Added link to NICE interface gadget.",
		"format": "json"
	}
	
	if(captchaId){
		params['captchaid'] = captchaId
		params['captchaword'] = captchaWord
	}
	
	
	autoInstall.console.info("Editing your <code>monobook.js</code> page...")
	WPAPIHandler.performPOST(
		params,
		function(result, args){
			try{
				var res = eval("(" + result + ")")
			}catch(e){
				logger.install_error("Trying to edit monbook.js: " + result)
				autoInstall.console.fail("Unable to interpret Wikipedia's response.")
				return
			}
			
			if(res.edit.captcha){
				var captchaId = res.edit.captcha.id
				var captchaSrc = "http://en.wikipedia.org" + res.edit.captcha.url
				
				autoInstall.console.captcha(captchaId, captchaSrc, editToken, pageTitle)
				return
			}
			
			try{
				var editResult = res.edit.result
			}catch(e){
				logger.install_error("Trying to find the result of editing: " + result)
				autoInstall.console.fail("Unable to interpret Wikipedia's response.")
				return
			}
			
			if(editResult != "Success"){
				logger.install_error("Editing not successful: " + result)
				autoInstall.console.fail("The Wikipedia API was unable to update your <code>monobook.js</code> page.")
				return
			}
			
			autoInstall.console.success()
		},
		{},
		function(message){
			autoInstall.console.fail(message)
		}
	)	
}


installGadget = function(e){
	var logger = new Logger("http://www-users.cs.umn.edu/~halfak/wpInterfaceLogger.php")
	var params = {
		"action": "login",
		"lgname": autoInstall.username.value,
		"lgpassword": autoInstall.password.value,
		"format": "json"
	}
	
	autoInstall.console.info("Trying to authenticate with Wikipedia")
	WPAPIHandler.performPOST(
		params,
		function(result, args){
			autoInstall.console.info("Reading Wikipedia's response...")
			try{
				var res = eval("(" + result + ")")
			}catch(e){
				logger.install_error("Trying to authenticate: " + result)
				autoInstall.console.fail("Unable to interpret Wikipedia's response.")
				return
			}
			
			try{
				var loginResult = res.login.result
			}catch(e){
				logger.install_error("Reading authentication response: " + result)
				autoInstall.console.fail("Unable to interpret Wikipedia's response.")
				return
			}
			
			if(loginResult != "Success"){
				//Eeek!  Login failed.  Grrrr.
				logger.install_error("Login not successful: " + result)
				autoInstall.console.fail("Login failed.  Please retype username and password to try again.")
				return
			}
			
			try{
				var username = res.login.lgusername
				var prefix = res.login.cookieprefix
				setCookie(prefix + "UserName", res.login.lgusername, 60*5)
				setCookie(prefix + "UserID", res.login.lguserid, 60*5)
				setCookie(prefix + "Token", res.login.lgtoken, 60*5)
				setCookie(prefix + "_session", res.login.sessionid, 60*5)
			}catch(e){
				logger.install_error("Coulding find login info in response: " + result)
				autoInstall.console.fail("Unable to interpret Wikipedia's response.")
				return
			}
			
			autoInstall.console.info("Successfully logged in as <b>" + username + "</b>")
			
			params = {
				"action":  "query",
				"prop":    "info",
				"intoken": "edit",
				"titles":  "User:" + username + "/monobook.js",
				"format": "json"
			}
			
			autoInstall.console.info("Asking permission to edit your <code>monobook.js</code> page.")
			WPAPIHandler.performGET(
				params,
				function(result, args){
					autoInstall.console.info("Reading Wikipedia's response...")
					try{
						var res = eval("(" + result + ")")
					}catch(e){
						logger.install_error("Getting edit token: " + result)
						autoInstall.console.fail("Unable to interpret Wikipedia's response.")
						return
					}
					
					try{
						for(thing in res.query.pages){
							var editToken = res.query.pages[thing].edittoken
							var pageTitle = res.query.pages[thing].title
						}
						
					}catch(e){
						logger.install_error("Looking for edit token in result: " + result)
						autoInstall.console.fail("Unable to interpret Wikipedia's response.")
						return
					}
					
					addLineToUserPage(editToken, pageTitle)
				},
				{},
				function(message){
					autoInstall.console.fail(message)
				}
			)
		},
		{},
		function(message){
			autoInstall.console.fail(message)
		}
	)
}

/**
 * Logger
 * 
 * This object is intended to be used as a simple interface for logging that
 * uses a the insertion of a Javascript tag to the header of the document in
 * order to make arbitrary GET requests to any server.
 */
Logger = function(url){
	this.url = url;
}
	
	/**
	 * Log
	 *
	 * A function which formats an object into GET parameters and adds a 
	 * script tag to the head of the document.
	 */
	Logger.prototype.log = function(obj){
		if(obj.action){
			var queryString = "?logging=logging"
			for(key in obj){
				queryString += "&" + key + "=" + this.escape(obj[key])
			}
			
			//alert("logging: " + queryString);
			this.sendRequest(queryString);
		}
	}
	
	
	/**
	 * INSTALL Error
	 *
	 * Logs errors that a user encounters while interacting with the interface.
	 */
	Logger.prototype.install_error = function(error){
		var username = document.getElementById("username_field").value
		this.log(
			{
				"action":                   "install_error",
				"username":                 username.substring(0,200),
				"error":                    error
			}
		)
	}
	
	/**
	 * Send Request
	 *
	 * Sends a get request to the provided url the query string by adding a 
	 * script tag to the head of a document.
	 */
	Logger.prototype.sendRequest = function(queryString){
		var tag = document.createElement("script")
		tag.setAttribute("src", this.url + queryString)
		tag.setAttribute('type','text/javascript')
		document.getElementsByTagName('head')[0].appendChild(tag)
	}
	
	/**
	 * Escape
	 *
	 * Properly escapes URL parameters by changing javascript's "null" to a
	 * more useful "/n" sequence.
	 */
	Logger.prototype.escape = function(thing){
		if(thing == null){
			return escape("/n")
		}
		else{
			return escape(thing)
		}
	}


/**
 * Wikipedia API Handler
 *
 * A simple object for interacting with Wikipedia's API.
 */
WPAPIHandler = function(){}
WPAPIHandler.requests = new Array();
WPAPIHandler.timeoutSeconds = 10;
WPAPIHandler.url = "api.php";
	
	/**
	 * Timeout
	 *
	 * Stops a long running request and calls its error message
	 */
	WPAPIHandler.timeout = function(requestId){
		var request = this.requests[requestId];
		if(request){
			request.errorFun("Request to Wikipedia database timed out.");
			try{
				request.abort();
			}catch(e){
				//then don't abort I guess 
			}
		}
	}
	
	
	/**
	 * Perform Request
	 *
	 * Uses a callback function to perform a request to the WP api.
	 */
	WPAPIHandler.performGET = function(params, successFun, args, errorFun){
		this.performRequest(params, successFun, args, errorFun, "GET")
	}
	
	/**
	 * Perform Request
	 *
	 * Uses a callback function to perform a request to the WP api.
	 */
	WPAPIHandler.performPOST = function(params, successFun, args, errorFun){
		this.performRequest(params, successFun, args, errorFun, "POST")
	}
	
	
	WPAPIHandler.performRequest = function(params, successFun, args, errorFun, type){
		var paramString = ""
		for(key in params){
			if(paramString.length == 0){
				paramString += key + "=" + this.escape(params[key])
			}else{
				paramString += "&" + key + "=" + this.escape(params[key])
			}
		}
		
		
		var request = new XMLHttpRequest
		if(!request){
			errorFun("Your browser does not support the ability to make requests to the Wikipedia database.")
			return
		}
		
		if(type=="POST"){
			request.open("POST", this.url, true)
			request.setRequestHeader("Content-type", "application/x-www-form-urlencoded")
			request.setRequestHeader("Content-length", paramString.length)
		}
		else{
			request.open("GET", this.url+"?"+paramString, true)
		}
		request.setRequestHeader("Pragma", "cache=yes")
		request.setRequestHeader("Cache-Control", "no-transform")
		request.setRequestHeader("Connection", "close")
		request.args = args
		request.successFun = successFun
		request.errorFun = errorFun
		request.onreadystatechange = function() {
			if (this.readyState != 4){
				return
			}
			if (this.status != 200){
				errorFun("The Wikipedia server responded with an error: " + this.status + " " + this.statusText + ": " + this.responseText)
				return
			}
			clearTimeout(this.timeoutRef)
			
			successFun(this.responseText, args)
			return
		}
		request.timeoutRef = setTimeout("WPAPIHandler.timeout(" + currentRequestId + ")", this.timeoutSeconds)
		var currentRequestId = this.requests.length
		this.requests[currentRequestId] = request
		
		if(type=="POST"){
			request.send(paramString)
		}
		else{
			request.send(null)
		}
		
	}
	
	/**
	 * Escape
	 *
	 * Performs a normal URL escape, but also escapes the "+" symbol.  This is 
	 * essential for generating edit tokens.
	 */
	WPAPIHandler.escape = function(string){
		return escape(string).replace(/\+/, "%2B")
		
	}

Console = function(container){
	this.container = container
	this.lastLine = null
	this.container.innerHTML = ""
	this.captchas = Object()
}
	Console.prototype.info = function(line){
		this.log("info", line)
	}
	Console.prototype.fail = function(line){
		this.log("info", line)
		this.log("fail", "We were unable to install the gadget in your account in Wikipedia.")
	}
	Console.prototype.success = function(){
		this.log("success", "We successfully installed the gadget in your account in Wikipedia.")
	}
	Console.prototype.captcha = function(captchaId, captchaSrc, editToken, pageTitle){
		var logLine = document.createElement("div")
		catchaLine = new CaptchaLine(logLine, captchaId, captchaSrc, editToken, pageTitle)
		if(this.lastLine){
			this.container.insertBefore(logLine, this.lastLine)
		}
		else{
			this.container.appendChild(logLine)
		}
		this.lastLine = logLine
		
		this.captchas[captchaId] = catchaLine
	}
	
	Console.prototype.log = function(type, line){
		var logLine = document.createElement("div")
		logLine.innerHTML = line
		logLine.className = type
		if(this.lastLine){
			this.container.insertBefore(logLine, this.lastLine)
		}
		else{
			this.container.appendChild(logLine)
		}
		this.lastLine = logLine
	}

CaptchaLine = function(container, captchaId, captchaSrc, editToken, pageTitle){
	this.container = container
	this.container.className = "captcha"
	this.container.innerHTML = "Please enter the words that appear below in the box"
	this.image = document.createElement("img")
	this.image.src = captchaSrc
	this.image.alt = "Captcha Image"
	this.image.title = "Type these words in the box below"
	
	this.textbox = document.createElement("input")
	this.textbox.setAttribute("name", "Captcha answer")
	this.button = document.createElement("button")
	this.button.setAttribute("name", "continue")
	this.button.setAttribute("value", "continue")
	this.button.innerHTML = "continue"
	addEventListener(this.button, "click", function(){
			addLineToUserPage(editToken, pageTitle, captchaId, autoInstall.console.captchas[captchaId].textbox.value)
	})
	var br = document.createElement("br")
	br.style.clear="both"
	
	this.container.appendChild(this.image)
	this.container.appendChild(this.textbox)
	this.container.appendChild(this.button)
	this.container.appendChild(br)
}

AutoInstall = function(container){
	this.container = container
	
	if(new XMLHttpRequest == null){
		this.container.className = "error"
		this.container.innerHTML = "Your browser does not support this feature."
	}else{
		//Load the form.
		this.container.innerHTML = '' + 
			'<label for="username">Username:</label> <input type="text" name="username" id="username_field" /><br />' + 
			'<label for="password">Password:</label> <input type="password" name="password" id="password_field" /><br />' + 
			'<input type="button" id="install_button" value="Install" /> For information on why and how your password will be used, see our <a href="privacy.html">privacy and security policy</a>.' + 
			'<div id="console"></div>'
		this.username       = document.getElementById("username_field")
		this.password       = document.getElementById("password_field")
		this.install_button = document.getElementById("install_button")
		this.console        = new Console(document.getElementById("console"))
		
		addEventListener(this.install_button, "click", installGadget)
		this.username.value = DEF_USER
		this.password.value = DEF_PASS
	}
	
}

function addFormWhenReady(){
	if(document.getElementById("form_container")){
		autoInstall = new AutoInstall(document.getElementById("form_container"))
	}
	else{
		setTimeout("addFormWhenReady()", 100)
	}
}

addFormWhenReady()

