<?php if (!defined('PmWiki')) exit();
/*  Copyright 2007 Patrick R. Michaud (pmichaud@pobox.com)
    This file is converttiki.php; 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.  

    This script attempts to convert TikiWiki pages to PmWiki.  It's
    still a preliminary implementation.  

    The first step is to use TikiWiki's "export" function to get
    a tar image of all of the wiki pages, then extract that tar
    image into a directory.  The resulting directory should contain
    one file for each page stored in TikiWiki.

    Then, in PmWiki, add the following lines to local/config.php:

        include_once('cookbook/converttiki.php');
        UseTikiDir('tiki.d', 'Tiki');

    Here, 'tiki.d' is the name of the directory containing the page files
    exported from TikiWiki, and 'Tiki' is the name of the PmWiki group
    to use for the pages.  

    If all works well, then the TikiWiki pages should appear as though
    they are standard PmWiki pages.  Any edits made to pages in the Tiki/
    group will be saved in PmWiki's wiki.d/ directory (thus leaving
    the original TikiWiki exported files intact).

    This script also adds "?action=converttiki", which allows a wiki
    administrator to batch convert some or all of the TikiWiki pages
    into PmWiki format.

*/

$RecipeInfo['ConvertTikiWiki']['Version'] = '2007-03-30';


##  TikiWiki markup to PmWiki markup conversions

SDVA($ConvertTiki, array(

  # {CODE(0,0)}...{CODE} --> [@...@]
  '/\\{CODE\\(0,0\\)\\}(.+?)\\{CODE\\}/s' => '[@$1@]',

  # ==underline== --> '+underline+'
  '/==(.+)==/' => "'+$1+'",

  # __bold__ --> '''bold'''
  '/__(.+)__/' => "'''$1'''",

  # ;term:definition --> :term:definition
  '/(;+)(.*?:)/e' => "str_replace(';', ':', '$1') . PSS('$2')",

  # -+monospace+-  --> @@monospace@@
  '/-\\+(.+?)\\+-/' => '@@$1@@',

  # ((pagename)) --> [[pagename]]
  '/\\(\\((.+?)\\)\\)/' => '[[$1]]',
));



class PageStoreTiki extends PageStore {
  var $group;
  function PageStoreTiki($path, $group) {
    $this->dirfmt = $path;
    $this->group = $group;
    $this->iswrite = 0;
    $GLOBALS['PageExistsCache'] = array();
  }
  function pagefile($pagename) {
    if (!preg_match("/^{$this->group}\\./", $pagename)) return '';
    return FmtPageName($this->dirfmt, $pagename);
  }
  function read($pagename) {
    global $ConvertTiki;
    $pagefile = $this->pagefile($pagename);
    if ($pagefile && ($fp=@fopen($pagefile, "r"))) {
      ##  get heading details into $attr
      $seenboundary = 0;
      $boundary='--xxx';
      while (!feof($fp)) {
        $line = fgets($fp, 4096);
        while (substr($line, -1, 1) != "\n" && !feof($fp))
          $line .= fgets($fp, 4096);
        $line = rtrim($line);
        if (preg_match('/^\\s+(\\w+)=(.*)$/', $line, $match)) {
          list($x, $k, $v) = $match;
          $v = preg_replace('/;$/', '', $v);
          $attr[$k] = preg_replace('/^"(.*)"$/', '$1', $v);
          if ($k == 'boundary') $boundary = "--{$attr[$k]}"; 
          continue;
        }
        if ($line == $boundary) $seenboundary = 1;
        if ($line == '' && $seenboundary) break;
      }
      ##  get page markup into $text
      $text = '';
      while (!feof($fp)) { 
        $line = fgets($fp, 4096);
        while (substr($line, -1, 1) != "\n" && !feof($fp))
          $line .= fgets($fp, 4096);
        $line = rtrim($line);
        if ($line == $boundary) break;
        $text .= $line . "\n";
      }
      fclose($fp);
      ## convert TikiWiki attributes to PmWiki attributes
      foreach(array('pagename'=>'name', 'author'=>'author', 'lastmodified'=>'time',
                    'version'=>'rev') as $t=>$p)
        if (isset($attr[$t])) $page[$p] = $attr[$t];
      $page['text'] = 
        preg_replace(array_keys($ConvertTiki), array_values($ConvertTiki), $text);
    }
    return @$page;
  }
  function ls($pats = NULL) {
    global $GroupPattern, $NamePattern;
    StopWatch("PageStoreTiki::ls begin {$this->dirfmt}");
    $pats=(array)$pats;
    array_push($pats, "/^$GroupPattern\.$NamePattern$/");
    $maxslash = substr_count($dir, '/');
    $dir = preg_replace('!/*[^/]*\\$.*$!','',$this->dirfmt);
    $out = array();
    $dfp = @opendir($dir);
    if ($dfp) {
      while ( ($pagefile = readdir($dfp)) !== false) {
        if ($pagefile{0} == '.') continue;
        $o[] = $this->group . ".$pagefile";
      }
      closedir($dfp);
      StopWatch("PageStore::ls merge {$this->dirfmt}");
      $out = array_merge($out, MatchPageNames($o, $pats));
    }
    StopWatch("PageStore::ls end {$this->dirfmt}");
    return $out;
  }
}

function UseTikiDir($path, $group = 'Tiki') {
  global $WikiLibDirs;
  if (!is_dir($path)) {
    Abort("?$path is not an accessible directory");
    exit();
  }
  array_splice($WikiLibDirs, 1, 0,
               array(new PageStoreTiki("$path/\$Name", $group)));
}


SDV($HandleActions['converttiki'], 'HandleConvertTiki');
SDV($HandleAuth['converttiki'], 'admin');

function HandleConvertTiki($pagename, $auth = 'admin') {
  $page = RetrieveAuthPage($pagename, $auth, true, READPAGE_CURRENT);
  if (!$page) Abort("?$auth permission required");

  global $WikiDir, $WikiLibDirs;
  Lock(2);

  $from = 'TikiWiki';
  $to = 'PmWiki';

  $oldlist = array(); $olddirs = array();  $path = '';
  foreach($WikiLibDirs as $d) {
    if (!is_a($d, 'PageStoreTiki')) continue;
    $olddirs[] = $d;
    $path .= ' ' . preg_replace('![^/]*\\$.*!', '', $d->dirfmt);
    $oldlist = array_merge($oldlist, $d->ls());
  }
  $newlist = ListPages();
  $bothlist = array_intersect($oldlist,$newlist); sort($bothlist);
  $difflist = array_diff($oldlist,$newlist); sort($difflist);
  $bcount = count($bothlist);
  $dcount = count($difflist);

  echo "
    <html>
    <head>
    <title>Convert $from pages to $to</title>
    </head>
    <body>
    <h2>Convert and Copy $from pages into $to</h2>
  ";

  $copy = array();
  if (@$_POST['copydiff']) $copy = $difflist;
  if (@$_POST['copyboth']) $copy = array_merge($copy,$bothlist);
  if (@$_POST['copy']) $copy = array_merge($copy,$_POST['copy']);
  if (@$copy) {
    echo "<p>Okay, I'm now converting the pages you've requested.
       When this is finished, you can see if anything else needs to
       be converted, otherwise you can remove this conversion script
       from your local/config.php file.</p>";
    $copy = array_unique($copy);
    foreach($copy as $p) {
      echo "<li>Converting $p</li>\n";
      foreach($olddirs as $d) 
        if ($d->exists($p)) { $page = $d->read($p); break; }
      WritePage($p,$page);
    }
    echo "<p>Converted ", count($copy), " pages.</p>\n";
  } else {
    echo "
      <p>This function will migrate pages from a $from directory ($path)
      into your $to wiki.d/ directory, converting markups as it proceeds.
      Note that the files in your $from directory are not affected
      by this script, so if the conversion doesn't work out for any reason
      you still have your original pages lying around.</p>
    ";
  }

  /* now rebuild the lists */
  $oldlist = array(); $olddirs = array();
  foreach($WikiLibDirs as $d) {
    if (!is_a($d, 'PageStoreTiki')) continue;
    $olddirs[] = $d;
    $oldlist = array_merge($oldlist, $d->ls());
  }
  $newlist = ListPages();
  $bothlist = array_intersect($oldlist,$newlist); sort($bothlist);
  $difflist = array_diff($oldlist,$newlist); sort($difflist);
  $bcount = count($bothlist);
  $dcount = count($difflist);


  echo " <form method='post'> ";

  echo "<h3>Migrate pages from $from to $to (don't overwrite existing
    $to pages)</h3>";

  if ($difflist) {
    echo "
      <p>The following $dcount pages exist only in the $from directory.  </p>
      <dd><input type='submit' name='copydiff' value='Copy and convert all
        pages that do not already exist' /></dd>
      <p>or</p><dd><input type='submit' name='copyindv' value='Copy and convert
        pages checked in the list below' /><p></p></dd>
    ";
    foreach($difflist as $p)
      echo "<dd><input type='checkbox' name='copy[]' value='$p' /> $p</dd>\n";
  } else {
    echo "<p>There aren't any pages in your $from directory that
      are not already in your $to directory.</p>";
  }

  echo "<h3>Migrate pages from $from to $to (overwrite existing $to pages)</h3>
    <p>The following $bcount pages exist in <em>both</em> the $from and
    $to directories.  If you use one of the buttons below,
    then your converted $from pages will <em>overwrite</em> the existing
    $to pages, and you will lose any edits that you might have made
    in the $to installation (it's possible that this is what you want).</p>
    <dd><input type='submit' name='copyboth' value='Convert and overwrite
      pages that do already exist' /></dd>
    <p>or</p><dd><input type='submit' name='copyindv' value='Convert and
      overwrite pages checked in the list below' /><p></p></dd>
  ";
  foreach($bothlist as $p)
    echo "<dd><input type='checkbox' name='copy[]' value='$p' /> $p</dd>\n";

  echo "</form></body></html>\n";
  exit();
}