<!DOCTYPE html>
<html lang="en">
<!-- 
      https://www.thebubbleworks.com/TheBubbleWorks_WebBluetooth_PythonBlueZero_LightSwitch
      
      http://plnkr.co/edit/eJeCIn?p=preview
      
-->

<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, height=device-height, initial-scale=1.0, maximum-scale=1.0" />
  <title>Python BlueZero - Light Example</title>


  <script data-require="jquery@*" data-semver="2.2.0" src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>

  <!-- FontAwesome is a collection of icons, this uses the lightbulb, bluetooth and the switch -->
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.6.1/css/font-awesome.min.css" />

  <!-- App specifc styles -->
  <link rel="stylesheet" href="app.css" />

  <!-- WORK IN PROGRESS - AGENT NOT YET PUBLISHED -->
  <!-- If the browser aand platform  doesn't support WebBluetooth at all it's possible to fall back to using 
       a 'sidekick' that runs as a local service on the client machine by injecting this optional shim.
       The BubbleWorks cross platform & cross browser Web Bluetooth shim, requires client/native service to be running on local machine.
       See here: https://www.thebubbleworks.com/WebBluetoothSidekick/latest/agent/
  -->
  <!--
  <script src="https://www.thebubbleworks.com/WebBluetoothSidekick/latest/browser/lib/bluetooth.helpers.js"></script>
  <script src="https://www.thebubbleworks.com/WebBluetoothSidekick/latest/browser/lib/adapter.bubbleworks.js"></script>
  -->

</head>

<body>

  <div class="fixed-top-left">
    <div>
      <i class="fa fa-bluetooth fa-5x blue"></i>
    </div>
    <div>
      <button id="connectButton">
        <i class="fa fa-toggle fa-toggle-off fa-5x blue" id="bluetoothSwitch"></i>
      </button>
    </div>
  </div>


  <div class="fixed-top-right">
    <div>
      <i class="fa fa-lightbulb-o lightBulbOff" id="lightBulb"></i>
    </div>
    <div>
      <button id="offButton">
        <i class="fa fa-toggle fa-toggle-off fa-5x red" id="lightSwitch"></i>
      </button>
    </div>
  </div>

  <div id="footer">
    <h2>LightBulb Demo for Python <a href="https://github.com/ukBaz/python-bluezero">BlueZero</a></h2>

    <textarea class="console" id="consoleTextArea" readonly=""></textarea>
  </div>

  <script src="app.js"></script>
</body>

</html>
//-------------------------------------------------------------------------
// Logging 


function error(text) {
  log("ERROR:" + text);
}

function info(text) {
  log("INFO: " + text);
}

function log(line) {
  console.log(line);
  textarea = document.getElementById('consoleTextArea')
  if (textarea) {
    previous_text = textarea.innerHTML;
    textarea.innerHTML = previous_text + line + "\n";
    textarea.scrollTop = textarea.scrollHeight;
  }
}

window.onerror = function(msg, url, lineNumber, columnNumber, err) {
  error(msg + ' Script: ' + url + ' Line: ' + lineNumber);
  return false;
}


//-------------------------------------------------------------------------
// App starts when DOM is ready

$(document).ready(function() {
  info("App started");
  // UI Input handlers

  $('#connectButton').click(connectPressed);
  $('#lightSwitch').click(switchPressed);

  updateDisplay();
});


//-------------------------------------------------------------------------
// Constants


// Bluetooth 

// These 128-Bit ID's correspond to the python-bluezero light switch example
var SERVICE_UUID = '12341000-1234-1234-1234-123456789abc';
var CHAR_RX_UUID = '12341002-1234-1234-1234-123456789abc';
var CHAR_TX_UUID = '12341002-1234-1234-1234-123456789abc';

var LIGHT_OFF = [0x00];
var LIGHT_ON = [0x01];



//-------------------------------------------------------------------------
// App State

var isLightOn = false;
var connected = false;



//-------------------------------------------------------------------------
// Bluetooth state and connection setup
var bleDevice = null;
var gattServer = null;
var gattService = null;
var writeCharacteristic = null;
var readCharacteristic = null;


function setupBluetooth() {

  if (navigator.bluetooth === undefined) {
    error('Web Bluetooth support not found, please see: https://goo.gl/5p4zNM');
    return;
  }

  if (gattServer !== null && gattServer.connected) {
    info('(not yet) Disconnecting...');
    // TODO: inspect platform support, and/or
    // TODO: listen for an actual BLE event#
    //gattServer.disconnect();
    //updateBluetoothState(false); 

  } else {
    info('Connecting...');
    if (readCharacteristic === null) {
      navigator.bluetooth.requestDevice({
          filters: [{
            services: [SERVICE_UUID]
          }]
        })
        .then(function(device) {
          info('DeviceName=' + device.name);
          info('Connecting to GATT Server...');
          bleDevice = device;
          if (device.gatt)
            return device.gatt.connect(); // Connect to GATT Server on  device
          else
            return device.connectGATT();  // deprecated but a fallback
        }).then(function(server) {
          info('Found GATT server');
          gattServer = server;
          return gattServer.getPrimaryService(SERVICE_UUID); // Get  service
        }).then(function(service) {
          info('Found service');
          gattService = service;
          return gattService.getCharacteristic(CHAR_TX_UUID); // Get write characteristic
        }).then(function(characteristic) {
          info('Found write characteristic');
          writeCharacteristic = characteristic;
          return gattService.getCharacteristic(CHAR_RX_UUID); // Get read characteristic

        }).then(function(characteristic) {
          connected = true;
          info('Found read characteristic');
          readCharacteristic = characteristic;
          updateBluetoothState(true);


          // Listen to device notifications
          return readCharacteristic.startNotifications().then(function() {

            readCharacteristic.addEventListener('characteristicvaluechanged', function(event) {
              info('characteristicvaluechanged = ' + event.target.value + ' [' + event.target.value.byteLength + ']');
              if (event.target.value.byteLength > 0) {
                var data = new Uint8Array(event.target.value);
                onDataReceived(data);
              }
            });
          });
        }).catch(handleError);
    }
  }
}


function handleError(err) {
  error(err);
  updateBluetoothState(false);
  
}

//-------------------------------------------------------------------------
// Bluetooth sending and receiving


function send(data) {
  info("Sending: " + data);
  try {
    if (writeCharacteristic)
      writeCharacteristic.writeValue(new Uint8Array(data));
    else
      error("writeCharacteristic is not set");
  } catch (err) {
    error("Couldn't send, not connected? error was: " + err);
  }
}

function onDataReceived(data) {
  info("Recv data: " + data);

  if (data.length === 0)
    return;

  updateLightState(data[0] == 0x01);
}


//-------------------------------------------------------------------------
// UI Inputs


function connectPressed() {
  setupBluetooth();
}


function switchPressed() {
  isLightOn = !isLightOn;
  updateLightState(isLightOn);
}


//-------------------------------------------------------------------------
// UI Display

function updateDisplay() {
  updateBluetoothDisplay();
  updateLightDisplay();
}

function updateBluetoothDisplay() {
  if (connected)
    $('#bluetoothSwitch').removeClass('fa-toggle-off').addClass('fa-toggle-on');
  else
    $('#bluetoothSwitch').removeClass('fa-toggle-on').addClass('fa-toggle-off');
}

function updateLightDisplay() {
  if (isLightOn) {
    $('#lightBulb').removeClass('lightBulbOff').addClass('lightBulbOn');
    $('#lightSwitch').removeClass('fa-toggle-off').addClass('fa-toggle-on');
  } else {
    $('#lightBulb').removeClass('lightBulbOn').addClass('lightBulbOff');
    $('#lightSwitch').removeClass('fa-toggle-on').addClass('fa-toggle-off');
  }
}



//-------------------------------------------------------------------------
// State handling

function updateBluetoothState(newConnectedState) {
  connected=newConnectedState;
  updateBluetoothDisplay();
}

function updateLightState(newIsLightOnState) {
  if (newIsLightOnState) {
    isLightOn = true;
    send(LIGHT_ON);

  } else {
    isLightOn = false;
    send(LIGHT_OFF);
  }
  updateLightDisplay();
}
body {
  background-color: lightgrey;
  font-family: "Trebuchet MS", Helvetica, sans-serif;

}

.fa {
  text-shadow: 3px 3px 6px #888888;
}

.fa-bluetooth {
  color: blue;
  font-size: 64px;
}

.fa-lightbulb-o {
  color: lightgrey;
  font-size: 196px;
}

.fa-toggle {
  font-size: 48px;
  color: grey;
}


.lightBulbOff {
  color: grey;
}

.lightBulbOn {
  color: yellow;
}

.inner {
  width: 50%;
  margin: 0 auto;
}

.container {
  position: relative;
  width: 100%;
}

.inlineLeft,
.inlineRight {
  position: absolute;
  display: inline;
}

.inlineRight {
  right: 0;
}

button {
  border: none;
  padding: 20;
  background: none;
}

.console {
  width: 80%;
  height: 240px;
  border: 5px solid #cccccc;
  padding: 5px;
  font-family: "Lucida Console", Monaco, monospace;
  background-color: lightgrey;
  color: black;
  
}

.fixed-top-right {
  position: fixed;
  top: 1em;
  right: 1em;
}

.fixed-top-left {
  position: fixed;
  top: 1em;
  left: 1em;
}

#footer {
  position: fixed;
  bottom: 0;
  width: 100%;
}