var five = require('johnny-five');
var positions = {};
var servos = {};
var opts;

// Inicjalizacja modułu sterującego serwomotorami
function init(board, options, callback) {

  // Zapisanie opcji używanych w metodzie move()
  opts = options;

  // Inicjalizacja serwomotorów
  for (var servo in options.servos) {

    // Nadanie nazwy konfiguracji serwomotoru w celu ułatwienia dostępu
    var servoConfig = options.servos[servo];

    // Zapisanie bieżącej pozycji jako początkowej
    positions[servo] = servoConfig.startPosition;

    // Utworzenie instancji obiektu serwomotoru
    servos[servo] = new five.Servo({
      pin: servoConfig.pin,
      isInverted: servoConfig.isInverted
    });

    // Obrócenie serwomotoru do pozycji początkowej
    servos[servo].to(positions[servo]);
  }

  // Zwłoka, aby serwomotory przyjęły pozycje początkowe
  setTimeout(callback, 1000);
}

// Obracanie serwomotorami
function move(destinations, callback) {

  // Określenie największego kąta obrotu serwomotoru
  var largestChange = 0;
  for (var servo in destinations) {
    var delta = Math.abs(destinations[servo] - positions[servo]);
    if (delta > largestChange) {
      largestChange = delta;
    }
  }

  // Jeżeli nie trzeba obrócić żadnego serwomotoru, wykonywany jest poniższy kod
  if (largestChange === 0) {
    // Jednaj trzeba wywołać funkję zwrotną, ponieważ program musi działać asynchronicznie.
    // W tym celu wywoływana jest metoda process.nextTick.
    // Więcej informacji 
    
    // Jednak trzeba wywołać funkcję callback, ale musi ona zawsze być wykonywana asynchronicznie,
    // dlatego w tym przypadku wykorzystana jest metoda process.nextTick.
    // Więcej informacji o tym, że jest to dobry sposób, znajduje się pod adresem:
    // http://nodejs.org/api/process.html#process_process_nexttick_callback
    process.nextTick(callback);
    return;
  }

  // Wyliczenie czasu trwania obrotu na podstawie największego kąta. Oznacza to,
  // że tylko ten serwomotor będzie obracał się z maksymalną prędkością. 
  // Prędkości pozostałych serwomotorów będą mniejsze,
  // dzięki czemu wszystkie jednocześnie zajmą ostateczne pozycje.
  var duration = largestChange / opts.rate;

  // Ustawienie serwomotorów w zadanych położeniach
  for (servo in destinations) {
    positions[servo] = destinations[servo];
    servos[servo].to(destinations[servo], duration);
  }

  // Odczekanie na zakończenie ruchu i wywołanie funkcji callback
  setTimeout(callback, duration + opts.settleTime);
}

// Eksport metod, aby można było je wykorzystać w programie typebot.js
module.exports = {
  init: init,
  move: move
};
