#!/usr/bin/python
# -*- coding: utf-8 -*-

# Copyright 2008 - 2009 Harri Pitkänen (hatapitk@iki.fi)
# Test program for openoffice.org
# This program requires OpenOffice.org, openoffice.org-voikko and python-uno.

# 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 2 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, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

import sys
import getopt
import codecs
import uno
import voikkoutils
from subprocess import Popen
from time import sleep
from os import getpid
from locale import getpreferredencoding
from com.sun.star.lang import Locale, DisposedException
from com.sun.star.beans import PropertyValue
from com.sun.star.connection import NoConnectException

# Constants
LOCALE = Locale()
LOCALE.Language = "fi"
ENCODING = voikkoutils.get_preference('encoding')
COREVOIKKO = voikkoutils.get_preference('corevoikko')
HYPHENTESTS = COREVOIKKO + "/tests/ooovoikkotest/hyphen.txt"
LINE_ENC = getpreferredencoding()

def unoPropertySeq(props):
	propList = []
	for (name, value) in props.items():
		property = PropertyValue()
		property.Name = name
		property.Value = value
		propList.append(property)
	return tuple(propList)

def hyphenateStdin():
	"Hyphenate lines from stdin"
	properties = ()
	line = sys.stdin.readline()
	while line.endswith('\n'):
		line = unicode(line, LINE_ENC).strip()
		if len(line) > 0:
			hyphens = hyphenator.createPossibleHyphens(line, LOCALE, properties)
			if hyphens == None:
				print line.encode(LINE_ENC)
			else:
				print hyphens.PossibleHyphens.encode(LINE_ENC)
		line = sys.stdin.readline()

def spellStdin():
	"Check spelling of words from stdin"
	properties = ()
	line = sys.stdin.readline()
	while line.endswith('\n'):
		line = unicode(line, LINE_ENC).strip()
		if len(line) > 0:
			isValid = speller.isValid(line, LOCALE, properties)
			suggestions = speller.spell(line, LOCALE, properties)
			if (isValid and suggestions != None) or \
			   (not isValid and suggestions == None):
				print "ERROR: inconsistent results from isValid and spell"
			if isValid:
				print (u"C: " + line).encode(LINE_ENC)
			else:
				print (u"W: " + line).encode(LINE_ENC)
				for sug in suggestions.getAlternatives():
					print (u"S: " + sug).encode(LINE_ENC)
		line = sys.stdin.readline()

def grammarTests():
	"Run automated grammar checker tests"
	aDocumentIdentifier = "someDocumentIdentifier"
	aText = u"Kissa on joten kuten Märkä."
	nStartOfSentencePos = 0
	nSuggestedBehindEndOfSentencePosition = 24
	aProperties = ()
	result = gc.doProofreading(aDocumentIdentifier, aText, LOCALE,
	         nStartOfSentencePos, nSuggestedBehindEndOfSentencePosition,
	         aProperties)
	
	assert result.aDocumentIdentifier == aDocumentIdentifier
	assert result.xFlatParagraph == None
	assert result.aText == aText
	assert result.aLocale == LOCALE
	assert result.xProofreader == gc
	
	# TODO: start/end of sentence positions are not necessarily correct.
	# Find out where these are actually needed and fix as necessary.
	assert result.nStartOfSentencePosition == nStartOfSentencePos
	# 26 is the position of the end of last error
	assert result.nBehindEndOfSentencePosition == 26
	assert result.nStartOfNextSentencePosition == 26
	
	errors = result.aErrors
	assert len(errors) == 2
	
	error = errors[0]
	assert error.nErrorStart == 9
	assert error.nErrorLength == 11
	assert error.nErrorType == 2 # TextMarkupType.PROOFREADING
	assert error.aShortComment == u"Virheellinen kirjoitusasu"
	assert error.aFullComment == u"Virheellinen kirjoitusasu"
	suggestions = error.aSuggestions
	assert len(suggestions) == 1
	assert suggestions[0] == u"jotenkuten"
	
	error = errors[1]
	assert error.nErrorStart == 21
	assert error.nErrorLength == 5
	assert error.nErrorType == 2 # TextMarkupType.PROOFREADING
	assert error.aShortComment == u"Harkitse sanan kirjoittamista pienellä alkukirjaimella."
	assert error.aFullComment == u"Harkitse sanan kirjoittamista pienellä alkukirjaimella."
	suggestions = error.aSuggestions
	assert len(suggestions) == 1
	assert suggestions[0] == u"märkä"
	
	gc.ignoreRule(u"1", LOCALE) # GCERR_INVALID_SPELLING
	result = gc.doProofreading(aDocumentIdentifier, aText, LOCALE,
	         nStartOfSentencePos, nSuggestedBehindEndOfSentencePosition,
	         aProperties)
	assert len(result.aErrors) == 1
	
	gc.resetIgnoreRules()
	result = gc.doProofreading(aDocumentIdentifier, aText, LOCALE,
	         nStartOfSentencePos, nSuggestedBehindEndOfSentencePosition,
	         aProperties)
	assert len(result.aErrors) == 2
	
	print u"All grammar checker tests were successful."

def spellingTests():
	"Run the spell checker tests"
	properties = ()
	
	assert speller.isValid(u"märkä", LOCALE, properties)
	assert not speller.isValid(u"märrä", LOCALE, properties)
	
	suggestions = speller.spell(u"borrelioosipparantola", LOCALE, properties)
	assert suggestions.getWord() == u"borrelioosipparantola"
	assert suggestions.getLocale().Language == LOCALE.Language
	assert suggestions.getFailureType() == 4 # SpellFailure::SPELLING_ERROR
	assert suggestions.getAlternativesCount() == 1
	assert suggestions.getAlternatives()[0] == u"borrelioosiparantola"
	
	print u"All spell checker tests were successful."

def hyphenTests():
	"Run the hyphenator tests"
	try:
		inputfile = codecs.open(HYPHENTESTS, "r", ENCODING)
		testcount = 0
		failcount = 0
		section = u"(none)"
		inputwords = []
		expresults = []
		while True:
			line_orig = inputfile.readline()
			if line_orig == u'': break
			line = line_orig.strip()
			commentstart = line.find(u"#")
			if commentstart != -1: line = line[:commentstart].strip()
			if line.startswith(u'[') and line.endswith(u']'):
				section = line[1:-1]
				continue
			parts = line.split()
			if len(parts) == 0: continue
			inputword = parts[0].strip()
			expresult = parts[1].strip()
			testcount = testcount + 1
			properties = unoPropertySeq(eval("{" + section + "}"))
			hyphens = hyphenator.createPossibleHyphens(inputword, LOCALE, properties)
			if hyphens == None and inputword != expresult:
				print u'Hyphenation test failed in section "%s":' % section
				print u'  Expected "%s", got "%s"' % (expresult, inputword)
				failcount = failcount + 1
			if hyphens != None and hyphens.PossibleHyphens != expresult:
				print u'Hyphenation test failed in section "%s":' % section
				print u'  Expected "%s", got "%s"' % (expresult, hyphens.PossibleHyphens)
				failcount = failcount + 1
		inputfile.close()
		if failcount == 0:
			print u"All %i hyphenation tests were successful." % testcount
			return True
		else:
			print u"%i out of %i hyphenation tests failed." % (failcount, testcount)
			return False
	except IOError:
		sys.stderr.write("Could not read from file " + HYPHENTESTS + "\n")
		sys.exit(1)

# Read command line options
(opts, args) = ([], [])
try:
	(opts, args) = getopt.getopt(sys.argv[1:], "", ["hyphenate", "spell", "suggest"])
except getopt.GetoptError:
	sys.stderr.write("Usage: ooovoikkotest             (run only developer tests)\n")
	sys.stderr.write("Usage: ooovoikkotest --hyphenate (hyphenate words from stdin)\n")
	sys.stderr.write("Usage: ooovoikkotest --spell     (check spelling of words from stdin)\n")
	sys.exit(1)

# Start OpenOffice.org instance
CONSTR = "pipe,name=ooovoikkotest" + str(getpid()) + ";urp;"
ooo = Popen(["ooffice", "-accept=" + CONSTR, "-headless"])

# Connect to office and obtain the service manager
localContext = uno.getComponentContext()
resolver = localContext.ServiceManager.createInstanceWithContext(
           "com.sun.star.bridge.UnoUrlResolver", localContext)
while True:
	try:
		ctx = resolver.resolve("uno:" + CONSTR + "StarOffice.ComponentContext")
	except NoConnectException:
		sleep(1)
		continue
	break
smgr = ctx.ServiceManager

# Initialize the hyphenator
hyphenator = smgr.createInstance("voikko.Hyphenator")
hyphenator.initialize(())

# Initialize the spell checker
speller = smgr.createInstance("voikko.SpellChecker")
speller.initialize(())

# Initialize the grammar checker
gc = smgr.createInstance("voikko.GrammarChecker")
gc.initialize(())

# Run automated test
hyphenTests()
spellingTests()
grammarTests()

if "--hyphenate" in [opt[0] for opt in opts]:
	hyphenateStdin()
elif "--spell" in [opt[0] for opt in opts]:
	spellStdin()

# Terminate the office instance
desktop = smgr.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
try:
	desktop.terminate()
except DisposedException:
	pass
