// ===[ Page hooks ]===
client = new client_object();



// ===| onload hook |===
client.add_handler(window, 'Load', function()
{
	setTimeout(client.events.load, 50);
});



// ===| unload hook |===
client.add_handler(window, 'Unload', client.events.unload);




// ===[ <Object> client_object ]===
function client_object()
{
  //---[ Attributes ]---
  this.browser = {version:parseFloat(navigator.appVersion.split("MSIE")[1])};

  this.id_pool = new id_pool_object();

  this.loaded = {javascript: [], stylesheet: [], modules: []};



  //---[ Methods ]---
  this.new_delegate = _client__new_delegate;

  this.load_javascript = _client__load_javascript;
  this.load_stylesheet = _client__load_stylesheet;


  this.add_handler = _client__add_handler;
  this.remove_handler = _client__remove_handler;
  this.call_handlers = _client__call_handlers;
  this.end_event_chain = _client__end_event_chain;



  this.events =
  {
    load: this.new_delegate(this, _client__event__load),
    unload: this.new_delegate(this, _client__event__unload)
  };

  this.handlers =
  {
    load: [],
    unload: []
  };
}



// ===|  |===
function _client__event__load()
{
  this.call_handlers(this.handlers.load, "client_object::load()");

  return true;
}


function _client__event__unload()
{
  this.call_handlers(this.handlers.unload, "client_object::unload()");

  return true;
}



// ===| Scoped delegates |===
function _client__new_delegate(scope, method)
{
	if( arguments.length <= 2)
	{
		var delegate_function = new Function('return arguments.callee.method.apply(arguments.callee.scope, arguments);');
	}
	else
	{
		var parameters = [];
		for( var count_arguments = 2, num_arguments = arguments.length; count_arguments < num_arguments; count_arguments++ )
		{
			parameters.push(arguments[count_arguments]);;
		}


		var delegate_parameters = [];
		for( var count_parameters = 0, num_parameters = parameters.length; count_parameters < num_parameters; count_parameters++ )
		{
			var parameter = parameters[count_parameters];
			switch( typeof parameter )
			{
				case "string":
					if( (parameter.indexOf(".") == -1) && (parameter.search(/^"|'/) == -1) ) 
					{
						delegate_parameters.push("'"+ parameter +"'");
					}
					break;


				default:
					break;
			}
		}


		parameters = ( parameters.length && (parameters[0] != "") )?( ", "+ parameters.join(", ").replace(/'/g, "\\'") ):( "" );
		delegate_parameters = ( delegate_parameters.length )?( delegate_parameters.join(", ") +", " ):( "" );

		var delegate_function = eval("new Function("+ delegate_parameters +"'\
			return arguments.callee.method.call(arguments.callee.scope"+ parameters +");');");
	}


	delegate_function.scope = scope;
	delegate_function.method = method;

	return delegate_function;
}



// ===| Dynamic Loaders |===
function _client__load_javascript(script_name)
{
  if( (script_name != '') && (typeof this.loaded.javascript[script_name] == "undefined") )
  {
    var javascript = document.createElement('SCRIPT');
    javascript.setAttribute('language', 'javascript');
    javascript.setAttribute('type', 'text/javascript');


    javascript.setAttribute('src', script_name);


    document.getElementsByTagName('head')[0].appendChild(javascript);
    this.loaded.javascript[script_name] = javascript;
  }
}


function _client__load_stylesheet(stylesheet_name)
{
  if( (stylesheet_name != '') && (typeof this.loaded.stylesheet[stylesheet_name] == "undefined") )
  {
    var stylesheet = document.createElement('SCRIPT');
    stylesheet.setAttribute('type', 'text/css');
    stylesheet.setAttribute('rel', 'stylesheet');
    stylesheet.setAttribute('title', 'classhopper_styles');


    stylesheet.setAttribute('src', stylesheet_name);


    document.getElementsByTagName('head')[0].appendChild(stylesheet);
    this.loaded.stylesheet[stylesheet_name] = stylesheet;
  }
}



// ===| event handlers |===
function _client__add_handler(dom_element, event_name, handler)
{
  try
  {
    if( dom_element.addEventListener )
    {
      dom_element.addEventListener(event_name.toLowerCase(), handler, false);
    }
    else if( dom_element.attachEvent )
    {
      dom_element.attachEvent('on'+ event_name.toLowerCase(), handler);
    }
    else
    {
      dom_element['on'+ event_name] = handler;
    }


    return true;
  }
  catch(ex)
  {
    return false;
  }
}



// ===|  |===
function _client__remove_handler(dom_element, event_name, handler) 
{
  try
  {
    if( dom_element.addEventListener )
    {
      dom_element.removeEventListener(event_name.toLowerCase(), handler, false);
    }
    else if( dom_element.attachEvent )
    {
      dom_element.detachEvent('on'+ event_name.toLowerCase(), handler);
    }
    else
    {
      dom_element['on'+ event_name] = undefined;
    }


    return true;
  }
  catch(ex)
  {
    return false;
  }
}



// ===|  |===
function _client__call_handlers(handlers, callback)
{
  if( !(handlers instanceof Array) )
  {
    handlers = [handlers];
  }

  for( var count_handlers = 0, num_handlers = handlers.length; count_handlers < num_handlers; count_handlers++ )
  {
    try
    {
      var handler = handlers[count_handlers];
      switch( typeof handler )
      {
        case "function":
          handler();
          break;

        case "string":
          eval(handler);
          break;

        default:
          switch( typeof callback )
          {
            case "function":
              ex.handler = handler;
              ex.handler_string = handler_string;
              callback(ex);
              break;


            case "string":
              user_alert(callback +" - Could not execute handler at index ["+ count_handlers +"]");
              break;


            default:
              user_alert("client_object::call_handlers - Could not execute handler at index ["+ count_handlers +"]");
              break;
          }
          break;
      }
    }
    catch(ex)
    {
      var handler_string;
      switch( typeof handler )
      {
        case "function":
          handler_string = handler.toString().replace(/\{([\r\n]|.)*\}/gi, "");
          break;

        case "string":
          handler_string = handler;
          break;
      }


      switch( typeof callback )
      {
        case "function":
          ex.handler = handler;
          ex.handler_string = handler_string;
          callback(ex);
          break;


        case "string":
          user_alert("["+ callback +" - Error executing]\r\n"+ handler_string +"\r\n\r\n"+ ex.message);
          break;


        default:
          user_alert("[client_object::call_handlers - Error executing]\r\n"+ handler_string +"\r\n\r\n"+ ex.message);
          break;
      }
    }
  }
}



// ===|  |===
function _client__end_event_chain(event_object)
{
  if( (typeof event_object == "undefined") && (typeof event != "undefined") )
  {
    event_object = event;
  }

  if( event_object )
  {
    if( document.body.addEventListener )
    {
      event_object.stopPropagation();
      event_object.preventDefault();
    }
    else
    {
      event_object.cancelBubble = true;
      event_object.returnValue = false;
    }
  }
}




// ===[ id_pool_object ]===
function id_pool_object()
{
  // ---[ id_pool_object attributes ]---
  this.used_ids;
  this.available_ids;



  // ---[ id_pool_object methods ]---
  this.constructor = __id_pool__constructor;

  this.use = __id_pool__use;
  this.recycle = __id_pool__recycle;



  // ---[ id_pool_object contructor ]---
  this.constructor();
}



function __id_pool__constructor()
{
  this.next_id = 1;
  this.available_ids = new Array();
}



function __id_pool__use()
{
  if( this.available_ids.length )
    return this.available_ids.shift();
  else
    return this.next_id++;
}



function __id_pool__recycle(used_id)
{
  this.available_ids.push(used_id);
}




// ===[ Custom functions ]===
function $(element_id)
{ 
  if( typeof element_id == 'string' )
  {
    return document.getElementById(element_id);
  }
  else
  {
		return null
  }
}



function current_style(element)
{
	if( typeof element == 'string' )
	{
		element = $(element)
	}


	if( document.defaultView && document.defaultView.getComputedStyle )
	{
		return document.defaultView.getComputedStyle(element, null);
	}
	else if( element.currentStyle )
	{
		return element.currentStyle;
	}
	else
	{
		return null;
	}
}



function user_alert(value)
{
  alert(value);
}



function querystring(query)
{
}
querystring.get = _querystring__get;


function _querystring__get(name, default_value)
{
	var query = location.search.substring(1);

	if( arguments.length )
	{
    query = query.match(name +'=([^&$]*)')
    if( query )
    {
      query = unescape(query[1]);
    }
    else
    {
      query = default_value;
    }
	}


	return query;
}