"""
Thanks to yrlf for the 7-segment display code
https://github.com/Ferdi265/card10-digiclk

Thanks to lortas for the battery rendering code
"""
import os
import display
import utime
import buttons
import light_sensor
import bhi160
import ujson
import vibra

ALARMFILE = "alarm.json"
MESSAGEFILE = "messages.json"
DEFAULTMESSAGECOLOR = [0, 0, 255]
LONGESTMESSAGETIME = 3600

DIGITS = [
	(True, True, True, True, True, True, False),
	(False, True, True, False, False, False, False),
	(True, True, False, True, True, False, True),
	(True, True, True, True, False, False, True),
	(False, True, True, False, False, True, True),
	(True, False, True, True, False, True, True),
	(True, False, True, True, True, True, True),
	(True, True, True, False, False, False, False),
	(True, True, True, True, True, True, True),
	(True, True, True, True, False, True, True)
]

MONTH_STRING = ["Jan", "Feb", "Mar", "Apr", "Mai", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]


class Clock:
	def __init__(self):
		with display.open() as disp:
			disp.clear()
			disp.update()
			disp.backlight(0)
		self.display_state = 0
		self.states = 2

		# load alarms
		self.alarmsymbol = False
		if ALARMFILE in os.listdir("."):
			f = open(ALARMFILE, 'r')
			self.alarms = ujson.loads(f.read())
			f.close()
			for alarm in self.alarms:
				alarm["minute_time"] = utime.mktime(alarm["time"]+[1, 1])//60
		else:
			self.alarms = []

		# load messages
		self.message = ""
		self.messagecol = DEFAULTMESSAGECOLOR
		self.lastmessage = utime.time()
		if MESSAGEFILE in os.listdir("."):
			f = open(MESSAGEFILE, 'r')
			self.messages = ujson.loads(f.read())
			f.close()
		else:
			self.messages = []

	def check_for_future_alarms(self):
		self.alarmsymbol = False
		current = utime.time()
		for alarm in self.alarms:
			if current//60 < alarm["minute_time"] < current//60+60*12:
				self.alarmsymbol = True

	def draw_alertsymb(self, disp, x, y, fgcol):
		disp.circ(x, y, 6, filled=False, col=fgcol)
		disp.line(x, y, x, y-4, col=fgcol)
		disp.line(x, y, x+3, y, col=fgcol)
		disp.line(x-7, y-6, x-2, y-10, col=fgcol)
		disp.line(x+7, y-6, x+2, y-10, col=fgcol)

	def render_battery(self, disp, v, light):
		if v > 3.8:
			c = [0, light, 0]
		elif v > 3.6:
			c = [light, light, 0]
		else:
			c = [light, 0, 0]

		disp.rect(140, 71, 155, 78, filled=True, col=c)
		disp.rect(155, 73, 157, 76, filled=True, col=c)
		if v < 4.0:
			disp.rect(151, 72, 154, 77, filled=True, col=[0, 0, 0])
		if v < 3.8:
			disp.rect(146, 72, 151, 77, filled=True, col=[0, 0, 0])
		if v < 3.6:
			disp.rect(141, 72, 146, 77, filled=True, col=[0, 0, 0])

	def ceilDiv(self, a, b):
			return (a + (b - 1)) // b

	def tipHeight(self, w):
			return self.ceilDiv(w, 2) - 1

	def drawTip(self, d, x, y, w, c, invert=False, swapAxes=False):
		h = self.tipHeight(w)
		for dy in range(h):
			for dx in range(dy + 1, w - 1 - dy):
				px = x + dx
				py = y + dy if not invert else y + h - 1 - dy
				if swapAxes:
					px, py = py, px
				d.pixel(px, py, col=c)

	def drawSeg(self, d, x, y, w, h, c, swapAxes=False):
		tip_h = self.tipHeight(w)
		body_h = h - 2 * tip_h

		self.drawTip(d, x, y, w, c, invert=True, swapAxes=swapAxes)

		px1, px2 = x, x + w
		py1, py2 = y + tip_h, y + tip_h + body_h
		if swapAxes:
			px1, px2, py1, py2 = py1, py2, px1, px2
		d.rect(px1, py1, px2 - 1, py2 - 1, col=c)

		self.drawTip(d, x, y + tip_h + body_h, w, c, invert=False, swapAxes=swapAxes)

	def drawGridSeg(self, d, x, y, w, l, c, swapAxes=False):
		sw = w - 2
		tip_h = self.tipHeight(sw)

		x = x * w
		y = y * w
		l = (l - 1) * w
		self.drawSeg(d, x + 1, y + tip_h + 3, sw, l - 3, c, swapAxes=swapAxes)

	def drawGridVSeg(self, d, x, y, w, l, c):
		self.drawGridSeg(d, x, y, w, l, c)

	def drawGridHSeg(self, d, x, y, w, l, c):
		self.drawGridSeg(d, y, x, w, l, c, swapAxes=True)

	def drawGrid7Seg(self, d, x, y, w, segs, c):
		if segs[0]:
			self.drawGridHSeg(d, x, y, w, 4, c)
		if segs[1]:
			self.drawGridVSeg(d, x + 3, y, w, 4, c)
		if segs[2]:
			self.drawGridVSeg(d, x + 3, y + 3, w, 4, c)
		if segs[3]:
			self.drawGridHSeg(d, x, y + 6, w, 4, c)
		if segs[4]:
			self.drawGridVSeg(d, x, y + 3, w, 4, c)
		if segs[5]:
			self.drawGridVSeg(d, x, y, w, 4, c)
		if segs[6]:
			self.drawGridHSeg(d, x, y + 3, w, 4, c)

	def renderNum(self, d, num, x, c):
		self.drawGrid7Seg(d, x, 0, 7, DIGITS[num // 10], c)
		self.drawGrid7Seg(d, x + 5, 0, 7, DIGITS[num % 10], c)

	def renderColon(self, d, c):
		self.drawGridVSeg(d, 11, 2, 7, 2, c)
		self.drawGridVSeg(d, 11, 4, 7, 2, c)

	def loop(self):
		with display.open() as disp:
			while True:
				v = buttons.read(buttons.BOTTOM_LEFT | buttons.BOTTOM_RIGHT | buttons.TOP_RIGHT)
				(year, month, day, hour, minute, seconds, weekday, _yday) = utime.localtime()
				for message in self.messages:
					if (weekday in message["dow"] and [hour, minute, seconds] == message["time"]):
						self.lastmessage = utime.time()
						self.message = message["message"]
						if "color" in message:
							self.messagecol = message["color"]
						else:
							self.messagecol = DEFAULTMESSAGECOLOR
					elif (self.lastmessage < utime.time()-LONGESTMESSAGETIME):
						self.message = ""

				if v != 0:
					# some button pressed
					light = 255
					fgcol = [light]*3

					# update clock
					disp.clear()
					self.renderNum(disp, hour, 1, fgcol)
					self.renderNum(disp, minute, 13, fgcol)
					self.renderColon(disp, fgcol)
					self.render_battery(disp, os.read_battery(), light)
					disp.print(str(day)+"."+MONTH_STRING[month-1], fg=fgcol, posx=0, posy=66, font=2)

					disp.print(self.message, posy=50, font=0, fg=self.messagecol)

					if self.alarmsymbol and not self.alarm:
						self.draw_alertsymb(disp, 150, 60, fgcol)
					else:
						self.check_for_future_alarms()

					disp.update()
					disp.backlight(100)
					utime.sleep(5)
					disp.clear()
					disp.update()
					disp.backlight(0)

				self.alarm = False
				for alarm in self.alarms:
					if (alarm["minute_time"] == utime.time()//60):
						if v != 0:
							alarm["minute_time"] = 0
							self.check_for_future_alarms()
						else:
							disp.backlight(100)
							disp.print(alarm["message"], font=2, fg=[255, 0, 0], posy=30)
							disp.update()
							self.alarm = True

				if self.alarm:
					vibra.set(True)
					utime.sleep_ms(300)
					vibra.set(False)

				utime.sleep(1)


clock = Clock()
clock.loop()


clock.loadalarms()
print("loaded")
