const dataFile = "chrono_data.json";
let chronoTime = require("Storage").readJSON(dataFile) || {start: 0, elapsed: 0, laps: [], mode: undefined};

const midX = Bangle.appRect.x + Bangle.appRect.x2 / 2;
const midY = Bangle.appRect.y + Bangle.appRect.y2 / 2;
const buttonH = 50;
const buttonsRect = {x: Bangle.appRect.x, y: Bangle.appRect.y2 - buttonH, x2: Bangle.appRect.x2, y2: Bangle.appRect.y2};
const timeRect = {x: Bangle.appRect.x + 3, y: buttonsRect.y - 55, x2: Bangle.appRect.x2 - 3, y2: buttonsRect.y - 10};
const lapsRect = {x: Bangle.appRect.x, y: Bangle.appRect.y, x2: Bangle.appRect.x2, y2: timeRect.y - 3};

const lapsFont = "Vector:25";
const timeFont = "Vector:40";
const lapsStrW = g.setFont(lapsFont).stringWidth("00:00.0");
const timeStrW = g.setFont(timeFont).stringWidth("00:00.0");
let updateIntID;

const drawButton = function(button) {
	g.setFont("Vector:27").setFontAlign(0,0).setColor(0, 1, 1);
	g.fillRect({x: button.x, y: button.y, x2: button.x + button.w - 1, y2: button.y + button.h - 1, r: 12});
	g.setColor(0, 0, 0).fillRect({x: button.x + 3, y: button.y + 3, x2: button.x + button.w - 4, y2: button.y + button.h - 4, r: 9});
	g.setColor(-1);
	g.setFontAlign(0,0).drawString(button.label, button.x + (button.w / 2), button.y + (button.h / 2));
};

const clearButtons = function() {
	g.clearRect(buttonsRect);
};

const startButton = {x: Bangle.appRect.x, y: Bangle.appRect.y2 - buttonH, w: Bangle.appRect.w, h: buttonH, label: "Start"};
const lapButton = {x: Bangle.appRect.x, y: Bangle.appRect.y2 - buttonH, w: (Bangle.appRect.w / 2) - 2, h: buttonH, label: "Lap"};
const pauseButton = {x: this.midX + 1, y: Bangle.appRect.y2 - buttonH, w: (Bangle.appRect.w / 2) - 2, h: buttonH, label: "Stop"};
const resetButton = {x: Bangle.appRect.x, y: Bangle.appRect.y2 - buttonH, w: (Bangle.appRect.w / 2) - 2, h: buttonH, label: "Reset"};
const smallStartButton = {x: this.midX + 2, y: Bangle.appRect.y2 - buttonH, w: (Bangle.appRect.w / 2) - 2, h: buttonH, label: "Start"};

const drawTime = function(timeStr) {
	g.setBgColor(0, 0.25, 0.25);
	g.clearRect(timeRect);
	g.setFont(timeFont).setFontAlign(0,1);
	g.drawString(timeStr, midX, timeRect.y2);
	g.setBgColor(0, 0, 0);
};

const ms2str = function(ms) {
	const h = Math.floor(ms / 3600000);
	const m = Math.floor((ms / 60000) % 60);
	const s = Math.floor((ms / 1000) % 60);
	const tnth = Math.floor((ms % 1000) / 100);
	const format = (timePart) => (timePart < 10) ? "0" + timePart : timePart;

	return (h > 0 ? format(h) + ":" : "") + format(m) + ":" + format(s) + (h > 0 ? "" : "." + tnth);
};

const keepUpdated = function(shouldUpdate) {
	if (updateIntID) clearInterval(updateIntID);
	if (shouldUpdate) {
		updateIntID = setInterval(()=> {
			chronoTime.elapsed = getElapsed();
			drawTime(ms2str(chronoTime.elapsed));
		}, 100);
	}
};

const start = function() {
	chronoTime.mode = "running";
	if (chronoTime.start === 0) chronoTime.start = Date.now();
	saveState();
	keepUpdated(true);
	clearButtons();
	drawButton(lapButton);
	drawButton(pauseButton);
};

const pause = function() {
	chronoTime.mode = "stopped";
	const now = Date.now();
	chronoTime.elapsed = now - chronoTime.start;
	saveState();
	keepUpdated(false);
	drawTime(ms2str(chronoTime.elapsed));
	clearButtons();
	drawButton(resetButton);
	drawButton(smallStartButton);
};

const getElapsed = function() {
	return Date.now() - chronoTime.start;
}

const restart = function() {
	chronoTime.mode = "running";
	chronoTime.start = Date.now() - chronoTime.elapsed;
	saveState();
	keepUpdated(true);
	clearButtons();
	drawButton(lapButton);
	drawButton(pauseButton);
}

const reset = function() {
	chronoTime.start = 0;
	chronoTime.elapsed = 0;
	chronoTime.laps = [];
	chronoTime.mode = undefined;
	saveState();
	g.clearRect(lapsRect);
	drawTime(ms2str(chronoTime.elapsed));
	clearButtons();
	drawButton(startButton);
};

const saveState = function() {
	require("Storage").writeJSON(dataFile, chronoTime);
};

const lapScreen = {
	fh: g.setFont(lapsFont).getFontHeight(),
	numX: midX - (timeStrW / 2) + 5,
	strX: midX + (timeStrW / 2) - 5,
}
lapScreen.y0 = lapsRect.y2 - (chronoTime.laps.length * lapScreen.fh);

const addLap = function() {
	chronoTime.laps.push(chronoTime.elapsed);
	lapScreen.y0 = lapsRect.y2 - (chronoTime.laps.length * lapScreen.fh);
	saveState();
};

const drawLaps = function() {
	g.setFont(lapsFont);
	g.clearRect(lapsRect);
	g.setClipRect(lapsRect.x, lapsRect.y, lapsRect.x2, lapsRect.y2);
	let y = lapScreen.y0;
	let lapNum = 1;
	for (let lap of chronoTime.laps) {
		if (y + lapScreen.fh > lapsRect.y) {
			g.setColor(0.5, 0.5, 0.5).setFontAlign(-1, -1).drawString(lapNum, lapScreen.numX, y);
			g.setColor(-1).setFontAlign(1, -1).drawString(ms2str(lap), lapScreen.strX, y);
		}
		y += lapScreen.fh;
		lapNum++;
	}
	g.setClipRect(Bangle.appRect.x, Bangle.appRect.y, Bangle.appRect.x2, Bangle.appRect.y2);
};

const dragHandler = function(d) {
	const minY = lapsRect.y2 - (chronoTime.laps.length * lapScreen.fh);
	const maxY = minY > lapsRect.y ? lapsRect.y2 - (chronoTime.laps.length * lapScreen.fh) : lapsRect.y;
	if (d.dy && d.b) {
		lapScreen.y0 += d.dy;
		if (lapScreen.y0 < minY - 20) { // overscroll
			lapScreen.y0 = minY - 20;
		} else if (lapScreen.y0 > maxY + 20) {
			lapScreen.y0 = maxY + 20;
		}
	} else if (!d.b) {
		if (lapScreen.y0 < minY) {
			lapScreen.y0 = minY;
		} else if (lapScreen.y0 > maxY) {
			lapScreen.y0 = maxY;
		}
	}
	drawLaps(d.dy);
};

const buttonHandler = function(_n, e) {
	if (e.y < Bangle.appRect.y2 - buttonH) {
		return;
	}	else if (e.x < midX) {	// button 1
		switch (chronoTime.mode) {
			case undefined:
				start();
				break;
			case "running":
				addLap();
				drawLaps();
				break;
			case "stopped":
				reset();
				chronoTime.mode = undefined;
				break;
		}

	} else if (e.x > midX) {	// button 2
		switch (chronoTime.mode) {
			case undefined:
				start();
				break;
			case "running":
				pause();
				break;
			case "stopped":
				restart();
				break;
		}
	}
};

const main = function() {

	g.clear();
	if (chronoTime.mode == "running") {
		chronoTime.elapsed = getElapsed();
		start();
		drawLaps();
	} else if (chronoTime.mode == "stopped") {
		pause();
		drawLaps();
	} else if (chronoTime.mode == undefined){
		drawTime(ms2str(chronoTime.elapsed));
		drawButton(startButton);
	}

	Bangle.setUI({mode: "custom",
		touch: (_n, e) => buttonHandler(_n, e),
		drag: (e) => dragHandler(e),
		btn: (_n) => Bangle.showClock()
	});
};

main();
