// ==UserScript==
// @name           dActive
// @namespace      Zikes
// @description    Lists active deviants in dAmn
// @include        http://*.deviantart.com/*
// ==/UserScript==

// Get deviant's username
var deviant=unsafeWindow.deviantART.deviant.username;

// Get elements by xpath
function $x(xpath,root){
	var got=document.evaluate(xpath,root||document,null,null,null), result=[];
	while(next=got.iterateNext()) result.push(next);
	return result;
}

// Samy is my hero
var friends=GM_getValue('friends','Zikes').split(',');
// So is Tom

// For later
var readout;

// Retrieve hash key
var hash=GM_getValue("hashKey", false);
if(hash===false){
	registerDeviant();
}

// Prototype-like $ function for getting elements by ID
var $=function(id){
	if(typeof(id)=='string'){
		return document.getElementById(id);
	}else{
		return id;
	}
}

// Custom element building function
var $E=function(nodeName, properties, children){
	function applyProps(obj, props){
		for(prop in props) if(props.hasOwnProperty(prop)){
			if(prop=='events'){
				for(evt in props[prop]) if(props[prop].hasOwnProperty(evt)){
					node.addEventListener(evt, props.events[evt], true);
				}
			}else if(typeof(props[prop])=='object'){
				applyProps(obj[prop], props[prop]);
			}else{
				if(obj==node && prop!=='className'){
					node.setAttribute(prop, props[prop]);
				}else{
					obj[prop]=props[prop];
				}
			}
		}
	}

	var node=document.createElement(nodeName);
	for(var x=1; x<arguments.length; x++){
		if(typeof(arguments[x])=='object' && !(arguments[x] instanceof Array)){
			applyProps(node, arguments[x]);
		}else if(typeof(arguments[x])=='object' && !!(arguments[x] instanceof Array)){
			for(var y=0; y<arguments[x].length; y++){
				if(typeof(arguments[x][y])=='string'){
					node.appendChild(document.createTextNode(arguments[x][y]));
				}else{
					node.appendChild(arguments[x][y]);
				}
			}
		}
	}
	return node;
}

// Returns an array list of rooms deviant is currently in
function getRooms(){
	var out=[];
	if(unsafeWindow.dAmnChats){
		var aryChats=unsafeWindow.dAmnChats;
		for(prop in aryChats) if(aryChats.hasOwnProperty(prop)){
			out.push(prop.split(':')[1]);
		}
	}
	return out;
}

// Submits an optional list of rooms to server.  If no list is provided, it will grab using getRooms
function submitRooms(aryRooms){
	aryRooms=getRooms();
	
	var url="http://www.jasonwhutchinson.com/dAmn/update/"+deviant+"/"+hash+"/"+aryRooms.join(';');
	
	GM_log('Submitted rooms: '+aryRooms.join(', '));
	
	GM_xmlhttpRequest({
		method:"GET",
		url:url
	});
}

// Register and get yer hashKey
function registerDeviant(){
	GM_xmlhttpRequest({
		method:"GET",
		url:"http://www.jasonwhutchinson.com/dAmn/register/"+deviant,
		onload:function(response){
			if(response.status==200 && response.readyState==4){
				if(response.responseText.indexOf("Error:")==-1){
					GM_setValue("hashKey", response.responseText);
					hash=response.responseText;
					submitRooms();
				}else{
					alert("dActive "+response.responseText);
				}
			}
		}
	});
}

// For case-insensitive sorting
var ci=function(a,b){if(a.toLowerCase()>b.toLowerCase()){return 1}else{return -1}};

// Makin' the link
$x('//div[@id="logindock"]/div/div')[0].appendChild(
	$E('span',{className:'glink gspecial friendsmenu',style:{paddingRight:'104px',right:'210px'}},[
		$E('span',[
			$E('a',
				{
					id:'top-dActive', 
					className:'dockrocker', 
					href:'',
					popup:'dActive',
					style:{height:'100%'},
					events:{
						click:function(evt){
							evt.preventDefault();
							var el=evt.target;

							friends=GM_getValue('friends', 'Zikes').split(',');

							var url="http://jasonwhutchinson.com/dAmn/get/"+friends.sort(ci).join(';');
							if(readout){
								readout.innerHTML='Loading...';
							}

							if(!el.className.match(/popup\-active/i)){
								el.className+=' popup-active';
								GM_xmlhttpRequest({
									method:"GET",
									url:url,
									onload:function(response){
										if(response.status==200 && response.readyState==4){
											if(response.responseText.indexOf("Error:")==-1){
												readout.innerHTML='';
												var ul=$E('ul');
												readout.appendChild(ul);
												var obj=eval("("+response.responseText+")");
												var odd=true;
												for(friend in obj) if(obj.hasOwnProperty(friend)){
													var status='offline';

													var prop=obj[friend];

													if(typeof(prop)=='string'){
														if(prop=='Unregistered'){
															status='unregistered';
														}
													}else{ // It's an array
														if(prop.length>0){
															status='online';
														}
													}
													ul.appendChild($E('li',{className:(odd ? 'odd' : 'even')},[
														$E('span',{className:'status status-'+status},[status]),
														$E('a',{className:'friend'},[friend]),
														$E('span',{className:'message'},(function(ary){
															var out=[];
															if(typeof(ary)=='string'){
																if(ary=='Unregistered'){
																	out.push($E('span',{className:'error'},['This deviant does not have dActive, you should invite them to try it!']))
																}
															}else{
																ary.forEach(function(room,idx,ary){
																	if(idx>0){out.push(document.createTextNode(', '))}
																	out.push($E('a',{
																		href:'http://chat.deviantart.com/chat/'+room,
																		events:{
																			click:function(evt){
																				if(unsafeWindow.dAmn_Join){
																					evt.preventDefault();
																					unsafeWindow.dAmn_Join('chat:'+room);
																					unsafeWindow.Modals.pop();
																				}
																			}
																		}
																	},['#'+room]));
																});
															}
															return out;
														})(obj[friend])),
													]));
													odd=!odd;
												}
											}else{
												alert("dActive "+response.responseText);
											}
										}
									}
								});
							}
						}
					}
				},
				[
					$E('span',{className:'i'}),
					'dActive',
					$E('span',{className:'arrow'})
				]
			)
		])
	])
);

//HIJACKIN' ZE DEVIAN TART CODE
unsafeWindow.Popup.clicks['dActive']={
	create:function(popup, link){
		readout=$E('div',{className:'readout'},['Loading...']);
		
		return $E(
			'div',{className:'friendmachine dActive'},
			[
				$E('div',{className:'dActive-top'},[
					$E(
						'a',
						{
							className:'right',
							href:'',
							events:{
								click:function(evt){
									evt.preventDefault();
									var remFriends=prompt('Friends to remove (separate by commas)','').replace(/\s/g,'').split(',');
									var newFriends=[];
									friends.forEach(function(friend1){
										var remove=false;
										remFriends.forEach(function(friend2){
											if(friend2.toLowerCase()==friend1.toLowerCase()){
												remove=true;
											}
										});
										if(!remove){
											newFriends.push(friend1);
										}
									});
									friends=newFriends.sort(ci);
									GM_setValue('friends', friends.join(','));
								}
							}
						},[
							"Remove Friends"
						]
					),
					$E(
						'a',
						{
							className:'left',
							href:'',
							events:{
								click:function(evt){
									evt.preventDefault();
									var addFriends=prompt('Friends to add (separate by commas)','').replace(/\s/g,'').split(',');
									var newFriends=[];
									addFriends.forEach(function(friend1){
										var has=false;
										friends.forEach(function(friend2){
											if(friend2.toLowerCase()==friend1.toLowerCase()){
												has=true;
											}
										});
										if(!has){
											newFriends.push(friend1);
										}
									});
									friends=friends.concat(newFriends).sort(ci);
									GM_setValue('friends', friends.join(','));
								}
							}
						},[
							"Add Friends"
						]
					)
				]),
				readout,
				$E('div',
					{className:'dActive-bottom'},
					[
						// Pimpin'
						$E('a',{href:'http://zikes.deviantart.com'},['Zikes']),
						' was here.'
					]
				)
			]
		);
	}
};

// Custom stylin'
var styles=[
	"#top-dActive{width:105px; right:229px; cursor:pointer !important}",
	
	"#top-dActive.popup-active, #top-dActive.popup-active:hover{background-color:#AFC81C !important; color:#384112 !important;}",
	"#top-55 #top-deviant a#top-dActive.popup-active span.arrow{background-position:-73px -435px !important}",
	"#top-55 #top-deviant a#top-dActive.popup-active span.i{background-position:0px -435px !important}",
	
	"body.chatroom #top-dActive{right:205px}",
	
	"#top-55 #top-deviant a#top-dActive span.i{background-position:0px -381px}",
	"#top-55 #top-deviant a#top-dActive:hover span.i{background-position:0px -408px}",
	
	"#top-55 #top-deviant a#top-dActive span.arrow{background-position:-73px -381px;}",
	"#top-55 #top-deviant a#top-dActive:hover span.arrow{background-position:-73px -408px}",

	".dActive-top{width:100%; padding-top:6px;}",
	".dActive-top .left{color:#FFF !important; float:left; padding-left:6px;}",
	".dActive-top .right{color:#FFF !important; float:right; padding-right:6px;}",
	
	".dActive-bottom{position:absolute; bottom:0; color:#FFF; width:100%; text-align:center; padding-bottom:8px}",
	".dActive-bottom a{color:#FFF !important; text-decoration:none;}",

	".dActive .readout ul{margin:0; padding:0; list-style-type:none;}",
	".dActive .readout ul li{display:block; padding:1px 5px; clear:both;}",
	".dActive .readout ul li.even{background:#DADADA}",

	".dActive .readout ul li .status{float:right;}",
	".dActive .readout ul li .status-offline{color:#D00; font-weight:bolder;}",
	".dActive .readout ul li .status-unregistered{color:darkorange; font-weight:bolder;}",
	".dActive .readout ul li .status-online{color:#090; font-weight:bolder;}",

	".dActive .readout ul li a.friend{display:block;}",
	".dActive .readout ul li .message{display:none;}",
	".dActive .readout ul li:hover .message{display:block;}"
];
GM_addStyle(styles.join('\n'));

if(location.href.match(/.*chat.deviantart.com\/chat\/.+/)){
	window.setTimeout(submitRooms, 10000); // Give it a few seconds
	
	window.setInterval(submitRooms, 1000*60*5); // DO IT AGAIN
}
