function initClient()
{
   exec("~/defaults.cs");
   exec("./common/canvas.cs");

   initCanvas("TAP -- RumbleXInput Sample");
   
   // Load-up GUIs.
   exec("./RumbleXInput.gui");
   Canvas.setContent(RumbleXInput);
   Canvas.setCursor(DefaultCursor);

   $enableDirectInput = "1";
   activateDirectInput();
   enableXInput();

   // Bind some global keypresses
   GlobalActionMap.bind(keyboard, "tilde", "toggleConsole");
   GlobalActionMap.bindCmd(keyboard, "alt enter", "", "toggleFullScreen();");
   GlobalActionMap.bindCmd(keyboard, "escape", "", "quit();");
   bindControllerEvents();

   for ( %i = 0; %i < 4; %i++ )
   {
      $leftMotor[%i]  = 0;
      $rightMotor[%i] = 0;
      $rumbleLock[%i] = false;
      $buttonPressed[%i] = false;
   }

   updateGuiControls();
}

function updateGuiControls()
{
   for ( %i = 0; %i < 4; %i++ )
   {
      if ( $xiConnected[%i] )
         updateConnected( %i );
      else
         updateDisconnected( %i );
   }

   // Update the gui 30 times a second
   schedule( ( 1 / 30 ) * 1000, 0, "updateGuiControls" );
}

function updateConnected( %cid )
{
   if ( !$rumbleLock[%cid] )
   {
      $leftMotor[%cid]  = $xiTRIGGERL[%cid];
      $rightMotor[%cid] = $xiTRIGGERR[%cid];
      rumble("xinput" @ %cid, $leftMotor[%cid], $rightMotor[%cid]);
   }

   if ( $xiA[%cid] == 1 ) $buttonPressed[%cid] = true;
   if ( $xiA[%cid] == 0 && $buttonPressed[%cid])
   {
      $rumbleLock[%cid] = !$rumbleLock[%cid];
      $buttonPressed[%cid] = 0;
   }

   ("txtController" @ %cid).setText( "Controller" SPC %cid @ ":" SPC "Connected" );

   ("txtLMotor" @ %cid).setText( "Left Motor Speed: " @ $leftMotor[%cid] );
   ("txtRMotor" @ %cid).setText( "Right Motor Speed: " @ $rightMotor[%cid] );
   ("txtRumbleLock" @ %cid).setText( "Rumble Lock: " @ $rumbleLock[%cid] );

   ("txtLMotor" @ %cid).setVisible( 1 );
   ("txtRMotor" @ %cid).setVisible( 1 );
   ("txtRumbleLock" @ %cid).setVisible( 1 );
}

function updateDisconnected( %cid )
{
   ("txtController" @ %cid).setText( "Controller" SPC %cid @ ":" SPC "Not connected" );
   ("txtLMotor" @ %cid).setVisible( 0 );
   ("txtRMotor" @ %cid).setVisible( 0 );
   ("txtRumbleLock" @ %cid).setVisible( 0 );
}

function bindControllerEvents()
{
   GlobalActionMap.bindCmd("xinput0", "connect", "xi_connect(0, 1);", "xi_connect(0, 0);");
   GlobalActionMap.bindCmd("xinput0", "btn_a", "xi_a(0, 1);", "xi_a(0, 0);");
   GlobalActionMap.bindCmd("xinput0", "btn_b", "xi_b(0, 1);", "xi_b(0, 0);");
   GlobalActionMap.bindCmd("xinput0", "btn_x", "xi_x(0, 1);", "xi_x(0, 0);");
   GlobalActionMap.bindCmd("xinput0", "btn_y", "xi_y(0, 1);", "xi_y(0, 0);");
   GlobalActionMap.bindCmd("xinput0", "btn_l", "xi_l(0, 1);", "xi_l(0, 0);");
   GlobalActionMap.bindCmd("xinput0", "btn_r", "xi_r(0, 1);", "xi_r(0, 0);");
   GlobalActionMap.bindCmd("xinput0", "btn_lt", "xi_lt(0, 1);", "xi_lt(0, 0);");
   GlobalActionMap.bindCmd("xinput0", "btn_rt", "xi_rt(0, 1);", "xi_rt(0, 0);");
   GlobalActionMap.bindCmd("xinput0", "btn_start", "xi_start(0, 1);", "xi_start(0, 0);");
   GlobalActionMap.bindCmd("xinput0", "btn_back", "xi_back(0, 1);", "xi_back(0, 0);");
   GlobalActionMap.bindCmd("xinput0", "dpadu", "xi_dpadu(0, 1);", "xi_dpadu(0, 0);");
   GlobalActionMap.bindCmd("xinput0", "dpadd", "xi_dpadd(0, 1);", "xi_dpadd(0, 0);");
   GlobalActionMap.bindCmd("xinput0", "dpadl", "xi_dpadl(0, 1);", "xi_dpadl(0, 0);");
   GlobalActionMap.bindCmd("xinput0", "dpadr", "xi_dpadr(0, 1);", "xi_dpadr(0, 0);");
   GlobalActionMap.bind("xinput0", "thumblx", "xi_thumblx0");
   GlobalActionMap.bind("xinput0", "thumbly", "xi_thumbly0");
   GlobalActionMap.bind("xinput0", "thumbrx", "xi_thumbrx0");
   GlobalActionMap.bind("xinput0", "thumbry", "xi_thumbry0");
   GlobalActionMap.bind("xinput0", "triggerl", "xi_triggerl0");
   GlobalActionMap.bind("xinput0", "triggerr", "xi_triggerr0");

   GlobalActionMap.bindCmd("xinput1", "connect", "xi_connect(1, 1);", "xi_connect(1, 0);");
   GlobalActionMap.bindCmd("xinput1", "btn_a", "xi_a(1, 1);", "xi_a(1, 0);");
   GlobalActionMap.bindCmd("xinput1", "btn_b", "xi_b(1, 1);", "xi_b(1, 0);");
   GlobalActionMap.bindCmd("xinput1", "btn_x", "xi_x(1, 1);", "xi_x(1, 0);");
   GlobalActionMap.bindCmd("xinput1", "btn_y", "xi_y(1, 1);", "xi_y(1, 0);");
   GlobalActionMap.bindCmd("xinput1", "btn_l", "xi_l(1, 1);", "xi_l(1, 0);");
   GlobalActionMap.bindCmd("xinput1", "btn_r", "xi_r(1, 1);", "xi_r(1, 0);");
   GlobalActionMap.bindCmd("xinput1", "btn_lt", "xi_lt(1, 1);", "xi_lt(1, 0);");
   GlobalActionMap.bindCmd("xinput1", "btn_rt", "xi_rt(1, 1);", "xi_rt(1, 0);");
   GlobalActionMap.bindCmd("xinput1", "btn_start", "xi_start(1, 1);", "xi_start(1, 0);");
   GlobalActionMap.bindCmd("xinput1", "btn_back", "xi_back(1, 1);", "xi_back(1, 0);");
   GlobalActionMap.bindCmd("xinput1", "dpadu", "xi_dpadu(1, 1);", "xi_dpadu(1, 0);");
   GlobalActionMap.bindCmd("xinput1", "dpadd", "xi_dpadd(1, 1);", "xi_dpadd(1, 0);");
   GlobalActionMap.bindCmd("xinput1", "dpadl", "xi_dpadl(1, 1);", "xi_dpadl(1, 0);");
   GlobalActionMap.bindCmd("xinput1", "dpadr", "xi_dpadr(1, 1);", "xi_dpadr(1, 0);");
   GlobalActionMap.bind("xinput1", "thumblx", "xi_thumblx1");
   GlobalActionMap.bind("xinput1", "thumbly", "xi_thumbly1");
   GlobalActionMap.bind("xinput1", "thumbrx", "xi_thumbrx1");
   GlobalActionMap.bind("xinput1", "thumbry", "xi_thumbry1");
   GlobalActionMap.bind("xinput1", "triggerl", "xi_triggerl1");
   GlobalActionMap.bind("xinput1", "triggerr", "xi_triggerr1");

   GlobalActionMap.bindCmd("xinput2", "connect", "xi_connect(2, 1);", "xi_connect(2, 0);");
   GlobalActionMap.bindCmd("xinput2", "btn_a", "xi_a(2, 1);", "xi_a(2, 0);");
   GlobalActionMap.bindCmd("xinput2", "btn_b", "xi_b(2, 1);", "xi_b(2, 0);");
   GlobalActionMap.bindCmd("xinput2", "btn_x", "xi_x(2, 1);", "xi_x(2, 0);");
   GlobalActionMap.bindCmd("xinput2", "btn_y", "xi_y(2, 1);", "xi_y(2, 0);");
   GlobalActionMap.bindCmd("xinput2", "btn_l", "xi_l(2, 1);", "xi_l(2, 0);");
   GlobalActionMap.bindCmd("xinput2", "btn_r", "xi_r(2, 1);", "xi_r(2, 0);");
   GlobalActionMap.bindCmd("xinput2", "btn_lt", "xi_lt(2, 1);", "xi_lt(2, 0);");
   GlobalActionMap.bindCmd("xinput2", "btn_rt", "xi_rt(2, 1);", "xi_rt(2, 0);");
   GlobalActionMap.bindCmd("xinput2", "btn_start", "xi_start(2, 1);", "xi_start(2, 0);");
   GlobalActionMap.bindCmd("xinput2", "btn_back", "xi_back(2, 1);", "xi_back(2, 0);");
   GlobalActionMap.bindCmd("xinput2", "dpadu", "xi_dpadu(2, 1);", "xi_dpadu(2, 0);");
   GlobalActionMap.bindCmd("xinput2", "dpadd", "xi_dpadd(2, 1);", "xi_dpadd(2, 0);");
   GlobalActionMap.bindCmd("xinput2", "dpadl", "xi_dpadl(2, 1);", "xi_dpadl(2, 0);");
   GlobalActionMap.bindCmd("xinput2", "dpadr", "xi_dpadr(2, 1);", "xi_dpadr(2, 0);");
   GlobalActionMap.bind("xinput2", "thumblx", "xi_thumblx2");
   GlobalActionMap.bind("xinput2", "thumbly", "xi_thumbly2");
   GlobalActionMap.bind("xinput2", "thumbrx", "xi_thumbrx2");
   GlobalActionMap.bind("xinput2", "thumbry", "xi_thumbry2");
   GlobalActionMap.bind("xinput2", "triggerl", "xi_triggerl2");
   GlobalActionMap.bind("xinput2", "triggerr", "xi_triggerr2");

   GlobalActionMap.bindCmd("xinput3", "connect", "xi_connect(3, 1);", "xi_connect(3, 0);");
   GlobalActionMap.bindCmd("xinput3", "btn_a", "xi_a(3, 1);", "xi_a(3, 0);");
   GlobalActionMap.bindCmd("xinput3", "btn_b", "xi_b(3, 1);", "xi_b(3, 0);");
   GlobalActionMap.bindCmd("xinput3", "btn_x", "xi_x(3, 1);", "xi_x(3, 0);");
   GlobalActionMap.bindCmd("xinput3", "btn_y", "xi_y(3, 1);", "xi_y(3, 0);");
   GlobalActionMap.bindCmd("xinput3", "btn_l", "xi_l(3, 1);", "xi_l(3, 0);");
   GlobalActionMap.bindCmd("xinput3", "btn_r", "xi_r(3, 1);", "xi_r(3, 0);");
   GlobalActionMap.bindCmd("xinput3", "btn_lt", "xi_lt(3, 1);", "xi_lt(3, 0);");
   GlobalActionMap.bindCmd("xinput3", "btn_rt", "xi_rt(3, 1);", "xi_rt(3, 0);");
   GlobalActionMap.bindCmd("xinput3", "btn_start", "xi_start(3, 1);", "xi_start(3, 0);");
   GlobalActionMap.bindCmd("xinput3", "btn_back", "xi_back(3, 1);", "xi_back(3, 0);");
   GlobalActionMap.bindCmd("xinput3", "dpadu", "xi_dpadu(3, 1);", "xi_dpadu(3, 0);");
   GlobalActionMap.bindCmd("xinput3", "dpadd", "xi_dpadd(3, 1);", "xi_dpadd(3, 0);");
   GlobalActionMap.bindCmd("xinput3", "dpadl", "xi_dpadl(3, 1);", "xi_dpadl(3, 0);");
   GlobalActionMap.bindCmd("xinput3", "dpadr", "xi_dpadr(3, 1);", "xi_dpadr(3, 0);");
   GlobalActionMap.bind("xinput3", "thumblx", "xi_thumblx3");
   GlobalActionMap.bind("xinput3", "thumbly", "xi_thumbly3");
   GlobalActionMap.bind("xinput3", "thumbrx", "xi_thumbrx3");
   GlobalActionMap.bind("xinput3", "thumbry", "xi_thumbry3");
   GlobalActionMap.bind("xinput3", "triggerl", "xi_triggerl3");
   GlobalActionMap.bind("xinput3", "triggerr", "xi_triggerr3");

   xi_connect( 0, isXInputConnected( 0 ) );
   xi_connect( 1, isXInputConnected( 1 ) );
   xi_connect( 2, isXInputConnected( 2 ) );
   xi_connect( 3, isXInputConnected( 3 ) );
   
   // Force a one-time event refresh for every connected controller
   resetXInput();
}

function xi_connect( %controllerID, %connected )   { $xiConnected[%controllerID] = %connected; if ( !%connected ) xi_clear( %controllerID ); }
function xi_a( %controllerID, %pressed )           { $xiA[%controllerID] = %pressed; }
function xi_b( %controllerID, %pressed )           { $xiB[%controllerID] = %pressed; }
function xi_x( %controllerID, %pressed )           { $xiX[%controllerID] = %pressed; }
function xi_y( %controllerID, %pressed )           { $xiY[%controllerID] = %pressed; }
function xi_l( %controllerID, %pressed )           { $xiL[%controllerID] = %pressed; }
function xi_r( %controllerID, %pressed )           { $xiR[%controllerID] = %pressed; }
function xi_lt( %controllerID, %pressed )          { $xiLT[%controllerID] = %pressed; }
function xi_rt( %controllerID, %pressed )          { $xiRT[%controllerID] = %pressed; }
function xi_start( %controllerID, %pressed )       { $xiSTART[%controllerID] = %pressed; }
function xi_back( %controllerID, %pressed )        { $xiBACK[%controllerID] = %pressed; }
function xi_dpadu( %controllerID, %pressed )       { $xiDPADU[%controllerID] = %pressed; }
function xi_dpadd( %controllerID, %pressed )       { $xiDPADD[%controllerID] = %pressed; }
function xi_dpadl( %controllerID, %pressed )       { $xiDPADL[%controllerID] = %pressed; }
function xi_dpadr( %controllerID, %pressed )       { $xiDPADR[%controllerID] = %pressed; }
function xi_thumblx( %controllerID, %val )         { $xiTHUMBLX[%controllerID] = %val; }
function xi_thumbly( %controllerID, %val )         { $xiTHUMBLY[%controllerID] = %val; }
function xi_thumbrx( %controllerID, %val )         { $xiTHUMBRX[%controllerID] = %val; }
function xi_thumbry( %controllerID, %val )         { $xiTHUMBRY[%controllerID] = %val; }
function xi_triggerl( %controllerID, %val )        { $xiTRIGGERL[%controllerID] = %val; }
function xi_triggerr( %controllerID, %val )        { $xiTRIGGERR[%controllerID] = %val; }
function xi_clear( %i )                            { xi_clearButtons( %i ); xi_clearDPAD( %i ); }
function xi_clearButtons( %i )                     { $xiA[%i] = 0; $xiB[%i] = 0; $xiX[%i] = 0; $xiY[%i] = 0; $xiL[%i] = 0; $xiR[%i] = 0; $xiLT[%i] = 0; $xiRT[%i] = 0; $xiBACK[%i] = 0; $xiSTART[%i] = 0; }
function xi_clearDPAD( %i )                        { $xiDPADU[%i] = 0; $xiDPADD[%i] = 0; $xiDPADL[%i] = 0; $xiDPADR[%i] = 0; }
function xi_thumblx0( %val )                       { xi_thumblx( 0, %val ); }
function xi_thumbly0( %val )                       { xi_thumbly( 0, %val ); }
function xi_thumbrx0( %val )                       { xi_thumbrx( 0, %val ); }
function xi_thumbry0( %val )                       { xi_thumbry( 0, %val ); }
function xi_triggerl0( %val )                      { xi_triggerl( 0, %val ); }
function xi_triggerr0( %val )                      { xi_triggerr( 0, %val ); }
function xi_thumblx1( %val )                       { xi_thumblx( 1, %val ); }
function xi_thumbly1( %val )                       { xi_thumbly( 1, %val ); }
function xi_thumbrx1( %val )                       { xi_thumbrx( 1, %val ); }
function xi_thumbry1( %val )                       { xi_thumbry( 1, %val ); }
function xi_triggerl1( %val )                      { xi_triggerl( 1, %val ); }
function xi_triggerr1( %val )                      { xi_triggerr( 1, %val ); }
function xi_thumblx2( %val )                       { xi_thumblx( 2, %val ); }
function xi_thumbly2( %val )                       { xi_thumbly( 2, %val ); }
function xi_thumbrx2( %val )                       { xi_thumbrx( 2, %val ); }
function xi_thumbry2( %val )                       { xi_thumbry( 2, %val ); }
function xi_triggerl2( %val )                      { xi_triggerl( 2, %val ); }
function xi_triggerr2( %val )                      { xi_triggerr( 2, %val ); }
function xi_thumblx3( %val )                       { xi_thumblx( 3, %val ); }
function xi_thumbly3( %val )                       { xi_thumbly( 3, %val ); }
function xi_thumbrx3( %val )                       { xi_thumbrx( 3, %val ); }
function xi_thumbry3( %val )                       { xi_thumbry( 3, %val ); }
function xi_triggerl3( %val )                      { xi_triggerl( 3, %val ); }
function xi_triggerr3( %val )                      { xi_triggerr( 3, %val ); }

initClient();
