function CC(p_prefix, p_parentid, p_cb_set_state, p_cb_select)
{
	this.m_prefix       = p_prefix;
	this.m_parentid     = p_parentid;
	this.m_curr         = {};
	this.m_cb_set_state = p_cb_set_state.methodize();
	this.m_cb_select    = p_cb_select.methodize();
}

CC.prototype.ajaxload_start = function()
{
	Event.observe(document, 'mousemove', function(p_event) {
		if($('ajaxloader')) {
			$('ajaxloader').style.left = (Event.pointerX(p_event) + 20) + 'px';
			$('ajaxloader').style.top  = (Event.pointerY(p_event) - 2) + 'px';
		}
	});
	
	$('ajaxloader').style.display = 'block';
}

CC.prototype.ajaxload_stop = function()
{
	$('ajaxloader').style.display = 'none';
	
	Event.stopObserving(document, 'mousemove');
}

CC.prototype.ajax_calc_selection = function(p_vec, p_require, p_savestate, p_phpfunc, p_callback) 
{	
	var l_data = {
			method:    'calc_selection',
			parentid:  this.m_parentid,
			curr:      Object.toJSON(this.get_reduced_curr()),
			diff:      Object.toJSON(p_vec),
			require:   p_require,
			savestate: p_savestate,
			callback:  p_phpfunc
		};
	
	new Ajax.Request('cc.php', {
		parameters:   l_data,
		method:       'post',
		evalJSON:     'force',
		asynchronous: true,
		onSuccess:    p_callback
	});		
}

CC.prototype.ajax_build_question_dialog = function(p_option, p_ruletype, p_ruleidx, p_callback)
{
	new Ajax.Request('cc.php', {
		parameters: {
			method:   'build_question_dialog',
			parentid: this.m_parentid,
			option:   p_option,
			ruletype: p_ruletype,
			ruleidx:  p_ruleidx,
			prefix:   this.m_prefix
		},
		method:       'post',
		evalJSON:     'force',
		asynchronous: false,
		onSuccess:    p_callback
	});
}

CC.prototype.ajax_load_state = function(p_callback)
{
	new Ajax.Request('cc.php', {
		parameters: {
			method:   'load_state',
			parentid: this.m_parentid
		},
		method:       'post',
		evalJSON:     'force',
		asynchronous: false,
		onSuccess:    p_callback
	});
}

CC.prototype.load_state = function()
{
	this.ajax_load_state(function(p_transport) {
		// Nur gültige AJAX-Requests durchlassen
		if(p_transport.readyState != 4) return;
		var l_res = p_transport.responseJSON;

		// Bestandsvektor auf HTML-Controls übertragen
		this.m_curr = l_res.data.result;
		this.process_curr();
	}.bind(this));
}

CC.prototype.ajax_initialize_state_table = function(p_options, p_phpfunc, p_callback)
{
	new Ajax.Request('cc.php', {
		parameters: {
			method:   'initialize_state_table',
			parentid: this.m_parentid,
			options:  Object.toJSON(p_options),
			phpfunc:  p_phpfunc
		},
		method:       'post',
		evalJSON:     'force',
		asynchronous: true,
		onSuccess:    p_callback
	});
}

CC.prototype.initialize_state_table = function(p_options, p_phpfunc, p_process)
{
	this.ajaxload_start();

	this.ajax_initialize_state_table(p_options, p_phpfunc, function(p_transport) {
		var l_res = p_transport.responseJSON;
		if(p_transport.readyState != 4) {
			alert("CC: Error initializing state table!");
		} else if(l_res.status == CC_RESULT_STATUS__OK) {
			this.m_curr = l_res.data.result;
			console.log("before process_curr");
			// Wenn gewünscht, Bestandsvektor auf HTML-Controls übertragen
			if(p_process) this.process_curr();
			console.log("after process_curr");
			
			console.log("before eval");
			// Eval-After-Callback ausführen
			l_res.data.evalafter.evalScripts();
			console.log("after eval");
			
			// Event senden, dass Berechnung der Konfiguration abgeschlossen wurde+
			document.fire('cc:done');
		}
		this.ajaxload_stop();
	}.bind(this));
}

CC.prototype.process_curr = function()
{
	for(l_key in this.m_curr) {
		if(l_key.match('^\\w?\\d+$')) {
			this.m_cb_set_state(l_key);
		}
	}
}

CC.prototype.reset = function()
{
	this.m_curr = {};
}

CC.prototype.get_curr = function()
{
	return this.m_curr;
}

CC.prototype.get_reduced_curr = function()
{
	var l_curr = Object.clone(this.m_curr);
	for(l_key in l_curr) {
		if(l_key.match('^\\w?\\d+$')) {
			if(l_curr[l_key].state == CC_OPTION_STATUS__AVAIABLE) {
				delete l_curr[l_key];
			}
		}
	}
	return l_curr;
}

CC.prototype.select = function(
	p_vec, 
	p_require, 
	p_savestate,
	p_phpfunc,
	p_onOK, 
	p_onInconsistent
) {	
	this.ajaxload_start();

	this.ajax_calc_selection(p_vec, p_require, p_savestate, p_phpfunc, function(p_transport) {
		// Nur gültige AJAX-Requests durchlassen
		if(p_transport.readyState != 4) return;
		var l_res = p_transport.responseJSON;

		// Bestandsvektor auf HTML-Controls übertragen
		this.m_curr = l_res.data.result;
		this.process_curr();

		// Ergebnis auswerten
		switch(l_res.status) {
		case CC_RESULT_STATUS__OK:
			// Eval-After-Callback ausführen
			l_res.data.evalafter.evalScripts();
			p_onOK(l_res);
			
			// Event senden, dass Berechnung der Konfiguration abgeschlossen wurde
			document.fire('cc:done');
					
			break;
		case CC_RESULT_STATUS__INCONSISTENT:
			l_res.data.questions.each(function(p_question) {
				this.ajax_build_question_dialog(
					p_question['option'], 
					p_question['ruletype'], 
					p_question['ruleidx'], 
					function(p_transport) {
						if(p_transport.readyState != 4) return;
						var l_res = p_transport.responseJSON;
						if(l_res.status == CC_RESULT_STATUS__OK) {
							l_res.data.dialog.evalScripts();
							p_onInconsistent(l_res);
						}
					}.bind(this)
				);
			}.bind(this));

			break;
		}
		
		this.ajaxload_stop();
	}.bind(this));
}