<?php
  /**
   * bibtex-Plugin: Parses bibtex-blocks
   *
   * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
   * @author     Christophe Ambroise <ambroise@utc.fr>
   * @date       2005-08-10
   *
   * Modifications: 2006-07-03 Jean-Francois Lalande.
   * Adding:
   * - Chronological ordering support
   * - Type of references groups
   * - PDF and POSTSCRIPT links
   *
   * Modifications: 2006-08-22 Jean-Francois Lalande.
   * - Fix for hyphaned name in OSBib (reported to developers)
   */

  /**
   * Parameters for the plugin:
   *
   * - $conf['bibtex_format']
   *   default: "APA"
   *   This control the formatting output of the bibtex plugin. 
   *   Options are: APA, ieee, britishmedicaljournal, chicago, harvard, mla, turabian
   *
   * - $conf['bibtex_sort_year']
   *   default: no value (no sorting by date)
   *   Controls the sorting of the references by year.
   *   Options are: 1 (most recent) or -1 (oldest first)
   *
   * - $conf['bibtex_sort_type']
   *   default: no value (no sorting by type)
   *   Controls the sorting of the references by type.
   *   Options are: 1 (ascending order) or -1 (descending order)
   *   The values for each type of reference is controlled by
   *   the array of $conf["bibtex_types_order"]. You can overide this array
   *   in your local configuration. You can find an example of this array in
   *   the syntax.php file of this plugin.
   *  
   * - $conf["bibtex_types_order"]
   *   default: see below
   *   If the 'bibtex_sort_type' has been activated, this array controls
   *   the order of appearing of the different type of references. For each kind
   *   of reference a value is associated. For example a book is 10, an article 7
   *   and a techreport 1. If the same value is given for two kinds of references
   *   they are grouped (in the example inproceedings and conference are grouped)
   *
   *   Example of array:
   *   $conf["bibtex_types_order"] = array (
   *	"book"=> 10,
   *    "inbook"=> 9,
   *    "phdthesis"=> 8,
   *    "article"=> 7,
   *    "inproceedings"=> 3,
   *    "conference"=> 3,
   *    "techreport"=> 1,
   *    );  
   * 
   * - $conf["bibtex_types_names"]
   *   default see below
   *   If the 'bibtex_sort_type' has beec activated, this array controls
   *   the name of the section for each group of references. The idea
   *   is to personalize the titles for exemple for the entries 'inbook' by
   *   putting a label "Chapter in books". For each level defined in the
   *   array $conf["bibtex_types_order"], we associate a label.
   *   
   *   Example of array:
   *   $conf["bibtex_types_names"] = array (
   *    10 => "Books",
   *    9 => "Chapters in books",
   *    8 => "Phd Thesis",
   *    7 => "Articles",
   *    3 => "Proceedings",
   *    1 => "Technical reports",
   *    );   
   * 
   * - $conf['bibtex_types_title_level']
   *   default: 2
   *   This parameter sets the level of the label of each section of reference.
   *   By default the level is 2 corresponding to h2 tags.
   *
   *
   * Example of parameters for activating all features:
   *
   * $conf['bibtex_format'] = "ieee";
   * $conf['bibtex_sort_year'] = 1;
   * $conf['bibtex_sort_type'] = 1;
   * $conf['bibtex_sort_type_title'] = 1;
   *
   * Special parameters in the bibtex entry:
   * 
   * - The tag 'file' is considered as an internal document of dokuwiki
   * - The tag 'pdf' is considerd as an external url
   * - The tag 'postscript' is considered as an external url
   */
 
// Default values
global $conf;
if(!isset($conf["bibtex_types_order"])) 
{
	$conf["bibtex_types_order"] = array (
		"book"=> 10,
		"inbook"=> 9,
		"phdthesis"=> 8,
		"article"=> 7,
		"inproceedings"=> 3,
		"conference"=> 3,
		"techreport"=> 1,
	);
}
if(!isset($conf["bibtex_types_names"])) 
{
	$conf["bibtex_types_names"] = array (
		10 => "Books",
		9 => "Chapters in books",
		8 => "Phd Thesis",
		7 => "Articles",
		3 => "Proceedings",
		1 => "Technical reports",
	); 
}
if(!isset($conf["bibtex_types_title_level"])) 
{
	$conf['bibtex_types_title_level'] = 2;
}

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');

/**
* usort callback for years
*/
function compare_year($a, $b) {
	global $conf;

	// No sorting
	if ($conf['bibtex_sort_year'] == "")
	  return 0;

	$adist = $a['year'];
	$bdist = $b['year'];

	if ($adist == $bdist) {
		return 0;
	}
	return ($adist < $bdist) ? $conf['bibtex_sort_year'] : -$conf['bibtex_sort_year'];   
}

/**
* usort callback for types
*/
function compare_type($a, $b) {
	global $conf;

	// No sorting
	if ($conf['bibtex_sort_type'] == "")
	  return 0;

	$adist = $conf["bibtex_types_order"][$a['bibtexEntryType']];
	$bdist = $conf["bibtex_types_order"][$b['bibtexEntryType']];

	if ($adist == $bdist) {
		// If the year sorting is activated...
		if ($conf['bibtex_sort_year'] != "")
		{
			return compare_year($a,$b);
		}
		else
		{
			return 0;
		}
	}
	return ($adist < $bdist) ? $conf['bibtex_sort_type'] : -$conf['bibtex_sort_type'];   
}

/**
 * All DokuWiki plugins to extend the parser/rendering mechanism
 * need to inherit from this class
 */
class syntax_plugin_bibtex extends DokuWiki_Syntax_Plugin {

  function getInfo(){
    return array(
		 'author' => 'Christophe Ambroise',
		 'email'  => 'ambroise@utc.fr',
		 'date'   => '2006-06-29',
		 'name'   => 'Bitext Plugin',
		 'desc'   => 'parses bibtex blocks',
		 'url'    => 'http://www.hds.utc.fr/~ambroise/doku.php?id=softwares:dokuwikibibtexplugin'
		 );
  }
 
  /**
   * What kind of syntax are we?
   */
  function getType(){
    return 'protected';
  }
 
  /**
   * Where to sort in?
   */
  function getSort(){
    return 102;
  }
 
  /**
   * Connect pattern to lexer
   */
  function connectTo($mode) {
    $this->Lexer->addEntryPattern('<bibtex(?=.*\x3C/bibtex\x3E)',$mode,'plugin_bibtex');
  }
 
  function postConnect() {
    $this->Lexer->addExitPattern('</bibtex>','plugin_bibtex');
  }
 
  /**
   * Handle the match
   */
  function handle($match, $state, $pos) {
    if ( $state == DOKU_LEXER_UNMATCHED ) {
      $matches = preg_split('/>/u',$match,2);
      $matches[0] = trim($matches[0]);
      if ( trim($matches[0]) == '' ) {
	$matches[0] = NULL;
      }
      return array($matches[1],$matches[0]);
    }
    return TRUE;
  }
  /**
   * Create output
   */
  function render($mode, &$renderer, $data) {
    global $conf;
    if($mode == 'xhtml' && strlen($data[0]) > 1) {
      $renderer->doc .= $this->createCitations($data[0]);
      return true;
    }
  }
       
   
       
  function createCitations(&$data) {
    global $conf;
    $pathToOsbib = DOKU_PLUGIN.'bibtex/OSBib/';
    include_once($pathToOsbib.'format/bibtexParse/PARSEENTRIES.php');
    include_once( $pathToOsbib.'format/BIBFORMAT.php');

    // Getting conf (JFL)
    if ($conf['bibtex_format'] != "")
    {
	    $bibtex_format = $conf['bibtex_format'];
    }
    else
    {
	    $bibtex_format = "APA";
    }

    /* Get the bibtex entries into an associative array */
    $parse = NEW PARSEENTRIES();
    $parse->expandMacro = TRUE;
    $parse->fieldExtract = TRUE;
    $parse->removeDelimit = TRUE;
    $parse->loadBibtexString($data);
    $parse->extractEntries();
    list($preamble, $strings, $entries) = $parse->returnArrays();
         
    /* Format the entries array  for html output */
    $bibformat = NEW BIBFORMAT($pathToOsbib, TRUE);
    $bibformat->cleanEntry=TRUE; // The entries will be transformed into nice utf8
    list($info, $citation, $styleCommon, $styleTypes) = $bibformat->loadStyle(DOKU_PLUGIN.'bibtex/OSBib/styles/bibliography/', $bibtex_format);
    $bibformat->getStyle($styleCommon, $styleTypes);
        
    $citations='<dl>';

    // Sorting ?
    if ($conf['bibtex_sort_year'] != "")
    {
      usort($entries, "compare_year");
    }

    if ($conf['bibtex_sort_type'] != "")
    {
      usort($entries, "compare_type");
    }

    foreach ($entries as $entry){
      // Get the resource type ('book', 'article', 'inbook' etc.)
      $resourceType = $entry['bibtexEntryType'];

      if ($conf['bibtex_sort_type_title'] == 1)
      {
	      if ($conf['bibtex_types_order'][$resourceType] != $conf['bibtex_types_order'][$resourceTypeLast])
	      {
		      $resourceTypeLast = $resourceType;
		      $value = $conf['bibtex_types_order'][$resourceType];
		      $citations.="<h" . $conf['bibtex_types_title_level'] . ">";
		      $citations.=$conf['bibtex_types_names'][$value];
		      $citations.="</h" . $conf['bibtex_types_title_level'] . ">";
	      }
      }

      // In this case, BIBFORMAT::preProcess() adds all the resource elements automatically to the BIBFORMAT::item array...
      $bibformat->preProcess($resourceType, $entry);
      // Finally, get the formatted resource string ready for printing to the web browser or exporting to RTF, OpenOffice or plain text
      $citations.= '<dt><div id="bibtexdt">[' . $entry['year'] . ", " . $entry['bibtexEntryType'] . $this->toDownload($entry) . ']</div></dt><dd><div id="bibtexdd">'.   $bibformat->map()    . "</div></dd> \n" ;
    }
    $citations.= "</dl>";
    return $citations;
        
    //$entry['bibtexCitation']
        
  }
        
        
            
  function toDownload($entry) {
    $string="";
    if(array_key_exists('file',$entry)){
      $string.= " | ".$this->internalmedia($entry['file']); 
    }
    if(array_key_exists('url',$entry)){
      $string.= " | ".$this->externallink($entry['url'],"www"); 
    }
    if(array_key_exists('pdf',$entry)){
      $string.= " | ".$this->externallink($entry['pdf'],"pdf"); 
    }
    if(array_key_exists('postscript',$entry)){
      $string.= " | ".$this->externallink($entry['postscript'],"ps"); 
    }
    return $string;  
  }

    
  function externallink($url, $name = NULL) {
    global $conf;

    $name = $this->_getLinkTitle($name, $url, $isImage);

    // add protocol on simple short URLs
    if(substr($url,0,3) == 'ftp' && (substr($url,0,6) != 'ftp://')) $url = 'ftp://'.$url;
    if(substr($url,0,3) == 'www') $url = 'http://'.$url;
        
    if ( !$isImage ) {
      $class='urlextern';
    } else {
      $class='media';
    }
        
    //prepare for formating
    $link['target'] = $conf['target']['extern'];
    $link['style']  = '';
    $link['pre']    = '';
    $link['suf']    = '';
    $link['more']   = 'onclick="return svchk()" onkeypress="return svchk()"';
    $link['class']  = $class;
    $link['url']    = $url;
    $link['name']   = $name;
    $link['title']  = $this->_xmlEntities($url);
    if($conf['relnofollow']) $link['more'] .= ' rel="nofollow"';

    list($ext,$mime) = mimetype($url);
    if(substr($mime,0,15) == 'application/pdf' || substr($mime,0,24) == 'application/octet-stream'){
	    // add file icons
      $link['class'] = 'urlextern';
      if(@file_exists(DOKU_INC.'lib/images/fileicons/'.$ext.'.png')){
	$link['style']='background-image: url('.DOKU_BASE.'lib/images/fileicons/'.$ext.'.png)';
      }elseif(@file_exists(DOKU_INC.'lib/images/fileicons/'.$ext.'.gif')){
	$link['style']='background-image: url('.DOKU_BASE.'lib/images/fileicons/'.$ext.'.gif)';
      }else{
	$link['style']='background-image: url('.DOKU_BASE.'lib/images/fileicons/file.gif)';
      }
      //$link['url'] = ml($src,array('id'=>$ID,'cache'=>$cache),true);
    }

    //output formatted
    return $this->_formatLink($link);
  }
    
    
  function internalmedia ($src, $title=NULL, $align=NULL, $width=NULL,
			  $height=NULL, $cache=NULL, $linking=NULL) {
    global $conf;
    global $ID;
    resolve_mediaid(getNS($ID),$src, $exists);

    $link = array();
    $link['class']  = 'media';
    $link['style']  = '';
    $link['pre']    = '';
    $link['suf']    = '';
    $link['more']   = 'onclick="return svchk()" onkeypress="return svchk()"';
    $link['target'] = $conf['target']['media'];
    $link['title']  = $this->_xmlEntities($src);
    list($ext,$mime) = mimetype($src);
    if(substr($mime,0,5) == 'image'){
      // link only jpeg images
      // if ($ext != 'jpg' && $ext != 'jpeg') $noLink = TRUE;
      $link['url'] = ml($src,array('id'=>$ID,'cache'=>$cache),($linking=='direct'));
    }elseif($mime == 'application/x-shockwave-flash'){
      // don't link flash movies
      $noLink = TRUE;
    }else{
      // add file icons
      $link['class'] = 'urlextern';
      if(@file_exists(DOKU_INC.'lib/images/fileicons/'.$ext.'.png')){
	$link['style']='background-image: url('.DOKU_BASE.'lib/images/fileicons/'.$ext.'.png)';
      }elseif(@file_exists(DOKU_INC.'lib/images/fileicons/'.$ext.'.gif')){
	$link['style']='background-image: url('.DOKU_BASE.'lib/images/fileicons/'.$ext.'.gif)';
      }else{
	$link['style']='background-image: url('.DOKU_BASE.'lib/images/fileicons/file.gif)';
      }
      $link['url'] = ml($src,array('id'=>$ID,'cache'=>$cache),true);
    }
    $link['name']   = $this->_media ($src, $title, $align, $width, $height, $cache);

    //output formatted
    if ($linking == 'nolink' || $noLink){
      return  $link['name'];
    } else {
      return $this->_formatLink($link);
    }
  }
  
    
  function _formatLink($link){
    //make sure the url is XHTML compliant (skip mailto)
    if(substr($link['url'],0,7) != 'mailto:'){
      $link['url'] = str_replace('&','&amp;',$link['url']);
      $link['url'] = str_replace('&amp;amp;','&amp;',$link['url']);
    }
    //remove double encodings in titles
    $link['title'] = str_replace('&amp;amp;','&amp;',$link['title']);

    $ret  = '';
    $ret .= $link['pre'];
    $ret .= '<a href="'.$link['url'].'"';
    if($link['class'])  $ret .= ' class="'.$link['class'].'"';
    if($link['target']) $ret .= ' target="'.$link['target'].'"';
    if($link['title'])  $ret .= ' title="'.$link['title'].'"';
    if($link['style'])  $ret .= ' style="'.$link['style'].'"';
    if($link['more'])   $ret .= ' '.$link['more'];
    $ret .= '>';
    $ret .= $link['name'];
    $ret .= '</a>';
    $ret .= $link['suf'];
    return $ret;
  }
    
  /**
   * Construct a title and handle images in titles
   *
   * @author Harry Fuecks <hfuecks@gmail.com>
   */
  function _getLinkTitle($title, $default, & $isImage, $id=NULL) {
    global $conf;

    $isImage = FALSE;
    if ( is_null($title) ) {
      if ($conf['useheading'] && $id) {
	$heading = p_get_first_heading($id);
	if ($heading) {
	  return $this->_xmlEntities($heading);
	}
      }
      return $this->_xmlEntities($default);
    } else if ( is_string($title) ) {
      return $this->_xmlEntities($title);
    } else if ( is_array($title) ) {
      $isImage = TRUE;
      return $this->_imageTitle($title);
    }
  }
    
  function _xmlEntities($string) {
    return htmlspecialchars($string);
  }
    
  function _simpleTitle($name){
    global $conf;

    if($conf['useslash']){
      $nssep = '[:;/]';
    }else{
      $nssep = '[:;]';
    }
    $name = preg_replace('!.*'.$nssep.'!','',$name);
    //if there is a hash we use the ancor name only
    $name = preg_replace('!.*#!','',$name);
    return $name;
  }

  /**
   * Renders internal and external media
   * 
   * @author Andreas Gohr <andi@splitbrain.org>
   */
  function _media ($src, $title=NULL, $align=NULL, $width=NULL,
		   $height=NULL, $cache=NULL) {

    $ret = '';

    list($ext,$mime) = mimetype($src);
    if(substr($mime,0,5) == 'image'){
      //add image tag
      $ret .= '<img src="'.ml($src,array('w'=>$width,'h'=>$height,'cache'=>$cache)).'"';
      $ret .= ' class="media'.$align.'"';
        
      if (!is_null($title)) {
	$ret .= ' title="'.$this->_xmlEntities($title).'"';
	$ret .= ' alt="'.$this->_xmlEntities($title).'"';
      }elseif($ext == 'jpg' || $ext == 'jpeg'){
	//try to use the caption from IPTC/EXIF
	require_once(DOKU_INC.'inc/JpegMeta.php');
	$jpeg =& new JpegMeta(mediaFN($src));
	if($jpeg !== false) $cap = $jpeg->getTitle();
	if($cap){
	  $ret .= ' title="'.$this->_xmlEntities($cap).'"';
	  $ret .= ' alt="'.$this->_xmlEntities($cap).'"';
	}
      }else{
	$ret .= ' alt=""';
      }
            
      if ( !is_null($width) )
	$ret .= ' width="'.$this->_xmlEntities($width).'"';
        
      if ( !is_null($height) )
	$ret .= ' height="'.$this->_xmlEntities($height).'"';

      $ret .= ' />'; 

    }elseif($mime == 'application/x-shockwave-flash'){
      $ret .= '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"'.
	' codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"';
      if ( !is_null($width) ) $ret .= ' width="'.$this->_xmlEntities($width).'"';
      if ( !is_null($height) ) $ret .= ' height="'.$this->_xmlEntities($height).'"';
      $ret .= '>'.DOKU_LF;
      $ret .= '<param name="movie" value="'.ml($src).'" />'.DOKU_LF;
      $ret .= '<param name="quality" value="high" />'.DOKU_LF;
      $ret .= '<embed src="'.ml($src).'"'.
	' quality="high"';
      if ( !is_null($width) ) $ret .= ' width="'.$this->_xmlEntities($width).'"';
      if ( !is_null($height) ) $ret .= ' height="'.$this->_xmlEntities($height).'"';
      $ret .= ' type="application/x-shockwave-flash"'.
	' pluginspage="http://www.macromedia.com/go/getflashplayer"></embed>'.DOKU_LF;
      $ret .= '</object>'.DOKU_LF;

    }elseif(!is_null($title)){
      // well at least we have a title to display
      $ret .= $this->_xmlEntities($title);
    }else{
      // just show the sourcename
      $ret .= $this->_xmlEntities(noNS($src));
    }

    return $ret;
  }
  

}
?>
