//-----------------------------------------------------
// ©2007 Ecliptic Code, INC. All rights reserved.
//-----------------------------------------------------
function Left(str, n){
	    if (n <= 0)
	        return "";
	    else if (n > String(str).length)
	        return str;
	    else
	        return String(str).substring(0,n);
    }
    function Right(str, n){
        if (n <= 0)
           return "";
        else if (n > String(str).length)
           return str;
        else {
           var iLen = String(str).length;
           return String(str).substring(iLen, iLen - n);
            }
    }
	
	

function ATB_DataService()
{
   this.ATB_DEBUG = true;
   var ATB_XML;
   var ATB_OBJ;
   
   var self;
   
   this.IsIE = false;
   this.UserData = new UserData();
   
   
   var host = window.location.hostname;
   
   var subdir = (host.indexOf("allterrainbrain.org") == -1) ? "/atbweb" : "";
   
   this.PostURL = "http://"+host+subdir+"/db.aspx?"; //WebDev Local Var
   

   this.Init = function(){  
      self = this;
      if( parent.navigator.appVersion.indexOf('MSIE') > 0 ) this.IsIE = true;
      HandlePageLoad();
   }
	
   this.Init();
 	
   this.sendData = function(url, data){
	  ATB_OBJ.open('POST', url, false);
      ATB_OBJ.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
      ATB_OBJ.send(data);
	}

   this.Login = function(username, password){
      var DataToSend;
      var PostOp = 'Login';
            
      try{
         DataToSend = "username=" + username + "&password=" + password;
         this.sendData(this.PostURL+PostOp,DataToSend);
		   var result = ATB_OBJ.responseText;
		   
		   if(ATB_OBJ.status != 200){
		      self.UserData.IsAuthenticated = false;
              self.UserData.CompletedCode   = "0";
              self.UserData.ErrorMessage    = ATB_OBJ.statusText;
		    return this.UserData;
		   }
		     
		   //Parse the Results. Note the Branch for browser types. Yes got to love the locked down specifications.
		   if(this.IsIE) {  
		      ATB_XML.loadXML(result);
		      FillUserData();
		   }else{
		      var parser = new DOMParser();
		      ATB_XML = parser.parseFromString(result,'text/xml');
		      FillUserData();
		   }
		   
		   if(true && this.UserData.IsAuthenticated){
		      //Update the Session
		    	result = this.UpdateSession();
		   }
		   
		   //return our newly retrieved User
		   return this.UserData;
      }catch(ex){  
         //alert('Error Thrown');
         this.UserData.IsAuthenticated = false;
         this.UserData.CompletedCode   = "0";
         this.UserData.ErrorMessage = ex.message;
			
         HandleError('ATB_DataService.Login', ex);
         return this.UserData;
      }
   }
   
   
   this.emailPassword=function(username,email){
		var DataToSend;
		var PostOp = 'LOOKUPUSER';
		
		try{
			//Save the User
			//Configure the Header information to send to the webservice.
			DataToSend = "UserName="+username+"&Email="+email;
			//Open the XMLHTTP object and send the info.
			this.sendData( this.PostURL+PostOp,DataToSend);
			
			//Retrieve the XML Results.
			var result = ATB_OBJ.responseText;
		}
		catch(ex){
			HandleError('ATB_DataService.emailPassword', ex);
		}
		
		return result;
		
		
      //need to update the session information
   }
	/**
	* updates the session values for this user....
	*/
	this.UpdateSession = function(){
		var SessionURL = "ATBSessonMgr.aspx";
		DataToSend = "action=SaveUser&data=" + self.UserData.EncodedString();
		this.sendData( SessionURL,DataToSend);
		return ATB_OBJ.responseText;
	}
	this.UpdateSession2 = function(udata){
	    self.UserData = udata;
		var SessionURL = "ATBSessonMgr.aspx";
		DataToSend = "action=SaveUser&data=" + self.UserData.EncodedString();
		this.sendData( SessionURL,DataToSend);
		return ATB_OBJ.responseText;
	}
		/**
	*
	*Logs the user out
	*
	*/
	
		this.LogoutUser = function(){
		var SessionURL = "ATBSessonMgr.aspx";
		DataToSend = "action=LogoutUser&data=";
		this.sendData( SessionURL,DataToSend);
		return ATB_OBJ.responseText;
	}
	
	
	
	
	/**
	*
	*
	*
	*/
   this.UpdateUser = function(udata)
   {
      var DataToSend;
      var PostOp = 'UpdateUser';
      var completedcode;
	  
	  completedcode = udata.CompletedCode;
	  completedcode = Right(completedcode,25);
	  udata.CompletedCode = completedcode;
      self.UserData = udata;
      
      try{
         //Save the User
         //Configure the Header information to send to the webservice.
         DataToSend = "udata=" + udata.toString();
         //Open the XMLHTTP object and send the info.
		 this.sendData( this.PostURL+PostOp,DataToSend);
         
	   //Retrieve the XML Results.
	   var result = ATB_OBJ.responseText;
      }
      catch(ex)
      {
         HandleError('ATB_DataService.UpdateUserData', ex);
      }
      
      result += this.UpdateSession2(udata);
	  return result;
      //need to update the session information
   }

   this.UpdateUserProgress = function(udata)
   {
      var DataToSend;
      var PostOp = 'UpdateUserProgress';
      var s;
      var completedcode;
	  
	  completedcode = udata.CompletedCode;
	  completedcode = Right(completedcode,25);
	  udata.CompletedCode = completedcode;
	  self.UserData = udata;
      try
      {
         //Save the User
         //Configure the Header information to send to the webservice.
			s = "<udata>";
			s += "  <UserName>"+udata.UserName+"</UserName>";
			s += "  <IsAuthenticated>"+udata.IsAuthenticated+"</IsAuthenticated>";
			s += "  <CompletedCode>"+completedcode+"</CompletedCode>";
			s += "  <ErrorMessage>"+udata.ErrorMessage+"</ErrorMessage>";
			s += "  <Bucks>"+udata.Bucks+"</Bucks>";
			s += "</udata>";
			
         DataToSend = "udata=" + s;
         //alert("UpdateUserProgress data = "+DataToSend);
         
         this.sendData( this.PostURL+PostOp,DataToSend);
         
	   //Retrieve the XML Results.
	   var result = ATB_OBJ.responseText;
		
	   //alert('Results: ' + result);
      } catch(ex) {
         HandleError('ATB_DataService.UpdateUserProgress', ex);
      }
      
      this.UpdateSession2(udata);
      //need to update the session information
   }
	

   this.CreateUser = function(fname, lname, uname, email, password)
   {
      var DataToSend;
      var PostOp = 'create';
      //var PostURL = 'http://localhost/ATBWeb/ATBDataService.asmx/CreateUser';
      
      try
      {
         //Create the User [Include simulating login]
         
         //Configure the Header information to send to the webservice.
         DataToSend = "FirstName=" + "FirstName";
         DataToSend += "&LastName=" + "LastName";
         DataToSend += "&UserName=" + uname;
         DataToSend += "&Email=" + email;
         DataToSend += "&Password=" + password;
         
         //alert(DataToSend);
         
         //Open the XMLHTTP object and send the info.
			this.sendData( this.PostURL+PostOp,DataToSend);
         
		   //Retrieve the XML Results.
		   var result = ATB_OBJ.responseText;
		   
		   //Parse the Results. Note the Branch for browser types. Yes got to love the locked down specifications.
		   if(this.IsIE)
		   {  
		      ATB_XML.loadXML(result);
		      FillUserData();
		   }
		   
		   else
		   {
		      var parser = new DOMParser();
		      ATB_XML = parser.parseFromString(result,'text/xml');
		      FillUserData();
		   }
		   
			
		   if(true && this.UserData.IsAuthenticated){
		     //update session
			  var result = this.UpdateSession();
		   }
		   //return our newly retrieved User
		   return this.UserData;
      }
      catch(ex)
      {
         HandleError('CreateUser',ex);
      }
   }
   

   function FillUserData()
   {  
      try
      {
		  self.UserData.ErrorMessage    = ATB_XML.getElementsByTagName("ErrorMessage")[0].childNodes[0].nodeValue;
		  if (self.UserData.ErrorMessage.indexOf("Duplicate entry") != -1){
			  alert("That username is already taken");
		  }else {
			self.UserData.IsAuthenticated = ATB_XML.getElementsByTagName("IsAuthenticated")[0].childNodes[0].nodeValue.toLowerCase() == 'true' ? true : false;
			self.UserData.CompletedCode   = ATB_XML.getElementsByTagName("CompletedCode")[0].childNodes[0].nodeValue+"";
			self.UserData.ErrorMessage    = ATB_XML.getElementsByTagName("ErrorMessage")[0].childNodes[0].nodeValue;
			
			if(self.UserData.IsAuthenticated)
			{
			self.UserData.UserName        = ATB_XML.getElementsByTagName("Name")[0].childNodes[0].nodeValue;
			self.UserData.FirstName       = ATB_XML.getElementsByTagName("FirstName")[0].childNodes[0].nodeValue;
			self.UserData.LastName        = ATB_XML.getElementsByTagName("LastName")[0].childNodes[0].nodeValue;
			self.UserData.Email           = ATB_XML.getElementsByTagName("Email")[0].childNodes[0].nodeValue;
			self.UserData.Password        = ATB_XML.getElementsByTagName("Password")[0].childNodes[0].nodeValue;
			self.UserData.Bucks           = ATB_XML.getElementsByTagName("Bucks")[0].childNodes[0].nodeValue;
			}
		  }
	   }
	   catch(ex)
	   {  
	      HandleError('FillUserData',ex);
	      return false;
	   }
   }
   
   
   /*
      HandlePageLoad
      This is a helper function internal to the ATB_DataService about.
      It helps set state of the object.
      
      Parameters: None
      Returns: Void
   */
   function HandlePageLoad() 
   {
	   try 
	   {  
		   //Create the XMLHTTP object...		   
		   if(self.IsIE) 
		   {  
			   ATB_OBJ = new ActiveXObject('Microsoft.XMLHTTP');
			   ATB_XML = new ActiveXObject('MSXML2.DOMDocument.3.0');
		   } 
		   else 
		   {      
			   ATB_OBJ = new XMLHttpRequest();
		   }
	   }
	   catch(ex) 
	   { 
		   HandleError('HandlePageLoad',ex);
	   }
   }
   
   /*
      HandleError
      This is a helper function internal to the object.
      This wraps the error handling of this object making error handling
      in one location.
      
      Parameteres:
      component (string) Name of the Method that the error occured.
      ex (Error) The error object.
      
      Returns: Void
   */
   function HandleError(component,ex) 
   {
      if(!self.ATB_DEBUG) return;
      alert(ex.message + ' in ' + component);
   }
}


/*
   UserData
   This object represents the ATB User.
   The ATB User can be created (instansiated) 2 ways.
   One via the Login call of the ATB_DataService object, or 
   via the CreateUser call of the ATB_DataService.
   
   The UserData object also has functionality to check if a given Intersticial part is completed.
   
   Note: The ATB_DataService uses this object as a return type for the CreateUser and Login method calls.
   The Login call will return a User object even if the Login process fails. To check Login status use 
   the IsAuthenticated to check for authenticated status, and then check the ErrorCode is IsAuthenticated comes
   back false;
*/
function UserData()
{
   this.UserName = "";
   this.Password = "";
   this.FirstName = "";
   this.LastName = "";
   this.IsAuthenticated = false;
   this.CompletedCode = "0";
   this.ErrorCode = "";
   this.Email = "";
   this.Bucks = 0;
   
   var ICount = 25; //The number of intersticials
   var PartCount = 3; //The numbers of parts to the Intersticial
   
   /*
      Sets the Completed Status of a given Intersticial and its badge part.
      The inputs are the Intersticial number and Intersticial part number (Badge Part).
      This has no return value. Also this does not update the database only the UserData in memory.
   */
   this.SetCompletedStatus = function(INum, IPart)
   {
      var newCode;
      
      try
      {
         //Validate the Intersticial Input
         if(isNaN(INum) || (INum > ICount || INum < 1)){
            throw new Error(10,'Intersticial Number Incorrect');
         }
         
         //Validate the Part Input
         if(isNaN(IPart) || (IPart > 3 || IPart < 1)){
            throw new Error(11,'Part Number Incorrect');
		  }
        
		var pos = 24-(INum-1);

		var code = this.getIDCodeString();
		var newPart = code.charAt(pos);
		var newCode='';

         //Set the new data - Same Algorythm as the Check function
        //var part = (3 * (IPart - 1));
        part = 1 << (IPart - 1);
		newPart |= part;
		
		if(pos > 0) newCode = code.substring(0,pos);
		newCode +=  newPart;
		if(pos < 24) newCode += code.substring(pos+1);

         this.CompletedCode = newCode;
      }catch(ex){
		 alert("ERROR!!!");
         throw ex;
      }
   }
   
   
   /*
      Checks Intersticial Completed status.
      The input parameters are the Intersticial number and Intersticial part number (Badge Part).
      Returns true is completed or false if not completed.
   */
   this.CheckCompletedStatus = function(INum, IPart)
   {
      var IsCodeCompleted = false;
      
      try
      {
         //Validate the Intersticial Input
         if(isNaN(INum) || (INum > ICount || INum < 1))
         {
            throw new Error(10,'Intersticial Number Incorrect');
         }
         
         //Validate the Part Input
         if(isNaN(IPart) || (IPart > 3 || IPart < 1))
         {
            throw new Error(11,'Part Number Incorrect');
         }
         
		var pos = 24-(INum-1);
		//now try the shane binary conversion
		 var part = this.getIDCodeString(); 
		 part = part.charAt(pos); 

         flag = (IPart - 1);
         flag = 1 << flag;
         
         IsCodeCompleted = CheckFlag(part, flag);
         return IsCodeCompleted;
      }
      catch(ex)
      {
         throw ex;
      }
   }
   
	this.getIDCodeString = function(){
		//convert the completed code to string and pad on the left;
		var code = this.CompletedCode+'';
		var len = 25 - code.length;
		var s = '';
		for(var i =0;i< len; ++i){
			s+='0';
		}
		code = s + code;
		return code;
	}

   /*
      Checks for a given Intersticial Part and returns if that part is Completed.
   */
   this.CheckCode = function(flag, data)
   {  
      var IsCodeCompleted = false;
      
      //Check for Valid Code
      if(isNaN(flag) || (flag < 0 || flag > (ICount * PartCount) ))
      {
         //alert('Code must be a valid number 0 - 63');
         //Throw new error
         return false;
      }
      
      //Convert Flag
      flag = 1 << flag;
      
      IsCodeCompleted = CheckFlag(data,flag);
      return IsCodeCompleted;
   }
   
   this.EncodedString = function()
   {
      udata = "FirstName:" + this.FirstName + "::";      
      udata += "LastName:" + this.LastName + "::";
      udata += "Name:" + this.UserName + "::";
      udata += "Email:" + this.Email + "::";
      udata += "Password:" + this.Password + "::";
      udata += "IsAuthenticated:" + this.IsAuthenticated + "::";
      udata += "CompletedCode:" + this.CompletedCode + "::";
      udata += "Bucks:" + this.Bucks + "::";
      udata += "ErrorMessage:" + this.ErrorCode;
      
      return udata;
   }
   
   UserData.prototype.toString = function()
   {  
      var udata = "<udata>";
      udata += "  <FirstName>"+this.FirstName+"</FirstName>";
      udata += "  <LastName>"+this.LastName+"</LastName>";
      udata += "  <UserName>"+this.UserName+"</UserName>";
      udata += "  <Password>"+this.Password+"</Password>";
      udata += "  <Email>"+this.Email+"</Email>";
      udata += "  <IsAuthenticated>"+this.IsAuthenticated+"</IsAuthenticated>";
      udata += "  <CompletedCode>"+this.CompletedCode+"</CompletedCode>";
      udata += "  <ErrorMessage>"+this.ErrorCode+"</ErrorMessage>";
      udata += "  <Bucks>"+this.Bucks+"</Bucks>";
      udata += "</udata>";

      return udata;
   } 
   
   
}

/*
   Global Utility Functions
*/
function CheckFlag(data, flag)
{
   try
   {  
      return ((data & flag) != 0 ? true : false);
   }
   catch(ex)
   {
      //Do something with the error         
      return false;
   }
}



/*
   Function Facade for the FormatString Function.
   If the param1 parameter is an array then it forwards to the array handling version of the FormatString functino
   If the param1 is not an array then processing goes to the four param value function handler.
*/
function FormatString(txt, param1, param2, param3, param4)
{  
   if(param1.constructor.toString().indexOf("Array") == -1)
      return FormatStringInternal1(txt, param1, param2, param3, param4);
   else   
      return FormatStringInternal2(txt, param1);
}

/*
   Helper function for replacing string values
   txt = string to modify (required)
   param1 = first param to replace (%1 will be replaced)
   param2 = second param to replace (%2 will be replaced) (optional)
   param3 = third param to replace (%3 will be replaced)(optional)
*/
function FormatStringInternal1(txt, param1, param2, param3, param4)
{
   var results, regex;
   
   try
   {
      //Replace the first param
      regex = /%1/g;      
      results = txt.replace(regex, param1);
      
      if(param2 != null && param2 != "")
      {
         regex = /%2/g;
         results = results.replace(regex, param2);
      }
         
      if(param3 != null && param3 != "")
      {
         regex = /%3/g;
         results = results.replace(regex, param3);
      }
      
      if(param4 != null && param4 != "")
      {
         regex = /%4/g;
         results = results.replace(regex, param4);
      }
      
      return results;
   }
   catch(ex)
   {
      if(true)
         alert(ex.message);
   }
}

/*
   Helper function for replacing string values
   txt = string to modify (required)
   params = an array of parameters to replace
   
   example:
      var tst = "onclick='%1' onmouseover='%2' onmouseoff='%3'";
      var params = {"alert('hi')","alert('on')","alert('off')"};
      var method = FormatString(tst, params);
      
*/
function FormatStringInternal2(txt, QueryParams)
{
   var results, regex;
   var cnt = QueryParams.length + 1;
   //regex = /%i/g;
   
   try
   {      
      for(i = 1; i < cnt; i++)
      {
         regex = eval("/%" + i + "/g;");                 
         txt = txt.replace(regex, QueryParams[i-1]);
      }    
      
      return txt;
   }
   catch(ex)
   {
      if(true)
         alert(ex.message);
   }
}


