<?php
/**
 * Zend Framework
 *
 * LICENSE
 *
 * This source file is subject to the new BSD license that is bundled
 * with this package in the file LICENSE.txt.
 * It is also available through the world-wide-web at this URL:
 * http://framework.zend.com/license/new-bsd
 * If you did not receive a copy of the license and are unable to
 * obtain it through the world-wide-web, please send an email
 * to license@zend.com so we can send you a copy immediately.
 *
 * @category   Zend
 * @package    Zend_Search_Lucene
 * @subpackage Document
 * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
 * @license    http://framework.zend.com/license/new-bsd     New BSD License
 */

/** Zend_Search_Lucene_Document */
require_once 'Zend/Search/Lucene/Document.php';

/**
 * Doc document.
 *
 * @category   Zend
 * @package    Zend_Search_Lucene
 * @subpackage Document
 * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
 * @license    http://framework.zend.com/license/new-bsd     New BSD License
 */
class Zend_Search_Lucene_Document_Doc extends Zend_Search_Lucene_Document{
    /**
     * File charset text encoding
     *
     * @var String
     */
    protected $_fileEncoding = 'CP1252';

    /**
     * Charset to be used internally
     *
     * @var String
     */
    protected $_internalEncoding = 'UTF-8';

    /**
     * Object constructor
     *
     * @param string  $fileName
     * @param boolean $storeContent
     * @param string  $fileEncoding
     * @param string  $internalEncoding
     * @throws Zend_Search_Lucene_Exception
     */
    private function __construct($fileName, $storeContent, $fileEncoding = null, $internalEncoding = null) {
        if (!is_null($fileEncoding)){
            $this->_fileEncoding = $fileEncoding;
        }
        if (!is_null($internalEncoding)){
            $this->_internalEncoding = $internalEncoding;
        }
        $fileHandle = fopen($fileName, "r");
        $fileContents = @fread($fileHandle, filesize($fileName));

        // Data holders
        $coreProperties = array('Key' => md5_file($fileName));


        $documentBody = $this->parseWord($fileContents);
        // Store filename
        $this->addField(Zend_Search_Lucene_Field::Text('filename', basename($fileName), $this->_internalEncoding));

        // Store contents
        if ($storeContent) {
            $this->addField(Zend_Search_Lucene_Field::Text('body', $documentBody, $this->_internalEncoding));
        } else {
            $this->addField(Zend_Search_Lucene_Field::UnStored('body', $documentBody, $this->_internalEncoding));
        }

        // Store meta data properties
        foreach ($coreProperties as $key => $value) {
            if ($value) $this->addField(Zend_Search_Lucene_Field::Text($key, $value, $this->_internalEncoding));
        }

        // Store title (if not present in meta data)
        if (!isset($coreProperties['title'])) {
            $this->addField(Zend_Search_Lucene_Field::Text('title', basename($fileName), $this->_internalEncoding));
        }
    }

    /**
     * Parse word document contents
     * ref: http://stackoverflow.com/questions/188452/reading-writing-a-ms-word-file-in-php/265017#265017
     *
     * @param string $line
     * @return string
     */
    protected function parseWord($line) {
        $lines = explode(chr(0x0D),$line);
        $outtext = "";
        foreach($lines as $thisline) {
            $pos = strpos($thisline, chr(0x00));
            if (($pos !== FALSE)||(strlen($thisline)==0)) {

            } else {
                $outtext .= $thisline."\n";
            }
        }
        if ($this->_fileEncoding != $this->_internalEncoding){
            $outtext = @iconv($this->_fileEncoding, $this->_internalEncoding.'//TRANSLIT//IGNORE', $outtext);
        }
        // Convert accentuated to non-accentuated characters
        // @todo latin alphabets only, no greek, chinese, russian ...
        $data = $this->_clearString($outtext);
        // Clean up
        // @todo this is only valid for latin alphabets, no greek, chinese, russian ...
        $data = trim(preg_replace('/([^a-z0-9 ])/i', ' ', $data));
        $data = preg_replace('/\s\s+/', ' ', $data);
        return $data;
    }

    /**
     * Add special characters used in CP1252
     * ref: http://php.net/manual/en/function.get-html-translation-table.php#76564
     *
     * @return array
     */
    protected function _get_html_translation_table_CP1252() {
        $trans = get_html_translation_table(HTML_ENTITIES);
        $trans[chr(130)] = '&sbquo;';    // Single Low-9 Quotation Mark
        $trans[chr(131)] = '&fnof;';    // Latin Small Letter F With Hook
        $trans[chr(132)] = '&bdquo;';    // Double Low-9 Quotation Mark
        $trans[chr(133)] = '&hellip;';    // Horizontal Ellipsis
        $trans[chr(134)] = '&dagger;';    // Dagger
        $trans[chr(135)] = '&Dagger;';    // Double Dagger
        $trans[chr(136)] = '&circ;';    // Modifier Letter Circumflex Accent
        $trans[chr(137)] = '&permil;';    // Per Mille Sign
        $trans[chr(138)] = '&Scaron;';    // Latin Capital Letter S With Caron
        $trans[chr(139)] = '&lsaquo;';    // Single Left-Pointing Angle Quotation Mark
        $trans[chr(140)] = '&OElig;    ';    // Latin Capital Ligature OE
        $trans[chr(145)] = '&lsquo;';    // Left Single Quotation Mark
        $trans[chr(146)] = '&rsquo;';    // Right Single Quotation Mark
        $trans[chr(147)] = '&ldquo;';    // Left Double Quotation Mark
        $trans[chr(148)] = '&rdquo;';    // Right Double Quotation Mark
        $trans[chr(149)] = '&bull;';    // Bullet
        $trans[chr(150)] = '&ndash;';    // En Dash
        $trans[chr(151)] = '&mdash;';    // Em Dash
        $trans[chr(152)] = '&tilde;';    // Small Tilde
        $trans[chr(153)] = '&trade;';    // Trade Mark Sign
        $trans[chr(154)] = '&scaron;';    // Latin Small Letter S With Caron
        $trans[chr(155)] = '&rsaquo;';    // Single Right-Pointing Angle Quotation Mark
        $trans[chr(156)] = '&oelig;';    // Latin Small Ligature OE
        $trans[chr(159)] = '&Yuml;';    // Latin Capital Letter Y With Diaeresis
        ksort($trans);
        return $trans;
    }

    /**
     * Remove accented characters
     *
     * @param String $sString
     * @return String
     */
    protected function _clearString($sString) {
        if (in_array(strtolower($this->_internalEncoding), array('utf-8', 'utf8'))){
            $sString = utf8_decode($sString);
        }
        $string = strtr($sString, $this->_get_html_translation_table_CP1252());
        $string = preg_replace("/\&(.)[^;]*;/", "\\1", $string);
        return $string;
    }

    /**
     * Load Doc document from a file
     *
     * @param string  $fileName
     * @param boolean $storeContent
     * @param string  $fileEncoding
     * @param string  $internalEncoding
     * @return Zend_Search_Lucene_Document_Doc
     * @throws Zend_Search_Lucene_Document_Exception
     */
    public static function loadDocFile($fileName, $storeContent = false, $fileEncoding = null, $internalEncoding = null) {
        if (!is_readable($fileName)) {
            require_once 'Zend/Search/Lucene/Document/Exception.php';
            throw new Zend_Search_Lucene_Document_Exception('Provided file \'' . $fileName . '\' is not readable.');
        }

        return new Zend_Search_Lucene_Document_Doc($fileName, $storeContent, $fileEncoding, $internalEncoding);
    }
}