"""
Copyright (C) 2015-2021 Alibaba Group Holding Limited

    MicroPython's driver for MAX7219

    Author: HaaS
    Date:   2022/03/15
"""

from driver import GPIO
from utime import sleep_ms
from micropython import const
import math

digit_array_0 = bytearray([0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c])
digit_array_1 = bytearray([0x10, 0x18, 0x14, 0x10, 0x10, 0x10, 0x10, 0x10])
digit_array_2 = bytearray([0x7E, 0x2, 0x2, 0x7E, 0x40, 0x40, 0x40, 0x7E])
digit_array_3 = bytearray([0x3E, 0x2, 0x2, 0x3E, 0x2, 0x2, 0x3E, 0x0])
digit_array_4 = bytearray([0x8, 0x18, 0x28, 0x48, 0xFE, 0x8, 0x8, 0x8])
digit_array_5 = bytearray([0x3C, 0x20, 0x20, 0x3C, 0x4, 0x4, 0x3C, 0x0])
digit_array_6 = bytearray([0x3C, 0x20, 0x20, 0x3C, 0x24, 0x24, 0x3C, 0x0])
digit_array_7 = bytearray([0x3E, 0x22, 0x4, 0x8, 0x8, 0x8, 0x8, 0x8])
digit_array_8 = bytearray([0x0, 0x3E, 0x22, 0x22, 0x3E, 0x22, 0x22, 0x3E])
digit_array_9 = bytearray([0x3E, 0x22, 0x22, 0x3E, 0x2, 0x2, 0x2, 0x3E])
digit_array_A = bytearray([0x8, 0x14, 0x22, 0x3E, 0x22, 0x22, 0x22, 0x22])
digit_array_B = bytearray([0x3C, 0x22, 0x22, 0x3E, 0x22, 0x22, 0x3C, 0x0])
digit_array_C = bytearray([0x3C, 0x40, 0x40, 0x40, 0x40, 0x40, 0x3C, 0x0])
digit_array_D = bytearray([0x7C, 0x42, 0x42, 0x42, 0x42, 0x42, 0x7C, 0x0])
digit_array_E = bytearray([0x7C, 0x40, 0x40, 0x7C, 0x40, 0x40, 0x40, 0x7C])
digit_array_F = bytearray([0x7C, 0x40, 0x40, 0x7C, 0x40, 0x40, 0x40, 0x40])
digit_array_G = bytearray([0x3C, 0x40, 0x40, 0x40, 0x40, 0x44, 0x44, 0x3C])
digit_array_H = bytearray([0x44, 0x44, 0x44, 0x7C, 0x44, 0x44, 0x44, 0x44])
digit_array_I = bytearray([0x7C, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x7C])
digit_array_J = bytearray([0x3C, 0x8, 0x8, 0x8, 0x8, 0x8, 0x48, 0x30])
digit_array_K = bytearray([0x0, 0x24, 0x28, 0x30, 0x20, 0x30, 0x28, 0x24])
digit_array_L = bytearray([0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x7C])
digit_array_M = bytearray([0x81, 0xC3, 0xA5, 0x99, 0x81, 0x81, 0x81, 0x81])
digit_array_N = bytearray([0x0, 0x42, 0x62, 0x52, 0x4A, 0x46, 0x42, 0x0])
digit_array_O = bytearray([0x3C, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3C])
digit_array_P = bytearray([0x3C, 0x22, 0x22, 0x22, 0x3C, 0x20, 0x20, 0x20])
digit_array_Q = bytearray([0x1C, 0x22, 0x22, 0x22, 0x22, 0x26, 0x22, 0x1D])
digit_array_R = bytearray([0x3C, 0x22, 0x22, 0x22, 0x3C, 0x24, 0x22, 0x21])
digit_array_S = bytearray([0x0, 0x1E, 0x20, 0x20, 0x3E, 0x2, 0x2, 0x3C])
digit_array_T = bytearray([0x0, 0x3E, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8])
digit_array_U = bytearray([0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x22, 0x1C])
digit_array_V = bytearray([0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x24, 0x18])
digit_array_W = bytearray([0x0, 0x49, 0x49, 0x49, 0x49, 0x2A, 0x1C, 0x0])
digit_array_X = bytearray([0x0, 0x41, 0x22, 0x14, 0x8, 0x14, 0x22, 0x41])
digit_array_Y = bytearray([0x41, 0x22, 0x14, 0x8, 0x8, 0x8, 0x8, 0x8])
digit_array_Z = bytearray([0x0, 0x7F, 0x2, 0x4, 0x8, 0x10, 0x20, 0x7F])

digit_array = [
    digit_array_0, digit_array_1, digit_array_2, digit_array_3, digit_array_4,
    digit_array_5, digit_array_6, digit_array_7, digit_array_8, digit_array_9,
    digit_array_A, digit_array_B, digit_array_C, digit_array_D, digit_array_E,
    digit_array_F, digit_array_G, digit_array_H, digit_array_I, digit_array_G,
    digit_array_K, digit_array_L, digit_array_M, digit_array_N, digit_array_O,
    digit_array_P, digit_array_Q, digit_array_R, digit_array_S, digit_array_T,
    digit_array_U, digit_array_V, digit_array_W, digit_array_X, digit_array_Y,
    digit_array_Z
]


class MAX7219(object):
    """
    This class implements max7219 chip's defs.
    """

    def __init__(self, clk, cs, din):
        self._clk = None
        self._cs = None
        self._din = None
        if not isinstance(clk, GPIO):
            raise ValueError("parameter is not an GPIO object")
        if not isinstance(cs, GPIO):
            raise ValueError("parameter is not an GPIO object")
        if not isinstance(din, GPIO):
            raise ValueError("parameter is not an GPIO object")
        # make 74HC595's internal object points to gpio
        self._clk = clk
        self._cs = cs
        self._din = din
        self._digit_array = digit_array

    def write(self, data):
        self._cs.write(0)
        for i in range(8):
            self._clk.write(0)
            if (data & 0x80) != 0:
                self._din.write(1)
            else:
                self._din.write(0)
            data <<= 1
            self._clk.write(1)

    def write_reg(self, address, value):
        self._cs.write(0)
        self.write(address)
        self.write(value)
        self._cs.write(1)

    def outSegmentDigit(self, position, digit):
        position += 1
        self._cs.write(0)
        self.write(position)
        self.write(digit)
        self._cs.write(1)

    def outMatrixChar(self, digit):
        if ord(digit) <= ord('9') and ord(digit) >= ord('0'):
            for i in range(8):
                self.write_reg(i + 1,
                               self._digit_array[ord(digit) - ord('0')][i])
        if ord(digit) >= ord('A') and ord(digit) <= ord('Z'):
            for i in range(8):
                self.write_reg(
                    i + 1, self._digit_array[ord(digit) - ord('A') + 10][i])

    def initSegmentLed(self):
        self.write_reg(0x09, 0xff)
        self.write_reg(0x0a, 0x03)
        self.write_reg(0x0b, 0x07)
        self.write_reg(0x0c, 0x01)
        self.write_reg(0x0f, 0x00)

    def initMatrixLed(self):
        self.write_reg(0x09, 0x00)
        self.write_reg(0x0a, 0x03)
        self.write_reg(0x0b, 0x07)
        self.write_reg(0x0c, 0x01)
        self.write_reg(0x0f, 0x00)
