module REXML
	# If you add a method, keep in mind two things:
	# (1) the first argument will always be a list of nodes from which to
	# filter.  In the case of context methods (such as position), the function
	# should return an array with a value for each child in the array.
	# (2) all method calls from XML will have "-" replaced with "_".
	# Therefore, in XML, "local-name()" is identical (and actually becomes)
	# "local_name()"
	class Functions
		def Functions::text( nodes )
			nodes.find_all { |i| i.kind_of? Text }
		end

		def Functions::last( elements )
			return elements.size
		end

		def Functions::position( nodes )
			count = 0
			nodes.collect{|item| count+=1}
		end

		def Functions::count( nodes )
			nodes.size
		end

		# Since REXML is non-validating, this method is not implemented as it
		# requires a DTD
		def Functions::id( nodes )
		end

		# NOT TESTED
		def Functions::local_name( nodes )
			nodes.collect do |node| node.local_name end
		end

		# NOT TESTED
		def Functions::namespace_uri( nodes )
			nodes.collect do |node|
				if node.kind_of? Namespace
					node.namespace
				else
					""
				end
			end
		end

		def Functions::name( nodes )
			nodes.collect do |element| 
				if element.kind_of? Namespace
					element.expanded_name
				else
					""
				end
			end.compact
		end

		# UNTESTED
		def Functions::string( nodes, object )
			if object.kind_of? Text
				object.to_s
			elsif object.kind_of? Element
				object.name
			else
				object.to_s
			end
		end

		# UNTESTED
		def Functions::concat( nodes, *objects )
			objects.join
		end

		# UNTESTED
		def Functions::starts_with( nodes, string, test )
			string.index(test) == 0
		end

		# UNTESTED
		def Functions::contains( nodes, string, test )
			string.include? test
		end

		# UNTESTED
		def Functions::substring_before( nodes, string, test )
			string[ 0...string.index(test) ]
		end

		# UNTESTED
		def Functions::substring_after( nodes, string, test )
			string[ string.index(test)+1..-1 ]
		end

		# UNTESTED
		def Functions::substring( nodes, string, start, length=0 )
			length = string.size if length==0
			string[start-1,length]
		end

		# UNTESTED
		def Functions::string_length( nodes, string )
			string.size
		end

		# UNTESTED
		def Functions::normalize_space( nodes, string=nil )
			string = nodes[0].text if string.nil
			string.strip.gsub(/\s+/m, ' ')
		end

		# UNTESTED
		def Functions::translate( nodes, string, tr1, tr2 )
			string.tr tr1,tr2
		end

		# UNTESTED
		def Functions::boolean( nodes, object=nil )
			if object.kind_of? String
				if object =~ /\d+/
					return object.to_f != 0
				else
					return object.size > 0
				end
			else
				nodes.size > 0
			end
		end

		# UNTESTED
		def Functions::not( nodes, object )
			return object == "true" if object.is_a? String
			not object
		end

		# UNTESTED
		def Functions::true( nodes )
			true
		end

		# UNTESTED
		def Functions::false( nodes )
			false
		end

		# UNTESTED
		def Functions::lang( nodes, language )
			nodes.collect do |node|
				if node.kind_of? Element
					lang = false
					until node.nil? or lang
						lang = compare_language node.attributes["xml:lang"], language
						node = node.parent
					end
				end
			end
		end

		def Functions::compare_language lang1, lang2
			lang2.downcase.index(lang1.downcase) == 0
		end

		def Functions::number( nodes, object=nil )
		end

		def Functions::sum( nodes )
		end
		
		def Functions::floor( nodes, number )
			number = number.to_f if number.kind_of? String
			number.floor
		end

		def Functions::ceiling( nodes, number )
			number = number.to_f if number.kind_of? String
			number.ceil
		end

		def Functions::round( nodes, number )
			number = number.to_f if number.kind_of? String
			number.round
		end
	end
end
