<?php
/**
 * Include Plugin: displays a wiki page within another
 * Usage:
 * {{fortune}}
 *
 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
 * @author     Otto Vainio <oiv-plugins@valjakko.net>
 */

if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../../').'/');
if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
require_once(DOKU_PLUGIN.'syntax.php');

/**
 * All DokuWiki plugins to extend the parser/rendering mechanism
 * need to inherit from this class
 */
class syntax_plugin_fortune extends DokuWiki_Syntax_Plugin {

    /**
     * return some info
     */
    function getInfo(){
        return array(
            'author' => 'Otto Vainio',
            'email'  => 'oiv-plugins@valjakko.net',
            'date'   => '2005-10-14',
            'name'   => 'Fortune Plugin',
            'desc'   => 'Displays qotd (Quote Of The Day)',
            'url'    => 'http://wiki.splitbrain.org/plugin:fortune',
        );
    }

    /**
     * What kind of syntax are we?
     */
    function getType(){
        return 'substition';
    }

    /**
     * Where to sort in?
     */
    function getSort(){
        return 56;
    }

    /**
     * Paragraph Type
     */
    function getPType(){
        return 'block';
    }


    /**
     * Connect pattern to lexer
     */
    function connectTo($mode) {
      $this->Lexer->addSpecialPattern("{{fortune}}",$mode,'plugin_fortune');
    }

    /**
     * Handle the match
     */
    function handle($match, $state, $pos, &$handler){
        return $match;
    }

    /**
     * Create output
     */
    function render($mode, &$renderer, $data) {

        if($mode == 'xhtml'){
//           include_once "fortuneclass.php";
            $f = new Fortune;
            $fortunecookie = $f->quoteFromDir(DOKU_PLUGIN . "fortune/dat/");
            $renderer->doc .= "<div class=\"fortune\">";
            $renderer->doc .= nl2br(htmlspecialchars($fortunecookie));
            $renderer->doc .= "</div>";

            return true;
        }
        return false;
    }
}
/*
Main methods to use:
 quoteFromDir($dir):
   Quotes from any of the fortune-files in the dir.
 getRandomQuote($file):
   Quotes from the specific file.

 Written by Henrik Aasted Sorensen, henrik@aasted.org
 Read more at http://www.aasted.org/quote
 Edited by Otto Vainio
*/

class Fortune {
  function quoteFromDir($dir) {
    $amount = 0;
    $index = 0;
    clearstatcache();
    if ( $handle = opendir($dir) ) {
      while (false !== ($file = readdir($handle))) {
        if (strlen($file)>2 && $file!="_dummy") {
          if (substr($file,-4) == ".dat"){
            if (@filemtime(substr($file,0,-4))>@filemtime($dir.$file)) {
                $this->createIndexFile($dir.substr($file,0,-4));
            }
            $number = $this->getNumberOfQuotes($dir . $file);
            $amount += $number;
            $quotes[$index] = $amount;
            $files[$index] = $file;
            $index++;
          } else {
            if (!is_file($dir.$file.".dat") || (@filemtime($dir.$file)>@filemtime($dir.$file.".dat"))) {
                $this->createIndexFile($dir.$file);
                $number = $this->getNumberOfQuotes($dir . $file . ".dat");
                $amount += $number;
                $quotes[$index] = $amount;
                $files[$index] = $file.".dat";
                $index++;
            }
          }
        }
      }
      srand((double)microtime()*1000000);
      $index = rand(0, $amount);
      $i = 0;
      while ($quotes[$i] < $index)  {
        $i++;
      }
      return $this->getRandomQuote($dir .$files[$i]);
    }
    return "";
  }
  /*
   Reads the number of quotes in the file.
  */
  function getNumberOfQuotes($file) {
    $len=0;
    if ($fd = @fopen($file, "rb")) {
      $this->readLong($fd); // Just move over the first long. Might as well be fseek.
      $len =  $this->readLong($fd);
      fclose($fd);
    }
    return $len;
  }
  /*
   Picks quote number $index from the dat-file in $file.
  */
  function getExactQuote($file, $index) {
    if (is_file($file) == FALSE) {
      return;
    }

    if ( ($fd = fopen($file, "rb")) == FALSE ) {
      return;
    }
    fseek($fd, 24 + 4 * $index);

    $phys_index = $this->readLong($fd);

    fclose($fd);

    $quotefile = substr($file, 0, strlen($file) - 4);

    if ( ($fd = fopen($quotefile, "rb")) == FALSE ) {
      return;
    }

    $res = $this->getQuote($fd, $phys_index);
    fclose($fd);

    return $res;
  }

  /*
   Returns a random quote from $file.
  */
  function getRandomQuote($file) {
    $number = $this->getNumberOfQuotes($file);

    $index = rand(0, $number - 1);

    return $this->getExactQuote($file, $index);
  }

  /*
   Reads a quote from the specified index.
  */
  function getQuote($fd, $index) {
   fseek($fd, $index);
   $line=""; $res = "";
   do {
    $res = $res . $line;
    $line = fgets($fd, 1024);
   } while ( ($line[0] != "%") && (!feof($fd)) );

   return $res;
  }

  /*
   Gets indexes from the file pointed to by the filedescriptor $fd.
  */
  function getIndices($fd) {
    fseek($fd, 24, SEEK_SET);
    $i = 0;

    while ( feof($fd) == FALSE ) {
      $res[$i] = readLong($fd);
      $i++;
    }
    return $res;
  }

  function readLong($fd) {
    $res = fread($fd, 4);
    $l = ord($res[3]);
    $l += ord($res[2]) << 8;
    $l += ord($res[1]) << 16;
    $l += ord($res[0]) << 24;
    return $l;
  }
  function createIndexFile($file) {
    $fd = fopen($file, "r");
    if ($fd == false) {
//                  echo "File error!";
      exit;
    }

    $i = 1;
    $length = 0;
    $longest = 0;
    $shortest = 100000;
    $indices[0] = 0;
    while (!feof($fd)) {
      $line = fgets($fd);
      if ($line == "%\n") {
        $indices[$i] = ftell($fd);
        $i++;
        if ($length > $longest)
           $longest = $length;
        if ($length < $shortest)
           $shortest = $length;
        $length = 0;
      } else {
        $length = $length + strlen($line);
      }
    }
    fclose($fd);
    $fd = @fopen($file . ".dat", "w");
    if ($fd == false) {
//                  echo "<!-- createIndexFile: Could not write to file....-->";
      exit;
    }

    // Write header.
    $this->writeLong($fd, 2);
    $this->writeLong($fd, count($indices));
    $this->writeLong($fd, $longest);
    $this->writeLong($fd, $shortest);
    $this->writeLong($fd, 0);
    $this->writeLong($fd, 37 << 24);

    for ($i = 0 ; $i < count($indices) ; $i++) {
      $this->writeLong($fd, $indices[$i]);
    }

    fclose($fd);
  }

  function writeLong($fd, $l) {
    fwrite($fd, chr ( ($l >> 24) & 255));
    fwrite($fd, chr ( ($l >> 16) & 255));
    fwrite($fd, chr ( ($l >> 8) & 255));
    fwrite($fd, chr ( $l & 255));
  }
}// End of class
?>