<?php
/*
This file is part of Thomas Bley's moregroupware webmail2/calendar2/admin2 module. (tb-mgw)

More information:
-----------------

Simple Groupware Solutions Thomas Bley
Fichtenstr. 23
Germany, 85640 Putzbrunn

Contact:
--------

info@simple-groupware.de

http://www.simple-groupware.de


Copyright 2002-2003 Thomas Bley
tb-mgw is distributed under the terms of the GNU General Public License 

tb-mgw is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

tb-mgw is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with tb-mgw; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

// Class imported ftom TikiWiki

// This class is included by all the Tiki php scripts, so it's important
// to keep the class as small as possible to improve performance.
// What goes in this class:
// * generic functions that MANY scripts must use
// * shared functions (marked as /*shared*/) are functions that are
//   called from Tiki modules.

  function wiki_parse_data($data,$page)
  {

	$page_regex = "([A-Za-z0-9_])([\\.: A-Za-z0-9_\\-])*([A-Za-z0-9_])([A-Za-z0-9_])([\\.: A-Za-z0-9_\\-])*([A-Za-z0-9_])";
	$tikidomain = "/";
	$feature_wiki_tables = "old";
	$feature_wiki_pictures = "y";
	$feature_wikiwords = "y";
	$feature_drawings = "y";

    // Handle pre- and no-parse sections and plugins
    $preparsed = Array();
    $noparsed  = Array();
	
    wiki_parse_first( $data, $preparsed, $noparsed );


    // Replace special characters
    wiki_parse_htmlchar( $data );

    // Extract [link] sections (to be re-inserted later)
    $noparsedlinks=Array();
    preg_match_all("/\[([^\]]*)\]/",$data,$noparseurl);
    foreach(array_unique($noparseurl[1]) as $np) {
      $key=md5(wiki_genPass());
      $aux["key"]=$key;
      $aux["data"]=$np;
      $noparsedlinks[]=$aux;
      $data=str_replace("$np",$key,$data);
    }

/*
    // Now replace a TOC
    preg_match_all("/\{toc\}/i",$data,$tocs);
    if(count($tocs[0])>0) {
      include_once("lib/structures/structlib.php");
      if($structlib->page_is_in_structure($page)) {
        $html='';
        $toc=$structlib->get_subtree_toc($page,$page,$html);
        // Loop over all the case-specific versions of {toc} used
        // (if the user is consistent, this is a loop of count 1)
        for ($i=0; $i<count($tocs[0]); $i++) {
          $data=str_replace($tocs[0],$html,$data);
        }
      }
    }
*/
	
    //unset($smc);
    if($feature_wiki_tables != 'new') {
	    // New syntax for tables
	    if (preg_match_all("/\|\|(.*)\|\|/", $data, $tables)) {
	     $maxcols = 1;
	      $cols = array();
	      for($i = 0; $i < count($tables[0]); $i++) {
	        $rows = explode('||', $tables[0][$i]);
	        $col[$i] = array();
	        for ($j = 0; $j < count($rows); $j++) {
	          $cols[$i][$j] = explode('|', $rows[$j]);
	          if (count($cols[$i][$j]) > $maxcols)
	            $maxcols = count($cols[$i][$j]);
	        }
	      }
	      for ($i = 0; $i < count($tables[0]); $i++) {
	        $repl = '<table class="wikitable">';
	        for ($j = 0; $j < count($cols[$i]); $j++) {
	          $ncols = count($cols[$i][$j]);
	          if ($ncols == 1 && !$cols[$i][$j][0])
	            continue;
	          $repl .= '<tr>';
	          for ($k = 0; $k < $ncols; $k++) {
	            $repl .= '<td class="wikicell" ';
	            if ($k == $ncols - 1 && $ncols < $maxcols)
	              $repl .= ' colspan=' . ($maxcols-$k);
	            $repl .= '>' . $cols[$i][$j][$k] . '</td>';
	          }
	          $repl.='</tr>';
	        }
	        $repl.='</table>';
	        $data = str_replace($tables[0][$i],$repl,$data);
	      }
	    }
    } else {
	    // New syntax for tables
	    // REWRITE THIS CODE
	    if (preg_match_all("/\|\|(.*?)\|\|/s", $data, $tables)) {
 	      $maxcols = 1;
	      $cols = array();
	      for($i = 0; $i < count($tables[0]); $i++) {
	        $rows = split("\n|\<br\/\>", $tables[0][$i]);
	        $col[$i] = array();
	        for ($j = 0; $j < count($rows); $j++) {
	          $rows[$j]=str_replace('||','',$rows[$j]);
	          $cols[$i][$j] = explode('|', $rows[$j]);
	          if (count($cols[$i][$j]) > $maxcols)
	            $maxcols = count($cols[$i][$j]);
	        }
	      }
	      for ($i = 0; $i < count($tables[0]); $i++) {
	        $repl = '<table class="wikitable">';
	        for ($j = 0; $j < count($cols[$i]); $j++) {
	          $ncols = count($cols[$i][$j]);
	          if ($ncols == 1 && !$cols[$i][$j][0])
	            continue;
	          $repl .= '<tr>';
	          for ($k = 0; $k < $ncols; $k++) {
	            $repl .= '<td class="wikicell" ';
	            if ($k == $ncols - 1 && $ncols < $maxcols)
	              $repl .= ' colspan=' . ($maxcols-$k);
	            $repl .= '>' . $cols[$i][$j][$k] . '</td>';
	          }
	          $repl.='</tr>';
	        }
	        $repl.='</table>';
	        $data = str_replace($tables[0][$i],$repl,$data);
	      }
	    }
    
    }

    // Now search for images uploaded by users
    if($feature_wiki_pictures=='y') {
      preg_match_all("/\{picture file=([^\}]+)\}/",$data,$pics);
      for($i=0;$i<count($pics[0]);$i++) {
        // Check if the image exists
        $name=$pics[1][$i];
        if(file_exists($name)) {
          // Replace by the img tag to show the image
         $repl = "<img src='$name?nocache=1' alt='$name' />";
        } else {
          $repl=tra('picture not found');
        }
        // Replace by $repl
        $data = str_replace($pics[0][$i],$repl,$data);
      }
    }

    //$data = strip_tags($data);
    // BiDi markers
    $bidiCount = 0;
    $bidiCount = preg_match_all("/(\{l2r\})/",$data,$pages);
    $bidiCount += preg_match_all("/(\{r2l\})/",$data,$pages);

    $data = preg_replace("/\{l2r\}/", "<div dir='ltr'>", $data);
    $data = preg_replace("/\{r2l\}/", "<div dir='rtl'>", $data);
    $data = preg_replace("/\{lm\}/", "&lrm;", $data);
    $data = preg_replace("/\{rm\}/", "&rlm;", $data);
    // smileys
    $data = wiki_parse_smileys($data);


    // Replace links to slideshows
    if($feature_drawings == 'y') {
    // Replace drawings
    // Replace rss modules
    $pars=parse_url($_SERVER["REQUEST_URI"]);
    $pars_parts=split('/',$pars["path"]);
    $pars=Array();
    for($i=0;$i<count($pars_parts)-1;$i++) {
      $pars[]=$pars_parts[$i];
    }
    $pars=join('/',$pars);
    if(preg_match_all("/\{draw +name=([A-Za-z_\-0-9]+) *\}/",$data,$draws)) {
      for($i=0;$i<count($draws[0]);$i++) {
        $id = $draws[1][$i];
        $repl='';
        $name=$id.'.gif';
        if(file_exists("img/wiki/$tikidomain$name")) {
          $repl="<img border='0' src='img/wiki/$tikidomain$name' alt='a drawing' />";
        } else {
          $repl=tra('drawing not found');
        }
        $data = str_replace($draws[0][$i],$repl,$data);
      }
    }
    }

    // Replace cookies
    if(preg_match_all("/\{cookie\}/",$data,$rsss)) {
      for($i=0;$i<count($rsss[0]);$i++) {
        $data = str_replace($rsss[0][$i],"",$data);
      }
    }

    // Replace dynamic content occurrences
    if(preg_match_all("/\{content +id=([0-9]+)\}/",$data,$dcs)) {
      for($i=0;$i<count($dcs[0]);$i++) {
        $data = str_replace($dcs[0][$i],"",$data);
      }
    }
    // Replace Dynamic content with random selection
    if(preg_match_all("/\{rcontent +id=([0-9]+)\}/",$data,$dcs)) {
      for($i=0;$i<count($dcs[0]);$i++) {
        $data = str_replace($dcs[0][$i],"",$data);
      }
    }


    // Replace boxes
    $data = preg_replace("/\^([^\^]+)\^/","<div class='simplebox' align='center'>$1</div>",$data);
    // Replace colors ~~color:text~~
    $data = preg_replace("/\~\~([^\:]+):([^\~]+)\~\~/","<span style='color:$1;'>$2</span>",$data);
    // Underlined text
    $data = preg_replace("/===([^\=]+)===/","<span style='text-decoration:underline;'>$1</span>",$data);
    // Center text
    $data = preg_replace("/::([^\:]+)::/","<div align='center'>$1</div>",$data);

    // Links to internal pages
    // If they are parenthesized then don't treat as links
    // Prevent ))PageName(( from being expanded    \"\'
    //[A-Z][a-z0-9_\-]+[A-Z][a-z0-9_\-]+[A-Za-z0-9\-_]*

    if($feature_wikiwords == 'y') {
	    // The first part is now mandatory to prevent [Foo|MyPage] from being converted!
	    preg_match_all("/([ \n\t\r\,\;]|^)([A-Z][a-z0-9_\-]+[A-Z][a-z0-9_\-]+[A-Za-z0-9\-_]*)($|[ \n\t\r\,\;\.])/",$data,$pages);
	    foreach(array_unique($pages[2]) as $page_parse) {
	        $repl = '<a title="" href="tiki-index.php?page='.urlencode($page_parse).'" class="wiki">'.$page_parse.'</a>';
	      $data = preg_replace("/([ \n\t\r\,\;]|^)$page_parse($|[ \n\t\r\,\;\.])/","$1"."$repl"."$2",$data);
	      //$data = str_replace($page_parse,$repl,$data);
	    }
    }

    $data = preg_replace("/([ \n\t\r\,\;]|^)\)\)([^\(]+)\(\(($|[ \n\t\r\,\;\.])/","$1"."$2"."$3",$data);
    // New syntax for wiki pages ((name|desc)) Where desc can be anything
    preg_match_all("/\(\(($page_regex)\|(.+?)\)\)/",$data,$pages);
    for($i=0;$i<count($pages[1]);$i++) {
      $pattern = $pages[0][$i];
      //$pattern=str_replace('|','\|',$pattern);
      //$pattern=str_replace('(','\(',$pattern);
      //$pattern=str_replace(')','\)',$pattern);
      $pattern=str_replace('/','\/',preg_quote($pattern));

      $pattern = "/".$pattern."/";
      // Replace links to external wikis

      $repl2=true;
      if(strstr($pages[1][$i],':')) {
        $wexs = explode(':',$pages[1][$i]);
        if(count($wexs)==2) {
          $wkname = $wexs[0];       
        }
      }

      if($repl2) {
        // 24-Jun-2003, by zaufi
        // TODO: future optimize: get page description and modification time at once.

        // text[0] = link description (previous format)
        // text[1] = timeout in seconds (new field)
        // text[2..N] = drop
        $text=explode("|",$pages[5][$i]);

		$uri_ref = "tiki-index.php?page=".urlencode($pages[1][$i]);
		$repl = "<a title=\"\" href='$uri_ref' class='wiki'>".(strlen(trim($text[0]))>0?$text[0]:$pages[1][$i])."</a>";
        // Check is timeout expired?
		if (isset($text[1]) && (time() - intval(0)) < intval($text[1]))
          $repl.="&nbsp;<img src='img/icons/new.gif'>";

		$data = preg_replace($pattern,"$repl",$data);
      }
    }

    // New syntax for wiki pages ((name)) Where name can be anything
    preg_match_all("/\(\(($page_regex)\)\)/",$data,$pages);
    foreach(array_unique($pages[1]) as $page_parse) {
      $repl2=true;
      if(strstr($page_parse,':')) {
        $wexs = explode(':',$page_parse);
        if(count($wexs)==2) {
          $wkname = $wexs[0];        
        }
      }
      if($repl2) {
	      $repl = "<a title=\"\" href='tiki-index.php?page=".urlencode($page_parse)."' class='wiki'>$page_parse</a>";
	      $data = preg_replace("/\(\($page_parse\)\)/","$repl",$data);
      }
     
    }

    // reinsert hash-replaced links into page
    foreach($noparsedlinks as $np) {
      $data = str_replace($np["key"],$np["data"],$data);
    }

    // TODO: I think this is 1. just wrong and 2. not needed here? remove it?
    // Replace ))Words((
    $data = preg_replace("/\(\(([^\)]+)\)\)/","$1",$data);

    // Images
    preg_match_all("/(\{img [^\}]+})/",$data,$pages);
    foreach(array_unique($pages[1]) as $page_parse) {
      $parts = explode(" ",$page_parse);
      $imgdata = Array();
      $imgdata["src"]='';
      $imgdata["height"]='';
      $imgdata["width"]='';
      $imgdata["link"]='';
      $imgdata["align"]='';
      $imgdata["desc"]='';
      foreach($parts as $part) {
        $part = str_replace('}','',$part);
        $part = str_replace('{','',$part);
        $part = str_replace('\'','',$part);
        $part = str_replace('"','',$part);
        if(strstr($part,'=')) {
            $subs = explode("=",$part,2);
            $imgdata[$subs[0]]=$subs[1];
        }
      }
      //print("todo el tag es: ".$page_parse."<br/>");
      //print_r($imgdata);
      $repl = "<div class=\"innerimg\"><img alt='an image' src='".$imgdata["src"]."' border='0' ";
      if($imgdata["width"]) $repl.=" width='".$imgdata["width"]."'";
      if($imgdata["height"]) $repl.=" height='".$imgdata["height"]."'";
      $repl.= " /></div>";
      if($imgdata["link"]) {
        $repl ="<a href='".$imgdata["link"]."'>".$repl."</a>";
      }
      if($imgdata["desc"]) {
        $repl="<table cellpadding='0' cellspacing='0'><tr><td>".$repl."</td></tr><tr><td class='mini'>".$imgdata["desc"]."</td></tr></table>";
      }
      if($imgdata["align"]) {
        $repl ="<div align='".$imgdata["align"]."'>".$repl."</div>";
      }
      $data = str_replace($page_parse,$repl,$data);
    }

    $links = wiki_get_links($data);
    
    $notcachedlinks = wiki_get_links_nocache($data);
    
	$cachedlinks = array_diff($links, $notcachedlinks);
	
    // Note that there're links that are replaced

    foreach($links as $link) {
      $target='';
      $target='target="_blank"';
	  if(strstr($link,$_SERVER["SERVER_NAME"])) {
		$target='';
	  }
	  if(!strstr($link,'//')) {
	    $target='';
	  }
      //$link2 = str_replace("/","\/",$link);
      //$link2 = str_replace("?","\?",$link2);
      //$link2 = str_replace("&","\&",$link2);
	  $link2=str_replace("/","\/",preg_quote($link));
      $pattern = "/\[$link2\|([^\]\|]+)([^\]])*\]/";
      $data = preg_replace($pattern,"<a class='wiki' $target href='$link'>$1</a>",$data);
      $pattern = "/\[$link2\]/";
      $data = preg_replace($pattern,"<a class='wiki' $target href='$link'>$link</a>",$data);
    }



    // tables
    /*
    preg_match_all("/(\%[^\%]+\%)/",$data,$pages);
    foreach(array_unique($pages[1]) as $page_parse) {
      $pagex=substr($page_parse,1,strlen($page_parse)-2);
      $repl='<table cellpadding="0" cellspacing="0" border="1">';
      // First split by lines
      $lines = explode("\\",$pagex);
      foreach ($lines as $line) {
        $repl.='<tr>';
        $columns = explode("&",$line);
        foreach($columns as $column) {
          $repl.='<td valign="top">'.$column.'</td>';
        }
        $repl.='</tr>';
      }
      $repl.='</table>';
      $data = str_replace($page_parse, $repl, $data);
    }
    */


    // 26-Jun-2003, by zaufi
    //
    // {maketoc} --> create TOC from '!', '!!', '!!!' in current document
    //
    preg_match_all("/\{maketoc\}/",$data,$tocs);
    $anch=array();

    // 08-Jul-2003, by zaufi
    // HotWords will be replace only in ordinal text
    // It looks __realy__ goofy in Headers or Titles

    // Now tokenize the expression and process the tokens
    // Use tab and newline as tokenizing characters as well  ////
    $lines = explode("\n",$data);
    $data = '';
    $listbeg = array();
    $divdepth = array();
    $inTable = 0;

    // loop: process all lines
    foreach ($lines as $line) {

      // Check for titlebars...
      // NOTE: that title bar should be start from begining of line and
      //       be alone on that line to be autoaligned... else it is old styled
      //       styled title bar...
      
      if (substr(ltrim($line), 0, 2) == '-='
       && substr(rtrim($line), -2, 2) == '=-')
      {
        // This is not list item -- must close lists currently opened
	while(count($listbeg)) $data.=array_shift($listbeg);
	//
	$align_len = strlen($line) - strlen(ltrim($line));

	// My textarea size is about 120 space chars.
        //define('TEXTAREA_SZ', 120);

	// NOTE: That strict math formula (split into 3 areas) gives
	//       bad visual effects...
	// $align = ($align_len < (TEXTAREA_SZ / 3)) ? "left" 
        //        : (($align_len > (2 * TEXTAREA_SZ / 3)) ? "right" : "center");
	//
	// Going to introduce some heuristic here :)
        // Visualy (remember that space char is thin) center starts at 25 pos
	// and 'right' from 60 (HALF of full width!) -- thats all :)
	//
	// NOTE: Guess align only if more than 10 spaces before -=title=-
	if ($align_len > 10)
	{
	    $align = ($align_len < 25) ? "left" : (($align_len > 60) ? "right" : "center");
	    $align = ' style="text-align: '.$align.';"';
	}
	else $align='';	
	//
	$line = trim($line);
	$line = '<div class="titlebar"'.$align.'>'.substr($line, 2, strlen($line) - 4).'</div>';
	$data .= $line;
	// TODO: Case is handled ...  no need to check other conditions
	//       (it is apriory known all they false, moreover sometimes
	//       check procedure need > O(0) of compexity)
	//       -- continue to next line...
	//       MUST replace all remaining parse blocks to the same logic...
	continue;
      }
      // Replace old styled titlebars 
      if (strlen($line) != strlen($line = preg_replace("/-=(.+?)=-/","<div class='titlebar'>$1</div>",$line)))
      {
	$data .= $line;
	continue;
      }
      // check if we are inside a table, if so, ignore monospaced and do
      // not insert <br/>
      $inTable += substr_count($line,"<table");
      $inTable -= substr_count($line,"</table");

      // If the first character is ' ' and we are not in pre then we are in pre
      global $feature_wiki_monosp;
      if(substr($line,0,1)==' ' && $feature_wiki_monosp=='y' && $inTable==0 ) {
        // This is not list item -- must close lists currently opened
	while(count($listbeg)) $data.=array_shift($listbeg);
        // If the first character is space then
        // change spaces for &nbsp;
        $line = '<font face="courier" size="2">'.str_replace(' ','&nbsp;',substr($line,1)).'</font>';
        $line.='<br/>';
      } else {
        // Replace monospaced text
        $line = preg_replace("/-\+(.*?)\+-/","<code>$1</code>",$line);
        // Replace bold text
        $line = preg_replace("/__(.*?)__/","<b>$1</b>",$line);
        $line = preg_replace("/\'\'(.*?)\'\'/","<i>$1</i>",$line);
        // Replace definition lists
        $line = preg_replace("/^;([^:]+):([^\n]+)/","<dl><dt>$1</dt><dd>$2</dd></dl>",$line);
        if(0) {
        $line = preg_replace("/\[([^\|]+)\|([^\]]+)\]/","<a class='wiki' $target href='$1'>$2</a>",$line);
        // Segundo intento reemplazar los [link] comunes
        $line = preg_replace("/\[([^\]]+)\]/","<a class='wiki' $target href='$1'>$1</a>",$line);
        $line = preg_replace("/\-\=([^=]+)\=\-/","<div class='wikihead'>$1</div>",$line);
        }

        // This line is parseable then we have to see what we have
        if(substr($line,0,3)=='---') {
          // This is not list item -- must close lists currently opened
          while(count($listbeg)) $data.=array_shift($listbeg);
          $line='<hr/>';
        } else {
          $litype=substr($line,0,1);
          if ($litype=='*'||$litype=='#') {
            $listlevel=wiki_how_many_at_start($line,$litype);
            $liclose='</li>';
            $addremove=0;
            if ($listlevel<count($listbeg)) {
              while($listlevel!=count($listbeg)) $data.=array_shift($listbeg);
              if(substr(current($listbeg),0,5)!='</li>') $liclose='';
            } elseif($listlevel>count($listbeg)) {
              $listyle='';
              while ($listlevel!=count($listbeg)) {
                array_unshift($listbeg,($litype=='*'?'</ul>':'</ol>'));
                if ($listlevel==count($listbeg)) {
                  $listate=substr($line,$listlevel,1);
                  if(($listate=='+'||$listate=='-')
                   &&!($litype=='*'&&!strstr(current($listbeg),'</ul>')
                    || $litype=='#'&&!strstr(current($listbeg),'</ol>'))) {
                    $thisid='id'.microtime()*1000000;
                    $data.='<br/><a id="flipper'.$thisid.'" class="link" href="javascript:flipWithSign(\''.$thisid.'\')">['.($listate=='-'?'+':'-').']</a>';
                    $listyle=' id="'.$thisid.'" style="display:'.($listate=='+'?'block':'none').';"';
                    $addremove=1;
                  }
                }
                $data.=($litype=='*'?"<ul$listyle>":"<ol$listyle>");
              }
              $liclose='';
            }
            if ($litype=='*'&&!strstr(current($listbeg),'</ul>')
             || $litype=='#'&&!strstr(current($listbeg),'</ol>')) {
              $data.=array_shift($listbeg);
              $listyle='';
              $listate=substr($line,$listlevel,1);
              if(($listate=='+'||$listate=='-')) {
                $thisid='id'.microtime()*1000000;
                $data.='<br/><a id="flipper'.$thisid.'" class="link" href="javascript:flipWithSign(\''.$thisid.'\')">['.($listate=='-'?'+':'-').']</a>';
                $listyle=' id="'.$thisid.'" style="display:'.($listate=='+'?'block':'none').';"';
                $addremove=1;
              }
              $data.=($litype=='*'?"<ul$listyle>":"<ol$listyle>");
              $liclose='';
              array_unshift($listbeg, ($litype=='*'?'</li></ul>':'</li></ol>'));
            }
            $line=$liclose.'<li>'.substr($line,$listlevel+$addremove);
            if(substr(current($listbeg),0,5)!='</li>')
              array_unshift($listbeg,'</li>'.array_shift($listbeg));
	  } elseif($litype=='+') {
            // Must append paragraph for list item of given depth...
            $listlevel=wiki_how_many_at_start($line,$litype);
            // Close lists down to requested level
            while($listlevel<count($listbeg)) $data.=array_shift($listbeg);
            if(count($listbeg)) {
              if(substr(current($listbeg),0,5) != '</li>') {
                array_unshift($listbeg,'</li>'.array_shift($listbeg));
                $liclose='<li>';
              } else $liclose='<br/>';
            } else $liclose='';
            $line=$liclose.substr($line,count($listbeg));
          } else {
            // This is not list item -- must close lists currently opened
            while(count($listbeg)) $data.=array_shift($listbeg);
            // Get count of (possible) header signs at start
            $hdrlevel=wiki_how_many_at_start($line,'!');
            // If 1st char on line is '!' and its count less than 6 (max in HTML)
            if($litype=='!'&&$hdrlevel>0&&$hdrlevel<=6) {
              // Remove possible hotwords replaced :)
              $line = strip_tags($line);
              // OK. Parse headers here...
              $anchor=''; $aclose=''; $addremove=0;
              // Close lower level divs if opened
              for(;current($divdepth)>=$hdrlevel;array_shift($divdepth)) $data.='</div>';
              // May be spesial signs present after '!'s?
              $divstate=substr($line,$hdrlevel,1);
              if($divstate=='+'||$divstate=='-') {
                // OK. Must insert flipper after HEADER, and then open new div...
                $thisid='id'.microtime()*1000000;
                $aclose='<a id="flipper'.$thisid.'" class="link" href="javascript:flipWithSign(\''.$thisid.'\')">['.($divstate=='-'?'+':'-').']</a>';
                $aclose.='<div id="'.$thisid.'" style="display:'.($divstate=='+'?'block':'none').';">';
                array_unshift($divdepth, $hdrlevel);
                $addremove=1;
              }
              // Is any {maketoc} present on page?
	      if(count($tocs[0])>0) {
                // OK. Must insert <a id=...> before HEADER and collect TOC entry
                $thisid='id'.microtime()*1000000;
	        array_push($anch,str_repeat("*",$hdrlevel)." <a href='#$thisid'>".substr($line,$hdrlevel+$addremove).'</a>');
                $anchor="<a id='$thisid'>"; $aclose='</a>'.$aclose;
	      }
              $line = $anchor."<h$hdrlevel>".substr($line,$hdrlevel+$addremove)."</h$hdrlevel>".$aclose;
            } else {
              if (!strcmp($line, "...page...")) {
                // Close lists and divs currently opened
                while(count($listbeg)) $data.=array_shift($listbeg);
                while(count($divdepth)) {
                  $data.='</div>';
                  array_shift($divdepth);
                }
                // Leave line unchanged... tiki-index.php will split wiki here
                $line="\n...page...\n";
              } else {
                // Usual paragraph.
                if ($inTable == 0) { $line.='<br/>'; }
	      }
	    }
          }
        }
      }
      $data.=$line;
    }


    // Close lists may remains opened
    while(count($listbeg)) $data.=array_shift($listbeg);
    // Close header divs may remains opened
    for($i=1;$i<=count($divdepth);$i++) $data.='</div>';

    // 26-Jun-2003, by zaufi
    // Replace {maketoc} from collected list of headers
    $html='';
    foreach($anch as $tocentry) {
      $html.=$tocentry."\n"; 
    }
    if(count($anch)) $html=wiki_parse_data($html);
    $data=str_replace("{maketoc}",$html,$data);

/*    
    // Replace rss modules
    if(preg_match_all("/\{rss +id=([0-9]+) *(max=([0-9]+))? *\}/",$data,$rsss)) {
	  if(!isset($rsslib)) {
	  include('lib/rss/rsslib.php');
	  }

      for($i=0;$i<count($rsss[0]);$i++) {
        $id = $rsss[1][$i];
        $max = $rsss[3][$i];
        if(empty($max)) $max=99;
        $rssdata = $rsslib->get_rss_module_content($id);
        $items = $rsslib->parse_rss_data($rssdata);
        $repl='';
        for($j=0;$j<count($items) && $j<$max;$j++) {
         $repl.='<li><a target="_blank" href="'.$items[$j]["link"].'" class="wiki">'.$items[$j]["title"].'</a></li>';
        }
        $repl='<ul>'.$repl.'</ul>';
        $data = str_replace($rsss[0][$i],$repl,$data);
      }
    }
*/

    // Close BiDi DIVs if any
    for ($i = 0; $i < $bidiCount; $i++) {
      $data.="</div>";
    }


    foreach($noparsed as $np) {
      $data = str_replace($np["key"],$np["data"],$data);
    }
    

    foreach($preparsed as $pp) {
      $data = str_replace($pp["key"],"<pre>".$pp["data"]."</pre>",$data);
    }

    return $data;
  }
  

  function wiki_parse_first( &$data, &$preparsed, &$noparsed )
  {
    // Handle pre- and no-parse sections
    parse_wiki_pp_np( $data, $preparsed, $noparsed );
    
    // Find the plugins
    // note: [1] is plugin name, [2] is plugin arguments

/*
    preg_match_all( "/\{([A-Z]+)\(([^\)]*)\)\}/", $data, $plugins );

	// if true, replace only CODE plugin, if false, replace all other plugins
	$code_first=true;
	
    // Process plugins in reverse order, so that nested plugins are handled
    // from the inside out.
    $i=count($plugins[0])-1;
    while ($i>=0) {
      $plugin_start = $plugins[0][$i];
      $plugin = $plugins[1][$i];
      $plugin_end = '{'.$plugin.'}';
      $plugin_start_base = '{'.$plugins[1][$i].'(';
      $pos = strpos( $data, $plugin_start );         // where plugin starts
      $pos_end = strpos( $data, $plugin_end, $pos ); // where plugin data ends
      if (
      	  // when in CODE parsing mode, replace only CODE plugins 
	      ( (($code_first) && ($plugin=='CODE'))
	      ||
      	  // when NOT in CODE parsing mode, replace all other plugins 
	      ((!$code_first) && ($plugin<>'CODE')) )
	      &&
	      ($pos_end > $pos)
	      )
      {
        // Extract the plugin data
        $plugin_data_len = $pos_end - $pos - strlen($plugins[0][$i]);
        $plugin_data = substr( $data, $pos + strlen($plugin_start),
                               $plugin_data_len );

        // Construct plugin file pathname
        $php_name = 'lib/wiki-plugins/wikiplugin_';
        $php_name.= strtolower($plugins[1][$i]).'.php';

        // Construct plugin function name
        $func_name = 'wikiplugin_'.strtolower($plugins[1][$i]);

        // Construct argument list array
        $params = split(',',trim($plugins[2][$i]));
        $arguments = Array();
        foreach ($params as $param) {
          $parts = explode( '=>', $param );
          if (isset( $parts[0] ) && isset( $parts[1]) ) {
            $name = trim( $parts[0] );
            $arguments[$name] = trim( $parts[1] );
          }
        }

        if (file_exists($php_name)) {
          include_once($php_name);
          $ret = $func_name( $plugin_data, $arguments );

          // Handle pre- & no-parse sections and plugins inserted by this plugin
          wiki_parse_first( $ret, $preparsed, $noparsed );

          // Replace plugin section with its output in data
          $data = substr_replace( $data, $ret, $pos,
                                  $pos_end - $pos + strlen($plugin_end) );
        }
      }
      $i--;
      // if we are in CODE parsing mode and list is done, switch to 'parse other plugins' mode and start all over
      if (($code_first) && ($i<0)) { $i=count($plugins[0])-1; $code_first=false; }
    } // while
	
*/
  }


  function parse_wiki_pp_np( &$data, &$preparsed, &$noparsed )
  {
    // Find all sections delimited by ~pp~ ... ~/pp~
    // and replace them in the data stream with a unique key
    preg_match_all("/\~pp\~((.|\n)*?)\~\/pp\~/",$data,$preparse);
    foreach(array_unique($preparse[1]) as $pp) {
      $key=md5(wiki_genPass());
      $aux["key"]=$key;
      $aux["data"]=$pp;
      $preparsed[]=$aux;
      $data=str_replace( "~pp~$pp~/pp~", $key, $data );
    } 
    // Temporary remove <pre> tags too
    // TODO: Is this a problem if user insert <PRE> but after parsing
    //       will get <pre> (lowercase)?? :)
    preg_match_all("/(<[Pp][Rr][Ee]>)((.|\n)*?)(<\/[Pp][Rr][Ee]>)/",$data,$preparse);
    $idx=0;
    foreach(array_unique($preparse[2]) as $pp) {
      $key=md5(wiki_genPass());
      $aux["key"]=$key;
      $aux["data"]=$pp;
      $preparsed[]=$aux;
      $data=str_replace($preparse[1][$idx].$pp.$preparse[4][$idx],$key,$data);
      $idx=$idx+1;
    }

    // Find all sections delimited by ~np~ ... ~/np~
    $new_data = '';
    $nopa = '';
    $state = true;
    $skip = false;
    for ($i=0; $i<strlen($data); $i++) {
      $tag5 = substr($data,$i,5);
      $tag4 = substr($tag5,0,4);
      $tag1 = substr($tag4,0,1);
      // Beginning of a noparse section found
      if($state && $tag4 == '~np~') {
        $i+=3;
        $state = false;
        $skip=true;
      }
      // Termination of a noparse section found
      if(!$state && ($tag5 == '~/np~')) {
        $state = true;
        $i+=4;
        $skip=true;
        $key = md5(wiki_genPass());
        $new_data.=$key;
        $aux["key"]=$key;
        $aux["data"]=$nopa;
        $noparsed[]=$aux;
        $nopa='';
      }
      if(!$skip) {   // This character is not part of a noparse tag
        if($state) {    // This character is not within a noparse section
          $new_data .= $tag1;
        } else {        // This character is within a noparse section
          $nopa .= $tag1;
        }
      } else {       // Tag is now skipped over
        $skip = false;
      }
    }
    $data = $new_data;
  }

  function wiki_parse_htmlchar(&$data)
  {
	// cleaning some user input
	$data = preg_replace( "/&(?!([a-z]{1,7};))/", "&amp;", $data );
		
    // oft-used characters (case insensitive)
    $data = preg_replace( "/~bs~/i", "&#92;", $data );
    $data = preg_replace( "/~hs~/i", "&nbsp;", $data );
    $data = preg_replace( "/~amp~/i", "&amp;", $data );
    $data = preg_replace( "/~ldq~/i", "&ldquo;", $data );
    $data = preg_replace( "/~rdq~/i", "&rdquo;", $data );
    $data = preg_replace( "/~lsq~/i", "&lsquo;", $data );
    $data = preg_replace( "/~rsq~/i", "&rsquo;", $data );
    $data = preg_replace( "/~c~/i", "&copy;", $data );
    $data = preg_replace( "/~--~/", "&mdash;", $data );
    $data = preg_replace( "/~lt~/i", "&lt;", $data );
    $data = preg_replace( "/~gt~/i", "&gt;", $data );

    // HTML numeric character entities
    $data = preg_replace( "/~([0-9]+)~/", "&#$1;", $data );
  }

  /*shared*/ function wiki_genPass()
  {
        $vocales="aeiouAEIOU";
        $consonantes="bcdfghjklmnpqrstvwxyzBCDFGHJKLMNPQRSTVWXYZ0123456789_";
        $r='';
        for($i=0; $i<8; $i++){
                if ($i%2){
                        $r.=$vocales{rand(0,strlen($vocales)-1)};
                }else{
                        $r.=$consonantes{rand(0,strlen($consonantes)-1)};
                }
        }
        return $r;
  }


  function wiki_parse_smileys($data)
  {
    $data = preg_replace("/\(:([^:]+):\)/","<img title=\"$1\" src=\"templates/default/media/wiki_smiles/icon_$1.gif\" />",$data);
    return $data;
  }


  function wiki_get_links($data)
  {
    $links = Array();
    if(preg_match_all("/\[([^\[\|\]]+)(\||\])/",$data,$r1)) {

      $res = $r1[1];
      $links = array_unique($res);
    }

    return $links;
  }

  
  function wiki_get_links_nocache($data)
  {
    $links = Array();
    if(preg_match_all("/\[([^\]]+)/",$data,$r1)) {
      $res = Array();
      foreach($r1[1] as $alink) {
        $parts = explode('|',$alink);
        if(isset($parts[1])&& $parts[1] == 'nocache' ) {
          $res[] = $parts[0];
        } else {
          if(isset($parts[2]) && $parts[2] == 'nocache') {
            $res[] = $parts[0];
          }
        }
      }

      $links = array_unique($res);
    }

    return $links;
  }

  function wiki_how_many_at_start($str,$car)
  {
    $cant =0;
    $i=0;
    while(($i<strlen($str)) && (isset($str{$i})) && ($str{$i}==$car)){
      $i++;
      $cant++;
    }
    return $cant;
  }

?>
