// ==UserScript==
// @name           Multi rating graph for Codeforces
// @namespace      http://yak2.myhome.cx/
// @description    Enable to show rating history graph with other accounts on profile pages at Codeforces
// @license        http://creativecommons.org/publicdomain/zero/1.0/
// @copyright      yak_ex
// @version        1.3
// @include        https://www.codeforces.com/profile/*
// @include        https://codeforces.com/profile/*
// @include        https://www.codeforces.ru/profile/*
// @include        https://codeforces.ru/profile/*
// ==/UserScript==

// v1.3  2015/05/05 Sync with site changes.
// v1.2  2014/06/05 Autocomplete account names
//                  Keep the color of the highest dots
// v1.1  2013/03/15 Fix failure to get log-in account
//                  Version jump because Chrome recognizes 0.0x as 1.0
// v0.03 2011/04/17 Show log-in account always
// v0.02 2011/04/16 Adjust yaxis scale
//                  Warn if data can't be obtained
// v0.01 2011/04/16 Initial version

///////////////////////////////////////////////////////////////////////
//
// The following part is executed in content page scope
//

function extract_data(cont)
{
	var re1 = new RegExp('data\\.push\\(([\\S\\s]*?)\\);\\s*data\\.push\\(([\\S\\s]*?)\\);', 'm');
	return re1.test(cont) ? [RegExp.$1, RegExp.$2] : undefined;
}

function extract_scale(cont)
{
	var re2 = new RegExp('yaxis:\\s*{\\s*min:\\s*(\\d+),\\s*max:\\s*(\\d+),');
	return re2.test(cont) ? [RegExp.$1, RegExp.$2] : undefined;
}

function get_account_data(id)
{
	var xhr = new XMLHttpRequest();
	xhr.open('GET', 'https://' + window.location.host + '/profile/' + id, false);
	xhr.send(null);
	if(xhr.status == 200) {
		return [extract_data(xhr.responseText), extract_scale(xhr.responseText)];
	}
	return undefined;
}

function update_graph(input)
{
	if(input == null) return;
	var handle = window.location.href.match(/[^/]*$/);
	input = handle + ' ' + input;
	var accounts = input.split(' ');
	var check = {};
	data = new Array();
	datas = [];
	var mymin = 900, mymax = 2000;
	var idx = 0;
	for(var i = 0; i < accounts.length; ++i) {
		if(accounts[i] != '' && check[accounts[i]] == undefined) {
			check[accounts[i]] = 1;
			var d = get_account_data(accounts[i]);
			if(d != undefined && d[0] != undefined) {
				data.push(eval(d[0][0]));
				data.push(eval(d[0][1]));
				datas[2*idx] = { label: accounts[i], data: data[2*idx] };
				datas[2*idx+1] = { clickable: false, hoverable: false, color: "red", data: data[2*idx+1], points: {radius: 1} };
				++idx;
				if(d[1] != undefined) {
					if(d[1][0] < mymin) mymin = d[1][0];
					if(d[1][1] > mymax) mymax = d[1][1];
				}
			} else {
				alert("Can't get information for account: " + accounts[i] + ".");
			}
		}
	}
	if(idx == 1) {
		options.legend.position = "ne";
	} else {
		options.legend.position = "se";
	}
	options.yaxis.min = mymin;
	options.yaxis.max = mymax;
    options.yaxis.panRange = [mymin, mymax];
	plot = $.plot($("#usersRatingGraphPlaceholder"), datas, options);
	$("#usersRatingGraphPlaceholder .legend").unbind("click");
	$("#usersRatingGraphPlaceholder .legend").bind("click", account_manage);
}

function account_manage()
{
	var handle = window.location.href.match(/[^/]*$/);
	var dialog = $('<div id="account-dialog"/>').css({
		position:'fixed',padding:'5px',width:'30em',zIndex:2000,left:'50%',top:'50%',marginTop:'-3.5em',marginLeft:'-15em',
		border:'1px solid', borderRadius:'5px',background:'rgb(255,255,255)',boxShadow:'rgb(64,64,64) 5px 5px 5px'
	}).html(
		'<p>Input space-separated accounts without this account.</p>' +
		'<form id="account-form"><p><input type="text" id="accounts" size="40" value="'+(handle !=  login_account ? login_account : '')+'"></p>' +
		'<p><input type="submit" id="ok" value="OK"> <input type="button" id="cancel" value="cancel"></p></form>'
	);
	$('p', dialog).css({margin:'1em'});
	$('#cancel', dialog).click(function() {
		$('#account-dialog').remove();
		$('#account-dialog-blocker').remove();
	});
	$('#account-form', dialog).submit(function() {
		var input = $('#accounts').val();
		$('#account-dialog').remove();
		$('#account-dialog-blocker').remove();
		update_graph(input);
		return false;
	}).keydown(function(e) {
		if(e.keyCode == 27) {
			$('#cancel').click();
		}
	});
	var blocker = $('<div id="account-dialog-blocker"/>').css({
		position:'fixed',top:0,left:0,bottom:0,right:0,width:'100%',height:'100%',zIndex:15,
		background:'rgb(64,64,64)',opacity:0.75
	});
	$('body').append(blocker);
	$('body').append(dialog);
	$('#accounts').autocomplete("/data/handles", {
		delay: 200,
		width: 200,
		selectFirst: false,
		matchContains: true,
		multiple: true,
		multipleSeparator: ' ',
		minChars: 3,
		scroll: true,
	});
	$('#accounts').focus();
}

///////////////////////////////////////////////////////////////////////
//
// The following part is executed in userjs scope.
//

function add_unbind(cont)
{
	var marker = '$("#placeholder").bind("plothover"';
	return cont.replace(marker, '$("#placeholder").unbind("plothover");\n' + marker);
}

function get_login_account()
{
	var e = document.getElementById('header');
	var re3 = new RegExp('<a href="/profile/([^"]*)">[^<]*</a>[^<]*<a href="[^"]*/logout">');
	return re3.test(e.innerHTML) ? RegExp.$1 : undefined;
}

function disable_default_plot(cont)
{
	return cont.replace('var plot = $.plot($("#placeholder"), datas, options);', '').replace('var ctx = plot.getCanvas().getContext("2d");', '');
}

function add_account_manage(cont)
{
	var marker = 'var prev = -1;';
	var target = '';
	target += 'var extract_data = ' + extract_data + ';\n';
	target += 'var extract_scale = ' + extract_scale + ';\n';
	target += 'var get_account_data = ' + get_account_data + ';\n';
	var login_account = get_login_account();
	if(login_account != undefined) {
		target += 'var login_account = "' + get_login_account() + '";\n';
	} else {
		target += 'var login_account = "";\n';
	}
	target += 'options.legend = {};\n';
	target += 'var account_manage;\n';
	target += 'var update_graph = ' + update_graph + ';\n';
	target += 'account_manage = ' + account_manage + ';\n';
	target += 'update_graph(login_account);\n';
	target += '$("#placeholder .legend").unbind("click");\n';
	target += '$("#placeholder .legend").bind("click", account_manage);\n';
// CAUTION FRAGILE: monkey patch for Autocompleter to handle multiple words correctly
	target += '$(function() {\n';
	target += 'var old = $.Autocompleter;\n';
	target += 'eval("$.Autocompleter = " + (""+$.Autocompleter).replace("currentValue == q", "lastWord(currentValue) == q"));\n';
	target += '$.Autocompleter.defaults = old.defaults;$.Autocompleter.Cache = old.Cache;$.Autocompleter.Select = old.Select;\n';
	target += '});\n';

	return cont.replace(marker, target + marker);
}

function get_target_script()
{
	var e = document.getElementById('pageContent').getElementsByTagName('script');
	for(var i = 0; i < e.length; ++i) {
		if(e[i].textContent.match(/data\.push/) != null) {
			return e[i];
		}
	}
}

script = document.createElement('script');
script.setAttribute("type", "application/javascript");
script.textContent = disable_default_plot(add_account_manage(add_unbind(get_target_script().textContent)));

document.body.appendChild(script);
document.body.removeChild(script);