
require("advancedLua")
local fs = require("filesystem")
local buffer = require("doubleBuffering")
local GUI = require("GUI")
local unicode = require("unicode")
local MineOSInterface = require("MineOSInterface")

---------------------------------------------------------------------------------------------------------

local mainContainer, window = MineOSInterface.addWindow(GUI.filledWindow(nil, nil, 110, 25, 0xF0F0F0))
local yDependencyString = "math.sin(x)"
local xOffset, yOffset, xDrag, yDrag, points = 0, 0, 1, 1

---------------------------------------------------------------------------------------------------------

window.backgroundPanel.localPosition.y, window.backgroundPanel.height = 4, window.backgroundPanel.height - 3
local titlePanel = window:addChild(GUI.panel(1, 1, window.width, 3, 0x2D2D2D))
local layout = window:addChild(GUI.layout(1, 1, window.width, 3, 1, 1))
layout:setCellDirection(1, 1, GUI.directions.horizontal)
layout:setCellSpacing(1, 1, 3)

local switchAndLabel = layout:addChild(GUI.switchAndLabel(1, 1, 16, 6, 0x66DB80, 0x1E1E1E, 0xF0F0F0, 0xBBBBBB, "Quants:", false))
local scaleSlider = layout:addChild(GUI.slider(1, 1, 12, 0x66DB80, 0x0, 0xFFFFFF, 0xBBBBBB, 1, 1000, 400, false, "Scale: ", "%"))
local rangeSlider = layout:addChild(GUI.slider(1, 1, 12, 0x66DB80, 0x0, 0xFFFFFF, 0xBBBBBB, 2, 60, 25, false, "Range: ", ""))
local precisionSlider = layout:addChild(GUI.slider(1, 1, 12, 0x66DB80, 0x0, 0xFFFFFF, 0xBBBBBB, 10, 99, 72, false, "Step: 0.", ""))
local functionButton = window:addChild(GUI.button(1, 1, 1, 3, 0xF0F0F0, 0x3C3C3C, 0xCCCCCC, 0x3C3C3C, ""))

window.actionButtons:moveToFront()

local graph = window:addChild(GUI.object(1, 4, window.width, window.height - 3))
graph.draw = function(graph)
	local x1, x2, y1, y2 = buffer.getDrawLimit()
	buffer.setDrawLimit(graph.x, graph.y, graph.x + graph.width - 1, graph.y + graph.height - 1)

	local xCenter, yCenter = graph.x + xOffset + graph.width / 2 - 1, graph.y + yOffset + graph.height / 2 - 1
	
	buffer.semiPixelLine(math.floor(graph.x), math.floor(yCenter * 2), math.floor(graph.x + graph.width - 1), math.floor(yCenter * 2), 0xD2D2D2)
	buffer.semiPixelLine(math.floor(xCenter), math.floor(graph.y * 2 - 1), math.floor(xCenter), math.floor(graph.y + graph.height - 1) * 2, 0xD2D2D2)

	for i = 1, #points - 1 do
		local x1, x2, y1, y2 = math.floor(xCenter + points[i].x), math.floor(yCenter - points[i].y + 1) * 2, math.floor(xCenter + points[i + 1].x), math.floor(yCenter - points[i + 1].y + 1) * 2
		buffer.semiPixelLine(x1, x2, y1, y2, 0x0)
		if switchAndLabel.switch.state then
			buffer.semiPixelSet(x1, x2, 0x66DB80)
		end
	end

	buffer.setDrawLimit(x1, x2, y1, y2)
end

local function update()
	functionButton.text = "f(x)=" .. yDependencyString:gsub("%s+", "")
	functionButton.width = unicode.len(functionButton.text) + 4
	functionButton.localPosition.x = window.width - functionButton.width + 1
	titlePanel.width = window.width - functionButton.width
	layout.width = titlePanel.width

	points = {}
	local scale = scaleSlider.value / 100
	local xRange = rangeSlider.value
	local step = precisionSlider.value / 100

	for x = -xRange, xRange, step do
		local success, y = pcall(load("local x = " .. x .. "; local y = " .. yDependencyString .. "; return y"))
		if success and tonumber(y) then
			if not (y ~= y) then
				table.insert(points, {
					x = x * scale,
					y = y * scale
				})
			end
		else
			GUI.error("Invalid input function")
			return
		end
	end
end

functionButton.onTouch = function()
	local container = MineOSInterface.addUniversalContainer(window, "Set function f(x)")
	local inputField = container.layout:addChild(GUI.input(1, 1, 36, 3, 0xEEEEEE, 0x666666, 0x666666, 0xEEEEEE, 0x262626, yDependencyString, "f(x)", false))
	inputField.onInputFinished = function()
		if inputField.text then
			yDependencyString = inputField.text
			update()

			container:delete()
			mainContainer:draw()
			buffer.draw()
		end
	end

	mainContainer:draw()
	buffer.draw()
end

scaleSlider.onValueChanged = function()
	update()
	mainContainer:draw()
	buffer.draw()
end
rangeSlider.onValueChanged = scaleSlider.onValueChanged
precisionSlider.onValueChanged = scaleSlider.onValueChanged

scaleSlider.roundValues, rangeSlider.roundValues, precisionSlider.roundValues = true, true, true

window.onResize = function(width, height)
	window.backgroundPanel.width, window.backgroundPanel.height = width, height - 3
	graph.width, graph.height = width, height - 3

	update()
end

graph.eventHandler = function(mainContainer, graph, eventData)
	if eventData[1] == "touch" then
		xDrag, yDrag = eventData[3], eventData[4]
	elseif eventData[1] == "drag" then
		xOffset, yOffset = xOffset + (eventData[3] - xDrag), yOffset + (eventData[4] - yDrag)
		mainContainer:draw()
		buffer.draw()

		xDrag, yDrag = eventData[3], eventData[4]
	elseif eventData[1] == "scroll" then
		scaleSlider.value = scaleSlider.value + eventData[5] * 10
		if scaleSlider.value < scaleSlider.minimumValue then
			scaleSlider.value = scaleSlider.minimumValue
		elseif scaleSlider.value > scaleSlider.maximumValue then
			scaleSlider.value = scaleSlider.maximumValue
		end

		update()

		mainContainer:draw()
		buffer.draw()
	end
end

---------------------------------------------------------------------------------------------------------

update()
mainContainer:draw()
buffer.draw()



