/*
This software is subject to the license described in the License.txt file 
included with this software distribution. You may not use this file except in compliance 
with this license.

Copyright (c) Dynastream Innovations Inc. 2012
All rights reserved.
*/
 

#include "StdAfx.h"
#include "RacquetSensor.h"


/**************************************************************************
* RacquetSensor::ANT_eventNotification
* 
* Process ANT channel event
*
* ucEventCode_: code of ANT channel event
* pucEventBuffer_: pointer to buffer containing data received from ANT,
*		or a pointer to the transmit buffer in the case of an EVENT_TX
* 
* returns: N/A
*
**************************************************************************/
void RacquetSensor::ANT_eventNotification(UCHAR ucEventCode_, UCHAR *pucEventBuffer_)
{
	switch(ucEventCode_)
	{
	case EVENT_TX:
		if(startTime == System::DateTime::MinValue)
			startTime = System::DateTime::Now;
		HandleTransmit((UCHAR*) pucEventBuffer_);
		UpdateDisplay();
		break;

	case EVENT_RX_ACKNOWLEDGED:
	case EVENT_RX_BURST_PACKET:
	case EVENT_RX_BROADCAST:
		HandleReceive((UCHAR*) pucEventBuffer_);
		break;

	default:
		break;
	}
}

/**************************************************************************
 * RacquetSensor::InitializeSim
 * 
 * Initializes simulator variables
 * 
 * returns: N/A
 *
 **************************************************************************/
void RacquetSensor::InitializeSim()
{
	zones = gcnew array<array<USHORT>^>(AntPlusRacquet::NUMBER_OF_ZONES);
	for(int i = 0; i < zones->Length; i++)
	{
		zones[i] = gcnew array<USHORT> (AntPlusRacquet::NUMBER_OF_STROKE_TYPES);
	}
	startTime = System::DateTime::MinValue;
	lastTime = System::DateTime::Now;
	StrokeEvents = gcnew array<Event^>(256);

	// Initialize event array
	for(int i = 0; i < StrokeEvents->Length; i++)
	{
		StrokeEvents[i] = gcnew Event();
		StrokeEvents[i]->EventCount = Double::NaN;
		StrokeEvents[i]->EventTime = 0;
		StrokeEvents[i]->EventType = (UCHAR)AntPlusRacquet::StrokeTypes::NO_EVENT;
		StrokeEvents[i]->BallSpeed = 0;
	}
	ulTimerInterval = 250;

   ulTotalTime = 0;

	// Initialize Racquet Object data
	RacquetData->ucEventCount = 0x00;
	RacquetData->usEventTime = 0x00;
	RacquetData->ucEventType = (UCHAR)AntPlusRacquet::StrokeTypes::UNKNOWN;
	RacquetData->ucRacquetZone = (UCHAR)AntPlusRacquet::RacquetZones::UNKNOWN;
	RacquetData->usSpeed = AntPlusRacquet::UNKNOWN;

	// Initialize Common Object data
	Common->ucHwVersion = System::Convert::ToByte(tbHardwareVer->Text);
	Common->usMfgID = System::Convert::ToUInt16(tbManfId->Text);
	Common->usModelNum = System::Convert::ToUInt16(tbModelNum->Text);
	Common->ulSerialNum = System::Convert::ToUInt32(tbSerialNumber->Text);
	Common->ucSwVersion = System::Convert::ToByte(tbSoftwareVer->Text);
   if(radioResolution2->Checked)
      Common->eTimeResolution = CommonData::TimeResolution::TWO;
   else
      Common->eTimeResolution = CommonData::TimeResolution::SIXTEEN;
   Common->ulOpTime = ulTotalTime / (UCHAR)Common->eTimeResolution;
   Common->bBattPageEnabled = true;
   Common->usBatVoltage256 = ((USHORT)System::Convert::ToByte(numericCoarseVoltage->Value)) << 8 | (Common->usBatVoltage256 & 0xFF);
   Common->usBatVoltage256 = System::Convert::ToByte(numericFractionalVoltage->Value) | (Common->usBatVoltage256 & 0xFF00);
   Common->eBatStatus = (CommonData::BatStatus::OK);

	// Initialize the first Stroke Event in the array
	StrokeEvents[RacquetData->ucEventCount]->EventCount = RacquetData->ucEventCount;
	StrokeEvents[RacquetData->ucEventCount]->EventTime = RacquetData->usEventTime;
	StrokeEvents[RacquetData->ucEventCount]->EventType = RacquetData->ucEventType;
	StrokeEvents[RacquetData->ucEventCount]->BallSpeed = RacquetData->usSpeed;

	cbEventCount->Items->Clear();
	cbEventCount->Items->Add(RacquetData->ucEventCount.ToString());

	time = 0;
   

	timerSession = gcnew System::Timers::Timer(1000);
	timerSession->Elapsed += gcnew ElapsedEventHandler(RacquetSensor::timerSession_Tick);
}

/**************************************************************************
 * RacquetSensor::HandleTransmit
 * 
 * Encode data generated by simulator for transmission
 *
 * pucTxBuffer_: pointer to the transmit buffer
 * 
 * returns: N/A
 *
 **************************************************************************/
void RacquetSensor::HandleTransmit(UCHAR* pucTxBuffer_)
{
	static ULONG ulMessageCount =  0;
	static UCHAR ucReqCommonPatternCount = 0;

	if (bTxRequest == true)   
	{
		if (ucRequestCount == 0)   // if count is zero, then reset 
		{
			bTxRequest = false;
			goto page1;
		}
      
		RacquetData->Encode(Common->ucReqPageNum, pucTxBuffer_);
		
		ucRequestCount--;		   // subtract one from requested transmission count
		
      return;			   // skip the rest of the function in this case
	}	
	
page1:
	if (ulMessageCount >= 120)
	{
		ulMessageCount = 0;     // reset count
		// send common data pages 80 and 81

      switch(ucReqCommonPatternCount)
      {
      case 0:
         Common->Encode(CommonData::PAGE80, pucTxBuffer_);
         break;
      case 1:
         Common->Encode(CommonData::PAGE81, pucTxBuffer_);
         break;
      case 2:
         Common->Encode(CommonData::PAGE82, pucTxBuffer_);
         break;
      default:
         break;
      }

		ucReqCommonPatternCount++;
		
		if (ucReqCommonPatternCount >= 3)
			ucReqCommonPatternCount = 0;
	}
	else		
      RacquetData->Encode(AntPlusRacquet::PAGE_STROKE_EVENT, pucTxBuffer_); 
	
	ulMessageCount++;

   static UCHAR ucTimeCount = 0;
   
   if(ucTimeCount++ == 3)
   {
      ulTotalTime++;
      Common->ulOpTime = ulTotalTime / (UCHAR)Common->eTimeResolution;
      ucTimeCount = 0;
   }
}

/**************************************************************************
 * RacquetSensor::UpdateDisplay
 * 
 * Updates the GUI according to the current information to be displayed
 * 
 * returns: N/A
 *
 **************************************************************************/
void RacquetSensor::UpdateDisplay()
{
   labelElpTime->Text = ulTotalTime.ToString();
	lbTime->Text = RacquetData->usEventTime.ToString();
	
	lbDisplayTime->Text = RacquetData->usEventTime.ToString();
	lbDisplaySpeed->Text = (RacquetData->usSpeed == AntPlusRacquet::UNKNOWN ?
							"Invalid" :
                     checkMpS->Checked ? 
                     ((double)RacquetData->usSpeed / 100).ToString("F2"):
                     (((double)RacquetData->usSpeed / 100) * ((double)36/(double)10)).ToString("F2"));
	lbDisplayEvent->Text = RacquetData->ucEventCount.ToString();
	
   //Session Metabolic Data
   lbMaxHRDisplay->Text = RacquetData->ucMaxHeartRate.ToString();
   lbAvgHRDisplay->Text = RacquetData->ucAvgHeartRate.ToString();
   lbTotCaloriesDisplay->Text = RacquetData->usTotalCalories.ToString();

   //Session Speed Data
   lbMaxRunSpdDisplay->Text = RacquetData->usMaxRunningSpeed.ToString();
   lbAvgRunSpdDisplay->Text = RacquetData->usAvgRunningSpeed.ToString();

   //Session Distance Data
   lbTotDistanceDisplay->Text = RacquetData->uiTotalDistance.ToString();

	switch(RacquetData->ucRacquetZone)
	{
	case (UCHAR)AntPlusRacquet::RacquetZones::MISS:
		lbDisplayZone->Text = "Miss";
		break;
	case (UCHAR)AntPlusRacquet::RacquetZones::TOP_RIGHT:
		lbDisplayZone->Text = "Top Right";
		break;
	case (UCHAR)AntPlusRacquet::RacquetZones::MIDDLE_RIGHT:
		lbDisplayZone->Text = "Middle Right";
		break;
	case (UCHAR)AntPlusRacquet::RacquetZones::BOTTOM_RIGHT:
		lbDisplayZone->Text = "Bottom Right";
		break;
	case (UCHAR)AntPlusRacquet::RacquetZones::BOTTOM_CENTRE:
		lbDisplayZone->Text = "Bottom Centre";
		break;
	case (UCHAR)AntPlusRacquet::RacquetZones::BOTTOM_LEFT:
		lbDisplayZone->Text = "Bottom Left";
		break;
	case (UCHAR)AntPlusRacquet::RacquetZones::MIDDLE_CENTRE:
		lbDisplayZone->Text = "Middle Centre";
		break;
	case (UCHAR)AntPlusRacquet::RacquetZones::MIDDLE_LEFT:
		lbDisplayZone->Text = "Middle Left";
		break;
	case (UCHAR)AntPlusRacquet::RacquetZones::TOP_CENTRE:
		lbDisplayZone->Text = "Top Centre";
		break;
	case (UCHAR)AntPlusRacquet::RacquetZones::TOP_LEFT:
		lbDisplayZone->Text = "Top Left";
		break;
	case (UCHAR)AntPlusRacquet::RacquetZones::RIM_OTHER:
		lbDisplayZone->Text = "Rim/Other";
		break;
	case (UCHAR)AntPlusRacquet::RacquetZones::UNKNOWN:
		lbDisplayZone->Text = "Unknown";
		break;
	default:
		lbDisplayZone->Text = "----";
		break;
	}

	switch(RacquetData->ucEventType)
	{
	case (UCHAR)AntPlusRacquet::StrokeTypes::NO_EVENT:
		lbDisplayStroke->Text = "No Event";
		break;

	case (UCHAR)AntPlusRacquet::StrokeTypes::BACKHAND:
		lbDisplayStroke->Text = "Backhand";
		break;

	case (UCHAR)AntPlusRacquet::StrokeTypes::FOREHAND:
		lbDisplayStroke->Text = "Forehand";
		break;

	case (UCHAR)AntPlusRacquet::StrokeTypes::OTHER:
		lbDisplayStroke->Text = "Other";
		break;

	case (UCHAR)AntPlusRacquet::StrokeTypes::SERVE:
		lbDisplayStroke->Text = "Serve";
		break;

	case (UCHAR)AntPlusRacquet::StrokeTypes::SMASH:
		lbDisplayStroke->Text = "Smash";
		break;

	case (UCHAR)AntPlusRacquet::StrokeTypes::UNKNOWN:
		lbDisplayStroke->Text = "Unknown";
		break;

	default:
		lbDisplayStroke->Text = "----";
		break;
	}
}

/**************************************************************************
 * RacquetSensor::HandleReceive
 * 
 * Process the data received from a receiving ANT device
 *
 * pucRxBuffer_: pointer to the receive buffer
 * 
 * returns: N/A
 *
 **************************************************************************/
void RacquetSensor::HandleReceive(UCHAR* pucRxBuffer_)
{
	UCHAR ucPageNumber = pucRxBuffer_[0];
	USHORT count;
	UCHAR stroke1Index;
	UCHAR stroke2Index;
	UCHAR zone1Index;
	UCHAR zone2Index;
	AntPlusRacquet::FITSubSports oldGameMode = RacquetData->eGameMode;

	switch(ucPageNumber)
	{
	case Common->PAGE70:
		Common->Decode(pucRxBuffer_);

		ucRequestCount = Common->ucReqTransResp & 0x7F;
		bTxRequest = true;

		switch(Common->ucReqPageNum)
		{
		case AntPlusRacquet::PAGE_PREVIOUS_STROKE_EVENT:
			RacquetData->ucPreviousEventCount = Common->ucDescriptorByte1;
			RacquetData->ucPreviousEventType = StrokeEvents[RacquetData->ucPreviousEventCount]->EventType;
			RacquetData->usPreviousEventTime = StrokeEvents[RacquetData->ucPreviousEventCount]->EventTime;
			RacquetData->usPreviousSpeed = StrokeEvents[RacquetData->ucPreviousEventCount]->BallSpeed;
			RacquetData->ucPreviousRacquetZone = StrokeEvents[RacquetData->ucPreviousEventCount]->RacquetZone;
			break;

		case AntPlusRacquet::PAGE_STROKE_COUNT:
			count = 0;
			RacquetData->ucStrokeType1 = Common->ucDescriptorByte1;
			RacquetData->ucStrokeType2 = Common->ucDescriptorByte2;

			stroke1Index = (RacquetData->ucStrokeType1 == (UCHAR)AntPlusRacquet::StrokeTypes::UNKNOWN ? 
									AntPlusRacquet::NUMBER_OF_STROKE_TYPES - 1 :
									RacquetData->ucStrokeType1);

			stroke2Index = (RacquetData->ucStrokeType2 == (UCHAR)AntPlusRacquet::StrokeTypes::UNKNOWN ? 
									AntPlusRacquet::NUMBER_OF_STROKE_TYPES - 1 :
									RacquetData->ucStrokeType2);

			// Transmit unknown Stroke Counts
			if(cbUnknownStrokeCount->Checked)
				count = AntPlusRacquet::UNKNOWN;
			else if(RacquetData->ucStrokeType1 == (UCHAR)AntPlusRacquet::StrokeTypes::ALL_STROKES)
			{
				// All Strokes 
				for(int i = 0; i < zones->Length; i++)
					for(int j =	1; j < zones[i]->Length; j++)
						count += zones[i][j];
			}
			else // Specific Stroke
			{
				for(int i = 0; i < zones->Length; i++)
					count += zones[i][stroke1Index];
			}
			RacquetData->usStrokeCount1 = count;
			
			count = 0;

			if(cbUnknownStrokeCount->Checked)
				count = AntPlusRacquet::UNKNOWN;
			else if(RacquetData->ucStrokeType2 == (UCHAR)AntPlusRacquet::StrokeTypes::ALL_STROKES)
			{
				// All Strokes
				for(int i = 0; i < zones->Length; i++)
					for(int j = 1; j < zones[i]->Length; j++)
						count += zones[i][j];
			}
			else // Specific Stroke
			{
				for(int i = 0; i < zones->Length; i++)
					count += zones[i][stroke2Index];
			}
			RacquetData->usStrokeCount2 = count;
			break;

		case AntPlusRacquet::PAGE_ZONE_COUNT:
			count = 0;
			RacquetData->ucType = Common->ucDescriptorByte1;
			RacquetData->ucZone = Common->ucDescriptorByte2;

			// Get array indexes to look for 
			
			// If Zone is between 0 and 10 (Miss and Rim/Other), then that is the index. 
			// If zone is 0x3F (Unknown), set index to 11 
			zone1Index = ((RacquetData->ucZone == (UCHAR)AntPlusRacquet::RacquetZones::UNKNOWN) ?
								AntPlusRacquet::NUMBER_OF_ZONES - 1 : 
								RacquetData->ucZone);

			// If Zone is 10 (Rim/Other)or 11 (unknown), set second index to index 11 (Unknown) 
								zone2Index = (((RacquetData->ucZone == (UCHAR)AntPlusRacquet::RacquetZones::RIM_OTHER) || (RacquetData->ucZone == (UCHAR)AntPlusRacquet::RacquetZones::UNKNOWN)) ? 
								AntPlusRacquet::NUMBER_OF_ZONES - 1 :  
								RacquetData->ucZone + 1);
 
			if(cbUnknownZoneCount->Checked)
			{
				// User wishes to transmit unknown counts
				RacquetData->usCount = AntPlusRacquet::UNKNOWN;
				RacquetData->usCountPlus1 = AntPlusRacquet::UNKNOWN;
				break;
			}
			else if(RacquetData->ucType == (UCHAR)AntPlusRacquet::StrokeTypes::ALL_STROKES)
			{
				// Get all strokes for that particular zone
				for(int i = 1; i < zones[zone1Index]->Length; i++)
					count += zones[zone1Index][i];

				// Update the Count for the first zone
				RacquetData->usCount = count;
				
				// If the user requested Unknown zone (i.e. rollover makes zone2 index 0)
				// Set the count to unknown
				if(zone2Index == (UCHAR)AntPlusRacquet::RacquetZones::MISS)
					RacquetData->usCountPlus1 = AntPlusRacquet::UNKNOWN;
				else 
				{
					// Else, get all strokes for that particular zone
					count = 0;
					for(int i = 1; i < zones[zone2Index]->Length; i++)
						count += zones[zone2Index][i];
					RacquetData->usCountPlus1 = count;
				}
				break;
			}
			else if(RacquetData->ucType == (UCHAR)AntPlusRacquet::StrokeTypes::UNKNOWN)
			{
				// Get the count at the particular zone and the index for unknown stroke (6)
				RacquetData->usCount = zones[zone1Index][AntPlusRacquet::NUMBER_OF_STROKE_TYPES - 1];
				
				// If the user requestes Unknown zone (i.e. rollover makes zone2 index 0)
				// set the count for next zone to 0
				if(zone2Index == (UCHAR)AntPlusRacquet::RacquetZones::MISS)
					RacquetData->usCountPlus1 = AntPlusRacquet::UNKNOWN;
				else
					RacquetData->usCountPlus1 = zones[zone2Index][AntPlusRacquet::NUMBER_OF_STROKE_TYPES - 1];
				break;
			}
			else
			{
				RacquetData->usCount = zones[zone1Index][RacquetData->ucType];
			
				if(zone2Index == (UCHAR)AntPlusRacquet::RacquetZones::MISS)
					RacquetData->usCountPlus1 = AntPlusRacquet::UNKNOWN;
				else
					RacquetData->usCountPlus1 = zones[zone2Index][RacquetData->ucType]; 
			}
			break;

		default:
			break;
		}
		break;

	case AntPlusRacquet::PAGE_EVENT_DATA:
		RacquetData->Decode(pucRxBuffer_);

		switch(RacquetData->eEvent)
		{
      case AntPlusRacquet::FITEvents::TIMER:
		case AntPlusRacquet::FITEvents::SESSION:
			if(RacquetData->eEventType == AntPlusRacquet::FITEventTypes::START)
			{	
				timerSession->Enabled = true;
				timerSession->Start();
			}
			else 
			{
				timerSession->Stop();
				timerSession->Enabled = false;
			
            if(RacquetData->eEvent == AntPlusRacquet::FITEvents::SESSION)
            {
               time = 0;
			      lbSessionTime->Text = "00:00:00";
            }
         }
			break;

		case AntPlusRacquet::FITEvents::USER_MARKER:
			if(RacquetData->eEventType == AntPlusRacquet::FITEventTypes::MARKER)
			{
				if(lbUserMarker->Text == "----")
					lbUserMarker->Text = "1";
				else
				{
					int i;
					i = System::Convert::ToInt32(lbUserMarker->Text);
					lbUserMarker->Text = (i + 1).ToString();
					
				}
			}
			break;

		case AntPlusRacquet::FITEvents::SPORT_POINT:
			if((RacquetData->ulEventData & 0xFFFF) == AntPlusRacquet::UNKNOWN)
				lbMyScore->Text = "Invalid";
			else
				lbMyScore->Text = ((USHORT)(RacquetData->ulEventData & 0xFFFF)).ToString();
			
			if(((RacquetData->ulEventData >> 16) & 0xFFFF) == AntPlusRacquet::UNKNOWN)
				lbOpponentScore->Text = "Invalid";
			else
				lbOpponentScore->Text = ((USHORT)(RacquetData->ulEventData >> 16) & 0xFFFF).ToString(); 
			break;
					
		default:
			break;
		}
		break;

	case AntPlusRacquet::PAGE_SESSION_DATA:
		RacquetData->Decode(pucRxBuffer_);

		if(oldGameMode != RacquetData->eGameMode)
		{
			time = 0;
			lbSessionTime->Text = "00:00:00";
		}

		switch(RacquetData->eGameMode)
		{
		case AntPlusRacquet::FITSubSports::WARM_UP:
			lbGameMode->Text = "Warm Up";
			lbGameModeText->Text = "Warm Up Count (Session)";
			break;
		case AntPlusRacquet::FITSubSports::MATCH:
			lbGameMode->Text = "Match";
			lbGameModeText->Text = "Match Count (Session)";
			break;
		case AntPlusRacquet::FITSubSports::EXERCISE:
			lbGameMode->Text = "Exercise";
			lbGameModeText->Text = "Exercise Count (Session)";
			break;
		case AntPlusRacquet::FITSubSports::CHALLENGE:
			lbGameMode->Text = "Challenge";
			lbGameModeText->Text = "Challenge Count (Session)";
			break;
		default:
			lbGameMode->Text = "Session";
			lbGameModeText->Text = "Session Count (Session)";
			break;
		}

		if(RacquetData->usMySessionsWon == AntPlusRacquet::UNKNOWN)
			lbMySessionsWon->Text = "Invalid";
		else
			lbMySessionsWon->Text = RacquetData->usMySessionsWon.ToString();

		if(RacquetData->usOpponentSessionsWon == AntPlusRacquet::UNKNOWN)
			lbOpponentSessionsWon->Text = "Invalid";
		else
			lbOpponentSessionsWon->Text = RacquetData->usOpponentSessionsWon.ToString();
		break;

	case AntPlusRacquet::PAGE_LAP_DATA:
		RacquetData->Decode(pucRxBuffer_);
		if(RacquetData->usMySetCount == AntPlusRacquet::UNKNOWN)
			lbMySetCount->Text = "Invalid";
		else
			lbMySetCount->Text = RacquetData->usMySetCount.ToString();

		if(RacquetData->usOpponentSetCount == AntPlusRacquet::UNKNOWN)
			lbOpponentSetCount->Text = "Invalid";
		else 
			lbOpponentSetCount->Text = RacquetData->usOpponentSetCount.ToString();
		break;

	case AntPlusRacquet::PAGE_LENGTH_DATA:
		RacquetData->Decode(pucRxBuffer_);
		if(RacquetData->usMyGameCount == AntPlusRacquet::UNKNOWN)
			lbMyGameCount->Text = "Invalid";
		else
			lbMyGameCount->Text = RacquetData->usMyGameCount.ToString();

		if(RacquetData->usOpponentGameCount == AntPlusRacquet::UNKNOWN)
			lbOpponentGameCount->Text = "Invalid";
		else
			lbOpponentGameCount->Text = RacquetData->usOpponentGameCount.ToString();
		break;

      case AntPlusRacquet::PAGE_METABOLIC_DATA:
      case AntPlusRacquet::PAGE_SPEED_DATA:
      case AntPlusRacquet::PAGE_DISTANCE_DATA: //Intentional Fallthroughs
         RacquetData->Decode(pucRxBuffer_);
         UpdateDisplay();
         break;

	default:
		break;
	}
}

/**************************************************************************
 * RacquetSensor::OnTimerTock
 * 
 * Required by the ISimBase interface. Currently unused for this simulator
 *
 * eventTime: current time (ms)
 * 
 * returns: N/A
 *
 **************************************************************************/
void RacquetSensor::onTimerTock(USHORT eventTime)
{
	System::DateTime time = System::DateTime::Now;
	System::Int64 elapsedTicks = (time.Ticks - lastTime.Ticks);
	TimeSpan elapsedTime = TimeSpan(elapsedTicks);

	// 4 minutes has passed
	if(elapsedTime.TotalSeconds >= 240)
	{
		TimeSpan elapsedSpan = TimeSpan(time.Ticks - startTime.Ticks);
		lastTime = time;
		RacquetData->ucEventCount++;
		RacquetData->usEventTime = (USHORT)(elapsedSpan.TotalSeconds * 256);
		RacquetData->ucEventType = (UCHAR)AntPlusRacquet::StrokeTypes::NO_EVENT;
		RacquetData->ucRacquetZone = (UCHAR)AntPlusRacquet::RacquetZones::UNKNOWN;
		RacquetData->usSpeed = AntPlusRacquet::UNKNOWN;
		zones[AntPlusRacquet::NUMBER_OF_ZONES - 1][AntPlusRacquet::NUMBER_OF_STROKE_TYPES - 1]++;
		AddEvent();
	}
}

/**************************************************************************
 * RacquetSensor::zoneOne_Click
 * 
 * Handles zoneOne button click event. Updates event being transmitted.
 *
 * sender: Object raising event 
 * e: Event arguments
 * 
 * returns: N/A
 *
 **************************************************************************/
void RacquetSensor::zoneOne_Click(System::Object ^sender, System::EventArgs ^e)
{
	DateTime currentTime = DateTime::Now;
	lastTime = currentTime;
	System::Int64 elapsedTicks = (currentTime.Ticks - startTime.Ticks);
	TimeSpan elapsedSpan = TimeSpan(elapsedTicks);

	RacquetData->ucEventCount++;
	RacquetData->usEventTime = (USHORT)(elapsedSpan.TotalSeconds * 256);
	RacquetData->ucEventType = (comboType->SelectedIndex == 6 ?
								(UCHAR)AntPlusRacquet::UNKNOWN :
								(UCHAR)(this->comboType->SelectedIndex));
	RacquetData->ucRacquetZone = (UCHAR)(AntPlusRacquet::RacquetZones::TOP_RIGHT);
	RacquetData->usSpeed = (ckInvalidSpeed->Checked ?
							AntPlusRacquet::UNKNOWN :
                     (checkMpS->Checked ?
                     (USHORT)(this->valueSpeed->Value * 100):
                     (USHORT) Math::Round((valueSpeed->Value * 1000/36), System::MidpointRounding::AwayFromZero)));
	zones[(UCHAR)AntPlusRacquet::RacquetZones::TOP_RIGHT][comboType->SelectedIndex]++;
	AddEvent();
}
/**************************************************************************
 * RacquetSensor::zoneTwo_Click
 * 
 * Handles zoneTwo button click event. Updates event being transmitted.
 *
 * sender: Object raising event 
 * e: Event arguments
 * 
 * returns: N/A
 *
 **************************************************************************/
void RacquetSensor::zoneTwo_Click(System::Object ^sender, System::EventArgs ^e)
{
	DateTime currentTime = DateTime::Now;
	lastTime = currentTime;
	System::Int64 elapsedTicks = (currentTime.Ticks - startTime.Ticks);
	TimeSpan elapsedSpan = TimeSpan(elapsedTicks);

	RacquetData->ucEventCount++;
	RacquetData->usEventTime = (USHORT)(elapsedSpan.TotalSeconds * 256);
	RacquetData->ucEventType = (comboType->SelectedIndex == 6 ?
								(UCHAR)AntPlusRacquet::UNKNOWN :
								(UCHAR)(this->comboType->SelectedIndex));
	RacquetData->ucRacquetZone = (UCHAR)(AntPlusRacquet::RacquetZones::MIDDLE_RIGHT);
	RacquetData->usSpeed = (ckInvalidSpeed->Checked ?
							AntPlusRacquet::UNKNOWN :
                     (checkMpS->Checked ?
                     (USHORT)(this->valueSpeed->Value * 100):
                     (USHORT) Math::Round((valueSpeed->Value * 1000/36), System::MidpointRounding::AwayFromZero)));
	zones[(UCHAR)AntPlusRacquet::RacquetZones::MIDDLE_RIGHT][comboType->SelectedIndex]++;
	AddEvent();
}
/**************************************************************************
 * RacquetSensor::zoneThree_Click
 * 
 * Handles zoneThree button click event. Updates event being transmitted.
 *
 * sender: Object raising event 
 * e: Event arguments
 * 
 * returns: N/A
 *
 **************************************************************************/
void RacquetSensor::zoneThree_Click(System::Object ^sender, System::EventArgs ^e)
{
	DateTime currentTime = DateTime::Now;
	lastTime = currentTime;
	System::Int64 elapsedTicks = (currentTime.Ticks - startTime.Ticks);
	TimeSpan elapsedSpan = TimeSpan(elapsedTicks);

	RacquetData->ucEventCount++;
	RacquetData->usEventTime = (USHORT)(elapsedSpan.TotalSeconds * 256);
	RacquetData->ucEventType = (comboType->SelectedIndex == 6 ?
								(UCHAR)AntPlusRacquet::UNKNOWN :
								(UCHAR)(this->comboType->SelectedIndex));
	RacquetData->ucRacquetZone = (UCHAR)(AntPlusRacquet::RacquetZones::BOTTOM_RIGHT);
	RacquetData->usSpeed = (ckInvalidSpeed->Checked ?
							AntPlusRacquet::UNKNOWN :
                     (checkMpS->Checked ?
                     (USHORT)(this->valueSpeed->Value * 100):
                     (USHORT) Math::Round((valueSpeed->Value * 1000/36), System::MidpointRounding::AwayFromZero)));
	zones[(UCHAR)AntPlusRacquet::RacquetZones::BOTTOM_RIGHT][comboType->SelectedIndex]++;
	AddEvent();
}
/**************************************************************************
 * RacquetSensor::zoneFour_Click
 * 
 * Handles zoneFour button click event. Updates event being transmitted.
 *
 * sender: Object raising event 
 * e: Event arguments
 * 
 * returns: N/A
 *
 **************************************************************************/
void RacquetSensor::zoneFour_Click(System::Object ^sender, System::EventArgs ^e)
{
	DateTime currentTime = DateTime::Now;
	lastTime = currentTime;
	System::Int64 elapsedTicks = (currentTime.Ticks - startTime.Ticks);
	TimeSpan elapsedSpan = TimeSpan(elapsedTicks);

	RacquetData->ucEventCount++;
	RacquetData->usEventTime = (USHORT)(elapsedSpan.TotalSeconds * 256);
	RacquetData->ucEventType = (comboType->SelectedIndex == 6 ?
								(UCHAR)AntPlusRacquet::UNKNOWN :
								(UCHAR)(this->comboType->SelectedIndex));
	RacquetData->ucRacquetZone = (UCHAR)(AntPlusRacquet::RacquetZones::BOTTOM_CENTRE);
	RacquetData->usSpeed = (ckInvalidSpeed->Checked ?
							AntPlusRacquet::UNKNOWN :
                     (checkMpS->Checked ?
                     (USHORT)(this->valueSpeed->Value * 100):
                     (USHORT) Math::Round((valueSpeed->Value * 1000/36), System::MidpointRounding::AwayFromZero)));
	zones[(UCHAR)AntPlusRacquet::RacquetZones::BOTTOM_CENTRE][comboType->SelectedIndex]++;
	AddEvent();
}
/**************************************************************************
 * RacquetSensor::zoneFive_Click
 * 
 * Handles zoneFive button click event. Updates event being transmitted.
 *
 * sender: Object raising event 
 * e: Event arguments
 * 
 * returns: N/A
 *
 **************************************************************************/
void RacquetSensor::zoneFive_Click(System::Object ^sender, System::EventArgs ^e)
{
	DateTime currentTime = DateTime::Now;
	lastTime = currentTime;
	System::Int64 elapsedTicks = (currentTime.Ticks - startTime.Ticks);
	TimeSpan elapsedSpan = TimeSpan(elapsedTicks);

	RacquetData->ucEventCount++;
	RacquetData->usEventTime = (USHORT)(elapsedSpan.TotalSeconds * 256);
	RacquetData->ucEventType = (comboType->SelectedIndex == 6 ?
								(UCHAR)AntPlusRacquet::UNKNOWN :
								(UCHAR)(this->comboType->SelectedIndex));
	RacquetData->ucRacquetZone = (UCHAR)(AntPlusRacquet::RacquetZones::BOTTOM_LEFT);
	RacquetData->usSpeed = (ckInvalidSpeed->Checked ?
							AntPlusRacquet::UNKNOWN :
                     (checkMpS->Checked ?
                     (USHORT)(this->valueSpeed->Value * 100):
                     (USHORT) Math::Round((valueSpeed->Value * 1000/36), System::MidpointRounding::AwayFromZero)));
	zones[(UCHAR)AntPlusRacquet::RacquetZones::BOTTOM_LEFT][comboType->SelectedIndex]++;
	AddEvent();
}
/**************************************************************************
 * RacquetSensor::zoneSix_Click
 * 
 * Handles zoneSix button click event. Updates event being transmitted.
 *
 * sender: Object raising event 
 * e: Event arguments
 * 
 * returns: N/A
 *
 **************************************************************************/
void RacquetSensor::zoneSix_Click(System::Object ^sender, System::EventArgs ^e)
{
	DateTime currentTime = DateTime::Now;
	lastTime = currentTime;
	System::Int64 elapsedTicks = (currentTime.Ticks - startTime.Ticks);
	TimeSpan elapsedSpan = TimeSpan(elapsedTicks);
	
	RacquetData->ucEventCount++;
	RacquetData->usEventTime = (USHORT)(elapsedSpan.TotalSeconds * 256);
	RacquetData->ucEventType = (comboType->SelectedIndex == 6 ?
								(UCHAR)AntPlusRacquet::UNKNOWN :
								(UCHAR)(this->comboType->SelectedIndex));
	RacquetData->ucRacquetZone = (UCHAR)(AntPlusRacquet::RacquetZones::MIDDLE_CENTRE);
	RacquetData->usSpeed = (ckInvalidSpeed->Checked ?
							AntPlusRacquet::UNKNOWN :
                     (checkMpS->Checked ?
                     (USHORT)(this->valueSpeed->Value * 100):
                     (USHORT) Math::Round((valueSpeed->Value * 1000/36), System::MidpointRounding::AwayFromZero)));
	zones[(UCHAR)AntPlusRacquet::RacquetZones::MIDDLE_CENTRE][comboType->SelectedIndex]++;
	AddEvent();
}
/**************************************************************************
 * RacquetSensor::zoneSeven_Click
 * 
 * Handles zoneSeven button click event. Updates event being transmitted.
 *
 * sender: Object raising event 
 * e: Event arguments
 * 
 * returns: N/A
 *
 **************************************************************************/
void RacquetSensor::zoneSeven_Click(System::Object ^sender, System::EventArgs ^e)
{
	DateTime currentTime = DateTime::Now;
	lastTime = currentTime;
	System::Int64 elapsedTicks = (currentTime.Ticks - startTime.Ticks);
	TimeSpan elapsedSpan = TimeSpan(elapsedTicks);

	RacquetData->ucEventCount++;
	RacquetData->usEventTime = (USHORT)(elapsedSpan.TotalSeconds * 256);
	RacquetData->ucEventType = (comboType->SelectedIndex == 6 ?
								(UCHAR)AntPlusRacquet::UNKNOWN :
								(UCHAR)(this->comboType->SelectedIndex));
	RacquetData->ucRacquetZone = (UCHAR)(AntPlusRacquet::RacquetZones::MIDDLE_LEFT);
	RacquetData->usSpeed = (ckInvalidSpeed->Checked ?
							AntPlusRacquet::UNKNOWN :
                     (checkMpS->Checked ?
                     (USHORT)(this->valueSpeed->Value * 100):
                     (USHORT) Math::Round((valueSpeed->Value * 1000/36), System::MidpointRounding::AwayFromZero)));
	zones[(UCHAR)AntPlusRacquet::RacquetZones::MIDDLE_LEFT][comboType->SelectedIndex]++;
	AddEvent();
}
/**************************************************************************
 * RacquetSensor::zoneEight_Click
 * 
 * Handles zoneEight button click event. Updates event being transmitted.
 *
 * sender: Object raising event 
 * e: Event arguments
 * 
 * returns: N/A
 *
 **************************************************************************/
void RacquetSensor::zoneEight_Click(System::Object ^sender, System::EventArgs ^e)
{
	DateTime currentTime = DateTime::Now;
	lastTime = currentTime;
	System::Int64 elapsedTicks = (currentTime.Ticks - startTime.Ticks);
	TimeSpan elapsedSpan = TimeSpan(elapsedTicks);

	RacquetData->ucEventCount++;
	RacquetData->usEventTime = (USHORT)(elapsedSpan.TotalSeconds * 256);
	RacquetData->ucEventType = (comboType->SelectedIndex == 6 ?
								(UCHAR)AntPlusRacquet::UNKNOWN :
								(UCHAR)(this->comboType->SelectedIndex));
	RacquetData->ucRacquetZone = (UCHAR)(AntPlusRacquet::RacquetZones::TOP_LEFT);
	RacquetData->usSpeed = (ckInvalidSpeed->Checked ?
							AntPlusRacquet::UNKNOWN :
                     (checkMpS->Checked ?
                     (USHORT)(this->valueSpeed->Value * 100):
                     (USHORT) Math::Round((valueSpeed->Value * 1000/36), System::MidpointRounding::AwayFromZero)));
	zones[(UCHAR)AntPlusRacquet::RacquetZones::TOP_LEFT][comboType->SelectedIndex]++;
	AddEvent();
}
/**************************************************************************
 * RacquetSensor::zoneNine_Click
 * 
 * Handles zoneNine button click event. Updates event being transmitted.
 *
 * sender: Object raising event 
 * e: Event arguments
 * 
 * returns: N/A
 *
 **************************************************************************/
void RacquetSensor::zoneNine_Click(System::Object ^sender, System::EventArgs ^e)
{
	DateTime currentTime = DateTime::Now;
	lastTime = currentTime;
	System::Int64 elapsedTicks = (currentTime.Ticks - startTime.Ticks);
	TimeSpan elapsedSpan = TimeSpan(elapsedTicks);

	RacquetData->ucEventCount++;
	RacquetData->usEventTime = (USHORT)(elapsedSpan.TotalSeconds * 256);
	RacquetData->ucEventType = (comboType->SelectedIndex == 6 ?
								(UCHAR)AntPlusRacquet::UNKNOWN :
								(UCHAR)(this->comboType->SelectedIndex));
	RacquetData->ucRacquetZone = (UCHAR)(AntPlusRacquet::RacquetZones::TOP_CENTRE);
	RacquetData->usSpeed = (ckInvalidSpeed->Checked ?
							AntPlusRacquet::UNKNOWN :
                     (checkMpS->Checked ?
                     (USHORT)(this->valueSpeed->Value * 100):
                     (USHORT) Math::Round((valueSpeed->Value * 1000/36), System::MidpointRounding::AwayFromZero)));
	zones[(UCHAR)AntPlusRacquet::RacquetZones::TOP_CENTRE][comboType->SelectedIndex]++;
	AddEvent();
}
/**************************************************************************
 * RacquetSensor::zoneOther_Click
 * 
 * Handles zoneOther button click event. Updates event being transmitted.
 *
 * sender: Object raising event 
 * e: Event arguments
 * 
 * returns: N/A
 *
 **************************************************************************/
void RacquetSensor::zoneOther_Click(System::Object ^sender, System::EventArgs ^e)
{
	DateTime currentTime = DateTime::Now;
	lastTime = currentTime;
	System::Int64 elapsedTicks = (currentTime.Ticks - startTime.Ticks);
	TimeSpan elapsedSpan = TimeSpan(elapsedTicks);

	RacquetData->ucEventCount++;
	RacquetData->usEventTime = (USHORT)(elapsedSpan.TotalSeconds * 256);
	RacquetData->ucEventType = (comboType->SelectedIndex == 6 ?
								(UCHAR)AntPlusRacquet::UNKNOWN :
								(UCHAR)(this->comboType->SelectedIndex));
	RacquetData->ucRacquetZone = (UCHAR)(AntPlusRacquet::RacquetZones::RIM_OTHER);
	RacquetData->usSpeed = (ckInvalidSpeed->Checked ?
							AntPlusRacquet::UNKNOWN :
                     (checkMpS->Checked ?
                     (USHORT)(this->valueSpeed->Value * 100):
                     (USHORT) Math::Round((valueSpeed->Value * 1000/36), System::MidpointRounding::AwayFromZero)));
	zones[(UCHAR)AntPlusRacquet::RacquetZones::RIM_OTHER][comboType->SelectedIndex]++;
	AddEvent();
}
/**************************************************************************
 * RacquetSensor::zoneUnknown_Click
 * 
 * Handles zoneUnknown button click event. Updates event being transmitted.
 *
 * sender: Object raising event 
 * e: Event arguments
 * 
 * returns: N/A
 *
 **************************************************************************/
void RacquetSensor::zoneUnknown_Click(System::Object ^sender, System::EventArgs ^e)
{
	DateTime currentTime = DateTime::Now;
	lastTime = currentTime;
	System::Int64 elapsedTicks = (currentTime.Ticks - startTime.Ticks);
	TimeSpan elapsedSpan = TimeSpan(elapsedTicks);

	RacquetData->ucEventCount++;
	RacquetData->usEventTime = (USHORT)(elapsedSpan.TotalSeconds * 256);
	RacquetData->ucEventType = (comboType->SelectedIndex == 6 ?
								(UCHAR)AntPlusRacquet::UNKNOWN :
								(UCHAR)(this->comboType->SelectedIndex));
	RacquetData->ucRacquetZone = (UCHAR)(AntPlusRacquet::RacquetZones::UNKNOWN);
	RacquetData->usSpeed = (ckInvalidSpeed->Checked ?
							AntPlusRacquet::UNKNOWN :
                     (checkMpS->Checked ?
                     (USHORT)(this->valueSpeed->Value * 100):
                     (USHORT) Math::Round((valueSpeed->Value * 1000/36), System::MidpointRounding::AwayFromZero)));
	zones[(UCHAR)AntPlusRacquet::NUMBER_OF_ZONES - 1][comboType->SelectedIndex]++;
	AddEvent();
}
/**************************************************************************
 * RacquetSensor::zoneMiss_Click
 * 
 * Handles zoneMiss button click event. Updates event being transmitted.
 *
 * sender: Object raising event 
 * e: Event arguments
 * 
 * returns: N/A
 *
 **************************************************************************/
void RacquetSensor::zoneMiss_Click(System::Object ^sender, System::EventArgs ^e)
{
	DateTime currentTime = DateTime::Now;
	lastTime = currentTime;
	System::Int64 elapsedTicks = (currentTime.Ticks - startTime.Ticks);
	TimeSpan elapsedSpan = TimeSpan(elapsedTicks);

	RacquetData->ucEventCount++;
	RacquetData->usEventTime = (USHORT)(elapsedSpan.TotalSeconds * 256);
	RacquetData->ucEventType = (comboType->SelectedIndex == 6 ?
								(UCHAR)AntPlusRacquet::UNKNOWN :
								(UCHAR)(this->comboType->SelectedIndex));
	RacquetData->ucRacquetZone = (UCHAR)(AntPlusRacquet::RacquetZones::MISS);
	RacquetData->usSpeed = (ckInvalidSpeed->Checked ?
							AntPlusRacquet::UNKNOWN :
                     (checkMpS->Checked ?
                     (USHORT)(this->valueSpeed->Value * 100):
                     (USHORT) Math::Round((valueSpeed->Value * 1000/36), System::MidpointRounding::AwayFromZero)));
	zones[(UCHAR)AntPlusRacquet::RacquetZones::MISS][comboType->SelectedIndex]++;
	AddEvent();
}

/**************************************************************************
 * RacquetSensor::AddEvent
 * 
 * Adds a new stroke event to the StrokeEvent array
 * 
 * returns: N/A
 *
 **************************************************************************/
void RacquetSensor::AddEvent()
{
	// Set the next element in StrokeEvent array to this event
	StrokeEvents[RacquetData->ucEventCount]->EventCount = RacquetData->ucEventCount;
	StrokeEvents[RacquetData->ucEventCount]->EventTime = RacquetData->usEventTime;
	StrokeEvents[RacquetData->ucEventCount]->EventType = RacquetData->ucEventType;
	StrokeEvents[RacquetData->ucEventCount]->BallSpeed = RacquetData->usSpeed;
	StrokeEvents[RacquetData->ucEventCount]->RacquetZone = RacquetData->ucRacquetZone;

	cbEventCount->Items->Add(RacquetData->ucEventCount.ToString());
}
/**************************************************************************
 * RacquetSensor::ckInvalidSpeed_CheckedChanged
 * 
 * Handles the ckInvalidSpeed Checked Changed event. If the checkbox  is 
 * checked, don't allow the user to change the speed field. If it is not
 * checked, allow the user to change the speed field. 
 *
 * sender: Object raising event 
 * e: Event arguments
 * 
 * returns: N/A
 *
 **************************************************************************/
void RacquetSensor::ckInvalidSpeed_CheckedChanged(System::Object ^sender, System::EventArgs ^e)
{
	if(this->ckInvalidSpeed->Checked)
		this->valueSpeed->Enabled = false;
	else
		this->valueSpeed->Enabled = true;
}
/**************************************************************************
 * RacquetSensor::cbEventCount_SelectedIndexChanged
 * 
 * Handles cbEventCount Selected Index Changed event. Displays the previous
 * event data based on the event count chosen by the user in the comboBox. 
 *
 * sender: Object raising event 
 * e: Event arguments
 * 
 * returns: N/A
 *
 **************************************************************************/
void RacquetSensor::cbEventCount_SelectedIndexChanged(System::Object ^sender, System::EventArgs ^e)
{
	switch(StrokeEvents[cbEventCount->SelectedIndex]->RacquetZone)
	{
	case AntPlusRacquet::RacquetZones::MISS:
		lbRacquetZone->Text = "Miss";
		break;
	case AntPlusRacquet::RacquetZones::TOP_RIGHT:
		lbRacquetZone->Text = "Top Right";
		break;
	case AntPlusRacquet::RacquetZones::MIDDLE_RIGHT:
		lbRacquetZone->Text = "Middle Right";
		break;
	case AntPlusRacquet::RacquetZones::BOTTOM_RIGHT:
		lbRacquetZone->Text = "Bottom Right";
		break;
	case AntPlusRacquet::RacquetZones::BOTTOM_CENTRE:
		lbRacquetZone->Text = "Bottom Center";
		break;
	case AntPlusRacquet::RacquetZones::BOTTOM_LEFT:
		lbRacquetZone->Text = "Botttom Left";
		break;
	case AntPlusRacquet::RacquetZones::MIDDLE_CENTRE:
		lbRacquetZone->Text = "Middle Center";
		break;
	case AntPlusRacquet::RacquetZones::MIDDLE_LEFT:
		lbRacquetZone->Text = "Middle Left";
		break;
	case AntPlusRacquet::RacquetZones::TOP_LEFT:
		lbRacquetZone->Text = "Top Left";
		break;
	case AntPlusRacquet::RacquetZones::TOP_CENTRE:
		lbRacquetZone->Text = "Top Center";
		break;
	case AntPlusRacquet::RacquetZones::RIM_OTHER:
		lbRacquetZone->Text = "Rim/Other";
		break;
	case AntPlusRacquet::RacquetZones::UNKNOWN:
		lbRacquetZone->Text = "Unknown";
		break;
	default:
		lbRacquetZone->Text = "----";
		break;
	}

	switch(StrokeEvents[cbEventCount->SelectedIndex]->EventType)
	{
	case AntPlusRacquet::StrokeTypes::NO_EVENT:
		lbStrokeType->Text = "No Event";
		break;
	case AntPlusRacquet::StrokeTypes::OTHER:
		lbStrokeType->Text = "Other";
		break;
	case AntPlusRacquet::StrokeTypes::SERVE:
		lbStrokeType->Text = "Serve";
		break;
	case AntPlusRacquet::StrokeTypes::FOREHAND:
		lbStrokeType->Text = "Forehand";
		break;
	case AntPlusRacquet::StrokeTypes::BACKHAND:
		lbStrokeType->Text = "Backhand";
		break;
	case AntPlusRacquet::StrokeTypes::SMASH:
		lbStrokeType->Text = "Smash";
		break;
	case AntPlusRacquet::StrokeTypes::UNKNOWN:
		lbStrokeType->Text = "Unknown";
		break;
	default:
		lbStrokeType->Text = "----";
		break;
	}

	lbBallSpeed->Text = (StrokeEvents[cbEventCount->SelectedIndex]->BallSpeed == AntPlusRacquet::UNKNOWN ?
						"Invalid" :
						((double)StrokeEvents[cbEventCount->SelectedIndex]->BallSpeed / 100).ToString("F2") + " m/s");
	lbEventTime->Text = StrokeEvents[cbEventCount->SelectedIndex]->EventTime.ToString(); 
}
/**************************************************************************
 * RacquetSensor::cbStrokeType_SelectedIndexChanged
 * 
 * Handles cbStrokeType Selected Index Changed event. Displays the stroke 
 * count based on the type of stroke selected. 
 *
 * sender: Object raising event 
 * e: Event arguments
 * 
 * returns: N/A
 *
 **************************************************************************/
void RacquetSensor::cbStrokeType_SelectedIndexChanged(System::Object ^sender, System::EventArgs ^e)
{
	USHORT count = 0;

	// All strokes
	if(cbStrokeType->SelectedIndex == 0)
	{
		for(int i = 0; i < zones->Length; i++)
		{
			for(int j =	1; j < zones[i]->Length; j++)
				count += zones[i][j];
		}
	}
	else // Certain stroke
	{
		for(int i = 0; i < zones->Length; i++)
			count += zones[i][cbStrokeType->SelectedIndex];
	}

	lbStrokes->Text = count.ToString();
}
/**************************************************************************
 * RacquetSensor::cbRacquetZone_SelectedIndexChanged
 * 
 * Handles cbRacquetZone Selected Index Changed event. Displays the stroke
 * count based on the Racquet Zone and Stroke Type selected by the user. 
 *
 * sender: Object raising event 
 * e: Event arguments
 * 
 * returns: N/A
 *
 **************************************************************************/
void RacquetSensor::cbRacquetZone_SelectedIndexChanged(System::Object ^sender, System::EventArgs ^e)
{
	USHORT count = 0;
	if(cbZoneStrokes->SelectedIndex == 0)
	{
		for(int i = 0; i < zones->Length; i++)
			for(int j = 1; j < zones[i]->Length; j++)
				count += zones[i][j];
	}
	else
		count = zones[cbRacquetZone->SelectedIndex][cbZoneStrokes->SelectedIndex];
	
	lbZoneStrokes->Text = count.ToString();
}
/**************************************************************************
 * RacquetSensor::cbZoneStrokes_SelectedIndexChanged
 * 
 * Handles cbZoneStrokes Selected Index Changed event. Displays the stroke 
 * count based on the Racquet Zone and Stroke Type selected by the user. 
 *
 * sender: Object raising event 
 * e: Event arguments
 * 
 * returns: N/A
 *
 **************************************************************************/
void RacquetSensor::cbZoneStrokes_SelectedIndexChanged(System::Object ^sender, System::EventArgs ^e)
{
	USHORT count = 0;
	if(cbZoneStrokes->SelectedIndex == 0)
	{
		for(int i = 0; i < zones->Length; i++)
			for(int j = 1; j < zones[i]->Length; j++)
				count += zones[i][j];
	}
	else
		count = zones[cbRacquetZone->SelectedIndex][cbZoneStrokes->SelectedIndex];

	lbZoneStrokes->Text = count.ToString();
}
void RacquetSensor::btUpdateCommon_Click(System::Object ^sender, System::EventArgs ^e)
{
	lbCommonError->Visible = false;
	try
	{
		Common->ucHwVersion = System::Convert::ToByte(tbHardwareVer->Text);
		Common->usMfgID = System::Convert::ToUInt16(tbManfId->Text);
		Common->usModelNum = System::Convert::ToUInt16(tbModelNum->Text);
		Common->ucSwVersion = System::Convert::ToByte(tbSoftwareVer->Text);

		if(cbInvalidSerial->Checked)
			Common->ulSerialNum = 0xFFFFFFFF;
		else
			Common->ulSerialNum = System::Convert::ToUInt32(tbSerialNumber->Text);
	}
	catch(...)
	{
		lbCommonError->Visible = true;
	}
}
void RacquetSensor::cbInvalidSerial_CheckedChanged(System::Object ^sender, System::EventArgs ^e)
{
	if(cbInvalidSerial->Checked)
		tbSerialNumber->Enabled = false;
	else
		tbSerialNumber->Enabled = true;
}
void RacquetSensor::timerSession_Tick(System::Object ^sender, System::Timers::ElapsedEventArgs ^e)
{
	time += 1;

	TimeSpan t = TimeSpan::FromSeconds(time);
	//If an error C2227 comes up  here, it's probably because something was changed in the designer
	// and this label needs to be declared as static. 
	// find where it is declared in RacquetSensor.h 
	// where it says public: System::Windows::Forms::Label^  lbSessionTime;
	// change it to public: static System::Windows::Forms::Label^  lbSessionTime;
	// This will get ride of the error

 	lbSessionTime->Text = System::String::Format("{0:D2}:{1:D2}:{2:D2}", t.Hours, t.Minutes, t.Seconds);
}
void RacquetSensor::checkMpS_CheckedChanged(System::Object ^sender, System::EventArgs ^e)
{
   if(checkMpS->Checked)
   {
      Decimal kmphValue = valueSpeed->Value;
      valueSpeed->DecimalPlaces = 2;
      valueSpeed->Maximum = (Decimal)(655.34);
      valueSpeed->Increment = (Decimal)(0.01);
      valueSpeed->Value = Math::Round((kmphValue) * (Decimal)((Decimal)10/(Decimal)36), 2, System::MidpointRounding::AwayFromZero);
   }
   else
   {
      Decimal mpsValue = valueSpeed->Value;
      valueSpeed->DecimalPlaces = 3;
      valueSpeed->Maximum = (Decimal)(655.34 * 36/10);
      valueSpeed->Increment = (Decimal)0.001;
      valueSpeed->Value = Math::Round(((mpsValue) * (Decimal)((Decimal)36/(Decimal)10)), 3, System::MidpointRounding::AwayFromZero);
   }
}

void RacquetSensor::checkANTFS_CheckedChanged(System::Object ^sender, System::EventArgs ^e)
{
	if(checkANTFS->Checked)
	{	
	RacquetData->ucANTFS = 1;
	}
	else
	{
	RacquetData->ucANTFS = 0;
	}
}


void RacquetSensor::comboBoxBatStatus_SelectedIndexChanged(System::Object ^sender, System::EventArgs ^e)
{
   if(comboBoxBatStatus->Text == "New")
      Common->eBatStatus = CommonData::BatStatus::NEW;
   if(comboBoxBatStatus->Text == "Good")
      Common->eBatStatus = CommonData::BatStatus::GOOD;
   if(comboBoxBatStatus->Text == "Ok")
      Common->eBatStatus = CommonData::BatStatus::OK;
   if(comboBoxBatStatus->Text == "Low")
      Common->eBatStatus = CommonData::BatStatus::LOW;
   if(comboBoxBatStatus->Text == "Critical")
      Common->eBatStatus = CommonData::BatStatus::CRITICAL;
   if(comboBoxBatStatus->Text == "Invalid")
      Common->eBatStatus = CommonData::BatStatus::INVALID;
}
void RacquetSensor::checkBox_Bat_Voltage_CheckedChanged(System::Object ^sender, System::EventArgs ^e)
{
   if(checkBox_Bat_Voltage->Checked)
   {
      numericCoarseVoltage->Enabled = false;
      numericFractionalVoltage->Enabled = false;
      Common->usBatVoltage256 = CommonData::BATTERY_VOLTAGE_INVALID;
   }
   else
   {
      numericCoarseVoltage->Enabled = true;
      numericFractionalVoltage->Enabled = true;
      Common->usBatVoltage256 = ((USHORT)System::Convert::ToByte(numericCoarseVoltage->Value)) << 8 | (Common->usBatVoltage256 & 0xFF);
      Common->usBatVoltage256 = System::Convert::ToByte(numericFractionalVoltage->Value) | (Common->usBatVoltage256 & 0xFF00);
   }
}
void RacquetSensor::numericCoarseVoltage_ValueChanged(System::Object ^sender, System::EventArgs ^e)
{
   Common->usBatVoltage256 = ((USHORT)System::Convert::ToByte(numericCoarseVoltage->Value)) << 8 | (Common->usBatVoltage256 & 0xFF);
}
void RacquetSensor::numericFractionalVoltage_ValueChanged(System::Object ^sender, System::EventArgs ^e)
{
   Common->usBatVoltage256 = System::Convert::ToByte(numericFractionalVoltage->Value) | (Common->usBatVoltage256 & 0xFF00);
}
void RacquetSensor::radioResolution2_CheckedChanged(System::Object ^sender, System::EventArgs ^e)
{
   if(radioResolution2->Checked)
      Common->eTimeResolution = CommonData::TimeResolution::TWO;
   else
      Common->eTimeResolution = CommonData::TimeResolution::SIXTEEN;
}
void RacquetSensor::buttonUpdateTime_Click(System::Object ^sender, System::EventArgs ^e)
{
   labelTimeError->Visible = false;
   try
   {
      ulTotalTime = System::Convert::ToUInt32(textBoxTime->Text);
   }
   catch (...)
   {
      labelTimeError->Visible = true;
      return;
   }

   Common->ulOpTime = ulTotalTime / (UCHAR)Common->eTimeResolution;

}