// Main AJAX classs
function Request() {}

Request.timeout = 5000; //5 seconds
Request.method = 'GET';
Request.headers = new Array();
Request.params = null;

Request.makeRequest = function(p_url, p_busyReq, p_progId, p_successCallBack, p_errorCallBack, p_pass, p_object) {
	//p_url: the web service url
	//p_busyReq: is a request for this object currently in progress?
	//p_progId: element id where progress HTML should be shown
	//p_successCallBack: callback function for successful response
	//p_errorCallBack: callback function for erroneous response
	//p_pass: string of params to pass to callback functions
	//p_object: object of params to pass to callback functions
	
	if (p_busyReq) return;
	var req = Request.getRequest();
	if (req != null) {
		p_busyReq = true;
		Request.showProgress(p_progId);
		req.onreadystatechange = function() {
			if (req.readyState == 4) {
				p_busyReq = false;
				window.clearTimeout(toId);
				if (req.status == 200) {
					p_successCallBack(req, p_pass, p_object);
				} else {
					p_errorCallBack(req, p_pass, p_object);
				}
				Request.hideProgress(p_progId);
			}
		}
		var $ajax_mark = (p_url.indexOf('?') ? '&' : '?') + 'ajax=yes';
		req.open(Request.method, p_url + $ajax_mark, true);
		
		if (Request.method == 'POST') {
			Request.headers['Content-type'] = 'application/x-www-form-urlencoded';
			Request.headers['referer'] = p_url;
		}
		else {
			Request.headers['If-Modified-Since'] = 'Sat, 1 Jan 2000 00:00:00 GMT';
		}
		
		Request.sendHeaders(req);
		if (Request.method == 'POST') {
			req.send(Request.params);
			Request.method = 'GET'; // restore method back to GET
		}
		else {
			req.send(null);
		}
		
		var toId = window.setTimeout( function() {if (p_busyReq) req.abort();}, Request.timeout );
	}
}

Request.sendHeaders = function($request) {
	for (var $header_name in Request.headers) {
		$request.setRequestHeader($header_name, Request.headers[$header_name]);
	}
	Request.headers = new Array(); // reset header afterwards
}

Request.getRequest = function() {
	var xmlHttp;
	try { xmlHttp = new ActiveXObject('MSXML2.XMLHTTP'); return xmlHttp; } catch (e) {}
	try { xmlHttp = new ActiveXObject('Microsoft.XMLHTTP'); return xmlHttp; } catch (e) {}
	try { xmlHttp = new XMLHttpRequest(); return xmlHttp; } catch(e) {}
	return null;
}

Request.showProgress = function(p_id) {
	if (p_id != '') {
		Request.setOpacity(20, p_id);
		
		if (!document.getElementById(p_id + '_progress')) {
			document.body.appendChild(Request.getProgressObject(p_id));
		}
		else {
			var $progress_div = document.getElementById(p_id + '_progress');
			$progress_div.style.top = getRealTop(p_id) + 'px';
			$progress_div.style.height = document.getElementById(p_id).clientHeight;
			$progress_div.style.display = 'block';
		}
//		document.getElementById(p_id).innerHTML = Request.getProgressHtml();
	}
}

Request.hideProgress = function(p_id) {
	if (p_id != '') {
		document.getElementById(p_id + '_progress').style.display = 'none';
		Request.setOpacity(100, p_id);
	}
}

Request.setOpacity = function (opacity, id) {
    var object = document.getElementById(id).style;
    object.opacity = (opacity / 100);
    object.MozOpacity = (opacity / 100);
    object.KhtmlOpacity = (opacity / 100);
    object.filter = "alpha(opacity=" + opacity + ")"; 
}

Request.getProgressHtml = function() {
	return "<p class='progress'>" + Request.progressText + "<br /><img src='img/ajax_progress.gif' align='absmiddle' width='100' height='7' alt='" + Request.progressText + "'/></p>";
}

Request.getProgressObject = function($id) {
	var $div = document.createElement('DIV');
	var $parent_div = document.getElementById($id);
	
	$div.id = $id + '_progress';
	
	$div.style.width = $parent_div.clientWidth + 'px';
	$div.style.height = '150px'; // default height if div is empty (first ajax request for div)
	$div.style.left = getRealLeft($parent_div) + 'px';	
	$div.style.top = getRealTop($parent_div) + 'px';
	$div.style.position = 'absolute';
	
	/*$div.style.border = '1px solid green';
	$div.style.backgroundColor = '#FF0000';*/

	$div.innerHTML = '<table style="width: 100%; height: 100%;"><tr><td style="text-align: center;">'+Request.progressText+'<br /><img src="img/ajax_progress.gif" align="absmiddle" width="100" height="7" alt="'+escape(Request.progressText)+'" /></td></tr></table>';
	return $div;
}

Request.getErrorHtml = function(p_req) {
	//TODO: implement accepted way to handle request error
	return '[status: ' + p_req.status + '; status_text: ' + p_req.statusText + '; responce_text: ' + p_req.responseText + ']';
}

Request.serializeForm = function(theform) {
	if (typeof(theform) == 'string') {
		theform = document.getElementById(theform);
	}
	
	var els = theform.elements;
	var len = els.length;
	var queryString = '';
	
	Request.addField = function(name, value) { 
		if (queryString.length > 0) queryString += '&';
		queryString += encodeURIComponent(name) + '=' + encodeURIComponent(value);
	};
  
	for (var i = 0; i<len; i++) {
		var el = els[i];
    	if (el.disabled) continue;
    
		switch(el.type) {
			case 'text':
			case 'password':
			case 'hidden':
			case 'textarea': 
          		Request.addField(el.name, el.value);
				break;
				
			case 'select-one':
				if (el.selectedIndex >= 0) {
            		Request.addField(el.name, el.options[el.selectedIndex].value);
          		}
          		break;
          		
			case 'select-multiple':
				for (var j = 0; j < el.options.length; j++) {
            		if (!el.options[j].selected) continue;
              		Request.addField(el.name, el.options[j].value);
          		}
          		break;
          		
			case 'checkbox':
			case 'radio':
          		if (!el.checked) continue;
            	Request.addField(el.name,el.value);
          		break;
      	}
	}
	return queryString;
};

// AJAX ProgressBar classs
function AjaxProgressBar($url) {
	this.WindowTitle = this.GetWindow().document.title;
	this.URL = $url;
	this.BusyRequest = false;
	this.LastResponceTime = this.GetMicroTime();
	this.ProgressPercent = 0; // progress percent
	this.ProgressTime = new Array();
	this.Query();
}

AjaxProgressBar.prototype.GetWindow = function() {
	return window.parent ? window.parent : window;
}

AjaxProgressBar.prototype.GetMicroTime = function() {
	var $now = new Date();
	return Math.round($now.getTime() / 1000); // because miliseconds are returned too
}

AjaxProgressBar.prototype.Query = function() {
	Request.makeRequest(this.URL, this.BusyRequest, '', this.successCallback, this.errorCallback, '', this);
}

// return time needed for progress to finish
AjaxProgressBar.prototype.GetEstimatedTime = function() {
	return Math.ceil((100 - this.ProgressPercent) * Math.sum(this.ProgressTime) / this.ProgressPercent);
}

AjaxProgressBar.prototype.successCallback = function($request, $params, $object) {
	var $responce = $request.responseText;
	var $match_redirect = new RegExp('^#redirect#(.*)').exec($responce);
	if ($match_redirect != null) {
		$object.showProgress(100);
		// redirect to external template requested
		window.location.href = $match_redirect[1];
		return false;
	}
	
	if ($object.showProgress($responce)) {
		$object.Query();
	}
}

AjaxProgressBar.prototype.errorCallback = function($request, $params, $object) {
	alert('AJAX Error; class: AjaxProgressBar; ' + Request.getErrorHtml($request));
}

AjaxProgressBar.prototype.FormatTime = function ($seconds) {
	$seconds = parseInt($seconds);
	
	var $minutes = Math.floor($seconds / 60);
	if ($minutes < 10) $minutes = '0' + $minutes;
	$seconds = $seconds % 60;
	if ($seconds < 10) $seconds = '0' + $seconds;
	
	return $minutes + ':' + $seconds;
}

AjaxProgressBar.prototype.showProgress = function ($percent) {
	this.ProgressPercent = $percent;
	var $now = this.GetMicroTime();
	this.ProgressTime[this.ProgressTime.length] = $now - this.LastResponceTime;
	this.LastResponceTime = $now;
	
	var $display_progress = parseInt(this.ProgressPercent);
	this.GetWindow().document.title = $display_progress + '% - ' + this.WindowTitle;
	document.getElementById('progress_display[percents_completed]').innerHTML = $display_progress + '%';
	document.getElementById('progress_display[elapsed_time]').innerHTML = this.FormatTime( Math.sum(this.ProgressTime) );
	document.getElementById('progress_display[Estimated_time]').innerHTML = this.FormatTime( this.GetEstimatedTime() );
	
	document.getElementById('progress_bar[done]').style.width = $display_progress + '%';
	document.getElementById('progress_bar[left]').style.width = (100 - $display_progress) + '%';
	return $percent < 100 ? true : false;
}

// AJAX MultiCategory classs
function AjaxMultipleCateogry($url, $category_id, $parent_category_id, $top_category_id) {
	this.URL = $url;
	this.BusyRequest = false;
	this.CategoryID = $category_id;
	this.ParentCategoryID = $parent_category_id;
	this.TopCategoryID = $top_category_id;
	this.Selector = document.getElementById('categories_selector');
}

AjaxMultipleCateogry.prototype.Query = function($action_type, $category_id) {
	
	var $url = this.URL.replace('#CATEGORY_ID#', $category_id).replace('#ACTION_TYPE#', $action_type);
	Request.makeRequest($url, this.BusyRequest, '', this.successCallback, this.errorCallback, $action_type, this);
}

AjaxMultipleCateogry.prototype.successCallback = function($request, $params, $object) {
	var $responce = $request.responseText;
	var $match_redirect = new RegExp('^#redirect#(.*)').exec($responce);
	if ($match_redirect != null) {
		// redirect to external template requested
		window.location.href = $match_redirect[1];
		return false;
	}

	switch ($params) {
		case 'sub_categories':
			var $list = $responce.split('@#@');
			$object.CategoryID = $list.shift();
			$object.ParentCategoryID = $list.shift();
			document.getElementById('category_path').innerHTML = $list.shift();
			$object.clearSelector();
			
			if ($object.CategoryID != $object.TopCategoryID) {
				$object.Selector.options[$object.Selector.options.length] = new Option('<----', -1);
			}
			
			if ($list.length > 0) {
				// has subcategories
				var $category_record = '';
				var $i = 0;
				while ($i < $list.length) {
					$category_record = $list[$i].split('#@#');
					$object.Selector.options[$object.Selector.options.length] = new Option($category_record[1], $category_record[0]);
					$i++;
				}
			}
			break;
			
		case 'add_category':
			var $list = $responce.split('@#@');
			var $category_id = $list.shift();
			if ($category_id > 0) {
				var $category_path = $list.shift();
			
				// such category still exists
				if (!$object.HasCategory($category_id)) {
					var $span = document.createElement('SPAN');
					$span.id = 'category_' + $category_id;
					$span.innerHTML = '<b>' + $category_path + '</b><input type="hidden" name="cat_ids[' + $category_id + ']" value="' + $category_id + '"/> <input type="button" class="button" value="Remove" onclick="$MultiCategory.RemoveFromCategory(' + $category_id + ');"/><br />';
					document.getElementById('categories_list').appendChild($span);	
				}
			}
			break;
	}
}

AjaxMultipleCateogry.prototype.errorCallback = function($request, $params, $object) {
	alert('AJAX Error; class: AjaxProgressBar; ' + Request.getErrorHtml($request));
}

AjaxMultipleCateogry.prototype.MoveDown = function() {
	this.Query('sub_categories', this.getSelected());
}

AjaxMultipleCateogry.prototype.getSelected = function() {
	var $value = this.Selector.options[this.Selector.selectedIndex].value;
	if ($value == -1) {
		// perform move_up
		$value = this.ParentCategoryID;
	}

	return $value;
}

AjaxMultipleCateogry.prototype.clearSelector = function() {
	while (this.Selector.options.length) {
		this.Selector.remove(0);
	}
}

AjaxMultipleCateogry.prototype.HasCategory = function($category_id) {
	return document.getElementById('category_' + $category_id) != null;
}

AjaxMultipleCateogry.prototype.AddToCategory = function() {
	var $category_id = this.getSelected();
	if (this.Selector.options[this.Selector.selectedIndex].innerHTML == '&lt;----') {
		// if not subcategories, then add current category
		$category_id = this.CategoryID;
	}
	
	if ($category_id > 0) {
		this.Query('add_category', $category_id);
	}
}

AjaxMultipleCateogry.prototype.RemoveFromCategory = function($category_id) {
	if (this.HasCategory($category_id)) {
		document.getElementById('categories_list').removeChild( document.getElementById('category_' + $category_id) );
	}
}
