﻿function ajax(url, post_vars, callback, callback_error, pass_data)
{   if (!window.XMLHttpRequest) XMLHttpRequest = function()
   {   try {return new ActiveXObject("MSXML3.XMLHTTP")} catch(e) {}
       try {return new ActiveXObject("MSXML2.XMLHTTP.3.0")} catch(e) {}
       try {return new ActiveXObject("Msxml2.XMLHTTP")} catch(e) {}
       try {return new ActiveXObject("Microsoft.XMLHTTP")} catch(e) {}
       throw new Error("Could not find an XMLHttpRequest alternative");
   };
   url += (url.match(/\?/) ? '&' : '?') + '__T=' + new Date().getTime();
   var request = new XMLHttpRequest();
   request.open(post_vars ? 'POST' : 'GET', url, true);
   if (post_vars) request.setRequestHeader("Content-Type",
        "application/x-www-form-urlencoded");
   request.onreadystatechange = function()
   {  
        if (request.readyState == 4)
       {   if (request.status != 200)
           {       
                   if (callback_error) callback_error('Invalid response from server: '+request.status, pass_data);
                   else alert('Invalid response from server: '+request.status);
                   return;
           }
            var response = (request.responseText+'').replace(/^\s*/, '').replace(/\s*$/, '');
            callback(response, pass_data);
       }
   };
   request.send(post_vars);
}
function as_hex_str(number)
{       var d = '';
       for (var i=0; number>=1; i++)
       {       var d0 = '0123456789ABCDEF'.charAt(number % 16);
               number -= d0;
               number /= 16;
               d = d0 + d;
       }
       return d;
}

function ajax_cached_continue()
{       if (ajax_cached_toload.length > 0)
       {       var tl = ajax_cached_toload[ajax_cached_toload.length-1];
               ajax_cached_toload.length--;
               ajax_cached(tl.url, tl.post_vars, tl.callback, tl.callback_error,
                            tl.pass_data, tl.may_skip, tl.cache_valid_since);
       }
}

var AJAX_MAX_CACHE_SIZE = 2*1024*1024; // 2 MByte
var ajax_cached_size = 0;
var ajax_cached_cache = new Object;
var ajax_cached_cache_time = new Object;
var ajax_cached_error = new Object;
var ajax_cached_error_time = new Object;
var ajax_cached_busy = false;
var ajax_cached_toload = new Array;
function ajax_cached(url, post_vars, callback, callback_error,
pass_data, may_skip, cache_valid_since)
{       var url_id = 'i';
       for (var i=0; i<url.length; i++) url_id += as_hex_str(url.charCodeAt(i));
       if (ajax_cached_busy)
       {       var i = ajax_cached_toload.length;
               if (ajax_cached_toload.length>0 && ajax_cached_toload[ajax_cached_toload.length-1].may_skip) i--;
               ajax_cached_toload[i] =
               {       url: url,
                       post_vars: post_vars,
                       callback: callback,
                       callback_error: callback_error,
                       pass_data: pass_data,
                       may_skip: may_skip,
                       cache_valid_since: cache_valid_since
               };
       }
       else if (ajax_cached_cache[url_id]!=null && (!cache_valid_since || ajax_cached_cache_time[url_id]>=cache_valid_since.getTime()))
       {       callback(ajax_cached_cache[url_id], pass_data);
               ajax_cached_continue();
       }
       else if (ajax_cached_error[url_id]!=null && (!cache_valid_since || ajax_cached_error_time[url_id]>=cache_valid_since.getTime()))
       {       callback_error(ajax_cached_error[url_id], pass_data);
               ajax_cached_continue();
       }
       else
       {       if (!pass_data) pass_data = new Object;
               if (!post_vars) pass_data['url___________id'] = url_id; // don't cache POST requests
               if (cache_valid_since)
               {       var glue = url.indexOf('?')==-1 ? '?' : '&';
                       url += glue+'cache_valid_since_168435='+cache_valid_since.getTime();
               }
               ajax_cached_busy = true;
               ajax
               (   url, post_vars,
                       function(response, pass_data)
                       {       if (pass_data.url___________id)
                               {       if (ajax_cached_size+response.length > AJAX_MAX_CACHE_SIZE)
                                       {       ajax_cached_size = 0;
                                               ajax_cached_cache = new Object;
                                               ajax_cached_cache_time = new Object;
                                       }
                                       ajax_cached_size += response.length;
                                       ajax_cached_cache[pass_data.url___________id] = response;
                                       ajax_cached_cache_time[pass_data.url___________id] = new Date().getTime();
                               }
                               callback(response, pass_data);
                               ajax_cached_busy = false;
                               ajax_cached_continue();
                       },
                       function(error, pass_data)
                       {       if (pass_data.url___________id)
                               {       ajax_cached_error[pass_data.url___________id] = error;
                                       ajax_cached_error_time[pass_data.url___________id] = new Date().getTime();
                               }
                               if (callback_error) callback_error(error, pass_data); else alert(error);
                               ajax_cached_busy = false;
                               ajax_cached_continue();
                       },
                       pass_data
               );
       }
}

