//
// Default vars, can be overridden by Chan itself via HEAD SCRIPT insertion on Page_Load (ish)
//
var C__Chan_Root              = "/Chan";
var C__Site_Root              = "/";
var C__Version				  = "0.8.2";
var C__Locale				  = "en";
//var C__IsIE6 = false /*@cc_on || @_jscript_version <= 5.7 @*/;

//fake classes/namespaces
//LOCALE : var Chan = {};
//LOCALE : var Locale = {};



//
// Client side page load
//
function C__Page_Load()
{
	//LOCALE : Chan.Locale = new Locale.en();
	
	//apply any IE6 fixes in ie6.js
	//if( C__IsIE6 && window.C__IE6_Page_Load )
	//	Chan_IE6_Page_Load();
	
	//initialise any Grids in Controls_Grid.js
	//if( window.CC_Grid_Load )
	//	CC_Grid_Load();
		
	//initialise any Image Panels
	if( window.CC_ImagePanel_Init )
		CC_ImagePanel_Init();	
		
	//initialise any scrolling panels
	//if( window.C__Scroll_Init )
	//	C__Scroll_Init();

	//prefetch images for javascript mouseovers etc
	if( window.CCI_Cache_Images )
		CCI_Cache_Images();

	//convert textareas to Rich Text
	CC_TextBox_InitRich();
}

//
// Generic Event container
//
function C__Event( e )
{
	if (!e) 
		var e = window.event;
		
	this.Event = e;
		
	if (e.target) 
		this.Target = e.target;
	else 
	if (e.srcElement) 
		this.Target = e.srcElement;
	
	// Safari
	if (this.Target.nodeType == 3)
		this.Target = this.Target.parentNode;

	return this;
}



//
// DOM Helper functions
//
function C__Show( h , b )
{
	if(h)
		h.style.display = (b ? "" : "none");
}

function C__AddClass( h , c )
{
	var s = " " + c;
	if( h && h.className.indexOf( s ) == -1 )
		h.className += s;
}

function C__RemClass( h , c )
{
	var s = " " + c;
	if( h )
	{
		if( h.className == c )
			h.className = "";
		else
		if( h.className.indexOf( s ) > -1 )
			h.className = h.className.replace( s , "g" );	
	}
}



//
// Convert input string into [a] HTML escaped string
//
function C__IntoHtml( s , bPreserveSpaces )
{
	if( s == "" )
		return "&nbsp;";
	
	if( bPreserveSpaces )		
		return s.replace( /&/g , "&amp;" ).replace( /\"/g , "&quot;" ).replace( /</g , "&lt;" ).replace( />/g , "&gt;" );
		
	return s.replace( /&/g , "&amp;" ).replace( /\"/g , "&quot;" ).replace( /</g , "&lt;" ).replace( />/g , "&gt;" ).replace( / /g , "&nbsp;" );
}

//
// Convert input string out o[f a] HTML escaped string
//
function C__OutoHtml( s )
{
	if( s == "&nbsp;" )
		return "";
		
	return s.replace( /&nbsp;/g , " " ).replace( /&quot;/g , "\"" ).replace( /&lt;/g , "<" ).replace( /&gt;/g , ">" ).replace( /&amp;/g , "&" );
}








//
//	SHARED / GENERIC FUNCTIONS
//

//
// Generic validation function, switches on object type
// which is embedded in the classname
//
function C__Validate( input_object )
{
	var type = input_object.className;
	
	//multiple class names?! find the chan-control one in there
	if( type.indexOf( " " ) > -1 )
	{
		var a = type.split( " " );
		var ia = 0;
		var na = a.length;
		
		for( ia = 0 ; ia < na ; ia ++ )
			if( a[ia].indexOf( "CC_" ) > -1 )
			{
				type = a[ia];
				break;
			}
	}
	
		
	switch( type )
	{
		case "CC_TextBox":
			return CC_TextBox_Validate( input_object );
			break;
		
		case "CC_Password":
			return CC_TextBox_Validate( input_object );
			break;
		
		case "CC_Date":
			//in Controls_Date.js
			if( window.CC_DateBox_Validate )
				return CC_DateBox_Validate( input_object );
			return true;
			break;
			
		case "CC_Numeric":
			return CC_Numeric_Validate( input_object );
			break;
	
		case "CC_Upload":
			return CC_Upload_Validate( input_object );
			break;
	
		// a Tab-Button belonging to a Tab-Panel?
		case "CC_Button":
			if( input_object.className.indexOf( "CC_Tab" ) > -1 )
				return CC_TabPanel_Validate( null , null , input_object );
			break;
	
		default:
			break;
	}	
	
	return true;
}


//
// Shows or hides a control's invalid image depending on the control's
// parameters, specifically it's Valid bool
//
function C__SetInvalidImage( CC )
{
	var IMG_ID = CC.ID + "___InvalidImage";
	var IMG = document.getElementById( IMG_ID );
	
	//if the control is Valid remove any "invalid" image associated with it	
	if( CC.Valid )
	{
		//remove any old Invalid image from the DOM
		if( IMG )
			IMG.parentNode.removeChild( IMG );
	}
	else
	{
		//no image, spawn one
		if( !IMG )
		{
			
			IMG = document.createElement( "SPAN" );
			IMG.id = IMG_ID;
			IMG.className = "CC_Invalid";		
			IMG.innerHTML = "<img src='" + C__Chan_Root + "/Icon16/exclamation.png'>";
			
			//i.e. insertAfter(this) !
			CC.DOMObject.parentNode.insertBefore( IMG , CC.DOMObject.nextSibling );	
		}
		
		//IMG is inside a SPAN
		IMG = IMG.firstChild;

		IMG.setAttribute( "alt" , CC.InvalidReason );
		IMG.setAttribute( "title" , CC.InvalidReason );
	}
}

//
// Adds leading zeros to a numeric input
//
function C__AddLeadingZeros( n , digits )
{ 
	if( digits > 10 )
		digits = 10;
	
	var s = "0000000000" + n;	
	
	if( s.indexOf(".") == -1 )
		return s.substring( s.length - digits );

	var a = s.split(".");
	
	return a[0].substring( s.a[0] - digits ) + "." + a[1];
}

//
// Accepts a string in the format "A {0} C" with a number of substitutes 
// e.g. var1 = "B". Not very scientific at the moment but it gets the job done
//
function C__String_Reduce( str , var0 , var1 , var2 , var3 , var4 )
{
	str = str.replace( "{0}" , var0 != null ? var0 : "" );
	str = str.replace( "{1}" , var1 != null ? var1 : "" );
	str = str.replace( "{2}" , var2 != null ? var2 : "" );
	str = str.replace( "{3}" , var3 != null ? var3 : "" );
	str = str.replace( "{4}" , var4 != null ? var4 : "" );
	
	return str;
}

//
// To debug a string just send it to this function, if not found it will slap a
// TEXTAREA on your page to act as a debug console - very handy
//
function C__Debug( s )
{
	if( s == null || s == "" )
		return;
		
	var d = document.getElementById("debug_console");
	
	//if the debug textarea does not exist then create it
	if(!d)
	{
	  d = document.createElement("TEXTAREA");
	  d.id = "debug_console";
	  d.rows = "10";
	  d.cols = "60";
	  d.style.position = "absolute";
	  d.style.top = "10";
	  d.style.left = "10";
	  d.style.zIndex = "10000";
	  
	  var b = document.getElementsByTagName( "BODY" )[0];
	  
	  b.insertBefore( d , b.firstChild );
	}
	
	d.value = d.value + s + "\n";
}		







//
//	EVENTS AND VALIDATION
//
//	CLIENT EVENTS SUCH AS ONKEYDOWN AND ONBLUR CAN PERFORM SUPERFICIAL REFORMATTING
//	OF AN INPUT'S CONTENTS, BUT MUST NOT SET/UNSET THE INVALID IMAGE
//
//	VALIDATION SHOULD ALSO PERFORM THE SAME CLEANUP FIRST AND WARN THE USER (SO
//	CLEANUP NOT CAUGHT IN ONBLUR CAN BE ADDRESSED). ONLY THE FORM SUBMIT VALIDATION
//	FUNCTION MAY SET/UNSET THE INVALID IMAGE
//


//
// Generic validator - validates all the controls in an array and prints
// the error message in the (optional) notification area
//
function C__Validate_Controls( aControls , sInvalidMessage , notify_object )
{
	var ii = 0;
	var ni = aControls.length;
	var Valid = true;
	var ValidTemp = true;
	
	for( ii = 0 ; ii < ni ; ii ++ )
	{
		//need to fetch and validate all controls, not just fail out on
		//the first one we find. but we don't want the whole form to be
		//flagged as Valid if the very last control happens to be valid
		ValidTemp = C__Validate( aControls[ ii ] );	
			
		if( !ValidTemp)
			Valid = false;
	}
	
	//notify the user if bad things happenned either via  a DOM object
	//(such as a bolded paragraph) or via a standard alert popup
	if( sInvalidMessage && sInvalidMessage != "" && !Valid )
	{
		if( notify_object != null )
			notify_object.innerHTML = sInvalidMessage;
		else
			alert( sInvalidMessage );
	}
	
	return Valid;
}



//  ----------------------------------------------------------------------------
//
//  Chan.Controls.Form
//
//  ----------------------------------------------------------------------------

function CC_Form_Validate( input_object , notify_object )
{
	return C__Validate_Controls( input_object.elements , STR_FORM_IS_INVALID , notify_object );
}


//  ----------------------------------------------------------------------------
//
//	CLASSES
//
//	All should publicly expose
//
//	ID			(string)
//	Text		(string)
//	Value		(variant type)
//	Valid		(bool)
//	InvalidReason	(string)
//	DOMObject	(HTML DOM input handle)
//
//	Most will also have the following:
//
//	Mandatory	(bool)
//
//  ----------------------------------------------------------------------------

//  ----------------------------------------------------------------------------
//
//  Chan.Controls.DecimalBox
//  Chan.Controls.Int32Box
//
//  ----------------------------------------------------------------------------

//
// Converts a DOM input into a local Chan Numeric Control
//
//CCV="{type:'dec',min:0,max:99999.9,places:1,digits:5,mandatory:true,autoLimit:true}"
function CC_Numeric_New( input_object )
{
	this.DOMObject	= input_object;
	
	this.ID			= String( input_object.id );
	this.Text		= String( input_object.value ).replace( /\s*/g , "" );
	this.Value		= parseFloat( this.Text );	
	
	var CCV = input_object.getAttribute( "CCV" );
	
	if( !CCV )
		CCV = "{}";
	
	var JSON = eval( "(" + CCV + ")" );
	
	if( !JSON )
		return null;

	this.Type = JSON.type;	
	this.Mandatory = JSON.mandatory;
	this.Min = JSON.min;
	this.Max = JSON.max;
	this.Places = JSON.places;
	this.Digits = JSON.digits;
	this.AutoLimit = JSON.autoLimit;
	this.AutoZero = JSON.autoZero;
	
	this.Valid		= true;						//assume valid
	this.InvalidReason = "";
		
	return this;
}

//
// Validate function, invoked from parent form
//
function CC_Numeric_Validate( input_object )
{
	var ctl = CC_Numeric_New( input_object );
	
	//call the onblur first, which will do some formatting
	//and may bound the value to min/max
	CC_Numeric_OnBlur_Ctl( ctl )
		
	// int32 overflow check
	if( ctl.Type == 'i32' && (ctl.Text > 2147483647 || ctl.Text < -2147483647 ) )
	{
		ctl.InvalidReason = STR_INT32_OVERFLOW;
		ctl.Valid = false;		
	}

	if( ctl.Valid && ctl.Text == "" )
	{
		//if it's not mandatory and the control is empty then quit out here
		if( !ctl.Mandatory )
		{
			C__SetInvalidImage( ctl );
			return true;
		}
		
		ctl.InvalidReason = STR_FIELD_IS_MANDATORY;
		ctl.Valid = false;
	}

	//basic negateable numeric test
	if( ctl.Valid && isNaN( ctl.Value ) )
	{
		ctl.InvalidReason = STR_NUMERIC_IS_NAN;
		ctl.Valid = false;
	}

	// Min
	if( ctl.Valid && !isNaN( ctl.Min ) && ctl.Value < ctl.Min )
	{
		ctl.InvalidReason = C__String_Reduce( STR_NUMERIC_BELOW_MIN , ctl.Min );
		ctl.Valid = false;
	}

	// Max
	if( ctl.Valid && !isNaN( ctl.Max ) && ctl.Value > ctl.Max )
	{
		ctl.InvalidReason = C__String_Reduce( STR_NUMERIC_ABOVE_MAX , ctl.Max );
		ctl.Valid = false;
	}
	
	//show (or hide) our invalid marker image
	C__SetInvalidImage( ctl );

	return ctl.Valid;
}

//
// onblur, reformat according to validation rules
//
// 0.8.0 - AutoFormat has been deprecated and this always
// runs on onblur, but now it only formats the number 
// according to the Digits and Places, rather than assuming
// a validation role
// 
//
function CC_Numeric_OnBlur( input_object )
{
	var ctl = CC_Numeric_New( input_object );
	
	CC_Numeric_OnBlur_Ctl( ctl );
}

//
// overload of above - accepts custom control object
//
function CC_Numeric_OnBlur_Ctl( ctl )
{
	//AutoZero sets a null (or non numeric) value to the
	//Min value, but only when the control is mandatory
	if( ctl.AutoZero && ctl.Mandatory && isNaN(ctl.Value) && !isNaN(ctl.Min) )
	{
		ctl.Value = ctl.Min;
	}	
	
	//set decimal places
	if( !isNaN(ctl.Value) )
	{
		// AutoLimit bounds the value to min/max
		if( ctl.AutoLimit )
		{
			//floor to min value
			if( !isNaN(ctl.Min) && ctl.Value < ctl.Min )
			{
				ctl.Value = ctl.Min;
			}

			//ceiling to max value
			if( !isNaN(ctl.Max) && ctl.Value > ctl.Max )
			{
				ctl.Value = ctl.Max;
			}
		}
		
		var sTmp = String( ctl.Value );
				
		//fixed number of decimal places and/or leading zeros
		//BUG : should truncate not round!
		if( ctl.Value.toFixed )
		{
			sTmp = ctl.Value.toFixed( ctl.Places )
		}
	
		//write the value back into the document
		if( ctl.Digits > 0 )
			ctl.DOMObject.value = C__AddLeadingZeros( sTmp , ctl.Digits );
		else
			ctl.DOMObject.value = sTmp;
	}
}




//  ----------------------------------------------------------------------------
//
//	Chan.Controls.TextBox
//
//  ----------------------------------------------------------------------------

//
// Converts a DOM input into a local Chan TextBox Control
//
function CC_TextBox_New( input_object )
{
	this.DOMObject	= input_object;
	this.ID			= String( input_object.id );
	this.Text		= String( input_object.value );
	this.Value		= this.Text;	
	this.Valid		= true;						//assume valid
	this.InvalidReason = "";
	
	this.Mandatory	= (input_object.getAttribute( "mandatory" ) == "true");
	
	//input.text will have this natively handled but textarea will not
	this.MaxLength	= parseInt( input_object.getAttribute( "maxlength" ) );
	
	//mainly needed for Password subtype
	this.MinLength	= parseInt( input_object.getAttribute( "minlength" ) );
		
	return this;
	
	//functions:
	//bool ...Validate( input )		
}

function CC_TextBox_Validate( input_object )
{
	var ctl = CC_TextBox_New( input_object );
	
	//alert( ctl.Text.length + " / " + ctl.MaxLength );

	//basic mandatory check
	if( ctl.Mandatory && ctl.Text == "" )
	{
		ctl.InvalidReason = STR_FIELD_IS_MANDATORY;
		ctl.Valid = false;
	}
		
	//need to handle this for textarea
	if( ctl.Valid && ctl.Text.length > ctl.MaxLength )
	{
		ctl.Valid = false;
		ctl.InvalidReason = C__String_Reduce( STR_STRING_TOO_LONG , ctl.Text.length , ctl.MaxLength );
	}
	//	ctl.DOMObject.value = ctl.Text.substr( 0 , ctl.MaxLength );
	
	//min length is for username / password fields etc.
	if( ctl.Valid && ctl.Text.length < ctl.MinLength )
	{
		ctl.Valid = false;
		ctl.InvalidReason = C__String_Reduce( STR_STRING_TOO_SHORT , ctl.Text.length , ctl.MinLength );
	}

	C__SetInvalidImage( ctl );
	
	return ctl.Valid;
}


function CC_TextBox_InitRich()
{	
	var a = document.getElementsByTagName( "TEXTAREA" );
	
	if( !a || !a.length )
		return;
	
	var ii = 0;
	var ni = a.length;
	
	for( ; ii < ni ; ii++ )
	{
		if( a[ii].id && a[ii].className.indexOf("C__Rich") > -1 )
		{
			var oFCKeditor = new FCKeditor( a[ii].id );
			oFCKeditor.BasePath = C__Chan_Root + '/cke/';
			oFCKeditor.ReplaceTextarea();
		}
	}
}
	
//
// onblur, reformat according to validation rules
//
//function CC_TextBox_OnBlur( input_object )
//{
//
//}
//
//
// overload of above - accepts custom control object
//
//function CC_TextBox_OnBlur_Ctl( ctl )
//{
//	
//}


//  ----------------------------------------------------------------------------
//
//	Chan.Controls.Upload
//
//  ----------------------------------------------------------------------------

//
// Converts a DOM input into a local Chan TextBox Control
//
function CC_Upload_New( input_object )
{
	this.DOMObject	= input_object;
	this.ID			= String( input_object.id );
	this.Text		= String( input_object.value );
	this.Value		= this.Text;	
	this.Valid		= true;						//assume valid
	this.InvalidReason = "";
	
	this.Mandatory	= (input_object.getAttribute( "mandatory" ) == "true");
		
	return this;
	
	//functions:
	//bool ...Validate( input )		
}

function CC_Upload_Validate( input_object )
{
	var ctl = CC_Upload_New( input_object );

	//basic mandatory check
	if( ctl.Mandatory && ctl.Text == "" )
	{
		ctl.InvalidReason = STR_FIELD_IS_MANDATORY;
		ctl.Valid = false;
	}

	C__SetInvalidImage( ctl );
	
	return ctl.Valid;
}

//
// Client side implimentation of the "Change" button which allows
// you to select a different file for upload than the current one
//
function CC_Upload_Change( event , UploadID )
{
	//UploadID is original upload control which may or may not exist in the DOM
	//UploadID + "___Current" is disabled textbox showing filename
	//UploadID + "___Change" is "Change" button
	//UploadID + "___Path" is temp path on server
	
	var upl = document.getElementById( UploadID );
	var txt = document.getElementById( UploadID + "___Current" );
	var btn = document.getElementById( UploadID + "___Change" );
	//var hid = document.getElementById( UploadID + "___Path" );

	
	//if upl exists then we're Undo-ing our request to change files
	if( upl != null )
	{
		upl.parentNode.removeChild( upl );
		
		//show the textbox
		txt.style.display = "";
		
		//change the button text
		btn.value = "Change";	
		btn.alt = btn.value;
		btn.title = btn.value;
	}
	else
	{	
		//re-create the upload control
		upl = document.createElement( "INPUT" );
		upl.type = "file";
		upl.id = UploadID;
		upl.name = UploadID;
		upl.className = "CC_Upload";
		
		//insert it before the textbox in the DOM tree
		txt.parentNode.insertBefore( upl , txt );
		
		//hide the textbox
		txt.style.display = "none";
		
		//change the button text
		btn.value = "Restore";
		btn.alt = btn.value;
		btn.title = btn.value;
	}
	
	return false;
}




//
// Image 
//

//
// Used by an input type="image" to replace another image with 
// it's own zoomed in one
//
// ImageID   - id of target DOM IMG tag to change
// Path      - src for IMG tag
// FormName  - [Optional] - Name of form in which to assign Path to the INPUT named "[ImageID]" value (base64 encoded)
// Tag       - [Optional] - value to assign to an INPUT named "[ImageID]___Tag"
//
function CC_Image_Zoom( ImageID , Path , FormName , Tag )
{
	//incorrect javascript version, revert to postback
	if( !document.getElementById )
		return true;
	
	var h = document.getElementById( ImageID );
	
	//target image not found, fail silently
	if( !h )
		return false;
	
	h.src = C__Chan_Root + "/Clear.gif";		//clear it first whilst the desired one loads, devs can then put a "Loading..." background image behind it if they want
	h.src = Path;
	
	// Target Image may have its Remember parameter set to true so we'll need to set its
	// hidden form field also
	if( FormName != null && FormName != "" && document.forms[ FormName ] != null  && document.forms[ FormName ][ ImageID ] != null )
	{
		document.forms[ FormName ][ ImageID ].value = C__B64Encode( Path );
		
		if( Tag != null && document.forms[ FormName ][ ImageID + "___Tag" ] != null )
			document.forms[ FormName ][ ImageID + "___Tag" ].value = Tag;
	}
	
	return false;
}

//
// Simply switch an image's src
//
function CC_Image_Switch( hImage , Path )
{
	if( hImage == null )
		return;
	
	hImage.src = Path;
}

















//
// Helper Functions
//


//
// Base64 code adapted from Tyler Akins -- http://rumkin.com
//

var C__B64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";

function C__B64Encode(input) 
{
	if( input == null || input == "" )
		return "";

	if( window.btoa )
		return window.btoa(input);
	
	var output = "";
	var c1, c2, c3;
	var e1, e2, e3, e4;
	var i = 0;

	do 
	{
	  c1 = input.charCodeAt(i++);
	  c2 = input.charCodeAt(i++);
	  c3 = input.charCodeAt(i++);

	  e1 = c1 >> 2;
	  e2 = ((c1 & 3) << 4) | (c2 >> 4);
	  e3 = ((c2 & 15) << 2) | (c3 >> 6);
	  e4 = c3 & 63;

	  if (isNaN(c2)) {
		 e3 = e4 = 64;
	  } else if (isNaN(c3)) {
		 e4 = 64;
	  }

	  output = C__Concat( output , C__B64.charAt(e1) , C__B64.charAt(e2) , C__B64.charAt(e3) , C__B64.charAt(e4) );
	  
	} while (i < input.length);

	return output;
}

function C__B64Decode(input) 
{
	if( input == null || input == "" )
		return "";

	if( window.atob )
		return window.atob(input);
	
   var output = "";
   var c1, c2, c3;
   var e1, e2, e3, e4;
   var i = 0;

   // remove all characters that are not A-Z, a-z, 0-9, +, /, or =
   input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");

   do 
   {
      e1 = C__B64.indexOf(input.charAt(i++));
      e2 = C__B64.indexOf(input.charAt(i++));
      e3 = C__B64.indexOf(input.charAt(i++));
      e4 = C__B64.indexOf(input.charAt(i++));

      c1 = (e1 << 2) | (e2 >> 4);
      c2 = ((e2 & 15) << 4) | (e3 >> 2);
      c3 = ((e3 & 3) << 6) | e4;

      output = output + String.fromCharCode(c1);

      if (e3 != 64) 
	  {
         output = output + String.fromCharCode(c2);
      }
      if (e4 != 64) 
	  {
         output = output + String.fromCharCode(c3);
      }
   } while (i < input.length);

   return output;
}


//
// For quickly joining strings
//

function C__Concat( s1 , s2 , s3 , s4 , s5 , s6 , s7 , s8 )
{	
	var a = new Array();
	
	a.push(s1);
	a.push(s2);
	a.push(s3);
	a.push(s4);
	a.push(s5);
	a.push(s6);
	a.push(s7);
	a.push(s8);
		
	return a.join("");
}






//
// Chan.Controls.CheckList
//

//
// Find the next DOM parent with the given nodename
//
function C__GetParent( hChild , sNodeName )
{
	if( !hChild )
		return null;
	
	while( hChild && hChild.nodeName != sNodeName )
		hChild = hChild.parentNode;
	
	return hChild;
}

//
// Check or Uncheck all the checkboxes in the given table
//
function CC_CheckList_CheckAll( event , hTable , bChecked )
{
	// find the table up the dom tree
	hTable = C__GetParent( hTable , "TABLE" );
	if( !hTable )
		return;
	
	var a = hTable.getElementsByTagName( "INPUT" );
	var hRow;
	var cb = null;
	var ii = 0;
	var ni = a.length;
	
	for( ; ii < ni ; ii++ )
	{
		cb = a[ii];
		
		if( cb.getAttribute( "type" ) != "checkbox" )
			continue;
			
		cb.checked = (bChecked == true);	//convert null to false
		
		hRow = C__GetParent( cb , "TR" );
		
		if( cb.checked )
		{
			hRow.className += " Selected";
		}
		else
		{
			hRow.className = hRow.className.replace( / *Selected/g , '' );
		}	
	}
}

//
// Toggle Checked / Selected state of a row
//
function CC_CheckList_Select( event , hRow )
{
	if (!event) 
		var event = window.event;
		
	var hTarget = event.target ? event.target : event.srcElement;

	// find the row up the dom tree
	hRow = C__GetParent( hRow , "TR" );
	if( !hRow )
		return;
	
	var a = hRow.getElementsByTagName( "INPUT" );
	var cb = null;
	var ii = 0;
	var ni = a.length;
	
	for( ; ii < ni ; ii++ )
	{
		cb = a[ii];
		
		if( cb.getAttribute( "type" ) != "checkbox" && cb.getAttribute( "type" ) != "radio" )
			continue;
		
		//the browser will do this part for us if the user clicked on the cb or label directly
		if( hTarget.nodeName != "INPUT" && hTarget.nodeName != "LABEL" )
			cb.checked = !cb.checked;
		
		if( cb.checked )
		{
			hRow.className += " Selected";
		}
		else
		{
			hRow.className = hRow.className.replace( / *Selected/g , '' );
		}			
			
		break;
	}
	
	// If we're a list with radio buttons we need to re-set all the rows to
	// not-selected			
	if( cb && cb.checked && cb.getAttribute( "type" ) == "radio" )
	{
		var hTable = C__GetParent( hRow , "TABLE" );
		
		ii = 0;
		ni = hTable.rows.length;
		
		for( ; ii < ni ; ii++ )
			hTable.rows[ii].className = hTable.rows[ii].className.replace( / *Selected/g , '' );
		
		hRow.className += " Selected";
	}
	


	event.cancelBubble = true;
	if (event.stopPropagation)
		event.stopPropagation();				
}