--[[
Copyright (c) 2006-2013 LOVE Development Team

This software is provided 'as-is', without any express or implied
warranty.  In no event will the authors be held liable for any damages
arising from the use of this software.

Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:

1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
--]]

do

	local vera_ttf = love.filesystem.newFileData([[
[encoded data, 90354 characters]
	]], "Vera.ttf", "base64")
	
	local table_concat = table.concat
	local type = type

	local _newFont = love.graphics.newFont
	love.graphics.newFont = function(font, size)
		if type(font) == "number" or not font then
			size = font
			font = vera_ttf
		end
		return _newFont(font, size or 12)
	end

	love.graphics.setNewFont = function(...)
		local font = love.graphics.newFont(...)
		love.graphics.setFont(font)
		return font
	end

	local _getFont = love.graphics.getFont
	love.graphics.getFont = function(...)
		local font = _getFont()
		if not font then
			font = love.graphics.setNewFont(12)
		end
		love.graphics.getFont = _getFont
		return font
	end

	local _print = love.graphics.print
	love.graphics.print = function (...)
		love.graphics.getFont() -- make sure we have a font
		love.graphics.print = _print
		love.graphics.print(...)
	end

	local _printf = love.graphics.printf
	love.graphics.printf = function (...)
		love.graphics.getFont() -- make sure we have a font
		love.graphics.printf = _printf
		love.graphics.printf(...)
	end


	-- SHADERS

	local GLSL_VERSION = "#version 120"
	
	local GLSL_SYNTAX = [[
#define number float
#define Image sampler2D
#define extern uniform
#define Texel texture2D]]

	local GLSL_UNIFORMS = [[
#define ModelViewMatrix gl_ModelViewMatrix
#define ProjectionMatrix gl_ProjectionMatrix
#define ModelViewProjectionMatrix gl_ModelViewProjectionMatrix
#define NormalMatrix gl_NormalMatrix
uniform sampler2D _tex0_;]]

	local GLSL_VERT = {
		HEADER = [[
#define VERTEX

#define VertexPosition gl_Vertex
#define VertexTexCoord gl_MultiTexCoord0
#define VertexColor gl_Color

#define VaryingTexCoord gl_TexCoord[0]
#define VaryingColor gl_FrontColor]],

		FOOTER = [[
void main() {
	VaryingTexCoord = VertexTexCoord;
	VaryingColor = VertexColor;
	gl_Position = position(ModelViewProjectionMatrix, VertexPosition);
}]],
	}

	local GLSL_FRAG = {
		HEADER = [[
#define PIXEL

#define VaryingTexCoord gl_TexCoord[0]
#define VaryingColor gl_Color]],

		FOOTER = [[
void main() {
	// fix weird crashing issue in OSX when _tex0_ is unused within effect()
	float dummy = texture2D(_tex0_, vec2(.5)).r;
	gl_FragColor = effect(VaryingColor, _tex0_, VaryingTexCoord.st, gl_FragCoord.xy);
}]],
	}

	local function createVertCode(vertcode)
		local vertcodes = {
			GLSL_VERSION,
			GLSL_SYNTAX, GLSL_VERT.HEADER, GLSL_UNIFORMS,
			"#line 0",
			vertcode,
			GLSL_VERT.FOOTER,
		}
		return table_concat(vertcodes, "\n")
	end

	local function createFragCode(fragcode)
		local fragcodes = {
			GLSL_VERSION,
			GLSL_SYNTAX, GLSL_FRAG.HEADER, GLSL_UNIFORMS,
			"#line 0",
			fragcode,
			GLSL_FRAG.FOOTER
		}
		return table_concat(fragcodes, "\n")
	end

	function love.graphics._shaderCodeToGLSL(vertcode, fragcode)
		if vertcode then
			local s = vertcode:gsub("\r\n\t", " ")
			s = s:gsub("%w+(%s+)%(", "")
			if s:match("vec4%s*effect%(") then
				fragcode = vertcode -- first argument contains frag shader code
			end
			if not s:match("vec4%s*position%(") then
				vertcode = nil -- first argument doesn't contain vert shader code
			end
		end
		if fragcode then
			local s = fragcode:gsub("\r\n\t", " ")
			s = s:gsub("%w+(%s+)%(", "")
			if s:match("vec4%s*position%(") then
				vertcode = fragcode -- second argument contains vert shader code
			end
			if not s:match("vec4%s*effect%(") then
				fragcode = nil -- second argument doesn't contain frag shader code
			end
		end

		if vertcode then
			vertcode = createVertCode(vertcode)
		end
		if fragcode then
			fragcode = createFragCode(fragcode)
		end

		return vertcode, fragcode
	end

	function love.graphics._transformGLSLErrorMessages(message)
		local shadertype = message:match("Cannot compile (%a+) shader code")
		if not shadertype then return message end
		local lines = {"Cannot compile "..shadertype.." shader code:"}
		for l in message:gmatch("[^\n]+") do
			-- nvidia compiler message:
			-- 0(<linenumber>) : error/warning [NUMBER]: <error message>
			local linenumber, what, message = l:match("^0%((%d+)%)%s*:%s*(%w+)[^:]+:%s*(.+)$")
			if not linenumber then
				-- ati compiler message:
				-- ERROR 0:<linenumber>: error/warning(#[NUMBER]) [ERRORNAME]: <errormessage>
				linenumber, what, message = l:match("^%w+: 0:(%d+):%s*(%w+)%([^%)]+%)%s*(.+)$")
				if not linenumber then
					-- OSX compiler message (?):
					-- ERROR: 0:<linenumber>: <errormessage>
					what, linenumber, message = l:match("^(%w+): %d+:(%d+): (.+)$")
				end
			end
			if linenumber and what and message then
				lines[#lines+1] = ("Line %d: %s: %s"):format(linenumber, what, message)
			end
		end
		-- did not match any known error messages
		if #lines == 1 then return message end
		return table_concat(lines, "\n")
	end

	-- helper to transform a matrix from {{a,b,c}, {d,e,f}, ...} to
	-- {a, b, c, d, e, f, ...}
	local function flattenMatrices(mat, ...)
		if not mat then return end

		local tonumber = tonumber

		local ret,l = {}, 1
		ret.dimension = #mat

		for i = 1,#mat do
			for k = 1,#mat[i] do
				ret[l], l = tonumber(mat[i][k]), l+1
			end
		end

		return ret, flattenMatrices(...)
	end

	-- automagic uniform setter
	local function shader_dispatch_send(self, name, value, ...)
		local valuetype = type(value)
		if valuetype == "number" or valuetype == "boolean" then -- scalar
			self:sendFloat(name, value, ...)
		elseif valuetype == "userdata" and value:typeOf("Image") then
			self:sendImage(name, value)
		elseif valuetype == "userdata" and value:typeOf("Canvas") then
			self:sendCanvas(name, value)
		elseif valuetype == "table" then      -- vector or matrix
			valuetype = type(value[1])
			if valuetype == "number" or valuetype == "boolean" then
				self:sendFloat(name, value, ...)
			elseif valuetype == "table" then
				self:sendMatrix(name, flattenMatrices(value, ...))
			else
				error("Cannot send value (unsupported type: {"..valuetype.."}).")
			end
		else
			if valuetype == "userdata" and value.type then valuetype = value.type end
			error("Cannot send value (unsupported type: "..valuetype..").")
		end
	end

	local newShader = love.graphics.newShader
	function love.graphics.newShader(vertcode, fragcode)
		love.graphics.newShader = function(vertcode, fragcode)
			if love.filesystem then
				if vertcode and love.filesystem.exists(vertcode) then
					vertcode = love.filesystem.read(vertcode)
				end
				if fragcode and love.filesystem.exists(fragcode) then
					fragcode = love.filesystem.read(fragcode)
				end
			end
			return newShader(vertcode, fragcode)
		end

		local shader = love.graphics.newShader(vertcode, fragcode)
		local meta = getmetatable(shader)
		meta.send = shader_dispatch_send
		meta.sendBoolean = meta.sendFloat
		return shader
	end
end
