//TODO cross browser xml support removed. see nczXMLDOMWrapper.js for wrapping Mozilla xml functions with IE style
var sDataFileName = "avatar";
var xmlBlankDataControl = '<?xml version="1.0" encoding="UTF-16"?><oDataControls schemaVersion="2"></oDataControls>';

function cast(obj,type){
	//TODO this a rather simplistic version, it should support more types.
	switch(type){
		case "string":
			return obj.toString();
		case "number":
			return parseFloat(obj);
		case "boolean":
		    return obj.toString().toLowerCase()=="true";
		default:
			//return "";
			//case "undefined","function","object":
		break;
	}
}


///////////////////////////////////////////////////////////////////////////
//	oWindow object
///////////////////////////////////////////////////////////////////////////
function oWindow(name,xx,yy,ww,hh,top,act,minw,minh,intask,dock){
	this.name = name;
	this.x = xx;

	this.y = yy;
	this.w = ww;
	this.h = hh;
	this.docked = dock;
	this.top = top;
	this.active = act;
	if(minw && minw > 0){this.minWidth = minw;}else{minw = 0;}
	if(minh && minh > 0){this.minHeight = minh;}else{minh = 0;}
	this.inTaskbar = intask;

	//these don't need to be in the contructor params
	this.querystring = " ";
	this.maximized = false;
	this.size = 3;
	
	try{
		if(typeof(document.body.offsetWidth) != "undefined"){
			this.clientHeight = document.body.offsetWidth;
			this.clientWidth = document.body.offsetHeight;
		}else{
			this.clientHeight = window.innerWidth;
			this.clientWidth = window.innerHeight;
		}
	}catch(e){
		this.clientHeight = window.innerWidth;
		this.clientWidth = window.innerHeight;
	}
}

///////////////////////////////////////////////////////////////////////////
//	oUser object
///////////////////////////////////////////////////////////////////////////
function oUser(uname,def,version,currentoutfit,csettings,cwsettings){
	this.FBConnected = 0;
	this.versionNumber = 0;
	this.currentOutfit = 0;
	this.username = "";
	this.gender = "";
	this.chatSettings = "";
	this.cwSettings = "";
	this.interstVer = 0;
	this.species = "";
	this.zBucks = 0;
	this.numPrchItms = -1;
	this.prevZchiveLvl=0;
	this.desktopSettings = "";
	this.nuqGamesCashinCount = 0;
	this.nuqChatNavigateCount = 0;
	if(version > 0){this.versionNumber = version;}
	if(currentoutfit > 0){this.currentOutfit = currentoutfit;}
	if(uname){this.username = uname;}
	if(def){this.gender = def;}
	if(csettings) {this.chatSettings = csettings;}
	if(cwsettings) {this.cwSettings = cwsettings;}
	
}

///////////////////////////////////////////////////////////////////////////
//	oDataControl object
///////////////////////////////////////////////////////////////////////////
function oDataControl(){
	//window objects
	this.windowWardrobe = new oWindow();
	this.windowDesktop = new oWindow();
	this.windowAvatar = new oWindow();
	this.windowLogin = new oWindow();
	this.windowChat = new oWindow();

	//user objects
	this.currentUser = new oUser();
		
	//Default values of the above objects set here
	//moved out of constructor for readability.
	this.initialize();
	
	//application flags
	this.flagInternetCheck = true;
	this.flagStartMinimized = false;
	this.lastLogin = 0;
	this.lastPing = 0;
	this.schemaVersion = 2;


	//Used so as not to have to examine the object
	this.arrWindowParams = ["clientWidth", "clientHeight",  "clientWidth",  "clientHeight",  "size",  "maximized",  "querystring",  "inTaskbar",  "minHeight",  "minWidth",  "active",  "top",  "docked",  "h",  "w",  "y",  "x",  "name"];
	this.arrUserParams = ["chatSettings", "cwSettings", "currentOutfit", "gender", "FBConnected", "versionNumber", "username","interstVer","species","numPrchItms","prevZchiveLvl","desktopSettings","nuqGamesCashinCount","nuqChatNavigateCount"];
	this.arrDataControlParams = ["flagInternetCheck", "flagStartMinimized", "lastLogin", "lastPing", "schemaVersion"];
	this.arrChildren = [
						["oUser","currentUser",this.currentUser,this.arrUserParams],
						["oWindow","windowWardrobe",this.windowWardrobe,this.arrWindowParams],
						["oWindow","windowDesktop",this.windowDesktop,this.arrWindowParams],
						["oWindow","windowChat",this.windowChat,this.arrWindowParams],
						["oWindow","windowAvatar",this.windowAvatar,this.arrWindowParams],
						["oWindow","windowLogin",this.windowLogin,this.arrWindowParams]
					   ];

	//Used to reduce number of writes
	this.xmlDoc = null;
}
oDataControl.prototype.createXMLDoc = function(){
	var bFound = false;
	if(!this.xmlDoc){
		if(window.ActiveXObject){
			var ARR_ACTIVEX = [ "MSXML2.DOMDocument","MSXML4.DOMDocument", "MSXML3.DOMDocument", "MSXML.DOMDocument", "Microsoft.XmlDom"];
			for (var i=0; i < ARR_ACTIVEX.length && !bFound; i++) {
				try {
					//try to create
					this.xmlDoc = new ActiveXObject(ARR_ACTIVEX[i]);
					this.xmlDoc.async=false;
					bFound = true                
				}catch(e){}
			}
		}
	}	
}
oDataControl.prototype.loadXML = function(strXml){
	//Init xmldoc, if needed
	this.createXMLDoc();
	//attempt to load string, or blank if fails
	//if(window.ActiveXObject){ //Firefox need diff load
	this.xmlDoc.loadXML(strXml);
	if(this.xmlDoc.parseError.errorCode !== 0){this.xmlDoc.loadXML(xmlBlankDataControl);}
	//}
	
	//Check this is in the correct schema, ish
	var nodeDataControls = this.xmlDoc.selectSingleNode("/oDataControls");
	if(!nodeDataControls){
		//Discard this xml, why is it here?, or should we save it??
		//save existing, we need /oDataControls as the root element
		var str = this.xmlDoc.xml;
		//reset 
		this.xmlDoc.loadXML(xmlBlankDataControl);
		//readd existing
		nodeDataControls = this.xmlDoc.selectSingleNode("/oDataControls");
		var elem = this.xmlDoc.createElement("oLegacyDataControl");

		elem.text = str;

		nodeDataControls.appendChild(elem);
	}
};

oDataControl.prototype.write = function(){
	//Write out current datacontrol from memory to Datacontrol filestore
	return oDataCntrl.SetData(this.xmlDoc.xml);
};
oDataControl.prototype.save = function(){

	//Save user's settings to the user's datastore
	if(this.currentUser && this.currentUser.username){
		this.saveUser(this.currentUser.username);
	}

	//Save user's settings to the default datastore
	//This is kinda bad, we should reset the app when we load a user's data??
	//   but it implements a "Current User" object
	this.saveUser("");

};

oDataControl.prototype.saveUser = function(uname){

	var nodeDataControls = this.xmlDoc.selectSingleNode("/oDataControls");

	//select user's datastore
	var nodeDataControlUser = nodeDataControls.selectSingleNode("oDataControl[@name='"+uname+"']");

	//If user's node doesn't exists, create a new one
	if(!nodeDataControlUser){
		nodeDataControlUser = nodeDataControls.appendChild(this.xmlDoc.createElement("oDataControl"));
		nodeDataControlUser.setAttribute("name",uname);
	}

	//Save user's user and window objects
	//Loop through arrChildren(oUser,oWindow,oWindow, etc)
	var i = this.arrChildren.length - 1;
	do{
		var arr = this.arrChildren[i];
		var key = arr[0];
		var nm = arr[1];
		var obj = arr[2];
		var arrParams = arr[3];
		var nodeObject = nodeDataControlUser.selectSingleNode(key+"[@name='"+nm+"']");
		if(!nodeObject){
			nodeObject = nodeDataControlUser.appendChild(this.xmlDoc.createElement(key));
			nodeObject.setAttribute("name",nm);
		}
		
		//Loop through child attributes of oUser/oWindow
		var j = arrParams.length - 1;
		do{
			var namej = arrParams[j];
			var nodej = nodeObject.selectSingleNode(namej);
			if(!nodej){nodej = nodeObject.appendChild(this.xmlDoc.createElement(namej));}
			try{
				nodej.text = obj[namej].toString();
			}catch(e){}
			if(namej == "querystring"){
				//hackdaddy - why does this be set to undefined? does mal set it to null?
				nodej.setAttribute("type","string");
			}else{
				nodej.setAttribute("type",typeof(obj[namej]));
			}
		}while(j--);
	}while(i--);
	
	//Save user's other data.
	var k = this.arrDataControlParams.length - 1;
	do{
		var namek = this.arrDataControlParams[k];
		var nodek = nodeDataControlUser.selectSingleNode(namek);
		if(!nodek){
			nodek = nodeDataControlUser.appendChild(this.xmlDoc.createElement(namek));
			nodek.setAttribute("type",typeof(this[namek]));
		}
		nodek.text = this[namek];
		
	}while(k--);
};


oDataControl.prototype.load = function(){
	this.loadUser();
};

oDataControl.prototype.loadUser = function(uname){
	var nodeDataControls = this.xmlDoc.selectSingleNode("/oDataControls");
	if(!nodeDataControls){return;} //no data to load
	if(!uname){
		var nodeCurUser = this.xmlDoc.selectSingleNode("/oDataControls/oDataControl[@name='']/oUser/username");
		if(!nodeCurUser){return;} //no data to load
		uname = nodeCurUser.text;
	}
	var xpDataControlUser ="oDataControl[@name='"+uname+"']";

	//select user's node
	var nodeDataControlUser = nodeDataControls.selectSingleNode(xpDataControlUser);
	if(!nodeDataControlUser){return;} //no data to load

	//load user's user object,
	//load user's window objects
	var i = this.arrChildren.length - 1;
	do{
		var arr = this.arrChildren[i];
		var key = arr[0];
		var nm = arr[1];
		var obj = arr[2];
		var arrParams = arr[3];

		var nodeObject = nodeDataControlUser.selectSingleNode(key+"[@name='"+nm+"']");
		if(nodeObject){
		
			var j = arrParams.length - 1;
			do{
				var namej = arrParams[j];
				var nodej = nodeObject.selectSingleNode(namej);
				if(namej=="username"){obj[namej]="";}
				if(nodej){
					obj[namej] = cast(nodej.text,nodej.getAttribute("type"));
				}
			}while(j--);
		}
	}while(i--);


	// Load user's other data.
	var k = this.arrDataControlParams.length - 1;
	do{
		var namek = this.arrDataControlParams[k];
		var nodek = nodeDataControlUser.selectSingleNode(namek);
		if(nodek){
			this[namek] = cast(nodek.text,nodek.getAttribute("type"));
		}
	}while(k--);

};


//Initialise objects to default values. Rather important as they're not initialised elsewhere
oDataControl.prototype.initialize = function(){

	var ww = 0;
	var hh = 0;
	var xx = 0;
	var yy = 0;
	var wxx = window.screen.availWidth;
	var wyy = window.screen.availHeight;

	//window objects
	//oWindow(name,xx,yy,ww,hh,cWidth,cHeight,top,act,minw,minh,intask,dock)
	//Wardrobe
	ww = 870;
	hh = 570;
	xx = 0;
	yy = 0;
	this.windowWardrobe = new oWindow("Wardrobe", xx,yy,ww,hh,false,true,870,570,true,"none");

	//Avatar
	ww = 246; //226+20
	hh = 331; //263+68
	xx = 0;
	yy = Math.floor(wxx - (hh * 2));
	this.windowAvatar = new oWindow("Avatar", xx,yy,ww,hh,true,true,-1,-1,false,"none");

	//Login
	ww = 480;
	hh = 420;
	xx = wxx - ww;
	yy = wyy - hh;
	this.windowLogin = new oWindow("Login", xx,yy,ww,hh,false,false,ww,hh,true,"none");
	
	//Chat Module
	this.windowChat = new oWindow("Chat", 0,0,wxx,wyy,false,true,360,311,true,"none");

	//Desktop Module
	this.windowDesktop = new oWindow("Desktop", 50,50,wxx - 100,wyy - 100,false,true,360,311,true,"none");
};

//Function to switch datastores
function updateDataUser(newUser){
	//Load from user's data store in data control
	oData.currentUser.username = newUser.username;
	oData.loadUser(oData.currentUser.username);

	//Set timestamp 
	var now = new Date();
	oData.lastLogin = now.getTime();

	//Update the prefs to match any values set in newUser
	for(key in newUser){
		if(key != "username"){
			try{
				//you can NOT have the number 0 in here 
				if(newUser[key]){oData.currentUser[key] = newUser[key];}
			}catch(e){}
		}
	}
	oData.currentUser.username = "";
	oData.currentUser.username = newUser.username;

	//write changes
	oData.save();
	oData.write();
}

//function to detect Datacontrol in Mozilla
function findPlugin(pMimeType){
	navigator.plugins.refresh(false);
	var numPlugins = navigator.plugins.length;
	for (var i = 0; i < numPlugins; i++) {
		var plugin = navigator.plugins[i];
		var numTypes = plugin.length;
        for (var j = 0; j < numTypes; j++) {
            if (plugin[j] && plugin[j].type == pMimeType) {
                	return true;
            }//end if
        }//end for
	}//end for
	return false;
}

/**** public functions ****/
/**
Add your own function named dataChangedCB (CallBack)
to handle specific updates need for datafile updates.
*** Also remember to call initData! ***
function dataChangedCB(){
	var iCurVer = oData.currentUser.versionNumber;
	updateData();
	if(oData.currentUser.versionNumber!=iCurVer){updateAvatar();}		
}
**/
if(window.ActiveXObject){
	document.write('<object CLASSID="clsid:25560540-9571-4D7B-9389-0F166788785A" id="DataControl" width="1" height="1" style="display:none;"></object>');
}else{
	if (findPlugin("application/x-mws-mywebsearchplugin")) {
		document.write("<embed id='DataControl' type='application/x-mws-mywebsearchplugin' ProgId='FunWebProducts.DataControl' style='display: none;'></embed>");		
	}
}

//Preferences Object
var oData = new oDataControl();
//DataControl ActiveX Object
var oDataCntrl=document.getElementById('DataControl');

//Global functions
function initData(){
	try{
		oDataCntrl.DataFileName = sDataFileName;
		try{oDataCntrl.OnDataChanged = dataChangedCB;}catch(e){}//Only if dataChangeDB available	
		try{
			updateData();
		}catch(ex){
			s = oDataCntrl.GetData();
			oDataCntrl.DataFileName = "corrupt";
			oDataCntrl.SetData(s);

			oDataCntrl.DataFileName = sDataFileName;
			oDataCntrl.SetData("");

			oData = new oDataControl();
		}
	}catch(e){}//blows on firefox
}

function updateData(){
	oData.loadXML(oDataCntrl.GetData());
	oData.load();
}
function setData(){
	oData.save();
	oData.write();
}