var SunCalc = require("suncalc"); // from modules folder
require("f_latosmall").add(Graphics);
const storage = require('Storage');
const locale = require("locale");
const SETTINGS_FILE = "pastel.json";
const LOCATION_FILE = "mylocation.json";
const w = g.getWidth();
const h = g.getHeight();
let settings;
let location;

// variable for controlling idle alert
let lastStep = getTime();
let lastStepTime = '??';
let warned = 0;
let idle = false;
let IDLE_MINUTES = 26;

// cloud, sun, partSun, snow, rain, storm, error
// create 1 bit, max contrast, brightness set to 85
var cloudIcon = require("heatshrink").decompress(atob("kEggIfcj+AAYM/8ADBuFwAYPAmADCCAMBwEf8ADBhFwg4aBnEPAYMYjAVBhgDDDoQDHCYc4jwDB+EP///FYIDBMTgA=="));
var sunIcon = require("heatshrink").decompress(atob("kEggILIgOAAZkDAYPAgeBwPAgIFBBgPhw4TBp/yAYMcnADBnEcAYMwhgDBsEGgE/AYP8AYYLDCYgbDEYYrD8fHIwI7CIYZLDL54AHA=="));
var sunPartIcon = require("heatshrink").decompress(atob("kEggIHEmADJjEwsEAjkw8EAh0B4EAg35wEAgP+CYMDwv8AYMDBAP2g8HgH+g0DBYMMgPwAYX8gOMEwMG3kAg8OvgSBjg2BgcYGQIcBAY5CBg0Av//HAM///4MYgNBEIMOCoUMDoUAnBwGkEA"));
var snowIcon = require("heatshrink").decompress(atob("kEggITQj/AAYM98ADBsEwAYPAjADCj+AgOAj/gAYMIuEHwEAjEPAYQVChk4AYQhCAYcYBYQTDnEPgEB+EH///IAQACE4IAB8EICIPghwDB4EeBYNAjgDBg8EAYQYCg4bCgZuFA=="));
var rainIcon = require("heatshrink").decompress(atob("kEggIPMh+AAYM/8ADBuFwAYPgmADB4EbAYOAj/ggOAhnwg4aBnAeCjEcCIMMjADCDoQDHjAPCnAXCuEP///8EDAYJECAAXBwkAgPDhwDBwUMgEEhkggEOjFgFgMQLYQAOA=="));
var errIcon = require("heatshrink").decompress(atob("kEggILIgOAAYsD4ADBg/gAYMGsADBhkwAYsYjADCjgDBmEMAYNxxwDBsOGAYPBwYDEgOBwOAgYDB4EDHYPAgwDBsADDhgDBFIcwjAHBjE4AYMcmADBhhNCKIcG/4AGOw4A=="));

// saves having to recode all the small font calls
function setSmallFont() {
  g.setFontLatoSmall();
}

function loadSettings() {
  settings = require("Storage").readJSON(SETTINGS_FILE,1)||{};
  settings.grid = settings.grid||false;
  settings.font = settings.font||"Lato";
  settings.idle_check = (settings.idle_check === undefined ? true : settings.idle_check);
}

// requires the myLocation app
function loadLocation() {
  location = require("Storage").readJSON(LOCATION_FILE,1)||{};
  location.lat = location.lat||51.5072;
  location.lon = location.lon||0.1276;
  location.location = location.location||"London";
}

function extractTime(d){
  var h = d.getHours(), m = d.getMinutes();
  return(("0"+h).substr(-2) + ":" + ("0"+m).substr(-2));
}

var sunRise = "00:00";
var sunSet = "00:00";
var drawCount = 0;

function updateSunRiseSunSet(now, lat, lon, line){
  // get today's sunlight times for lat/lon
  var times = SunCalc.getTimes(new Date(), lat, lon);

  // format sunrise time from the Date object
  sunRise = extractTime(times.sunrise);
  sunSet = extractTime(times.sunset);
}

function loadFonts() {
  // load font files based on settings.font
  if (settings.font == "Architect")
    require("f_architect").add(Graphics);
  else if (settings.font == "GochiHand")
    require("f_gochihand").add(Graphics);
  else if (settings.font == "CabinSketch")
    require("f_cabin").add(Graphics);
  else if (settings.font == "Orbitron")
    require("f_orbitron").add(Graphics);
  else if (settings.font == "Monoton")
    require("f_monoton").add(Graphics);
  else if (settings.font == "Elite")
    require("f_elite").add(Graphics);
  else
    require("f_lato").add(Graphics);
}

function getSteps() {
  try {
    return Bangle.getHealthStatus("day").steps;
  } catch (e) {
    if (WIDGETS.wpedom !== undefined)
      return WIDGETS.wpedom.getSteps();
    else
      return '???';
  }
}

const infoData = {
  ID_BLANK: { calc: () => '' },
  ID_DATE:  { calc: () => {var d = (new Date()).toString().split(" "); return d[2] + ' ' + d[1] + ' ' + d[3];} },
  ID_DAY:   { calc: () => {var d = require("locale").dow(new Date()).toLowerCase(); return d[0].toUpperCase() + d.substring(1);} },
  ID_SR:    { calc: () => 'Sunrise: ' + sunRise },
  ID_SS:    { calc: () => 'Sunset: ' + sunSet },
  ID_STEP:  { calc: () => 'Steps: ' + getSteps() },
  ID_LAST:  { calc: () => 'Last Step: ' + lastStepTime },
  ID_BATT:  { calc: () => 'Battery: ' + E.getBattery() + '%' },
  ID_MEM:   { calc: () => {var val = process.memory(false); return 'Ram: ' + Math.round(val.usage*100/val.total) + '%';} },
  ID_ID:    { calc: () => {var val = NRF.getAddress().split(':'); return 'Id: ' + val[4] + val[5];} },
  ID_FW:    { calc: () => 'Fw: ' + process.env.VERSION }
};

const infoList = Object.keys(infoData).sort();
let infoMode = infoList[0];

function nextInfo() {
  let idx = infoList.indexOf(infoMode);
  if (idx > -1) {
    if (idx === infoList.length - 1) infoMode = infoList[0];
    else infoMode = infoList[idx + 1];
  }
}

function prevInfo() {
  let idx = infoList.indexOf(infoMode);
  if (idx > -1) {
    if (idx === 0) infoMode = infoList[infoList.length - 1];
    else infoMode = infoList[idx - 1];
  }
}


/**
Choose weather icon to display based on condition.
Based on function from the Bangle weather app so it should handle all of the conditions
sent from gadget bridge.
*/
function chooseIcon(condition) {
  condition = condition.toLowerCase();
  if (condition.includes("thunderstorm")) return stormIcon;
  if (condition.includes("freezing")||condition.includes("snow")||
    condition.includes("sleet")) {
    return snowIcon;
  }
  if (condition.includes("drizzle")||
    condition.includes("shower")) {
    return rainIcon;
  }
  if (condition.includes("rain")) return rainIcon;
  if (condition.includes("clear")) return sunIcon;
  if (condition.includes("few clouds")) return partSunIcon;
  if (condition.includes("scattered clouds")) return cloudIcon;
  if (condition.includes("clouds")) return cloudIcon;
  if (condition.includes("mist") ||
    condition.includes("smoke") ||
    condition.includes("haze") ||
    condition.includes("sand") ||
    condition.includes("dust") ||
    condition.includes("fog") ||
    condition.includes("ash") ||
    condition.includes("squalls") ||
    condition.includes("tornado")) {
    return cloudIcon;
  }
  return cloudIcon;
}

/**
Get weather stored in json file by weather app.
*/
function getWeather() {
  let jsonWeather = storage.readJSON('weather.json');
  return jsonWeather;
}

function draw() {
  if (!idle)
    drawClock();
  else
    drawIdle();
  queueDraw();
}

function drawClock() {
  var d = new Date();
  var da = d.toString().split(" ");
  var time = da[4].substr(0,5);

  var hh = da[4].substr(0,2);
  var mm = da[4].substr(3,2);
  var day = da[0];
  var month_day = da[1] + " " + da[2];

  // fix hh for 12hr clock
  var h2 = "0" + parseInt(hh) % 12 || 12;
  if (parseInt(hh) > 12)
    hh = h2.substr(h2.length -2);

  var x = (g.getWidth()/2);
  var y = (g.getHeight()/3);
  var weatherJson = getWeather();
  var w_temp;
  var w_icon;
  var w_wind;

  if (settings.weather && weatherJson && weatherJson.weather) {
      var currentWeather = weatherJson.weather;
      const temp = locale.temp(currentWeather.temp-273.15).match(/^(\D*\d*)(.*)$/);
      w_temp = temp[1] + " " + temp[2];
      w_icon = chooseIcon(currentWeather.txt);
      const wind = locale.speed(currentWeather.wind).match(/^(\D*\d*)(.*)$/);
      w_wind = wind[1] + " " + wind[2] + " " + (currentWeather.wrose||'').toUpperCase();
  } else {
      w_temp = "Err";
      w_wind = "???";
      w_icon = errIcon;
  }

  g.reset();
  g.setColor(g.theme.bg);
  g.fillRect(Bangle.appRect);

  // draw a grid like graph paper
  if (settings.grid && process.env.HWVERSION !=1) {
    g.setColor("#0f0");
    for (var gx=20; gx <= w; gx += 20)
      g.drawLine(gx, 30, gx, h - 24);
    for (var gy=30; gy <= h - 24; gy += 20)
      g.drawLine(0, gy, w, gy);
  }

  g.setColor(g.theme.fg);

  // draw weather line
  if (settings.weather) {
    g.drawImage(w_icon, (w/2) - 40, 24);
    g.setFontLatoSmall();
    g.setFontAlign(-1,0); // left aligned
    if (drawCount % 2 == 0)
      g.drawString(w_temp, (w/2) + 6, 24 + ((y - 24)/2));
    else
      g.drawString( (w_wind.split(' ').slice(0, 2).join(' ')), (w/2) + 6, 24 + ((y - 24)/2));
  // display first 2 words of the wind string eg '4 mph'
  }

  if (settings.font == "Architect")
    g.setFontArchitect();
  else if (settings.font == "GochiHand")
    g.setFontGochiHand();
  else if (settings.font == "CabinSketch")
    g.setFontCabinSketch();
  else if (settings.font == "Orbitron")
    g.setFontOrbitron();
  else if (settings.font == "Monoton")
    g.setFontMonoton();
  else if (settings.font == "Elite")
    g.setFontSpecialElite();
  else
    g.setFontLato();

  g.setFontAlign(1,-1);  // right aligned
  g.drawString(hh, x - 6, y);
  g.setFontAlign(-1,-1); // left aligned
  g.drawString(mm, x + 6, y);

  // for the colon
  g.setFontAlign(0,-1); // centre aligned
  g.drawString(":", x,y);
  g.setFontLatoSmall();
  g.setFontAlign(0, -1);
  g.drawString((infoData[infoMode].calc()), w/2, h - 24 - 24);

  // recalc sunrise / sunset every hour
  if (drawCount % 60 == 0)
    updateSunRiseSunSet(new Date(), location.lat, location.lon);
  drawCount++;
  queueDraw();
}


/////////////////   IDLE TIMER /////////////////////////////////////

function log_debug(o) {
  //print(o);
}

function drawIdle() {
  let mins = Math.round((getTime() - lastStep) / 60);
  g.reset();
  g.setColor(g.theme.bg);
  g.fillRect(Bangle.appRect);
  g.setColor(g.theme.fg);
  setSmallFont();
  g.setFontAlign(0, 0);
  g.drawString('Last step was', w/2, (h/3));
  g.drawString(mins + ' minutes ago', w/2, 20+(h/3));
  dismissBtn.draw();
}

///////////////   BUTTON CLASS ///////////////////////////////////////////

// simple on screen button class
function BUTTON(name,x,y,w,h,c,f,tx) {
  this.name = name;
  this.x = x;
  this.y = y;
  this.w = w;
  this.h = h;
  this.color = c;
  this.callback = f;
  this.text = tx;
}

// if pressed the callback
BUTTON.prototype.check = function(x,y) {
  //console.log(this.name + ":check() x=" + x + " y=" + y +"\n");

  if (x>= this.x && x<= (this.x + this.w) && y>= this.y && y<= (this.y + this.h)) {
    log_debug(this.name + ":callback\n");
    this.callback();
    return true;
  }
  return false;
};

BUTTON.prototype.draw = function() {
  g.setColor(this.color);
  g.fillRect(this.x, this.y, this.x + this.w, this.y + this.h);
  g.setColor("#000"); // the icons and boxes are drawn black
  setSmallFont();
  g.setFontAlign(0, 0);
  g.drawString(this.text, (this.x + this.w/2), (this.y + this.h/2));
  g.drawRect(this.x, this.y, (this.x + this.w), (this.y + this.h));
};

function dismissPrompt() {
  idle = false;
  warned = false;
  lastStep = getTime();
  Bangle.buzz(100);
  draw();
}

var dismissBtn = new BUTTON("big",0, 3*h/4 ,w, h/4, "#0ff", dismissPrompt, "Dismiss");

Bangle.on('touch', function(button, xy) {
  if (idle && dismissBtn.check(xy.x, xy.y)) return;
});

// if we get a step then we are not idle
Bangle.on('step', s => {
  setLastStepTime();
  lastStep = getTime();
  // redraw if we had been idle
  if (idle == true) {
    dismissPrompt();
  }
  idle = false;
  warned = 0;
});

function setLastStepTime() {
  var date = new Date();
  lastStepTime = require("locale").time(date,1);
}

function checkIdle() {
  if (!settings.idle_check) {
    idle = false;
    warned = false;
    return;
  }

  let hour = (new Date()).getHours();
  let active = (hour >= 9 && hour < 21);
  //let active = true;
  let dur = getTime() - lastStep;

  if (active && dur > IDLE_MINUTES * 60) {
    drawIdle();
    if (warned++ < 3) {
      buzzer(warned);
      log_debug("checkIdle: warned=" + warned);
      Bangle.setLocked(false);
    }
    idle = true;
  } else {
    idle = false;
    warned = 0;
  }
}

setLastStepTime();

// timeout for multi-buzzer
var buzzTimeout;

// n buzzes
function buzzer(n) {
  log_debug("buzzer n=" + n);

  if (n-- < 1) return;
  Bangle.buzz(250);

  if (buzzTimeout) clearTimeout(buzzTimeout);
  buzzTimeout = setTimeout(function() {
    buzzTimeout = undefined;
    buzzer(n);
  }, 500);
}


///////////////////////////////////////////////////////////////////////////////

// timeout used to update every minute
var drawTimeout;

// schedule a draw for the next minute
function queueDraw() {
  if (drawTimeout) clearTimeout(drawTimeout);
  drawTimeout = setTimeout(function() {
    drawTimeout = undefined;
    prevInfo();
    checkIdle();
    draw();
  }, 60000 - (Date.now() % 60000));
}

// Stop updates when LCD is off, restart when on
Bangle.on('lcdPower',on=>{
  if (on) {
    draw(); // draw immediately, queue redraw
  } else { // stop draw timer
    if (drawTimeout) clearTimeout(drawTimeout);
    drawTimeout = undefined;
  }
});

Bangle.setUI("clockupdown", btn=> {
  if (btn<0) prevInfo();
  if (btn>0) nextInfo();
  draw();
});

loadSettings();
loadFonts();
loadLocation();

g.clear();
Bangle.loadWidgets();
Bangle.drawWidgets();
draw();
