<?php
set_error_handler ('php_error_handler');
error_reporting (E_ALL | E_STRICT); ini_set ('display_errors', 1);
date_default_timezone_set ('Europe/Moscow');

ini_set ('memory_limit', '2048M'); gc_enable();
ini_set ('max_execution_time', 0);

/* * */

$file_name = ''; $path = '';

if (count ($argv) == 3) {
    $file_name = $argv[1];
    $path = $argv[2];
}

$check_relations = 0;

if (count ($argv) == 4) {
    $check_relations = $argv[1];
    $file_name = $argv[2];
    $path = $argv[3];
}

if ($check_relations != '--check-relations') $check_relations = 0;

if (!$file_name || !file_exists ($file_name)) exit;
if (!$path || !file_exists ($path)) exit;

/* * */

$file = fopen ($file_name, 'r');
$book = fread ($file, filesize ($file_name));
fclose ($file); unset ($file);

$book = rtrim ($book); 

if ($check_relations) checkRelatedFiles ($book, $path);

/* * */

$book = processIncludes ($book, $path);

for ($step = 1; $step <= 4; $step ++) {
     $sequence = ':h'.$step.'.';
     $book = strreplace ($book, $sequence, '.br'."\r\n".$sequence);
}

$book = strreplace ($book, ':p.'."\r\n\r\n", '');
$book = strreplace ($book, ' '."\r\n", "\r\n");

$head = substr ($book, 0, strpos ($book, ':h1'));
$book = substr ($book, strpos ($book, ':h1'));
$head = strreplace ($head, '.br', '');
$book = $head.$book;

yield_time ();

$book = strreplace ($book, ':ul.', ':ul compact.');
$book = strreplace ($book, ':ol.', ':ol compact.');
$book = strreplace ($book, ':sl.', ':sl compact.');

$book = strreplace ($book, ':font facename=Courier.', 
                           ':font facename=Courier size=8x8.');

yield_time ();

for ($step = 1; $step <= 8; $step ++) {
     if ($step == 1) $symbol = '.';
     if ($step == 2) $symbol = '!';
     if ($step == 3) $symbol = '"';
     if ($step == 4) $symbol = "'";
     if ($step == 5) $symbol = '/';
     if ($step == 6) $symbol = "\\";
     if ($step == 7) $symbol = "\r";
     if ($step == 8) $symbol = "\n";

     $book = strreplace ($book, ':'.$symbol, '&colon.'.$symbol);
}

yield_time ();

$book = strreplace ($book, '<:>',   '&colon.');
$book = strreplace ($book, '<.>',   '&per.');
$book = strreplace ($book, '<&>',   '&amp.');
$book = strreplace ($book, '<...>', '&per.&per.&per.');

$book = strreplace ($book, '::',    '&colon.&colon.');
$book = strreplace ($book, ' : ',   ' &colon. ');
$book = strreplace ($book, ' & ',   ' &amp. ');

$book = strreplace ($book, ' :-)',  ' &colon.-)');
$book = strreplace ($book, ' :-(',  ' &colon.-(');
$book = strreplace ($book, ' :0)',  ' &colon.0)');
$book = strreplace ($book, ' :0(',  ' &colon.0(');
$book = strreplace ($book, ' :-\\', ' &colon.-\\');
$book = strreplace ($book, ' :-|',  ' &colon.-|');

$book = strreplace ($book, ':artwork align=\'center\' name=\'',
                           ':artwork align=\'center\' name=\''.$path."\\");

$book = strreplace ($book, chr (249), chr (7));

yield_time ();

$book = cutRSpaces ($book);

/* * */

$file = fopen ($file_name, 'w');
fwrite ($file, $book);
fclose ($file); unset ($file);

exit;

/* * */

function checkRelatedFiles ($book, $path) {
    print 'Checking related files...'."\n";

    $extensions = array ('rc', 'txt', 'bmp');

    foreach ($extensions as $ext) {
        $files = rglob ($path.'/', '*.'.$ext); sort ($files);

        foreach ($files as $file_name) {
            $short_name_1 = strreplace ($file_name, strreplace ($path, '\\', '/').'/', '');
            $short_name_2 = strreplace ($short_name_1, '/', '\\');

            if (!strpos ($book, $short_name_1) && !strpos ($book, $short_name_2)) {
                print 'Relation not found: '.$file_name."\n"; sleep (20); throw new Exception ();
            }
        }

        yield_time ();
    }

    print "\n";
}

function processIncludes ($book, $path) {
    $lines = explode ("\r\n", $book);
    $limit = count ($lines);

    $rc_file_names = array ();

    for ($line_cntr = 0; $line_cntr < $limit; $line_cntr ++) {
         $line = $lines[$line_cntr];

         if (strlen ($line) < 10) continue;
         if ($line[0] != ':' ||
             $line[1] != 'i' ||
             $line[2] != 'n' ||
             $line[3] != 'c' ||
             $line[4] != 'l' ||
             $line[5] != 'u' ||
             $line[6] != 'd' ||
             $line[7] != 'e' ||
             $line[8] != ' ') continue;

         $line = strtr ($line, '"', "'");

         $mode = 'IPF';
         if (strpos ($line, "mode='code'")) $mode = 'CODE';

         $file_name = $line;
         $file_name = substr ($file_name, strpos ($file_name, "file='") + strlen ("file='"));
         $file_name = substr ($file_name, 0, strpos ($file_name, "'."));
         $file_name = $path."\\".$file_name;

         if (!file_exists ($file_name)) continue;

         if (!filesize ($file_name)) {
             print 'File is empty: '.$file_name."\n"; sleep (20); throw new Exception ();
         }

         if (strpos ($file_name, '.rc')) rememberFile ($rc_file_names, $file_name);

         $file = fopen ($file_name, 'r');
         $text = fread ($file, filesize ($file_name));
         fclose ($file); unset ($file);

         $text = rtrim ($text);

         if ($mode == 'TXT' || $mode == 'CODE') {
             $text_lines = explode ("\r\n", $text);

             for ($tl_cntr = 0; $tl_cntr < count ($text_lines); $tl_cntr ++) {
                  $replace_tags = 1;
                  if (strpos (' '.$text_lines[$tl_cntr], ':color')) $replace_tags = 0;

                  if ($replace_tags) {
                      if (strpos (' '.$text_lines[$tl_cntr], ':'))   $text_lines[$tl_cntr] = strreplace ($text_lines[$tl_cntr], ':',   '<:>'  );
                      if (strpos (' '.$text_lines[$tl_cntr], '.'))   $text_lines[$tl_cntr] = strreplace ($text_lines[$tl_cntr], '.',   '<.>'  );
                      if (strpos (' '.$text_lines[$tl_cntr], '&'))   $text_lines[$tl_cntr] = strreplace ($text_lines[$tl_cntr], '&',   '<&>'  );
                      if (strpos (' '.$text_lines[$tl_cntr], '...')) $text_lines[$tl_cntr] = strreplace ($text_lines[$tl_cntr], '...', '<...>');
                  }

                  $text_lines[$tl_cntr] = rtrim ($text_lines[$tl_cntr]);
                  if ($mode == 'CODE') $text_lines[$tl_cntr] = chr(255).strreplace($text_lines[$tl_cntr], ' ', chr(255));

                  if ($tl_cntr > 0) $text_lines[$tl_cntr] = '.br'."\r\n".$text_lines[$tl_cntr];
             }

             $lines[$line_cntr] = implode ("\r\n", $text_lines);
         } else {
             $lines[$line_cntr] = $text;
         }

         if ($line_cntr % 1000 == 0) yield_time ();
    }

    if ($rc_file_names) checkParity ($rc_file_names);

    return implode ("\r\n", $lines);
}

function cutRSpaces ($book) {
    $lines = explode ("\r\n", $book);
    $limit = count ($lines);

    for ($line_cntr = 0; $line_cntr < $limit; $line_cntr ++) {
         $line = rtrim ($lines[$line_cntr]);
         if ($line != $lines[$line_cntr]) $lines[$line_cntr] = $line;
    }

    return implode ("\r\n", $lines);
}

function rememberFile (&$files, $file_name) {
    if (!isset ($files[$file_name])) {
        $files[$file_name] = 1;
    } else {
        $files[$file_name] ++;
    }
}

function checkParity ($files) {
    /* print count ($files)."\n"; */

    if (count ($files) % 2 != 0) {
        print 'Parity check failed ('.count ($files).')'; sleep (20); throw new Exception ();
    }
}

/* * */

function rglob ($path_w_slash, $pattern, $flags = 0) {
    if (substr ($path_w_slash, -1) != '/') $path_w_slash .= '/';

    $paths = glob ($path_w_slash.'*', GLOB_ONLYDIR);
    $files = glob ($path_w_slash.$pattern, $flags);

    foreach ($paths as $next_step_path) {
        $next_step_files = rglob ($next_step_path.'/', $pattern, $flags); 
        foreach ($next_step_files as $next_step_file) { $files[] = $next_step_file; }
    }

    return $files;
}

/* * */

function strreplace ($haystack, $needle, $str) { return str_replace ($needle, $str, $haystack); }
function yield_time () { if (function_exists ('proc_nice')) { proc_nice (abs (31)); } else { usleep (25); } }

function php_error_handler ($errno, $errstr, $errfile, $errline, $vars = null) { 
    if (strpos ($argv[1], '.ipf') && file_exists ($argv[1])) unlink ($argv[1]);
    die ("\n\n".'['.$errno.'] '.$errstr.' ('.strtr ($errfile, '\\', '/').', '.$errline.')'."\n\n");
}
