or
 is used, is should search for the closing tag, not until the end of the docblock.
 * - Sometimes the script hangs (after the first sentence).
 */ 

include ( "packages/Base/trunk/src/base.php" );
function __autoload( $class_name )
{
    if ( ezcBase::autoload( $class_name ) )
    {
        return;
    }
}

// Setup console parameters
$params = new ezcConsoleInput();
$file = new ezcConsoleOption( 'f', 'file', ezcConsoleInput::TYPE_STRING );
$file->shorthelp = "File that should be checked with ispell.";
$file->mandatory = true;
$params->registerOption( $file );

$noBackup = new ezcConsoleOption( 'B', 'nobackup', ezcConsoleInput::TYPE_NONE );
$noBackup->shorthelp = "Set this flag if no backup should be created.";
$params->registerOption( $noBackup );

$checkComponentWords = new ezcConsoleOption( 'c', 'check_component_words', ezcConsoleInput::TYPE_NONE );
$checkComponentWords->shorthelp = "Set this flag if the component words (like ezcArchive, ezcConsoleTools, etc) should be checked.";
$params->registerOption( $checkComponentWords );

$personalDictionary = new ezcConsoleOption( 'p', 'personal_dictionary', ezcConsoleInput::TYPE_STRING );
$personalDictionary->shorthelp = "Set a personal dictionary";
$params->registerOption( $personalDictionary );


try
{
    $params->process();
}
catch ( ezcConsoleOptionException $e )
{
    echo $e->getMessage(). "\n\n";
    echo $params->getSynopsis() . "\n\n";

    foreach ( $params->getOptions() as $option )
    {
        echo "-{$option->short}, --{$option->long}\t    {$option->shorthelp}\n";
    }

    echo "\n";
    exit();
}

// We should have a file name.
$file = $params->getOption( "file" )->value;
$checkComponentWords = $params->getOption( "check_component_words" )->value;
$personalDictionary = $params->getOption( "personal_dictionary" )->value;
if( $personalDictionary == false ) $personalDictionary = null;

$fp = fopen( $file, "r" );
if( $fp === false )
{
    exit( "Couldn't open the file: $file" );
}

$ispell = new ISpell( $personalDictionary );
$i = 0;

$inDocBlock = false;
$skip = false;


while( $sentence = fgets( $fp ) )
{
    if( preg_match( "@^\s*/\*\*\s*$@", $sentence ) )
    {
        $inDocBlock = true;
    }
    else if( $inDocBlock && preg_match( "@\s*\*/\s*$@", $sentence ) )
    {
        $inDocBlock = false;
        $skip = false;
    }
    else if( $inDocBlock && !$skip)
    {
        // If something contains an @, skip the rest until the new docblock.
        if( preg_match( "|@|", $sentence ) ) 
        {
            $skip = true;
        }
        else if( preg_match( "||", $sentence ) ) 
        {
            $skip = true;
        }
        else
        {
            $pos = strpos( $sentence, "*" ) + 1;

            $testForSpelling = substr( $sentence, $pos );
            $correct = $ispell->check( $testForSpelling, !$checkComponentWords ); 

            $sentence = substr( $sentence, 0, $pos ) . $correct;
        }
    }

    $correctedSentences[$i] = $sentence;
    $i++;
}

fclose( $fp );

// Backup
if ( !$params->getOption( "nobackup" )->value )
{
    copy( $file, $file.".bak" );
}

$fp = fopen( "$file", "w" );

if( $fp === false )
{
    exit ( "Cannot open the file <$file> for writing." );
}

// Write the changes
for( $i = 0; $i < sizeof( $correctedSentences ); $i++)
{
    fwrite( $fp, $correctedSentences[$i] );
}

// And close.
fclose( $fp);

   

class ISpell
{
    private $stdin = null;

    private $pipes;

    private $ispell;


    public function __construct( $personalDictionary = null )
    {
        $this->stdin = fopen("php://stdin","r");

        $descriptorspec = array(
            0 => array("pipe", "r"),  // stdin is a pipe that the child will read from
            1 => array("pipe", "w"),  // stdout is a pipe that the child will write to
            2 => array("file", "/tmp/error-output.txt", "a") // stderr is a file to write to
        );

        $personalDictionary = ( $personalDictionary === null ? "" : "-p $personalDictionary" ); 

        $this->ispell = proc_open( "/usr/bin/ispell -a $personalDictionary", $descriptorspec, $this->pipes ); 

        if ( !is_resource( $this->ispell ) ) 
        {
            die ("Cannot open Ispell\n");
        }
    }

    public function __destruct()
    {
        fclose( $this->stdin );
    }


    /**
     * Returns the corrected sentence.
     * 
     * This function requires input from the user.
     */
    public function check( $sentence, $skipComponentWords = true )
    {
        $newSentence = "";

        $read = fread( $this->pipes[1] , 1024); // read introduction, or anything and ignore.
        fwrite( $this->pipes[0], "$sentence\n" ); // write the sentence to ispell.

        $prefPos = 0;

        // Read the output
        while ( ($result = fgets( $this->pipes[1], 1024 ) ) && $result != "\n" )
        {
            // Each word is on a new line.
            if( !$this->isOk( $result ) )
            {
                list( $word, $position, $suggestions ) = $this->parseResult( $result );

                if( !( $skipComponentWords && preg_match( "@^ezc[A-Z]@", $word ) ) )
                {
                    $this->showHelp( $sentence, $word, $position, $suggestions );
                    $line = $this->getCorrection();

                    // Update the word, if something is filled in.
                    if( $line != "" )
                    {
                        // Add to the private dictionary
                        if( $line == "*" )
                        {
                            fwrite( $this->pipes[0], "*$word\n" ); // write the sentence to ispell.
                            echo ("WORD APPENDED");
                        }
                        else
                        {
                            $newSentence .= substr( $sentence, $prefPos, $position - $prefPos ) .  $line;
                            $prefPos = $position + strlen( $word );
                        }
                    }
                }
            }
        }

        $position = strlen( $sentence );
        $newSentence .= substr( $sentence, $prefPos, $position - $prefPos );

        return $newSentence;
    }

    private function showHelp( $sentence, $word, $position, $suggestions )
    {
        echo ("\n");
        echo ( $sentence . "\n" );

        echo ("Word not recognized: " . $word . "\n\n" );
        echo $suggestions;
    }
    
    private function getCorrection()
    {
        echo ("\nType replacement (return to accept): ");
        $line = rtrim( fgets($this->stdin, 1024) );
        return $line;
    }


    private function isOk( $result )
    {
        if( $result[0] == "*" ) return true;
        if( $result[0] == "+" ) return true;
        if( $result[0] == "-" ) return true;
        if( $result[0] == "\n" ) return true;

        return false;
    }

    private function parseResult( $result )
    {
        if( $result[0] == "&" )
        {
            $split =  split( " ", $result );
            $position = substr( $split[3], 0, -1 );

            return array( $split[1], $position, $result ); // $result should be suggestions.
        }
        else if( $result[0] == "#" )
        {
            $split =  split( " ", $result );

            return array( $split[1], $split[2], false );

        }
    }

}



?>