/***************************************************************************************
 ***************************************************************************************
 **
 ** Robot Galaxy SSFC API
 **


- There are a number of Javascript functions that can be called from the Flash. Their names and purpose are:


	- RGFCRegister: Register a new contact with the RG database, generating a Member ID in the process.

	- RGFCLookupContact: Lookup an existing contact in the RG database by Member ID

	- RGFCProgram: Program the data into the robot

	- RGFCPlaySound: Play a sound on the robot

	- RGFCSetLED: Set the Robot LED to a specified color

	- RGFCSetAlarm: Set the alarm for a specified date/time, or clear it.

	- RGFCSetClock: Set the on-board clock to a specified date/time.

	- RGFCIsConnected: Check if the SSFC is connected.

	- RGFCIsProgrammed: Check if the connected SSFC is programmed.

	- RGFCIsBatteryLow: Check if the SSFC gbattery volate is below a defined threshold.

	- RGFCGetId: Get the RG Force Code ID from the currently connected SSFC.
	- RGFCGetRobotType: Get the RG Robot Type (Core) from the currently connected SSFC.

	- RGFCGetConfiguration: Get the full current configuration details for the currently connected SSFC



	- RGFCErrorAsString:	Helper function to convert an error JSON object to a string.

- The basic process is:
	- Call RGFCRegister or RGFCLookupContact to get a new or existing Member ID.
	- Call RGFCIsConnected, RGFCIsProgrammed, and RGFCGetConfiguration as appropriate to determine the currently connected robot details.
	- Call RGFCProgram to program the data into the robot (assuming registration/lookup success)
	- Call RGFCSetClock to set the clock on the SSFC, and then RGFCSetAlarm to update the alarm clock setting.
	- Call RGFCPlaySound and RGFCSetLED in response to various game-related actions.
	- Periodically call RGFCIsBatteryLow to alert the user to replace the batteries.
	- Call RGFCErrorAsString to display any error details

- The test harness (rgfcTest.html) is a great way to check all of these API calls out.

- Right now, you would include the rgfc.js file in your Flash HTML file, which provides the above APIs. In the test harness, we include that file and those are the functions we call from the HTML forms.

- Right now, error handling is fairly minimal. Basically, if required fields are left blank, you'll get an error. I'm guessing that the Flash will handle this, and most error codes, so this may not be necessary. The Flash should handle most reasonable input checking, with only more advanced checking being relegated to the Javascript and plug-in code.

- Fields and requirements for the jsonDetails JSON object to RGFCRegister() are as follows:

Field name			Description			Required?	Data type
----------			-----------			---------	---------
contact_first_name		First Name			Required	varchar(32)
contact_last_name		Last Name					varchar(64)
contact_gender                  Gender                                          varchar(1)
contact_address_line_1		Address Line 1					varchar(255)
contact_city			City						varchar(100)
contact_state			State						varchar(2)
contact_postal_code		Zip/Postal code					varchar(10)
contact_email			Email address					varchar(128)
contact_dob			Date of Birth (YYYYMMDD)			varchar(8)
product_fuelcell_type		Fuel Cell Type			Required	integer
product_collection_fk		Robot Type			Required	integer
product_package_name		Robot Name			Required	varchar(32)
contact_member_id		Member ID					integer(6)

The Fuel Cell Type (product_fuelcell_type) options are:
	1 = Fuel Cell
	2 = Ultra Fuel Cell
        3 = SuperSonic Fuel Cell

The Robot Type (product_collection_fk) options are:
	2 = CJ-531 - Original White/Blue
        3 = Jo - Original Red
        4 = Pango - Original Yellow
        5 = Carson - Orginal Orange
        6 = Rah - Original Gray
        7 = Crystal
        8 = Drone
        9 = Henchman
        10 = CJ-531 - Red/White/Blue
        11 = Jo - Blue
        12 = Carson - Green
        13 = Rah - Red

The Member ID (contact_member_id) is always a number with at least 6 digits. For the SSFC, the Member ID may be much longer (32 digits).

The other variables are strings of maximum length specified above.


*********************************************************************************
*********************************************************************************/

function getRGFCPlugin() {
    return document.all.RGFCPlugin;
} // getRGFCPlugin()

function RGFCInitialize() {
    var plugin = getRGFCPlugin();
    var result = plugin.Initialize();

    return result;
} // RGFCInitialize()

function RGFCRegister( jsonDetails )
{
    var jsonResult;
    
    if( jsonDetails ) {
	if( jsonDetails["contact_first_name"] && (jsonDetails["contact_first_name"] != "") &&
	    jsonDetails["product_fuelcell_type"] && (jsonDetails["product_fuelcell_type"] != "") &&
	    jsonDetails["product_collection_fk"] && (jsonDetails["product_collection_fk"] != "") &&
	    jsonDetails["product_package_name"] && (jsonDetails["product_package_name"] != "") 
	    ) {
	    jsonResult = {
		"contacts" : [
	                      {
				  "contact_member_id" : "123456"
			      }
			      ]
	    };
	}
    }
    
    if( !jsonResult ) {
	jsonResult = {
	    "errors" : [
	                 {
			     "code" : 350,
			     "desc" : "This is the problem here. More details will display in the actual RGFC API."
			 }
			]		
	};
    }
	
    return jsonResult;
} // RGFCRegister()

function RGFCLookupContact( query )
{
    var jsonResults, jsonContact;
    
    if( query &&
	query != "" ) {
	/* this should either be all numbers (a Member ID) or an email address */
	var reMemberID = new RegExp( /^\d{6,}$/ ); /* Member ID is 6 or more digits */
	var reEmail = new RegExp( /^\w+\@\w+\.\w+/ ); /* TODO: too simple for email ?*/
	
	var r = query.match( reMemberID );
	if( r != null ) { // then Member ID entered
	    jsonContact = {
		"contact_first_name" : "First Name",
		"contact_last_name" : "Last Name",
		"contact_address_line_1" : "Address Line 1",
		"contact_city" : "City",
		"contact_state" : "NY",
		"contact_postal_code" : "10000",
		"contact_email" : "you@robotgalaxy.com",
		"contact_dob" : "19700101",
		
		"contact_member_id" : query,
		
		"product_fuelcell_type" : 2,
		"product_collection_fk" : 3,
		"product_package_name" : "My Robot"
	    };		
	} else if( reEmail.exec( query ) != null ) { // then Email entered
	    jsonContact = {
		"contact_first_name" : "First Name",
		"contact_last_name" : "Last Name",
		"contact_address_line_1" : "Address Line 1",
		"contact_city" : "City",
		"contact_state" : "NY",
		"contact_postal_code" : "10000",
		"contact_email" : query,
		"contact_dob" : "19700101",
		
		"contact_member_id" : "123456",
		
		"product_fuelcell_type" : 2,
		"product_collection_fk" : 3,
		"product_package_name" : "My Robot"
	    };
	} else { // invalid input
	    jsonContact = null;
	}			
    }
    
    
    if( jsonContact ) {
	jsonResults = {
	    "contacts" : [
			  jsonContact
			  ]
	};
    } else { // no contact found
	jsonResults = {
	    "errors" : [
	                {
			    "code" : 345,
			    "desc" : "Could not find contact."
			}
			]		
	};
    }

    return jsonResults;
} // RGFCLookupContact()


//
// RGFCProgram()
//
// Input:
//     contactFirstName:    Explorer first name
//     contactMemberId:     Robot Galaxy Force Code (Member ID)
//     productPackageName:  package name
//     productCollectionFk: robot core
//     contactPoints:       number of points this robot has in the online game
//     contactLevel:        current level of this robot in the online game
//
// Returns:
//     JSON object with no errors on success
//     JSON object containing errors otherwise
function RGFCProgram( contactFirstName, contactMemberId, productPackageName, productCollectionFk, contactPoints, contactLevel )
{
    var jsonResult;
    
    if( contactFirstName &&
	contactFirstName != "" &&
	productPackageName &&
	productPackageName != "" &&
	productCollectionFk &&
	productCollectionFk != "" &&
	contactMemberId &&
	contactMemberId != "" &&
	contactPoints &&
	contactPoints != "" &&
	contactLevel &&
	contactLevel != "" ) {

	var plugin = getRGFCPlugin();
	var nMemberId = parseInt( contactMemberId );
	var nCollectionFk = parseInt( productCollectionFk );
	var nPoints = parseInt( contactPoints );
	var nLevel = parseInt( contactLevel );
	var result = plugin.ProgramFuelCell( contactFirstName,
					     nMemberId,
					     productPackageName,
					     nCollectionFk,
					     nPoints, 
					     nLevel );

	if( result ) {
	    jsonResult = {
	    };
	}
    }

    if( !jsonResult ) {
	jsonResult = {
	    "errors" : [
	{
	    "code" : plugin.LastErrorCode,
	    "desc" : plugin.LastErrorMessage
	}
			]		
	};
    }
    
    
    return jsonResult;
} // RGFCProgram()


//
// RGFCInitializeFuelCell()
//
// Input:
//     n/a
//
// Returns:
//     JSON object with no errors on success
//     JSON object containing errors otherwise
function RGFCInitializeFuelCell()
{
    var jsonResult;
    
    var plugin = getRGFCPlugin();
    var result = plugin.InitializeFuelCell();
    
    if( result ) {
	jsonResult = {
	};
    }

    if( !jsonResult ) {
	jsonResult = {
	    "errors" : [
		{
		    "code" : plugin.LastErrorCode,
		    "desc" : plugin.LastErrorMessage
		}
	    ]		
	};
    }
    
    
    return jsonResult;
} // RGFCInitializeFuelCell()


//
// RGFCPlaySound()
//
// Input:
//     soundIndex: Integer value of index into sound table in the range 0 - 255
//
// Returns:
//     JSON object with no errors on success
//     JSON object containing errors otherwise
function RGFCPlaySound( soundIndex )
{
    var jsonResult;
    
    if( soundIndex &&
	soundIndex > 0 &&
	soundIndex <= 255 ) {

	jsonResult = {
	};
	
	// play sound
	var plugin = getRGFCPlugin();
	plugin.PlaySoundByIndex( soundIndex );
    }
    
    if( !jsonResult ) {
	jsonResult = {
	    "errors" : [
	                 {
			     "code" : 350,
			     "desc" : "There is the problem here. More details will display in the actual RGFC API."
			 }
			]		
	};
    }
    
    
    return jsonResult;
} // RGFCPlaySound()


//
// RGFCSetLED()
//
// Input:
//     r, g, b: Integer value of color code in the range 0 - 15
//
// Returns:
//     JSON object with no errors on success
//     JSON object containing errors otherwise
function RGFCSetLED( r, g, b )
{
    var jsonResult;
    
    if( r &&
	r >= 0 &&
	r <= 15 &&
	g &&
	g >= 0 &&
	g <= 15 &&
	b &&
	b >= 0 &&
	b <= 15 ) {
	jsonResult = {
	};

	// play sound
	var plugin = getRGFCPlugin();
	plugin.SetLED( r, g, b );
    }
    
    if( !jsonResult ) {
	jsonResult = {
	    "errors" : [
	{
	    "code" : 350,
	    "desc" : "There is the problem here. More details will display in the actual RGFC API."
	}
			]		
	};
    }
    
    return jsonResult;
} // RGFCSetLED()

//
// RGFCSetLEDStatus()
//
// Input:
//     bStatus: Boolean value of status (true = On, false = Off)
//
// Returns:
//     JSON object with no errors on success
//     JSON object containing errors otherwise
function RGFCSetLEDStatus( bStatus )
{
    var jsonResult;
    
    // set LED status
    var plugin = getRGFCPlugin();
    plugin.SetLEDStatus( bStatus );
    
    jsonResult = {
    };

    return jsonResult;
} // RGFCSetLEDStatus()


//
// RGFCSetAlarm()
//
// Input:
//     alarmSetting   : 0 to clear alarm, 1 to set one-time alarm, 2 to set daily (recurring) alarm
//     alarmMonth, alarmDay, alarmYear: Date to trigger alarm (only used for one-time alarm)
//     alarmHour, alarmMinute: Time to trigger alarm (used for daily alarm and one-time alarm)
//
// Returns:
//     JSON object with no errors on success
//     JSON object containing errors otherwise
function RGFCSetAlarm( alarmSetting,
		       alarmMonth, alarmDay, alarmYear,
		       alarmHour, alarmMinute )
{
    var jsonResult;
    
    // TODO: better input validation here
    if( alarmSetting &&
	(
	 // clear alarm
	 (alarmSetting == 0) ||
	 // set one-time alarm
	 ((alarmSetting == 1) && 
	  (alarmMonth && alarmDay && alarmYear && alarmHour && alarmMinute)) ||
	 // set daily alarm
	 ((alarmSetting == 2) && 
	  (alarmHour && alarmMinute))
	 )
	) {
	var plugin = getRGFCPlugin();
	var result = plugin.SetAlarm( alarmSetting, alarmMonth, alarmDay, alarmYear, alarmHour, alarmMinute );

	if( result ) {
	    jsonResult = {
	    };
	}

	jsonResult = {
	};
    }
    
    if( !jsonResult ) {
	jsonResult = {
	    "errors" : [
	                {
			    "code" : 350,
			    "desc" : "There is the problem here. More details will display in the actual RGFC API."
			}
			]		
	};
    }
    
    return jsonResult;
} // RGFCSetAlarm()


//
// RGFCSetClock()
//
// Input:
//     Current Month, Day, Year, Hour, Minutes, Seconds to set the the internal SSFC clock to current date/time.
//
// Returns:
//     JSON object with no errors on success
//     JSON object containing errors otherwise
function RGFCSetClock( month, day, year, hours, minutes, seconds )
{
    var jsonResult;
    
    // TODO: better input validation here
    if( true ) {
	var plugin = getRGFCPlugin();
	var result = plugin.SetClock( month, day, year, hours, minutes, seconds );
	if( result ) {
	    jsonResult = {
	    };
	}
    }

    if( !jsonResult ) {
	jsonResult = {
	    "errors" : [
	                 {
			     "code" : 350,
			     "desc" : "There is the problem here. More details will display in the actual RGFC API."
			 }
			]		
	};
    }

    return jsonResult;
} // RGFCSetClock()


//
// RGFCIsConnected()
//
// Returns:
//     true if the SSFC is connected
//     false otherwise
function RGFCIsConnected()
{
    var plugin = getRGFCPlugin();
    var result = plugin.IsConnected();

    return result;
} // RGFCIsConnected()


//
// RGFCIsProgrammed()
//
// Returns:
//     true if the SSFC has been programmed previously
//     false otherwise
function RGFCIsProgrammed()
{
    var plugin = getRGFCPlugin();
    var result = plugin.IsProgrammed();

    return result;
} // RGFCIsProgrammed()


//
// RGFCIsBatteryLow()
//
// Returns:
//     true if the SSFC reports a low battery voltage warning
//     false otherwise
function RGFCIsBatteryLow()
{
    var plugin = getRGFCPlugin();
    var result = plugin.IsBatteryLow();

    return result;
} // RGFCIsBatteryLow()


//
// RGFCGetId()
//
// Returns:
//     integer representing unique Robot Galaxy Force Code, if one exists
//     null otherwise
function RGFCGetId()
{
    var plugin = getRGFCPlugin();
    var result = plugin.GetConfiguration();

    if( result ) {
	return plugin.ConfigRobotID;
    } else {
	return null;
    }
} // RGFCGetId()


//
// RGFCGetRobotType()
//
// Returns:
//     integer representing the Robot Type (Core ID), if one is specified
//     null otherwise
function RGFCGetRobotType()
{
    var plugin = getRGFCPlugin();
    var result = plugin.GetConfiguration();

    if( result ) {
	return plugin.ConfigRobotType;
    } else {
	return null;
    }
} // RGFCGetRobotType()


//
// RGFCGetConfiguration()
//
// Returns:
//     JSON hash of the current robot configuration detected, if detected
//     JSON hash of errors otherwise
function RGFCGetConfiguration()
{
    var jsonResult;
    var plugin = getRGFCPlugin();
    var result = plugin.GetConfiguration();

    if( result ) {
	jsonResult = {
	    "contact_member_id" : plugin.ConfigRobotID,
	    "product_collection_fk" : plugin.ConfigRobotType,
	    "contact_points": plugin.ConfigPoints,
	    "contact_first_name" : plugin.ConfigFirstName,
	    "product_package_name" : plugin.ConfigRobotName,
   	    "version" : plugin.ConfigVersion,

	    "limb_flexor_left" : plugin.ConfigArmLeft,
	    "limb_flexor_right" : plugin.ConfigArmRight,
	    "limb_extender_left" : plugin.ConfigLegLeft,
	    "limb_extender_right" : plugin.ConfigLegRight,

	    "limb_flexor_left_type" : plugin.ConfigArmLeftType,
	    "limb_flexor_right_type" : plugin.ConfigArmRightType,
	    "limb_extender_left_type" : plugin.ConfigLegLeftType,
	    "limb_extender_right_type" : plugin.ConfigLegRightType,

	    "limb_flexor_left_sku" : plugin.ConfigArmLeftSKU,
	    "limb_flexor_right_sku" : plugin.ConfigArmRightSKU,
	    "limb_extender_left_sku" : plugin.ConfigLegLeftSKU,
	    "limb_extender_right_sku" : plugin.ConfigLegRightSKU,

	    "limb_flexor_left_sku_alt" : plugin.ConfigArmLeftSKUAlt,
	    "limb_flexor_right_sku_alt" : plugin.ConfigArmRightSKUAlt,
	    "limb_extender_left_sku_alt" : plugin.ConfigLegLeftSKUAlt,
	    "limb_extender_right_sku_alt" : plugin.ConfigLegRightSKUAlt
	};
    } else { // could not get configuration
	// TODO
    }
    
    if( !jsonResult ) {
	jsonResult = {
	    "errors" : [
	                {
			    "code" : 350,
			    "desc" : "This is the problem here. More details will display in the actual RGFC API."
			}
			]		
	};
    }
    
    return jsonResult;
} // RGFCGetConfiguration()





// ************************************************
// ************************************************
// Utility Functions
//
//

function RGFCErrorAsString( objErr )
{
    if( objErr.code > 0 ) {
	var str = objErr["code"] + ": " + objErr["desc"];
	if( objErr["field"] ) {
	    str += " in field " + objErr["field"];
	}
	
	return str;
    }
    
    return;
} // RGFCErrorAsString()


function RGFCDefaultResults()
{
    // Default jsonResults to unknown error
    var jsonResults = {
	contacts : [],
	errors   : [ 
	             { 
			 code : 100,
			 desc : 'Unknown error encountered'
		     }
	]
    };

    return jsonResults;
} // RGFCDefaultResults


// poor man's sleep function
function sleep( msec )
{
    var date = new Date();
    var now = null;
    
    do {
	now = new Date();
    } while( (now - date) < msec );
}
