--[[
    lama is a MUD server made in Lua.
    Copyright (C) 2013 Curtis Erickson

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
]]

--- Extension of the string library.
-- @author milkmanjack
module("ext.string", package.seeall)

--- Gets the next word in the given string.<br/>
-- A word is defined as the first series of unbroken alphanumeric characters.
-- Special delimiters can be defined for the word. For example, if the next
-- word starts with a single or double quote (', "), it will end with a
-- single or double quote, respectively. If neither are found after the
-- first, then it will merely return everything.<br/>
-- Also returns the remainder of the given string, if anything remains.
-- The remainder of the string has its whitespace truncated via
-- string.truncate().
-- @param s String to get the next word from.
-- @return The word.
-- @return The remainder of the string, or nil.
function string.getWord(s)
	if not s then return nil, nil end

	local length = string.len(s)

	-- handles empty strings
	if length < 1 then
		return "", nil
	end

	-- handles 1 character long strings
	if length == 1 then
		return s, nil
	end

	local _start, _end = 1, nil
	local first = string.sub(s, 1, 1)
	-- quotation mark delimiters
	if first == "'" or first == "\"" then
		_start = 2
		_end = string.find(s, first, _start)

	-- space delimiter
	else
		_end = string.find(s, " ", _start)
	end

	-- grab the observed word
	local word = string.sub(s, _start, (_end and _end-1) or nil)

	-- skip whitespace after the word
	if _end and _end < length then
		_end = _end+1
	end

	return word, (_end and _end < length and string.truncate(string.sub(s, _end))) or ""
end

--- Returns an iterator that iterates over the words within
-- the given string.
-- @param s String to iterate over.
-- @return Word iterator for the given string.
function string.getWords(s)
	local a, b = string.getWord(s)
	return function()
		-- return nil when done
		if not a then
			return nil
		end

		-- store previous iteration results
		local valueA, valueB = a, b

		-- iterate
		a,b = string.getWord(b)

		-- return previous results
		return valueA, valueB
	end
end

--- Remove whitespace from the front and back of a string.
-- @param s String to be truncated.
-- @return Truncated version of the string.
function string.truncate(s)
	local _start, _end = 1, string.len(s)
	while _start < _end and string.sub(s, _start, _start) == " " do
		_start = _start+1
	end

	while _end > _start and string.sub(s, _end, _end) == " " do
		_end = _end-1
	end

	return string.sub(s, _start, _end)
end

--- Matches a string of keywords to another string of keywords
-- @param haystack Keywords to compare to.
-- @param needle Keywords to compare.
-- @return Returns 'haystack' on a successful match.<br/>nil otherwise.
function string.matchKeywords(haystack, needle)
	haystack = string.lower(haystack)
	needle = string.lower(needle)
	local _haystack = {}
	for i in string.gmatch(haystack, "([a-zA-Z0-9'-]+)") do
		table.insert(_haystack, i)
	end

	for i in string.gmatch(needle, "([a-zA-Z0-9'-]+)") do
		local found = false
		for j, v in ipairs(_haystack) do
			print(i, v)
			if string.find(v, i) == 1 then
				found = true
			end
		end

		-- every keyword must be found, or it's not a match
		if not found then
			return false
		end
	end

	return true
end
