# $Id: Vorto.rb,v 1.25 2001/08/31 23:35:47 ser Exp $
#
# This represents a compound Esperanto word.  A compound word is a construction
# EO radicals forming a proper, well-constructed word.
module EO
	class Vorto
		include Enumerable
		# Part-of-speech, whether accusative or plural, the tense, the
		# participal.
		attr_reader :pos, :accusative, :plural, :tense, :participal, :correlative
		# Parts of speech
		NOUN = "n"
		ADJECTIVE = "adj"
		ADVERB = "adv"
		VERB = "v"
		WORD = "w"
		MEM = "vorto"
		NAME = "name"
		PRONOUN = "pronoun"
		CORRELATIVE = "correl."
		# Tenses
		PRESENT = "present"
		PAST = "past"
		FUTURE = "future"
		ACTIVE = "active"		# Also participal
		PASSIVE = "passive"	# Also participal
		INFINITIVE = "infinitive"
		IMPERITIVE = "imperitive"
		CONDITIONAL = "conditional"
		SUBJECTIVE = "subjective"

		def initialize
			@radikoj = []
			@valid = 0
			@structure = ""
			clear
		end

		# Returns the validity rating.  Higher values mean more validity.
		def validity
			@valid
		end

		# Clears the word to no meaning
		def clear
			@radikoj.clear
			@nomo = false
			@pos=@correlative=@accusative=@plural=@tense=@participal=nil
		end

		# Add a Radiko to this word.  Order is important.  Synonym for append()
		def <<( part )
			append part
		end

		# Add a Radiko to this word.  Order is important
		def append( v )
			@structure << v.tipo
			@structure << v.subtipo
			if v.tipo == "S"
				@nomo = true
				@radikoj << v
				@pos = NAME
			else
				@radikoj << v
			end
		end

		# The following matches are used by fixate!.
		# MATCH1 checks that the base word construction is properly formed; that
		# is, PREFIX + RADICAL + SUFFIX, possibly repeated
		MATCH1 = /^((((w.|c.|p.)+(r.)*)|((w.|c.|p.)*(r.)+))(s.)*(ga|ge|go)?)+(gi|gs|(ga|ge|go)(gj)?(gn)?)$/
		# MATCH2 checks that the ending of the word is proper; that is, that it
		# ends in either a verb ending, or [aeo]j?n?
		MATCH2 = /((g[^oaenj])|([^g].))(gi|gs|(ga|ge|go)(gj)?(gn)?)$/
		# MATCH3 matches self-standing words, such as correlative compounds or
		# memstara words.
		MATCH3 = /^([cw].)+(g[jn])?$/
		MATCH4 = /^cm(ga)?(gj)?(gn)?$/

		# Some further validation:  check that verb endings are matched with
		# r[iI] roots.  Check that cNs can be joined, but c[^N] aren't.
		
		# Validates the word.  Sets the word parts of speech.
		def fixate!
			#puts "Matching #{@structure} (#{anglu})"
			@valid += 1 if @structure =~ MATCH1
			#puts "MATCH1 -> #@valid"
			@valid += 1 if @structure =~ MATCH2 and @valid > 0
			#puts "MATCH2 -> #@valid"
			@valid += 2 if @structure =~ MATCH3
			#puts "MATCH3 -> #@valid"
			@valid += 2 if @structure =~ MATCH4
			#puts "MATCH4 -> #@valid"
			for part in @radikoj.reverse
			  if suffix part
				 @radikoj.pop
			  else
				 break
			  end
			end
		end

		def each()
			@radikoj.each { |n| yield n }
		end

		def to_s
			rv = ""
			@radikoj.each do |vorto|
				rv << vorto.vorto
			end
			rv
		end

		def anglu
			angla = ""
			@radikoj.reverse_each do |vorto|
				angla = "#{vorto.angla} #{angla}"
			end
			angla += "(#@pos"
			angla += " #@correlative" if @correlative
			angla += " accus." if @accusative
			angla += " plural" if @plural
			angla += " #@participal" if @participal
			angla += " #@tense" if @tense
			angla += " partic." if @participal
			#angla += ")"
			angla += " #@valid)"
		end

		private
		# Check for [oae]j?n?$ (noun, adverb, adjective)
		# If one of above, check for [iao]n?t (participal)
		# If POS not yet set, check for [iu]|[aiou]s (verb)
		def suffix part
			case part.tipo
			when 'g'
				case part.subtipo
				when 'a'
					@pos = ADJECTIVE
				when 's'
					@pos = VERB
					check_tense part
				when 'e'
					@pos = ADVERB
				when 'i'
					@pos = VERB
					@tense = INFINITIVE
				when 'j'
					@plural = true
				when 'n'
					@accusative = true
				when 'o'
					@pos = NOUN
				end
			when 'w'
				@pos = MEM
				return false
			when 'c'
				@pos = NOUN unless @pos
				@correlative = CORRELATIVE
				@correlative = PRONOUN if part.subtipo == 'm'
				return false
			when 's'
				case part.subtipo
				when 'i'
					if part.angla =~ /Partic$/
						case part.vorto
						when /^i/
							@tense = PAST
						when /^o/
							@tense = FUTURE
						when /^a/
							@tense = PRESENT
						end
						case part.vorto
						when /n/
							@participal = ACTIVE
						else
							@participal = PASSIVE
						end
					end
				else
					return false
				end
			else
				return false
			end
			return true
		end

		def check_tense part
			case part.vorto
			when 'is'
				@tense = PAST
			when 'as'
				@tense = PRESENT
			when 'os'
				@tense = FUTURE
			when 'u'
				@tense = IMPERITIVE
			when 'us'
				@tense = SUBJECTIVE
			end
		end
	end

	class String
		def angla
			self
		end
		def vorto
			self
		end
	end
end
