--OSDrawing--

	local _w, _h = term.getSize()
	
	Screen = {
		Width = _w,
		Height = _h
	}

	DrawEntity = function(entity)
		entity:Draw()
		OSDrawing.releaseOffset() --just incase there is an offset
	end

	DrawApplicationWindows = function(application)
		local containsCurrent = false
		for _,window in pairs(application.windows) do
			if window == OSCurrentWindow then
				containsCurrent = true
			else
				window:Draw()
				OSDrawing.releaseOffset() --just incase there is an offset
			end
		end

		if containsCurrent then
			OSCurrentWindow:Draw()
		end
	end

	Draw = function ()
		--draw the desktop
		desktop:Draw()

		--draw all windows

		--TODO: figure out how to correctly order the windows
		--[[
		for _,application in pairs(OSInterfaceApplications.list) do
		OSDrawing.MainLoop.DrawApplicationWindows(application)
		end
		]]--

		local currentApplication = OSInterfaceApplications.current()
		for _,key in ipairs(OSInterfaceApplications.order) do
			local application = OSInterfaceApplications.list[key]
			--don't render the current applications windows, we do that later
			if application.id ~= currentApplication.id then
				OSDrawing.DrawApplicationWindows(application)
			end
		end

		-- draw the current application
		OSDrawing.DrawApplicationWindows(currentApplication)

		--draw other entities

		OSDrawing.releaseOffset() --just incase there is an offset (which shouldn't be there!!)

		for _,entity in ipairs(OSInterfaceEntities.list) do
			OSDrawing.DrawEntity(entity)
			if OSServices.shouldBreakDrawLoop then
				break
			end
		end
		OSDrawing.releaseOffset() --just incase there is an offset (which shouldn't be there!!)
		OSDrawing.DrawBuffer()
	end

	Offset = {
	x = 0,
	y = 0
	}

	addOffset = function (_x, _y)
		OSDrawing.Offset.x = OSDrawing.Offset.x + _x - 1 --1 is subtracted as we want the units to be from 1, not 0
		OSDrawing.Offset.y = OSDrawing.Offset.y + _y - 1
	end

	setOffset = function (_x, _y)
		OSDrawing.Offset.x = _x - 1
		OSDrawing.Offset.y = _y - 1
	end

	releaseOffset = function ()
		OSDrawing.Offset.x = 0
		OSDrawing.Offset.y = 0
	end

	DrawCharacters = function (x, y, characters, textColour,bgColour)
		OSDrawing.WriteStringToBuffer(x, y, characters, textColour, bgColour)
	end
	
	DrawBlankArea = function (x, y, w, h, colour)
		OSDrawing.DrawArea (x, y, w, h, " ", colour, 1)
	end

	DrawArea = function (x, y, w, h, character, bgColour, textColour)
		--width must be greater than 1, other wise we get a stack overflow
		if w < 0 then
			w = w * -1
		elseif w == 0 then
			w = 1
		end

		for ix = 1, w do
			local currX = x + ix - 1
			for iy = 1, h do
				local currY = y + iy - 1
				OSDrawing.WriteToBuffer(currX, currY, character, textColour, bgColour)
			end
		end
	end


	DrawShadow = function (x, y, w, h) --the x, y etc are of the entity that shadow is being made from
		--draw the vertical shadow

		for iy = 1, h do
			OSDrawing.WriteStringToBuffer(x + w, iy + y, " ", colours.black, colours.black)
		end
		for ix = 1, w - 1 do
			OSDrawing.WriteStringToBuffer(ix + x, y + h, " ", colours.black, colours.black)
		end
	end

	DrawImage = function(xPos,yPos,tImage)
		for y=1,#tImage do
			local tLine = tImage[y]
			for x=1,#tLine do
				if tLine[x] > 0 then
					OSDrawing.WriteToBuffer(x + xPos - 1, y + yPos - 1, " ", colours.black,tLine[x])
				end
			end
		end
	end


	DrawCharactersCenter = function(x, y, w, h, characters, textColour,bgColour)
		w = w or OSDrawing.Screen.Width
		h = h or OSDrawing.Screen.Height
		x = x or math.floor((w - #characters) / 2)
		y = y or math.floor(h / 2)

		OSDrawing.DrawCharacters(x, y, characters, textColour, bgColour)
	end

	Clear = function (_colour)
		_colour = _colour or colours.black
		OSDrawing.ClearBuffer()
		OSDrawing.DrawBlankArea(1, 1, OSDrawing.Screen.Width, OSDrawing.Screen.Height, _colour)
	end

	Buffer = {}
	BackBuffer = {}

	DrawBuffer = function()
		for y,row in pairs(OSDrawing.Buffer) do
			for x,pixel in pairs(row) do
				local shouldDraw = true
				local hasBackBuffer = true

				if OSDrawing.BackBuffer[y] == nil or OSDrawing.BackBuffer[y][x] == nil or #OSDrawing.BackBuffer[y][x] ~= 3 then
					hasBackBuffer = false
				end
				if hasBackBuffer and OSDrawing.BackBuffer[y][x][1] == OSDrawing.Buffer[y][x][1] and OSDrawing.BackBuffer[y][x][2] == OSDrawing.Buffer[y][x][2] and OSDrawing.BackBuffer[y][x][3] == OSDrawing.Buffer[y][x][3] then
					shouldDraw = false
				end
				--shouldDraw = true
				if shouldDraw then
					term.setBackgroundColour(pixel[3])
					term.setTextColour(pixel[2])
					term.setCursorPos(x, y)
					term.write(pixel[1])
				end
			end
		end
		--OSDrawing.BackBuffer = OSDrawing.Buffer
		OSDrawing.Buffer = {}
		term.setCursorPos(1,10)
	end

	ClearBuffer = function()
		OSDrawing.Buffer = {}
	end

	WriteStringToBuffer = function (x, y, characters, textColour,bgColour)
		for i = 1, #characters do
   			local character = characters:sub(i,i)
   			OSDrawing.WriteToBuffer(x + i - 1, y, character, textColour, bgColour)
		end
	end

	WriteToBuffer = function(x, y, character, textColour,bgColour)
		y = y + OSDrawing.Offset.y
		x = x + OSDrawing.Offset.x
		OSDrawing.Buffer[y] = OSDrawing.Buffer[y] or {}
		OSDrawing.Buffer[y][x] = {character, textColour, bgColour}
	end