<?php
/**
 * The SpellChecker_hunspell:: class provides a driver for the 'hunspell' program.
 *
 * Copyright 2005-2009 The Horde Project (http://www.horde.org/)
 *
 * See the enclosed file COPYING for license information (LGPL). If you
 * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
 *
 * @author  Chuck Hagenbuch <chuck@horde.org>
 * @package IMP_SpellChecker
 */
/* modifications by Laszlo L. Tornoci, based on SpellChecker_aspell */
class IMP_SpellChecker_hunspell extends IMP_SpellChecker {

    var $_path = 'hunspell';

    /**
     *
     */
    function spellCheck($text)
    {
        if ($this->_html) {
            $input = strtr($text, "\n", ' ');
        } else {
            $words = $this->_getWords($text);
            if (!count($words)) {
                return array('bad' => array(), 'suggestions' => array());
            }
            $input = implode(' ', $words);
        }

        $charset = NLS::getCharset();
        // Descriptor array.
        $descspec = array(
            0 => array('pipe', 'r'),
            1 => array('pipe', 'w'),
            2 => array('pipe', 'w')
        );

        $process = proc_open($this->_cmd(), $descspec, $pipes);
        if (!is_resource($process)) {
            require_once 'PEAR.php';
            return PEAR::raiseError('spellcheck failed', null, null, null,
                                    $this->_cmd());
        } else {
              Horde::logMessage('Spellcheck debug: prog run=' . $this->_cmd(), __FILE__, __LINE__, PEAR_LOG_DEBUG);
        }
        // Write to stdin.
//        if ($this->_encoding) {
//           $input = String::convertCharset($input, $charset, $this->_encoding);
//        }
        // The '^' character tells aspell to spell check the entire line.
        $input2 = '^' . $input;
        Horde::logMessage('Spellcheck debug: input=' . $input2, __FILE__, __LINE__, PEAR_LOG_DEBUG);
        fwrite($pipes[0], $input2);
        fclose($pipes[0]);

        // Read stdout.
        $out = '';
        while (!feof($pipes[1])) {
            $out .= fread($pipes[1], 8192);
        }
        fclose($pipes[1]);
        Horde::logMessage('Spellcheck debug: output=' . $out, __FILE__, __LINE__, PEAR_LOG_DEBUG);

        // Read stderr.
        $err = '';
        while (!feof($pipes[2])) {
            $err .= fread($pipes[2], 8192);
        }
        fclose($pipes[2]);

        // We can't rely on the return value of proc_close:
        // http://bugs.php.net/bug.php?id=29123
        proc_close($process);

        if (strlen($out) === 0) {
            require_once 'PEAR.php';
            if ($this->_encoding) {
                $err = String::convertCharset($err, $this->_encoding, $charset);
            }
            return PEAR::raiseError('spellcheck failed: ' . $err);
        }

        if ($this->_encoding) {
            $out = String::convertCharset($out, $this->_encoding, $charset);
        }

        // Parse output.
        $bad = array();
        $suggestions = array();
        $lines = explode("\n", $out);
        foreach ($lines as $line) {
            $line = trim($line);
            if (empty($line)) {
                continue;
            }

            @list(,$word,) = explode(' ', $line, 3);

            if ($this->_inLocalDictionary($word) || in_array($word, $bad)) {
                continue;
            }

            switch ($line[1]) {
            case '#':
                // Misspelling with no suggestions.
                $bad[] = $word;
                $suggestions[] = array();
                break;

            case '&':
                // Suggestions.
                $bad[] = $word;
                $suggestions[] = array_slice(explode(', ', substr($line, strpos($line, ':') + 2)), 0, $this->_maxSuggestions);
                break;
            }
        }

        return array('bad' => $bad, 'suggestions' => $suggestions);
    }

    function _cmd()
    {
        $args = '';

        $args .= ' -d ' . $this->_locale;
        $args .= ' -i ' . $this->_encoding;

        if ($this->_html) {
            $args .= ' -H';
        }

        return sprintf('%s -a %s', $this->_path, $args);
    }

}