{
  const locale = require("locale");
  let heartRate = 0;
  let altitude = -9001;

  const fontColor = g.theme.dark ? "#0f0" : "#000";
  // handling the differents versions of the Banglejs smartwatch screen sizes
  // default BJS2
  let paddingY = 2;
  let font6x8At4Size = 32;
  let font6x8At2Size = 18;
  let font6x8FirstTextSize = 4;
  let font6x8DefaultTextSize = 2;
  if (process.env.HWVERSION == 1){
    paddingY = 3;
    font6x8At4Size = 48;
    font6x8At2Size = 27;
    font6x8FirstTextSize = 6;
    font6x8DefaultTextSize = 3;
  }
  // initialising the clockface
  const ClockFace = require("ClockFace");
  const clock = new ClockFace({
    precision: 60,
    settingsFile: "terminalclock.json",

    init: function () {
      // check settings and set default if needed
      this.showHRM = false;
      this.showAltitude = false;
      this.lock_precision = this.precision;
      this.unlock_precision = 1;
      if (this.HRMinConfidence === undefined) this.HRMinConfidence = 50;
      if (this.PowerOnInterval === undefined) this.PowerOnInterval = 15;
      if (this.powerSave===undefined) this.powerSave = this.powerSaving; // migrate old setting
      if (this.powerSave===undefined) this.powerSave = true;

      ["L2", "L3", "L4", "L5", "L6", "L7", "L8", "L9"].forEach(k => {
        if (this[k]===undefined){
          if(k == "L2") this[k] = "Date";
          else if(k == "L3") {
            this[k] = "HR";
            this.showHRM = true;
          }else if(k == "L4") this[k] = "Motion";
          else if(k == "L5") this[k] = "Steps";
          else if(k == "L6") this[k] = ">";
          else this[k] = "Empty"; 
        } 
        else if (this[k]==="HR") this.showHRM = true;
        else if (this[k]==="Alt") this.showAltitude = true && process.env.HWVERSION == 2;
      });

      // set the services (HRM, pressure sensor, etc....)
      if(!this.powerSave){
        turnOnServices();
      } else{
        this.turnOnInterval = setInterval(turnOnServices, this.PowerOnInterval*60000); // every PowerOnInterval min
      }
      // start the clock unlocked
      unlock();
    },

    draw: function (date) {
      let curPos = 1;
      g.setFontAlign(-1, -1);
      g.setColor(fontColor);
      drawTime(date, curPos);
      curPos++;

      ["L2", "L3", "L4", "L5", "L6", "L7", "L8", "L9"].forEach(line => {
        if (this[line]==='Date') drawDate(date, curPos);
        else if (this[line]==='HR') drawHRM(curPos);
        else if (this[line]==='Motion') drawMotion(curPos);
        else if (this[line]==='Alt') drawAltitude(curPos);
        else if (this[line]==='Steps') drawStepCount(curPos);
        else if (this[line]==='>') drawInput(curPos);
        curPos++;
      });
    },

    remove: function() {
      if (this.turnOnInterval){
        clearInterval(this.turnOnInterval);
        delete this.turnOnInterval;
      }
      if (this.turnOffServiceTimeout){
        clearTimeout(this.turnOffServiceTimeout)
        delete this.turnOffServiceTimeout
      }
      turnOffServices();
      if (this.onLock) Bangle.removeListener('lock', this.onLock);
      if (this.onHRM) Bangle.removeListener('HRM', this.onHRM);
      if (this.onPressure) Bangle.removeListener('pressure', this.onPressure);
    }

  });


  /* ---------------------------- 
  Draw related of specific lines
  -------------------------------- */

  let drawLine = function(line, pos){
    if(pos == 1)
      g.setFont("6x8", font6x8FirstTextSize);
    else
      g.setFont("6x8", font6x8DefaultTextSize);

    let yPos = Bangle.appRect.y +
        paddingY * (pos - 1) +
        font6x8At4Size * Math.min(1, pos-1) +
        font6x8At2Size * Math.max(0, pos-2);
    g.drawString(line, 5, yPos, true);
  };

  let drawTime = function(now, pos){
    let h = now.getHours();
    let m = now.getMinutes();
    let time = ">" + (""+h).substr(-2) + ":" + ("0"+m).substr(-2);
    drawLine(time, pos);
  };

  let drawDate = function(now, pos){
    let dow = locale.dow(now, 1);
    let date = locale.date(now, 1).substr(0,6) + locale.date(now, 1).substr(-2);
    let locale_date = ">" + dow + " " + date;
    drawLine(locale_date, pos);
  };

  let drawInput = function(pos){
    drawLine(">", pos);
  };

  let drawStepCount = function(pos){
    let health = Bangle.getHealthStatus("day");
    let steps_formated = ">Steps: " + health.steps;
    drawLine(steps_formated, pos);
  };

  let drawHRM = function(pos){
    if(heartRate != 0)
      drawLine(">HR: " + parseInt(heartRate), pos);
    else
      drawLine(
        ">HR: " + parseInt(Math.round(Bangle.getHealthStatus().bpm||Bangle.getHealthStatus("last").bpm)), 
        pos);
  };

  let drawAltitude = function(pos){
    if(altitude > 0)
      drawLine(">Alt: " + altitude.toFixed(1) + "m", pos);
    else
      drawLine(">Alt: unknown", pos);
  };
  
  let drawMotion = function(pos){
    let health = Bangle.getHealthStatus('last');
    let steps_formated = ">Motion: " + parseInt(health.movement);
    drawLine(steps_formated, pos);
  };

  /* -----------------------------------------------
  Services functions (HRM, pressure, etc...)
  -------------------------------------------------- */

  let turnOnServices = function(){
    if(clock.showHRM){
      Bangle.setHRMPower(true, "terminalclock");
    }
    if(clock.showAltitude){
      Bangle.setBarometerPower(true, "terminalclock");
    }
    if(clock.powerSave){
      if(clock.turnOffServiceTimeout) clearTimeout(clock.turnOffServiceTimeout);
      clock.turnOffServiceTimeout = setTimeout(function () {
        turnOffServices();
      }, 45000);
    }
  };

  let turnOffServices = function(){
    if(clock.showHRM){
      Bangle.setHRMPower(false, "terminalclock");
    }
    if(clock.showAltitude){
      Bangle.setBarometerPower(false, "terminalclock");
    }
  };

  // set the lock and unlock actions
  clock.onLock = lock_event => {
    if (lock_event) lock();
    else unlock();
  };
  Bangle.on("lock", clock.onLock);

  clock.onHRM = hrmInfo => {
    if(hrmInfo.confidence >= clock.HRMinConfidence)
      heartRate = hrmInfo.bpm;
  };
  Bangle.on('HRM', clock.onHRM);

  const MEDIANLENGTH = 20; // technical
  let avr = [], median; // technical
  clock.onPressure = pressureInfo => {
    while (avr.length>MEDIANLENGTH) avr.pop();
    avr.unshift(pressureInfo.altitude);
    median = avr.slice().sort();
    if (median.length>10) {
      let mid = median.length>>1;
      altitude = E.sum(median.slice(mid-4,mid+5)) / 9;
    }
    else
      altitude = pressureInfo.altitude; 
  };
  Bangle.on('pressure', clock.onPressure);


  /* -------------------------------------------------
  Clock related functions but not in the ClockFace module
  ---------------------------------------------------- */

  let unlock = function(){
    if(clock.powerSave){
      turnOnServices();
    }
    clock.precision = clock.unlock_precision;
    clock.tick();
  };

  let lock = function(){
    clock.precision = clock.lock_precision;
    clock.tick();
  };

  // starting the clock
  clock.start();
}