// Clock with large digits using the "Anton" bold font
Graphics.prototype.setFontAnton = function(scale) {
  // Actual height 69 (68 - 0)
  g.setFontCustom(atob("[encoded data, 5800 characters]"), 46, atob("EiAnGicnJycnJycnEw=="), 78 + (scale << 8) + (1 << 16));
};

Graphics.prototype.setFontAntonSmall = function(scale) {
  // Actual height 53 (52 - 0)
  g.setFontCustom(atob("AAAAAAAAAAAAAAAAAAAAAAAAAAf8AAAAAAAAf8AAAAAAAAf8AAAAAAAAf8AAAAAAAAf8AAAAAAAAf8AAAAAAAAf8AAAAAAAAf8AAAAAAAAf8AAAAAAAAf8AAAAAAAAf8AAAAAAAAAAAAAAAAAAAAMAAAAAAAAD8AAAAAAAA/8AAAAAAAf/8AAAAAAH//8AAAAAB///8AAAAA////8AAAAP////8AAAD/////8AAB//////8AAf//////8AH///////4A///////+AA///////AAA//////wAAA/////8AAAA////+AAAAA////gAAAAA///4AAAAAA//8AAAAAAA//AAAAAAAA/wAAAAAAAA4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH/////wAAA//////8AAB//////+AAH///////gAH///////gAP///////wAf///////4Af///////4A////////8A////////8A////////8A//AAAAD/8A/8AAAAA/8A/8AAAAA/8A/8AAAAA/8A/+AAAAB/8A////////8A////////8A////////8Af///////4Af///////4AP///////wAP///////wAH///////gAD///////AAA//////8AAAP/////wAAAAAAAAAAAAAAAAAAAAAAAfwAAAAAAAA/4AAAAAAAA/4AAAAAAAB/wAAAAAAAB/wAAAAAAAD/wAAAAAAAD/gAAAAAAAH///////8AP///////8A////////8A////////8A////////8A////////8A////////8A////////8A////////8A////////8A////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH/4AAAP8AA//4AAA/8AB//4AAH/8AH//4AAP/8AP//4AA//8AP//4AB//8Af//4AD//8Af//4AP//8A///4Af//8A///4A///8A///4D///8A//AAH///8A/8AAP///8A/8AA//+/8A/8AD//8/8A/+Af//w/8A//////g/8A/////+A/8A/////8A/8Af////4A/8Af////wA/8AP////AA/8AP///+AA/8AH///8AA/8AD///wAA/8AA///AAA/8AAP/4AAA/8AAAAAAAAAAAAAAAAAAAAAAH4AAf/gAAA/4AAf/8AAD/4AAf//AAH/4AAf//gAP/4AAf//wAP/4AAf//wAf/4AAf//4Af/4AAf//4A//4AAf//8A//4AAf//8A//4AAP//8A//A/8AB/8A/8A/8AA/8A/8B/8AA/8A/8B/8AA/8A/+D//AB/8A////////8A////////8A////////8Af///////4Af///////4Af///////wAP///////gAH//9////gAD//4///+AAB//wf//4AAAP/AH//gAAAAAAAAAAAAAAAAAAAAAAAAAAAH/wAAAAAAB//wAAAAAAP//wAAAAAD///wAAAAA////wAAAAH////wAAAB/////wAAAf/////wAAD//////wAA///////wAA/////h/wAA////wB/wAA///8AB/wAA///AAB/wAA//gAAB/wAA////////8A////////8A////////8A////////8A////////8A////////8A////////8A////////8A////////8A////////8A////////8AAAAAAB/wAAAAAAAB/wAAAAAAAB/wAAAAAAAAAAAAAAAAAAAAAAAAAAAP/4AA////4P/+AA////4P//AA////4P//gA////4P//wA////4P//wA////4P//4A////4P//4A////4P//8A////4P//8A////4P//8A/8H/AAB/8A/8H+AAA/8A/8P+AAA/8A/8P+AAA/8A/8P/gAD/8A/8P/////8A/8P/////8A/8P/////8A/8P/////4A/8H/////4A/8H/////wA/8D/////wA/8B/////gA/8A////+AA/8AP///4AAAAAB///AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/////wAAAf/////8AAB///////AAH///////gAP///////wAP///////wAf///////4Af///////4A////////8A////////8A////////8A/+AH/AB/8A/8AP+AA/8A/4Af+AA/8A/8Af+AA/8A/8Af/gH/8A//4f////8A//4f////8A//4f////8Af/4f////4Af/4f////4AP/4P////wAP/4P////gAH/4H////AAD/4D///+AAB/4B///4AAAP4AP//gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/8AAAAAAAA/8AAAAAAAA/8AAAAAB8A/8AAAAB/8A/8AAAAf/8A/8AAAH//8A/8AAA///8A/8AAH///8A/8AA////8A/8AD////8A/8Af////8A/8B/////8A/8P/////8A/8//////8A////////AA///////AAA//////gAAA/////4AAAA/////AAAAA////4AAAAA////AAAAAA///8AAAAAA///gAAAAAA//+AAAAAAA//wAAAAAAA/+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH/gD//gAAA//4P//8AAD//8f///AAH//+////gAH///////wAP///////4AP///////8Af///////8Af///////+Af///////+A////////+A//B//AB/+A/+A/+AA/+A/8Af+AA/+A/+Af+AA/+A//A//AB/+A////////+Af///////+Af///////+Af///////8Af///////8AP///////4AH///////4AH//+////wAD//+////AAA//4P//+AAAP/gH//wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH//gAfgAAA///8A/8AAB///+A//AAH////A//gAH////g//wAP////g//wAf////w//4Af////w//4A/////w//8A/////w//8A/////w//8A//gP/wA/8A/8AD/wA/8A/8AD/wAf8A/8AD/gA/8A/+AH/AB/8A////////8A////////8A////////8Af///////4Af///////4Af///////wAP///////wAH///////gAD//////+AAA//////4AAAP/////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP+AA/4AAAAP+AA/4AAAAP+AA/4AAAAP+AA/4AAAAP+AA/4AAAAP+AA/4AAAAP+AA/4AAAAP+AA/4AAAAP+AA/4AAAAP+AA/4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="), 46, atob("DhgeFB4eHh4eHh4eDw=="), 60 + (scale << 8) + (1 << 16));
};

{ // must be inside our own scope here so that when we are unloaded everything disappears
  // we also define functions using 'let fn = function() {..}' for the same reason. function decls are global

const SETTINGSFILE = "antonclk.json";
const isBangle1 = (process.env.HWVERSION == 1);

// variables defined from settings
let secondsMode;
let secondsColoured;
let secondsWithColon;
let dateOnMain;
let dateOnSecs;
let weekDay;
let calWeek;
let upperCase;
let vectorFont;

// dynamic variables
let drawTimeout;
let queueMillis = 1000;
let secondsScreen = true;



//For development purposes
/*
require('Storage').writeJSON(SETTINGSFILE, {
  secondsMode: "Unlocked", // "Never", "Unlocked", "Always"
  secondsColoured: true,
  secondsWithColon: true,
  dateOnMain: "Long", // "Short", "Long", "ISO8601"
  dateOnSecs: "Year", // "No", "Year", "Weekday", LEGACY: true/false
  weekDay: true,
  calWeek: true,
  upperCase: true,
  vectorFont: true,
});
*/

// OR (also for development purposes)
/*
require('Storage').erase(SETTINGSFILE);
*/

// Load settings
let loadSettings = function() {
  // Helper function default setting
  function def (value, def) {return value !== undefined ? value : def;}

  var settings = require('Storage').readJSON(SETTINGSFILE, true) || {};
  secondsMode = def(settings.secondsMode, "Never");
  secondsColoured = def(settings.secondsColoured, true);
  secondsWithColon = def(settings.secondsWithColon, true);
  dateOnMain = def(settings.dateOnMain, "Long");
  dateOnSecs = def(settings.dateOnSecs, "Year");
  weekDay = def(settings.weekDay, true);
  calWeek = def(settings.calWeek, false);
  upperCase = def(settings.upperCase, true);
  vectorFont = def(settings.vectorFont, false);

  // Legacy
  if (dateOnSecs === true)
    dateOnSecs = "Year";
  if (dateOnSecs === false)
    dateOnSecs = "No";
}

// schedule a draw for the next second or minute
let queueDraw = function() {
  if (drawTimeout) clearTimeout(drawTimeout);
  drawTimeout = setTimeout(function() {
    drawTimeout = undefined;
    draw();
  }, queueMillis - (Date.now() % queueMillis));
}

let updateState = function() {
  if (Bangle.isLCDOn()) {
    if ((secondsMode === "Unlocked" && !Bangle.isLocked()) || secondsMode === "Always") {
      secondsScreen = true;
      queueMillis = 1000;
    } else {
      secondsScreen = false;
      queueMillis = 60000;
    }
    draw(); // draw immediately, queue redraw
  } else { // stop draw timer
    if (drawTimeout) clearTimeout(drawTimeout);
    drawTimeout = undefined;
  }
}

let isoStr = function(date) {
  return date.getFullYear() + "-" + ("0" + (date.getMonth() + 1)).slice(-2) + "-" + ("0" + date.getDate()).slice(-2);
}

let calWeekBuffer = [false,false,false]; //buffer tz, date, week no (once calculated until other tz or date is requested)
let ISO8601calWeek = function(date) { //copied from: https://gist.github.com/IamSilviu/5899269#gistcomment-3035480
  dateNoTime = date; dateNoTime.setHours(0,0,0,0);
  if (calWeekBuffer[0] === date.getTimezoneOffset() && calWeekBuffer[1] === dateNoTime) return calWeekBuffer[2];
  calWeekBuffer[0] = date.getTimezoneOffset();
  calWeekBuffer[1] = dateNoTime;
  var tdt = new Date(date.valueOf());
  var dayn = (date.getDay() + 6) % 7;
  tdt.setDate(tdt.getDate() - dayn + 3);
  var firstThursday = tdt.valueOf();
  tdt.setMonth(0, 1);
  if (tdt.getDay() !== 4) {
      tdt.setMonth(0, 1 + ((4 - tdt.getDay()) + 7) % 7);
  }
  calWeekBuffer[2] = 1 + Math.ceil((firstThursday - tdt) / 604800000);
  return calWeekBuffer[2];
}

let doColor = function() {
  return !isBangle1 && !Bangle.isLocked() && secondsColoured;
}

// Actually draw the watch face
let draw = function() {
  var x = g.getWidth() / 2;
  var y = g.getHeight() / 2 - (secondsMode !== "Never" ? 24 : (vectorFont ? 12 : 0));
  g.reset();
  /* This is to mark the widget areas during development.
  g.setColor("#888")
    .fillRect(0, 0, g.getWidth(), 23)
    .fillRect(0, g.getHeight() - 23, g.getWidth(), g.getHeight()).reset();
  /* */
  g.clearRect(0, 24, g.getWidth(), g.getHeight() - 24); // clear whole background (w/o widgets)
  var date = new Date(); // Actually the current date, this one is shown
  var timeStr = require("locale").time(date, 1); // Hour and minute
  g.setFontAlign(0, 0).setFont("Anton").drawString(timeStr, x, y); // draw time
  if (secondsScreen) {
    y += 65;
    var secStr = (secondsWithColon ? ":" : "") + ("0" + date.getSeconds()).slice(-2);
    if (doColor())
      g.setColor(0, 0, 1);
    g.setFont("AntonSmall");
    if (dateOnSecs !== "No") { // A bit of a complex drawing with seconds on the right and date on the left
      g.setFontAlign(1, 0).drawString(secStr, g.getWidth() - (isBangle1 ? 32 : 2), y); // seconds
      y -= (vectorFont ? 15 : 13);
      x = g.getWidth() / 4 + (isBangle1 ? 12 : 4) + (secondsWithColon ? 0 : g.stringWidth(":") / 2);
      var dateStr2 = (dateOnMain === "ISO8601" ? isoStr(date) : require("locale").date(date, 1));
      var year;
      var md;
      var yearfirst;
      if (dateStr2.match(/\d\d\d\d$/)) { // formatted date ends with year
        year = (dateOnSecs === "Year" ? dateStr2.slice(-4) : require("locale").dow(date, 1));
        md = dateStr2.slice(0, -4);
        if (!md.endsWith(".")) // keep separator before the year only if it is a dot (31.12. but 31/12)
          md = md.slice(0, -1);
        yearfirst = false;
      } else { // formatted date begins with year
        if (!dateStr2.match(/^\d\d\d\d/)) // if year position cannot be detected...
          dateStr2 = isoStr(date); // ...use ISO date format instead
        year = (dateOnSecs === "Year" ? dateStr2.slice(0, 4) : require("locale").dow(date, 1));
        md = dateStr2.slice(5); // never keep separator directly after year
        yearfirst = true;
      }
      if (dateOnSecs === "Weekday" && upperCase)
        year = year.toUpperCase();
      g.setFontAlign(0, 0);
      if (vectorFont)
        g.setFont("Vector", 24);
      else
        g.setFont("6x8", 2);
      if (doColor())
        g.setColor(1, 0, 0);
      g.drawString(md, x, (yearfirst ? y + (vectorFont ? 26 : 16) : y));
      g.drawString(year, x, (yearfirst ? y : y + (vectorFont ? 26 : 16)));
    } else {
      g.setFontAlign(0, 0).drawString(secStr, x, y); // Just the seconds centered
    }
  } else { // No seconds screen: Show date and optionally day of week
    y += (vectorFont ? 50 : (secondsMode !== "Never") ? 52 : 40);
    var dateStr = (dateOnMain === "ISO8601" ? isoStr(date) : require("locale").date(date, (dateOnMain === "Long" ? 0 : 1)));
    if (upperCase)
      dateStr = dateStr.toUpperCase();
    g.setFontAlign(0, 0);
    if (vectorFont)
      g.setFont("Vector", 24);
    else
      g.setFont("6x8", 2);
    g.drawString(dateStr, x, y);
    if (calWeek || weekDay) {
      var dowcwStr = "";
      if (calWeek)
        dowcwStr = " #" + ("0" + ISO8601calWeek(date)).slice(-2);
      if (weekDay)
        dowcwStr = require("locale").dow(date, calWeek ? 1 : 0) + dowcwStr;  //weekDay e.g. Monday or weekDayShort #<calWeek> e.g. Mon #01
      else //week #01
        dowcwStr = /*LANG*/"week" + dowcwStr;
      if (upperCase)
      dowcwStr = dowcwStr.toUpperCase();
      g.drawString(dowcwStr, x, y + (vectorFont ? 26 : 16));
    }
  }

  // queue next draw
  queueDraw();
}

// Init the settings of the app
loadSettings();
// Clear the screen once, at startup
g.clear();
// Set dynamic state and perform initial drawing
updateState();
// Register hooks for LCD on/off event and screen lock on/off event
Bangle.on('lcdPower', updateState);
Bangle.on('lock', updateState);
// Show launcher when middle button pressed
Bangle.setUI({
  mode : "clock",
  remove : function() {
    // Called to unload all of the clock app
    Bangle.removeListener('lcdPower', updateState);
    Bangle.removeListener('lock', updateState);
    if (drawTimeout) clearTimeout(drawTimeout);
    drawTimeout = undefined;
    delete Graphics.prototype.setFontAnton;
    delete Graphics.prototype.setFontAntonSmall;
  }});
// Load widgets
Bangle.loadWidgets();
Bangle.drawWidgets();
}
