/* MESSAGES is a list of:
  {id:int,
    src,
    title,
    subject,
    body,
    sender,
    tel:string,
    new:true // not read yet
  }
*/

const ovrx = 10;
const ovry = 10;
const ovrw = g.getWidth()-2*ovrx;
const ovrh = g.getHeight()-2*ovry;
let _g = g;

let lockListener;
let quiet;

let LOG = function() {
  //print.apply(null, arguments);
};

let isQuiet = function(){
  if (quiet == undefined) quiet = (require('Storage').readJSON('setting.json', 1) || {}).quiet;
  return quiet;
};

let settings = {
  fontSmall:"6x8",
  fontMedium:"Vector:14",
  fontBig:"Vector:20",
  fontLarge:"Vector:30",
};

let eventQueue = [];
let callInProgress = false;

let show = function(ovr){
  let img = ovr;
  if (ovr.getBPP() == 1) {
    img = ovr.asImage();
    img.palette = new Uint16Array([_g.theme.fg,_g.theme.bg]);
  }
  Bangle.setLCDOverlay(img, ovrx, ovry);
};

let manageEvent = function(ovr, event) {
  event.new = true;

  LOG("manageEvent");
  if (event.id == "call") {
    showCall(ovr, event);
    return;
  }
  switch (event.t) {
    case "add":
      eventQueue.unshift(event);

      if (!callInProgress)
        showMessage(ovr, event);
      break;

    case "modify":
      let find = false;
      eventQueue.forEach(element => {
        if (element.id == event.id) {
          find = true;
          Object.assign(element, event);
        }
      });
      if (!find)
        eventQueue.unshift(event);

      if (!callInProgress)
        showMessage(ovr, event);
      break;

    case "remove":
      if (eventQueue.length == 0 && !callInProgress)
        next(ovr);

      if (!callInProgress && eventQueue[0] !== undefined && eventQueue[0].id == event.id)
        next(ovr);

      else {
        eventQueue.length = 0; // empty existing queue
        eventQueue.forEach(element => {
          if (element.id != event.id)
            neweventQueue.push(element);
        });
      }

      break;
    case "musicstate":
    case "musicinfo":

      break;
  }
};

let roundedRect = function(ovr, x,y,w,h,filled){
  var poly = [
    x,y+4,
    x+4,y,
    x+w-5,y,
    x+w-1,y+4,
    x+w-1,y+h-5,
    x+w-5,y+h-1,
    x+4,y+h-1,
    x,y+h-5,
    x,y+4
  ];
  ovr.drawPoly(poly,true);
  if (filled) ovr.fillPoly(poly,true);
};

let drawScreen = function(ovr, title, titleFont, src, iconcolor, icon){
  ovr.setBgColor(ovr.theme.bg2);
  ovr.clearRect(2,2,ovr.getWidth()-3,37);

  ovr.setColor(ovr.theme.fg2);
  ovr.setFont(settings.fontSmall);
  ovr.setFontAlign(0,-1);

  let textCenter = (ovr.getWidth()+35-26)/2;

  if (src) {
    let shortened = src;
    while (ovr.stringWidth(shortened) > ovr.getWidth()-80) shortened = shortened.substring(0,shortened.length-2);
    if (shortened.length != src.length) shortened += "...";
    ovr.drawString(shortened, textCenter, 2);
  }

  ovr.setFontAlign(0,0);
  ovr.setFont(titleFont);
  if (title) ovr.drawString(title, textCenter, 38/2 + 5);

  ovr.setColor(ovr.theme.fg2);

  ovr.setFont(settings.fontMedium);
  roundedRect(ovr, ovr.getWidth()-26,5,22,30,false);
  ovr.setFont("Vector:16");
  ovr.drawString("X",ovr.getWidth()-14,21);

  ovr.setColor("#888");
  roundedRect(ovr, 5,5,30,30,true);
  ovr.setColor(ovr.getBPP() != 1 ? iconcolor : ovr.theme.bg2);
  ovr.drawImage(icon,8,8);
};

let showMessage = function(ovr, msg) {
  LOG("showMessage");
  ovr.setBgColor(ovr.theme.bg);

  if (typeof msg.CanscrollDown === "undefined")
    msg.CanscrollDown = false;
  if (typeof msg.CanscrollUp === "undefined")
    msg.CanscrollUp = false;

  // Normal text message display
  let title = msg.title,
    titleFont = settings.fontLarge,
    lines;
  if (title) {
    let w = ovr.getWidth() - 35 - 26;
    if (ovr.setFont(titleFont).stringWidth(title) > w)
      titleFont = settings.fontMedium;
    if (ovr.setFont(titleFont).stringWidth(title) > w) {
      lines = ovr.wrapString(title, w);
      title = (lines.length > 2) ? lines.slice(0, 2).join("\n") + "..." : lines.join("\n");
    }
  }

  drawScreen(ovr, title, titleFont, msg.src || /*LANG*/ "Message", require("messageicons").getColor(msg), require("messageicons").getImage(msg));

  if (!isQuiet() && msg.new) {
    msg.new = false;
    Bangle.buzz();
  }

  drawMessage(ovr, msg);
};

let drawBorder = function(ovr) {
  if (Bangle.isLocked())
    ovr.setColor(ovr.theme.fgH);
  else
    ovr.setColor(ovr.theme.fg);
  ovr.drawRect(0,0,ovr.getWidth()-1,ovr.getHeight()-1);
  ovr.drawRect(1,1,ovr.getWidth()-2,ovr.getHeight()-2);
  show(ovr);
  if (!isQuiet()) Bangle.setLCDPower(1);
};

let showCall = function(ovr, msg) {
  LOG("showCall");
  LOG(msg);

  if (msg.t == "remove") {
    LOG("hide call screen");
    next(ovr); //dont shift
    return;
  }

  callInProgress = true;

  let title = msg.title,
    titleFont = settings.fontLarge,
    lines;
  if (title) {
    let w = ovr.getWidth() - 35 -26;
    if (ovr.setFont(titleFont).stringWidth(title) > w)
      titleFont = settings.fontMedium;
    if (ovr.setFont(titleFont).stringWidth(title) > w) {
      lines = ovr.wrapString(title, w);
      title = (lines.length > 2) ? lines.slice(0, 2).join("\n") + "..." : lines.join("\n");
    }
  }

  drawScreen(ovr, title, titleFont, msg.src || /*LANG*/ "Message", require("messageicons").getColor(msg), require("messageicons").getImage(msg));

  stopCallBuzz();
  if (!isQuiet()) {
    if (msg.new) {
      msg.new = false;
      if (callBuzzTimer) clearInterval(callBuzzTimer);
      callBuzzTimer = setInterval(function() {
        Bangle.buzz(500);
      }, 1000);

      Bangle.buzz(500);
    }
  }
  drawMessage(ovr, msg);
};

let next = function(ovr) {
  LOG("next");
  stopCallBuzz();

  if (!callInProgress)
    eventQueue.shift();

  callInProgress = false;
  if (eventQueue.length == 0) {
    LOG("no element in queue - closing");
    cleanup();
    return;
  }

  showMessage(ovr, eventQueue[0]);
};

let showMapMessage = function(ovr, msg) {
  ovr.clearRect(2,2,ovr.getWidth()-3,ovr.getHeight()-3);
  drawMessage(ovr, {
    body: "Not implemented!"
  });
};

let callBuzzTimer = null;
let stopCallBuzz = function() {
  if (callBuzzTimer) {
    clearInterval(callBuzzTimer);
    callBuzzTimer = undefined;
  }
};

let drawTriangleUp = function(ovr) {
  ovr.reset();
  ovr.fillPoly([ovr.getWidth()-9, 46,ovr.getWidth()-14, 56,ovr.getWidth()-4, 56]);
};

let drawTriangleDown = function(ovr) {
  ovr.reset();
  ovr.fillPoly([ovr.getWidth()-9, ovr.getHeight()-6, ovr.getWidth()-14, ovr.getHeight()-16, ovr.getWidth()-4, ovr.getHeight()-16]);
};

let linesScroll = 6;

let scrollUp = function(ovr) {
  msg = eventQueue[0];
  LOG("up", msg);
  if (typeof msg.FirstLine === "undefined")
    msg.FirstLine = 0;
  if (typeof msg.CanscrollUp === "undefined")
    msg.CanscrollUp = false;

  if (!msg.CanscrollUp) return;

  msg.FirstLine = msg.FirstLine > 0 ? msg.FirstLine - linesScroll : 0;

  drawMessage(ovr, msg);
};

let scrollDown = function(ovr) {
  msg = eventQueue[0];
  LOG("down", msg);
  if (typeof msg.FirstLine === "undefined")
    msg.FirstLine = 0;
  if (typeof msg.CanscrollDown === "undefined")
    msg.CanscrollDown = false;

  if (!msg.CanscrollDown) return;

  msg.FirstLine = msg.FirstLine + linesScroll;
  drawMessage(ovr, msg);
};

let drawMessage = function(ovr, msg) {
  let MyWrapString = function(str, maxWidth) {
    str = str.replace("\r\n", "\n").replace("\r", "\n");
    return ovr.wrapString(str, maxWidth);
  };

  if (typeof msg.FirstLine === "undefined") msg.FirstLine = 0;

  let bodyFont = typeof msg.bodyFont === "undefined" ? settings.fontMedium : msg.bodyFont;
  let Padding = 3;
  if (typeof msg.lines === "undefined") {
    ovr.setFont(bodyFont);
    msg.lines = MyWrapString(msg.body, ovr.getWidth() - (Padding * 2));
    if (msg.lines.length <= 2) {
      bodyFont = ovr.getFonts().includes("Vector") ? "Vector:20" : "6x8:3";
      ovr.setFont(bodyFont);
      msg.lines = MyWrapString(msg.body, ovr.getWidth() - (Padding * 2));
      msg.bodyFont = bodyFont;
    }
  }

  let NumLines = 7;

  let linesToPrint = (msg.lines.length > NumLines) ? msg.lines.slice(msg.FirstLine, msg.FirstLine + NumLines) : msg.lines;

  let yText = 40;

  ovr.setBgColor(ovr.theme.bg);
  ovr.setColor(ovr.theme.fg);
  ovr.clearRect(2, yText, ovrw-3, ovrh-3);
  let xText = Padding;
  yText += Padding;
  ovr.setFont(bodyFont);
  let HText = ovr.getFontHeight();

  yText = ((ovrh - yText) / 2) - (linesToPrint.length * HText / 2) + yText;

  if (linesToPrint.length <= 3) {
    ovr.setFontAlign(0, -1);
    xText = ovr.getWidth() / 2;
  } else
    ovr.setFontAlign(-1, -1);


  linesToPrint.forEach((line, i) => {
    ovr.drawString(line, xText, yText + HText * i);
  });

  if (msg.FirstLine != 0) {
    msg.CanscrollUp = true;
    drawTriangleUp(ovr);
  } else
    msg.CanscrollUp = false;

  if (msg.FirstLine + linesToPrint.length < msg.lines.length) {
    msg.CanscrollDown = true;
    drawTriangleDown(ovr);
  } else
    msg.CanscrollDown = false;
  show(ovr);
  if (!isQuiet()) Bangle.setLCDPower(1);
};

let getSwipeHandler = function(ovr){
  return (lr, ud) => {
    if (ud == 1) {
      scrollUp(ovr);
    } else if (ud == -1){
      scrollDown(ovr);
    }
  };
};

let getTouchHandler = function(ovr){
  return (_, xy) => {
    if (xy.y < ovry + 40){
      next(ovr);
    }
  };
};

let restoreHandler = function(event){
  LOG("Restore", event, backup[event]);
  Bangle.removeAllListeners(event);
  Bangle["#on" + event]=backup[event];
  backup[event] = undefined;
};

let backupHandler = function(event){
  if (backupDone) return; // do not backup, overlay is already up
  backup[event] = Bangle["#on" + event];
  LOG("Backed up", backup[event]);
  Bangle.removeAllListeners(event);
};

let cleanup = function(){
  if (lockListener) {
    Bangle.removeListener("lock", lockListener);
    lockListener = undefined;
  }
  restoreHandler("touch");
  restoreHandler("swipe");
  restoreHandler("drag");

  Bangle.setLCDOverlay();
  backupDone = false;
  ovr = undefined;
  quiet = undefined;
};

let backup = {};

let backupDone = false;

let main = function(ovr, event) {
  LOG("Main", event, settings);

  if (!lockListener) {
    lockListener = function (){
      drawBorder(ovr);
    };
    Bangle.on('lock', lockListener);
  }
  backupHandler("touch");
  backupHandler("swipe");
  backupHandler("drag");
  if (!backupDone){
    Bangle.on('touch', getTouchHandler(ovr));
    Bangle.on('swipe', getSwipeHandler(ovr));
  }
  backupDone=true;

  if (event !== undefined){
    drawBorder(ovr);
    manageEvent(ovr, event);
  } else {
    LOG("No event given");
    cleanup();
  }
};

let ovr;

exports.pushMessage = function(event) {
  if( event.id=="music") return require_real("messages").pushMessage(event);

  bpp = 4;
  if (process.memory().free < 2000) bpp = 1;

  if (!ovr) {
    ovr = Graphics.createArrayBuffer(ovrw, ovrh, bpp, {
      msb: true
    });
  } else {
    ovr.clear();
  }

  g = ovr;

  if (bpp == 4)
    ovr.theme = g.theme;
  else
    ovr.theme = { fg:0, bg:1, fg2:1, bg2:0, fgH:1, bgH:0 };

  main(ovr, event);

  g = _g;
};


//Call original message library
exports.clearAll = function() { return require_real("messages").clearAll();};
exports.getMessages = function() { return require_real("messages").getMessages();};
exports.status = function() { return require_real("messages").status();};
exports.buzz = function() { return require_real("messages").buzz(msgSrc);};
exports.stopBuzz = function() { return require_real("messages").stopBuzz();};
