// Note. Most of the code here uses jQuery 1.3.2

// Global vars... Some could be privatized
var SA_Valid = new Array();
var SA_LockAjaxCall = false;
var SA_X1Pos = 0;
var SA_Y1Pos = 0;
var SA_CallCount = 0; // for debugging

var SA_TileInfoCache = {
  
  cacheObjs: Array(), /*contains tile info details*/
  cacheLen: 0,
  cacheHits: 0,
	cacheMiss: 0,
	cacheIndx: 0,
  isInCache: function(x,y) {
    // x,y coords found in cache?
    // SA_InCache doubles as an index into the cache or
    // a sentinel value indicating coords are not in cache
    this.cacheIndx = -1;
    
		var x = Math.floor(x/6);
		var y = Math.floor(y/6);
		var t = x + y + (y * 99) + 1;
		
		if (typeof this.cacheObjs[t] !== "undefined") {
			this.cacheHits++;
		  this.cacheIndx = t;	
		}

    if (this.cacheIndx==-1) {
			this.cacheMiss++;
			$("#tile_info_detail > p:eq(0)").html("");
		}
		
    return this.cacheIndx;
  },
  
  loadCache: function(jsonIn) {
    // load processed json values into the cache
    // throw new SyntaxError("parseJSON");
    /* Expected JSON objects structure:
      cs: City, State
      h: Honoree Name - Maybe null
      i: index id - 1 based
      m: tile image name (path not included)
      u: Donor name
      x: xcoord
      y: ycoord
    */
      var jsonObjs = SA_JSON.parse(jsonIn);
		
		
      for (var i=0; i < jsonObjs.length; i++) {
			
      if (typeof this.cacheObjs[jsonObjs[i].i] == 'undefined') {

         this.cacheObjs[jsonObjs[i].i] = {
            "cs":jsonObjs[i].cs,
            "h":jsonObjs[i].h,
            /*"i":jsonObjs[i].i,*/
            "m":jsonObjs[i].m,
            "u":jsonObjs[i].u,
            "x":jsonObjs[i].x,
            "y":jsonObjs[i].y
            };
      }
      this.cacheLen++;
    }
  },
  
  displayInfoOff: function(){
    $("#tile_info_detail").html("");
  },
  
  displayInfoOn: function (cacheIndex) {
    // Generate & retrieve HTML to display from the cache
    
    var output = '<img src="images/tl/'+this.cacheObjs[cacheIndex].m+'">';
		
    output += '<table border="0">';
    
    if (this.cacheObjs[cacheIndex].h !== null) {
      output += '<tr><td>'
        +'<p><span  class="tile_info_heading">In Honor of:</span><br>'
        +'<span class="tile_info_content">'+this.cacheObjs[cacheIndex].h+'</span></p>'
        +'</td></tr>';
    }
		
    output += '<tr><td>'
        +'<p><span  class="tile_info_heading">Donated by:</span><br>'
        +'<span class="tile_info_content">'+this.cacheObjs[cacheIndex].u+'<br>'
        +this.cacheObjs[cacheIndex].cs+'</span></p>'
        +'</td></tr></table>';
      
    $("#tile_info_detail").html(output);
  },
	
	/** @todo - implement these two methods*/
	// Displays wait metaphor on
	displayWaitOn: function () {

  },
	
	// Displays wait metaphor off
	displayWaitOff: function () {

  }

};


/**
 * Setup event handlers...
 */

$(document).ready(function(){

  // Hook info tile - keeps info div from flickering
  $("#tile_info_cont").mouseover(function(event) {
		return false;
  });
  $("#tile_info_cont").mouseout(function(event) {
	  return false;
  });

  if (typeof SA_ViewDonorTile !== 'undefined') {
    // Display donor tile info and disallow event hooking of elements
		if (SA_ViewDonorTile) {
			var indx = SA_TileView['t'];
			var x = SA_TileView['x'];
			var y = SA_TileView['y'];
			
			SA_TileInfoCache.cacheIndx = indx;
			
			SA_TileInfoCache.cacheObjs[indx] = {
				"cs":SA_TileView['cs'],
				 "h":SA_TileView['h'],
				 "m":SA_TileView['m'],
				 "u":SA_TileView['u'],
				 "x":SA_TileView['x'],
				 "y":SA_TileView['y']
			};
				
			SA_TileInfoCache.cacheLen++;
			SA_TileInfoCache.displayInfoOn(indx);
			 
			$("#tile_info_cont").css("display","block");

      // Center ring over donor's tile
			$("#rd_ring").css("display","block");
			$("#rd_ring").css("top", y-9);
			$("#rd_ring").css("left",x-9);
			
			// Position tile info container. It's a Hack!
			if (x > 300) {
				x = x - 216;
			} else {
				x = x + 16;
			}
			if (y > 300) {
				y = y - 132;
			} else {
				y = y - 16;
			}
			
			$("#tile_info_cont").css("top", y);
			$("#tile_info_cont").css("left", x);
		} else {
			
		}
		SA_TileView = undefined; // GC
		return; 
  }
	 
  /**
   * Hook donate button(s) for "pre-form submission" "on page" validation
   */
  $("#donateButton").click(function(event) {
                                    
    var validated = SA_Validate(); 
    
    if (validated) {
    
      return true; // Allow form(s) to be submitted
    
    } else { // Something didn't validate, so the form(s) won't be submitted...

      $("form > label").removeClass('validation_error');

      // Step through the validation array
      // and add the class: "validation_error"
      // to the label for every element (checked) that failed validation
      
      for (var i=0; i < SA_Valid.length; i+=2) {
        if (!SA_Valid[i+1]) { /*This element failed validation*/
          for (var j=0; j < $("form > label").length; j++) {
            if ($("form label:eq(" + j + ")").attr("for") == SA_Valid[i]) {
               // Flag its label
              $("form label:eq(" + j + ")").addClass("validation_error");
              break;
            }
          }
        }
      }
      return false; // Dis-allow form(s) submission - stay on page...
    }
  }); // End: Hook donate button(s)
  

  /**
   * Hook mousemove event on sunflower div
   *
   * @todo - compensate for view window being scrolled down/up...
   */
  $("#sunflower").mousemove(function(event) {
                                     
    // All of the offset values were originally +-4 pixels, 
    // but the tile detail window blinked furiously - primarily in FireFox.
    // Ideally the values would be: xOffset = yOffset = 0 initially
    // and the values -242 and -140 would have been -238 and -136.
    // Setting the values keep the mouse event from bubbling through
    // the #tile_info_detail div on mousemoves. These values: -242 and -140
    // are based on the width and height of the tile_info_detail div.
		
		/** @debug - readjust by by 4 after nulling tile_info_cont's mousemove event */
		if (typeof SA_ViewDonorTile !== 'undefined') {
	    return false;
    }

    var xOffset = 16; 
    var yOffset = 16;
    
    // IE compatibility
    if (typeof event.offsetX == 'undefined' && typeof event.offsetY == 'undefined') {
      var offset = $(event.target).offset(false);
      event.offsetX = event.pageX - offset.left;
      event.offsetY = event.pageY - offset.top;
    }

    // Determine quandrant mouse is currently in...
    if (event.offsetX > 300) {
      xOffset = -216; //-242;
    } else {
      xOffset = 16;
    }
    if (event.offsetY > 300) {
      yOffset = -116; //-140;
    } else {
      yOffset = 16;
    }

    // Adjust tile info viewer's position based on quadrant & viewport
    $("#tile_info_cont").css("left", event.offsetX + xOffset ); //+ getViewportScrollX() ); 
    $("#tile_info_cont").css("top",  event.offsetY + yOffset ); //+ getViewportScrollY() ); 

    // Debounce mouse moves...
    if ( Math.abs(event.offsetX - SA_X1Pos) > 6 || Math.abs(event.offsetY - SA_Y1Pos) > 6) {
      SA_X1Pos = event.offsetX; SA_Y1Pos = event.offsetY; 
    } else {
      SA_TileFinder(Math.floor(event.offsetX), Math.floor(event.offsetY));
    }

  }); // End: Mousemove event hook


  // Hook mouseover event of sunflower div
  $("#sunflower").mouseover(function(event) {
		if (typeof SA_ViewDonorTile !== 'undefined') {
	    return false;
    }
      $("#tile_info_cont").css("display","block");                                  
  });
  
  // Hook mouseout event of sunflower div
  $("#sunflower").mouseout(function(event) {
		if (typeof SA_ViewDonorTile !== 'undefined') {
	    return false;
    }
      $("#tile_info_cont").css("display","none");
  });
  
}); // End: Document Ready enclosure


/**
 * The following two functions use old-school code for now
 * @todo - Maybe... implement in jQuery
 */

/**
 * Make ajax call to server to get tile info
 * 
 * @param int x - approx. x-coord of mag viewer
 * @param int y - approx. y-coord of mag viewer
 *
 * @todo - Clean up xhr reactions and add timeout
 */
function SA_TileFinder(x,y) {
  // Check cache first...
	try {
    var cacheIndex = SA_TileInfoCache.isInCache(x,y);
	} catch (e) {
		SA_TileInfoCache.displayInfoOff();
		return;
	}
  if (cacheIndex !== -1) {
    //alert ("in cache");
    SA_TileInfoCache.displayInfoOn(cacheIndex);
    return;
  }
	
  SA_TileInfoCache.displayInfoOff();
  
  var strURL="sajax.php?x="+x+"&y="+y;
  // send x and y coords of mouse after settling
  if (!SA_LockAjaxCall) {
		
		SA_CallCount++;
		
    var xmlHttp = SA_getXMLHTTP(); 
		
    SA_LockAjaxCall = true;
		
    //document.getElementById('tile_info_detail').innerHTML = "";
  } else {
		
    return;
		
  }
  
  if (xmlHttp) { 
    xmlHttp.onreadystatechange = function() { 
      if (xmlHttp.readyState==4) { 
        // only if "OK" 
        if (xmlHttp.status == 200) {
          /* @todo  Add timeout incase server doesn't respond
                    within a resonable amount of time
          */
          var jsonIn = xmlHttp.responseText;
								
          if (jsonIn.length > 0) {
            SA_TileInfoCache.loadCache(jsonIn);
          }
            SA_LockAjaxCall = false;
        } else { 
          // Just unlock the call trigger for now
          SA_LockAjaxCall = false; 
           
        } 
      }                
    } // ... function()
    
    // Make the request...
    xmlHttp.open("GET", strURL, true); 
    xmlHttp.send(null); 
    
  } // if (xmlHttp)        
}

// Standard x-browser XHR object creation
function SA_getXMLHTTP() {  
  var xmlHttp=false;     
  try{ 
    xmlHttp = new XMLHttpRequest(); 
  } 
  catch(e) {         
    try{             
      xmlHttp = new ActiveXObject("Microsoft.XMLHTTP"); 
    } 
    catch(e){ 
      try { 
        xmlHttp = new ActiveXObject("Msxml2.XMLHTTP"); 
      } 
      catch(e){ 
        xmlHttp = false; 
      } 
    } 
  } 
  return xmlHttp; 
} 


/**
 * Form(s) element validations
 *
 * Validate specific values that will be encountered on forms
 * before the forms are submitted. The values are stored in
 * the array SA_Valid which is in the global namespace.
 * The array values are organized in two contiguous array rows.
 * i.e. SA_Valid[n]   = form element name (n%2==0)
 *      SA_Valid[n+1] = true == validated; false == did not validate
 *
 * @called-by  -  The "#donate" button hook event handler located in
 *                the jQuery document.ready enclosure.
 *
 * @note Opera doesn't play nice with jQuery vis-a-vis the validation
 *       code, but the server's validation will pick up the slack
 *
 * @todo Figure out what's the problem with Opera and jQuery     
 *
 * @return boolean success -  True if all values validated
 *                            False if any value did not validate
 */
function SA_Validate(){
  
  var ndx = 0;
  var success = true;
  
  // Check is this page (form) has an Honoree
  var hasHonoree = typeof $("#h_fname").val() !== 'undefined';
  var hasDonor = typeof $("#u_fname").val() !== 'undefined';
  var hasEmailChk = typeof $("#emailaddr_chk").val() !== 'undefined';
	
  if (hasHonoree) {
    // Check honoree's first and last names
    SA_Valid[ndx++] = 'h_fname';
    SA_Valid[ndx++] = $("#h_fname").val().length > 0;
    
    success = success ? SA_Valid[ndx-1] : false;
  
    SA_Valid[ndx++] = 'h_lname';
    SA_Valid[ndx++] = $("#h_lname").val().length > 0;
    
    success = success ? SA_Valid[ndx-1] : false;
  }

  // Check donor's first and last names
	if (hasDonor) {
    SA_Valid[ndx++] = 'u_fname';
    SA_Valid[ndx++] = $("#u_fname").val().length > 0;
  
    success = success ? SA_Valid[ndx-1] : false;
  
    SA_Valid[ndx++] = 'u_lname';
    SA_Valid[ndx++] = $("#u_lname").val().length > 0;
  
    success = success ? SA_Valid[ndx-1] : false;
	}
	
  // Check email address (note: server's check is more thorough)
  var emailRegEx = /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z]{2,6})+$/;
  var emailaddr = $("#emailaddr").attr('value');
	if (hasEmailChk) {
    var emailaddr_chk = $("#emailaddr_chk").attr('value');
	}
	
  SA_Valid[ndx++] = 'emailaddr';
  SA_Valid[ndx++] = $("#emailaddr").attr('value').length > 0 && emailaddr.match(emailRegEx) ? true : false;
  
  success = success ? SA_Valid[ndx-1] : false;

  if (hasEmailChk) {
	  // Verify email address check matches
    SA_Valid[ndx++] = 'emailaddr_chk';
    SA_Valid[ndx++] = emailaddr == emailaddr_chk;
  
    success = success ? SA_Valid[ndx-1] : false
	}
	
  // Ensure minimum donation amount
  SA_Valid[ndx++] = 'donationamount';
  SA_Valid[ndx++] = ($("#donationamount").attr('value') >= 10);
  // Last index didn't have to bump, left in for expansion
	
  success = success ? SA_Valid[ndx-1] : false;

  // Clear out the email error element
	$("#email_on_file").html("");
	
  return success;
  
}

// Cross-Browser viewport width, height, scollX and scrollY detectors
getViewportWidth = function() {
  var width = 0;
  if( document.documentElement && document.documentElement.clientWidth ) {
    width = document.documentElement.clientWidth;
  }
  else if( document.body && document.body.clientWidth ) {
    width = document.body.clientWidth;
  }
  else if( window.innerWidth ) {
    width = window.innerWidth - 18;
  }
  return width;
};

getViewportHeight = function() {
  var height = 0;
  if( document.documentElement && document.documentElement.clientHeight ) {
    height = document.documentElement.clientHeight;
  }
  else if( document.body && document.body.clientHeight ) {
    height = document.body.clientHeight;
  }
  else if( window.innerHeight ) {
    height = window.innerHeight - 18;
  }
  return height;
};

getViewportScrollX = function() {
  var scrollX = 0;
  if( document.documentElement && document.documentElement.scrollLeft ) {
    scrollX = document.documentElement.scrollLeft;
  }
  else if( document.body && document.body.scrollLeft ) {
    scrollX = document.body.scrollLeft;
  }
  else if( window.pageXOffset ) {
    scrollX = window.pageXOffset;
  }
  else if( window.scrollX ) {
    scrollX = window.scrollX;
  }
  return scrollX;
};

getViewportScrollY = function() {
  var scrollY = 0;
  if( document.documentElement && document.documentElement.scrollTop ) {
    scrollY = document.documentElement.scrollTop;
  }
  else if( document.body && document.body.scrollTop ) {
    scrollY = document.body.scrollTop;
  }
  else if( window.pageYOffset ) {
    scrollY = window.pageYOffset;
  }
  else if( window.scrollY ) {
    scrollY = window.scrollY;
  }
  return scrollY;
};