<?php
/**
 * This plugin allows to embed wikipages into the current page
 * In addition, parts marked with id's can be replaced.
 *
 * Inspired (and copy&pasted) from the include plugin:
 *   http://wiki.splitbrain.org/plugin:include
 *
 * For wikipage-portion-replacements, the label-plugin is required: http://wiki.splitbrain.org/plugin:label
 * 
 * 
 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
 * @author     Pascal Bihler <bihler@iai.uni-bonn.de>
 */
 
// must be run within Dokuwiki
if(!defined('DOKU_INC')) die();

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

//

class syntax_plugin_embed extends DokuWiki_Syntax_Plugin {

		function syntax_plugin_embed() {
				global $embedded_pages_by_plugin_embed;
		    if (! $embedded_pages_by_plugin_embed) {
					 $embedded_pages_by_plugin_embed = array(); // To avoid recursion;
				}
		}
		
    function getInfo(){
        return array(
            'author' => 'Pascal Bihler',
            'email'  => 'bihler@iai.uni-bonn.de',
            'date'   => '2007-05-14',
            'name'   => 'Embed',
            'desc'   => 'Allows to embed wikipages in other ones, while offering the possibility to replace parts of the original page marked with labels.',
            'url'    => 'http://wiki.splitbrain.org/plugin:embed',
        );
    }
		
    function getType(){
        return 'substition';
    }
		
		function getSort(){
        return 500;
    }
		
		function connectTo($mode) {
      $this->Lexer->addSpecialPattern('<embed\s+[^>]+\s*>.*?</embed>',$mode,'plugin_embed');
      $this->Lexer->addSpecialPattern('<embed\s+[^/]+\s*/>',$mode,'plugin_embed');
    }
 
 
    /**
     * Handle the match
     */
    function handle($match, $state, $pos, &$handler){
        switch ($state) {
          case DOKU_LEXER_SPECIAL :
					  if (preg_match('/<embed\s+([^>]+)\s*>(.*?)<\/embed>/ms',$match,$matches)) 
							 return array($matches[1],$matches[2]);
						else if (preg_match('/<embed\s+([^>]+)\s*\/>/',$match,$matches)) 
							 return array($matches[1],'');
            break;
        }
        return array();
    }
 
    /**
     * Create output
     */
    function render($mode, &$renderer, $data) {
    	  global $ID;
				global $embedded_pages_by_plugin_embed;
				
				 
        if($mode == 'xhtml'){
						list($id,$replacement) = $data;
						
      			$renderer->info['cache'] = false; // prevent caching (to ensure ACL conformity) (TODO sometimes: make more intelligent)

						resolve_pageid(getNS($ID), $id, $exists); // resolve shortcuts 
						 
						//resolve_pageid(getNS($ID), $id, $exists); // resolve shortcuts 
						 
						// avoid circular references
						if (! (array_search($id,$embedded_pages_by_plugin_embed) === false))
						 		return false;
								
						array_push($embedded_pages_by_plugin_embed,$id);
					  
						$ins = $this->_embed_file($id,$replacement);	 
            $renderer->doc .= p_render('xhtml', $ins, $info);            // ptype = 'normal'
			
						array_pop($embedded_pages_by_plugin_embed);
					  
            return true;
        }
        return false;
    }
		
		function _embed_file($id,$replacement) { 
				
            
            // check permission
            $perm = auth_quickaclcheck($id);
            if ($perm < AUTH_READ) return false;
						
						
						//Read embeded page
						$page = io_readfile(wikiFN($id));
						
    				// convert relative links
						$page = $this->_convertInstructions($page,$id);
						
						// do replacements (on text-base to preserve List indentation and ordering etc.):
						$page = $this->_do_replacements($page,$replacement);
						
						$ins = p_get_instructions($page);						
						
						return $ins;
		}
		
		function _do_replacements($page,$r_str) {		  
			//Build up list of replacements (this needs to be done manually to allow several replacements with nesting if <label>s
			$r_list = array();
			preg_match_all('/<label\s+([a-zA-Z0-9_]+)\s*>/',$r_str, $matches_label, PREG_OFFSET_CAPTURE);
			preg_match_all('/<\/label>/',$r_str, $matches_labelx, PREG_OFFSET_CAPTURE);		
		
			$level = 0;
			$element = array_shift($matches_label[1]);
			$end_element = array_shift($matches_labelx[0]);
			while ($element || $end_element) {
			   if ($element && $element[1] < $end_element[1]) { // <label ..> before </label> 
  				 if ($level == 0) {		 
  			   	    $section_name = $element[0];
  			        $section_start = $element[1]+strlen($section_name)+1;
  				  } 
						$level++;
			      $element = array_shift($matches_label[1]);					  
				 } else {  //</label> before <label ..>
					   $level--;
				     if ($level == 0) {
							   $section_end = $end_element[1];
								 $r_list[$section_name] = substr($r_str,$section_start,$section_end-$section_start);
						}  
			       $end_element = array_shift($matches_labelx[0]);
				 }
			}
			
			// now do replacements
			foreach ($r_list as $section => $rep) {
							$page = preg_replace('/<label\s+' . $section .'\s*>.*?<\/label>/ms',$rep, $page);
			}
			return $page;
		}
		
		//Does not support CamelCase Links currently
		function _convert_link($link,$inclNS) {
		    
				//Check if external:
				if (preg_match('/^(https?:\/\/|mailto:|\\\\)/',$link)) 
				   return $link;
				
				//check if interwiki or email:
				if ((! strpos('>',$link) === false) || (! strpos('@',$link) === false))
				   return $link;
				
			// convert internal links and media from relative to absolute 
			
      // relative subnamespace 
			if ($link{0} == '.') {
			    // parent namespace
          if ($link{1} == '.')
            $link = getNS($inclNS).':'.substr($link, 2);
          // current namespace
          else
            $link = $inclNS.':'.substr($link, 1);
			} elseif (strpos($link, ':') === false){
          $link = $inclNS.':'.$link;
      } 
			
		  return $link;
		}
		
		function _convertInstructions($page,$page_id) {
      global $ID; 
				
  		if (! $page) return;
  		
  		// check if embeded page is in same namespace 
    		$inclNS = getNS($page_id);
    		if (getNS($ID) == $inclNS) return $page; 
  		
  		// convert links
  		$page = preg_replace("/\[\[([^\|\]]+)(\|[^\]]+)?\]\]/e",
             "'[[' . \$this->_convert_link('\\1','$inclNS') . '\\2]]'",
             $page);
  				 
  	  //convert embeddings
  		$page = preg_replace("/<embed\s+([^>]+)\s*\/?>/e",
             "'<embed ' . \$this->_convert_link('\\1','$inclNS') . '>'",
             $page);
  
  	  //convert images
  		$page = preg_replace("/{{(\s*)([^ \|}]+)(\s*)(||[^}]+)}}/e",
             "'{{\\1' . \$this->_convert_link('\\2','$inclNS') . '\\3\\4}}'",
             $page);
  		return $page;
		
		}
}
//Setup VIM: ex: et ts=4 enc=utf-8 :