--[[
 Copyright (c) 2005, Niels Martin Hansen, Rodrigo Braz Monteiro
 All rights reserved.

 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions are met:

   * Redistributions of source code must retain the above copyright notice,
     this list of conditions and the following disclaimer.
   * Redistributions in binary form must reproduce the above copyright notice,
     this list of conditions and the following disclaimer in the documentation
     and/or other materials provided with the distribution.
   * Neither the name of the Aegisub Group nor the names of its contributors
     may be used to endorse or promote products derived from this software
     without specific prior written permission.

 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 POSSIBILITY OF SUCH DAMAGE.
 ]]

-- Variables with tables only hold references to the actual tables
-- Since a line is a table, a line needs to be copied, otherwise things break in bad ways
function copy_line(input)
	local output = {}
	output.kind = input.kind
	if input.kind == "scomment" then
		output.text = input.text
	elseif input.kind == "comment" or input.kind == "dialogue" then
		output.layer = input.layer
		output.start_time = input.start_time
		output.end_time = input.end_time
		output.style = input.style
		output.name = input.name
		output.margin_l = input.margin_l
		output.margin_r = input.margin_r
		output.margin_v = input.margin_v
		output.effect = input.effect
		output.text = input.text
		output.text_stripped = input.text_stripped		
		output.karaoke = input.karaoke -- Don't bother copying the karaoke table, it shouldn't be changed anyway
	end
	return output
end


-- Generates ASS hexadecimal string from R,G,B integer components, in &HBBGGRR& format
function ass_color(r,g,b)
	return string.format("&H%02X%02X%02X&",b,g,r)
end
-- Format an alpha-string for \Xa style overrides
function ass_alpha(a)
	return string.format("&H%02X&", a)
end
-- Format an ABGR string for use in style definitions (these don't end with & either)
function ass_style_color(r,g,b,a)
	return string.format("&H%02X%02X%02X%02X",a,b,g,r)
end

-- Extract colour components of an ASS colour
function extract_color(s)
	local a, b, g, r, d1, d2
	
	-- Try a style first
	d1, d2, a, b, g, r = string.find(s, "&H(%x%x)(%x%x)(%x%x)(%x%x)")
	if a then
		return tonumber(r, 16), tonumber(g, 16), tonumber(b, 16), tonumber(a, 16)
	end
	
	-- Then a colour override
	d1, d2, b, g, r = string.find(s, "&H(%x%x)(%x%x)(%x%x)&")
	if b then
		return tonumber(r, 16), tonumber(g, 16), tonumber(b, 16), 0
	end
	
	-- Then an alpha override
	d1, d2, a = string.find(s, "&H(%x%x)&")
	if a then
		return 0, 0, 0, tonumber(a, 16)
	end
	
	-- Ok how about HTML format then?
	d1, d2, r, g, b, a = string.find(s, "#(%x%x)(%x%x)?(%x%x)?(%x%x)?")
	if r then
		return tonumber(r or 0, 16), tonumber(g or 0, 16), tonumber(b or 0, 16), tonumber(a or 0, 16)
	end
	
	-- Failed...
	return nil
end
aegisub.colorstring_to_rgb = extract_color

-- Create an alpha override code from a style definition colour code
function alpha_from_style(scolor)
	local r, g, b, a = extract_color(scolor)
	return ass_alpha(a)
end

-- Create an colour override code from a style definition colour code
function color_from_style(scolor)
	local r, g, b = extract_color(scolor)
	return ass_color(r, g, b)
end


-- Converts HSV (Hue, Saturation, Value)  to RGB
function HSV_to_RGB(H,S,V)
	local r,g,b;

	-- Saturation is zero, make grey
	if S == 0 then
		r = V*255
		if r < 0 then
			r = 0
		end
		if r > 255 then
			r = 255
		end
		g = r
		b = r
		
	-- Else, calculate color
	else
		-- Calculate subvalues
		local Hi = math.floor(H/60)
		local f = H/60.0 - Hi
		local p = V*(1-S)
		local q = V*(1-f*S)
		local t = V*(1-(1-f)*S)
		
		-- Do math based on hue index
		if Hi == 0 then
			r = V*255.0
			g = t*255.0
			b = p*255.0
		elseif Hi == 1 then
			r = q*255.0
			g = V*255.0
			b = p*255.0
		elseif Hi == 2 then
			r = p*255.0
			g = V*255.0
			b = t*255.0
		elseif Hi == 3 then
			r = p*255.0
			g = q*255.0
			b = V*255.0
		elseif Hi == 4 then
			r = t*255.0
			g = p*255.0
			b = V*255.0
		elseif Hi == 5 then
			r = V*255.0
			g = p*255.0
			b = q*255.0
		end
	end
	
	r = math.floor(r)
	g = math.floor(g)
	b = math.floor(b)
	return r,g,b
end


-- Removes spaces at the start and end of string
function trim (s)
	return (string.gsub(s, "^%s*(.-)%s*$", "%1"))
end


-- UTF-8 string handling functions
-- Contributed by roxfan

-- Get the offset for the next character in the string, given the current offset
function next_utf_char(str, off)
	local leadb = string.byte(str, off)
	if leadb < 128 then
		return off+1
	elseif leadb < 224 then
		return off+2
	elseif leadb < 240 then
		return off+3
	elseif leadb < 248 then
		return off+4
	end
	aegisub.output_debug(string.format("bad utf-8 in %q at %d",str,off))
	return -1
end

-- Get the number of characters in the UTF-8 string (not the number of bytes)
function utf_len(str)
	local i = 1
	local len = 0
	while i<=string.len(str) do
		i = next_utf_char(str, i)
		len = len + 1
	end
	-- aegisub.output_debug(string.format("utf_len(%q)=%d",str,len))
	return len
end


-- Get the "head" and "tail" of a string, treating it as a sequence of words separated by one or more space-characters
function string.headtail(s)
	local a, b, head, tail = string.find(s, "(.-)%s+(.*)")
	if a then
		return head, tail
	else
		return s, ""
	end
end


-- Exclusive or of two boolean values
function xor(a, b)
	if a and not b then
		return a
	elseif b and not a then
		return b
	else
		return false
	end
end