<?php if (!defined('PmWiki')) exit();
/*
 * Fortune - Fortune cookie for PmWiki 2.0
 * Copyright 2005-2006 by D.Faure (dfaure@cpan.org)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 * Adapted to PmWiki from code by Henrik Aasted Sorensen, henrik@aasted.org
 * Read more at http://www.aasted.org/quote
 *
 * See http://www.pmwiki.org/wiki/Cookbook/Fortune for info.
 */

Markup("fortune", "directives", "/\\(:fortune(\\s+.*)?\\s*:\\)/e",
  "'<:block>'.Oracle(PSS('$1'))");

function Oracle($opt) {
	global $FortunesDir;
  SDV($FortunesDir, dirname(__FILE__) . '/fortunes');

  $opt = ParseArgs($opt);

	$f = new Fortune;
	$out = ($opt['file']) ? $f->getRandomQuote("$FortunesDir/" . $opt['file'] . ".dat") : $f->quoteFromDir($FortunesDir);

   $spec = Array("/€/", "/‹/", "/›/", "/œ/", "/Ÿ/", "/¡/", "/¢/", "/£/", "/¤/", "/¥/", "/¦/", "/§/", "/¨/", "/©/", "/ª/", "/«/", "/¬/", "/­/", "/®/", "/¯/", "/°/", "/±/", "/²/", "/³/", "/´/", "/µ/", "/·/", "/¹/", "/º/", "/»/", "/¿/", "/À/", "/Á/", "/Â/", "/Ã/", "/Ä/", "/Å/", "/Æ/", "/Ç/", "/È/", "/É/", "/Ê/", "/Ë/", "/Ì/", "/Í/", "/Î/", "/Ï/", "/Ð/", "/Ñ/", "/Ò/", "/Ó/", "/Ô/", "/Õ/", "/Ö/", "/×/", "/Ù/", "/Ú/", "/Û/", "/Ü/", "/Ý/", "/à/", "/á/", "/â/", "/ã/", "/ä/", "/å/", "/æ/", "/ç/", "/è/", "/é/", "/ê/", "/ë/", "/ì/", "/í/", "/î/", "/ï/", "/ð/", "/ñ/", "/ò/", "/ó/", "/ô/", "/õ/", "/ö/", "/ø/", "/ù/", "/ú/", "/û/", "/ü/", "/ý/", "/ÿ/", "/</", "/>/");
   $rep_pat = Array("&euro;", "&lt;", "&gt;", "&oelig;", "&Yuml;", "&iexcl;", "&cent;", "&pound;", "&curren;", "&yen", "&brvbar;", "&sect;", "&uml;", "&copy", "&ordf;", "&laquo;", "&not;", "&shy;", "&reg;", "&masr;", "&deg;", "&plusmn;", "&sup2;", "&sup3;", "&acute;", "&micro;", "&middot;", "&sup1;", "&ordm;", "&raquo;", "&iquest;", "&Agrave;", "&Aacute;", "&Acirc;", "&Atilde;", "&Auml;", "&Aring;", "&Aelig", "&Ccedil;", "&Egrave;", "&Eacute;", "&Ecirc;", "&Euml;", "&Igrave;", "&Iacute;", "&Icirc;", "&Iuml;", "&eth;", "&Ntilde;", "&Ograve;", "&Oacute;", "&Ocirc;", "&Otilde;", "&Ouml;", "&times;", "&Ugrave;", "&Uacute;", "&Ucirc;", "&Uuml;", "&Yacute;", "&agrave;", "&aacute;", "&acirc;", "&atilde;", "&auml;", "&aring;", "&aelig;", "&ccedil;", "&egrave;", "&eacute;", "&ecirc;", "&euml;", "&igrave;", "&iacute;", "&icirc;", "&iuml;", "&eth;", "&ntilde;", "&ograve;", "&oacute;", "&ocirc;", "&otilde;", "&ouml;", "&oslash;", "&ugrave;", "&uacute;", "&ucirc;", "&uuml;", "&yacute;", "&yuml;", "&lt;", "&gt;");
   $out = preg_replace($spec, $rep_pat, $out);
   $out = str_replace("retourligne", "<br>", $out);

	return Keep("<div id='fortune'>$out</div>");
}

class Fortune {
  /*
   Main methods to use:
     quoteFromDir($dir): Quotes from any of the fortune-files in the dir.
     getRandomQuote($file): Quotes from the specific file.
  */
	function quoteFromDir($dir) {
		$amount = 0;
		$index = 0;

		if ( $handle = opendir($dir) ) {
			while (false !== ($file = readdir($handle))) {
			
				if ( strpos($file, ".dat") != false) {
					$len = strlen($file);
					if (substr($file, $len - 4) == ".dat"){
						$number = $this->getNumberOfQuotes($dir . "/" . $file);
						$amount += $number;
						$quotes[$index] = $amount;
						$files[$index] = $file;
						$index++;					
					}
				}			
			
			}
	
			srand((double)microtime()*1000000);
			$index = rand(0, $amount);
			$i = 0;
	
			while ($quotes[$i] < $index)  {
				$i++;	
			}

			return $this->getRandomQuote($dir . "/" . $files[$i]);
		}


		return -1;
	}

	/*
	 Reads the number of quotes in the file. 
	*/
	function getNumberOfQuotes($file) {
	  $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) {
			echo "Input must be a file!<br/>";
			return;
		}
	
		if ( ($fd = fopen($file, "rb")) == FALSE ) {
			echo "Cannot open $file<br/>";	
			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 ) {
			echo "Cannot find file $quotefile!<br/>";
		}		
	
		$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) . "retourligne";
	 } 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