# ---------- imports ---------- #
import gui
import CONSTANT
import vts
from image import Image_Bank
from os import getcwd

# ---------- read in data ---------- #
# NOTE: When reading in you data do not forget that the y axis is inverted.
# This means that the lower the number the higher the value on the graph

# ---------- display background of graph ---------- #
class Graph:
    def __init__(self, y_title = "SPEED", x_title = "TIME"):
        self.y_axis_title = y_title
        self.x_axis_title = x_title

    def create_graph(self):
        # Gets an image for title on y-axis.
        # This is much simpler than rotating it however it is less convenient.
        # It also makes use of image.py which may be confusing.
        # If a method is found to invert text then this file will be updated on our website.
        self.graph_DL = []
        x=10
        y=240
        tag = 255
        path = getcwd() + '/'
        image = Image_Bank((
            (path + 'speed.png',                   'SPEED'),
        ))
        SPEED = image.get('SPEED')

        self.graph_DL.extend([[gui.DL_BEGIN(gui.PRIM_BITMAPS)]])
        self.graph_DL.extend([SPEED.generate_gui_l(tag, (x, y))])
        self.graph_DL.extend([[gui.DL_END()]])

        # Creates the x axis title. This is simple as it doesn't need to be sideways
        self.graph_DL.extend([[gui.CTRL_TEXT, CONSTANT.DISTANCE_X_WALL + int(CONSTANT.X_AXIS/2), 440, 28, 1536, self.x_axis_title]])

        # create axis line
        self.graph_DL.extend([[gui.DL_COLOR_A(255)]])
        self.graph_DL.extend([[gui.DL_COLOR_RGB(255,255,255)]])
        self.graph_DL.extend([[gui.DL_BEGIN(gui.PRIM_LINE_STRIP)]])
        self.graph_DL.extend([[gui.DL_VERTEX2F(CONSTANT.DISTANCE_X_WALL, 100)]])
        self.graph_DL.extend([[gui.DL_VERTEX2F(CONSTANT.DISTANCE_X_WALL, 480 - CONSTANT.DISTANCE_Y_WALL)]])
        self.graph_DL.extend([[gui.DL_VERTEX2F(CONSTANT.DISTANCE_X_WALL + CONSTANT.X_AXIS, 480-CONSTANT.DISTANCE_Y_WALL)]])
        self.graph_DL.extend([[gui.DL_END()]])

        # create y scale markers
        for num in range(CONSTANT.Y_AXIS_MARKERS, -1, -1):
            self.graph_DL.extend([[gui.CTRL_TEXT, CONSTANT.DISTANCE_X_WALL-25, 100+((10-num)*CONSTANT.Y_SCALE), 26, 1536, str(num*int((CONSTANT.MAX_Y/CONSTANT.Y_AXIS_MARKERS)))]])
            self.graph_DL.extend([[gui.DL_BEGIN(gui.PRIM_LINE_STRIP)]])
            self.graph_DL.extend([[gui.DL_VERTEX2F(CONSTANT.DISTANCE_X_WALL, 100+((10-num)*CONSTANT.Y_SCALE))]])
            self.graph_DL.extend([[gui.DL_VERTEX2F(CONSTANT.DISTANCE_X_WALL-5, 100+((10-num)*CONSTANT.Y_SCALE))]])
            self.graph_DL.extend([[gui.DL_END()]])

    # return the graph's display list for it to be displayed by gui.show()
    def get_graph(self):
        return self.graph_DL

# ---------- lines ---------- #
class Lines:
    def __init__(self, points, colour = gui.RGB(0,255,0), thickness = 5):
        self.points = points
        self.line_colour = colour
        self.line_thickness = thickness
        self.points_DL = [[gui.DL_NOP()]]*(CONSTANT.SAMPLES_DISPLAYED)

    # update the points list
    def update_points(self, new_point):
        # if on the max number of points
        if len(self.points) == CONSTANT.SAMPLES_DISPLAYED:
            # remove first point
            self.points.pop(0)
            # move all other points back a position
            for num in range(0,len(self.points)):
                self.points[num][0] -= CONSTANT.X_SCALE

        # add new point at end
        self.points.extend([[CONSTANT.DISTANCE_X_WALL+(((len(self.points))*CONSTANT.X_SCALE)), new_point]])

    # updates the display list for gui.show()
    def update_list(self, new_point = None):
        # if there is a new point to update
        if new_point != None:
            self.update_points(new_point)
        
        # set the display list coordinates to equal the point list coordinates.
        for x in range(0,len(self.points)):
            self.points_DL[x] = [gui.DL_VERTEX2F(self.points[x][0], self.points[x][1])]

        # print("POINTS: {}".format(self.points_DL))

    # return the display list for the lines to be displayed by gui.show()
    def get_points_list(self):
        return self.points_DL

    # redraw the lines
    def redraw_lines(self):
        gui.redraw()


# Creates a graph object
graph = Graph()
graph.create_graph()

# Creates a line object with a start point at the equivalent of (0,0) on the graph
points = [[CONSTANT.DISTANCE_X_WALL,480-CONSTANT.DISTANCE_Y_WALL]]
line1 = Lines(points, gui.RGB(0,255,0), 2)
line1.update_list()

# Shows the graph and line and sets the background colour to black
gui.show(
    [[gui.DL_CLEAR_COLOR_RGB(0,0,0)],
    [gui.DL_CLEAR(1, 1, 1)],
    [gui.DL_COLOR_RGB(255,255,255)],] +
    graph.get_graph() +
    [[gui.DL_LINE_WIDTH(line1.line_thickness)],
    [gui.DL_COLOR_A(255)],
    [gui.DL_COLOR(line1.line_colour)],
    [gui.PRIM_LINE_STRIP, line1.get_points_list()],
])

# creates random data to demonstrate the graph.
# data is delayed so as to give a realistic amount of data per second
while 1:
    # vts.delay_ms(int(100*(CONSTANT.SECONDS_DISPLAYED/CONSTANT.SAMPLE_RATE)))
    vts.delay_ms(10)
    num = 100+(vts.rand32()%CONSTANT.Y_AXIS)
    line1.update_list(num)
    line1.redraw_lines()