<?php
/* israblog.php - Import the HTML format "backup" file generated by israblog into wordpress
 *
 * Copyright (C) 2006 Shachar Shemesh
 *
 *  This program 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.
 *
 *  This program 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 this program; if not, write to the Free Software Foundation, Inc.,
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

class Israblog_Import {
    var $FILEENC = 'Windows-1255';
    var $DSTENC = 'UTF-8';
    var $linenum=0; # Track the current line number

	function _die() {
	    wp_import_cleanup($file['id']);
	    exit( sprintf(__("Error importing Israblog file: line %d"), $this->linenum) );
	}

    // Shows the welcome screen
    function greet() {
	$title = __('Import Israblog');
	$welcome = __('Howdy! This importer allows you to import posts and comment from a Israblog HTML backup file.');
	echo "<div class='wrap'><h2>$title</h2><p>$welcome</p>";

	if( !isset($_GET['debug']) )
	    $upload_url="admin.php?import=israblog&amp;step=1";
	else
	    $upload_url="admin.php?import=israblog&amp;step=1&amp;debug";
	wp_import_upload_form($upload_url);
    }

    function aligncomment( $current_level, $desired_level )
    {
	//print "<br />$current_level $desired_level ";
	if( $current_level==$desired_level )
	    return $current_level;

	if( $desired_level>$current_level ) {
	    if( $desired_level==$current_level+1 ) {
		print "<ul>";
		$current_level++;
	    } else {
		wp_import_cleanup($file['id']);
		die (sprintf( __("Comment nesting parsing error (level skip) on line %d"), $this->linenum ));
	    }
	} else {
	    while( $desired_level<$current_level ) {
		print "</ul>";
		$current_level--;
	    }
	}

	return $current_level;
    }

    function get_posts() {
	global $wpdb;
	set_magic_quotes_runtime(0);

	$file=fopen($this->file, "rb");
	$state=0; // A state machine variable

	$post=array();

	$comment=array();

	printf ("<h3>%s</h3>\n", __("Parsing posts:\n") );
	print "<p><ol>";
	$comment_display_nesting=-1;
	$postnum=0;
	$comment_parents=array();
	$finished=false;

	while(($line=fgets($file)) && !$finished) {
	    $this->linenum++;
	    $line=trim($line, "\r\n");
	    // echo '"'.htmlspecialchars($line).'"<br />';

	    $repeat=false;
	    do {
		if( isset($_GET['debug']) ) {
		    print "Line $this->linenum, state $state<br />\n";
		}

		$repeat=false;
		switch($state) {
		case 0:
		    if( preg_match('|^<body|i', $line) )
			$state++;
		    elseif( preg_match('|^<!-- saved from url=|i', $line) ) {
			print("</ol></p>\n");
			print(__("<p>Cannot process files saved by Internet Explorer.<br>\n") );
			print(__("You can use <a href=\"http://www.mozilla.com/en-US/firefox/\">FireFox</a> to save the backup file from israblog.</p>\n") );

			return false;
		    }
		    break;
		case 1:
		    // Post header - mostly the date
		    $post=array();
		    $comment_parents=array();
		    $post['post_status']='publish';
		    $post['post_date']=$this->process_date( $line );
		    if( $post['post_date']!==null )
			$state++;
		    else
			$state=10; // Maybe it's the end of the file
		    break;
		case 2:
		    $post['post_title']=$this->process_title( $line );
		    // Need to escape the title to prevent SQL problems
		    $post['post_title']=$wpdb->escape($post['post_title']);
		    $state++;
		    break;
		case 3:
		    $this->process_body( $line ) and $state++;
		    $post['post_content'].=iconv( $this->FILEENC, $this->DSTENC, $line );
		    break;
		case 4:
		    // The line right after the post body is usually an empty horizonral line

		    // Store the post
		    $postnum=wp_insert_post($post);

		    $comment_display_nesting=$this->aligncomment( $comment_display_nesting, -1 );
		    printf ("<li>%s</li>\n", htmlspecialchars( $post['post_title'] ));
		    flush();

		    if( !preg_match('|^<hr />$|i', $line) )
			$repeat=true;
		    $state++;
		    break;
		case 5:
		    // Can be either comment or new post
		    $comment=$this->process_comment1( $line );
		    if( isset($comment['comment_author']) ) {
			// This is, indeed, a comment
			$comment['comment_post_ID']=$postnum;
			$state++;
		    } else {
			// This is actually a post header
			$state=1;
			$repeat=true;
		    }
		    break;
		case 6:
		    // Comment date
		    $comment['comment_date']=$this->process_comment2($line);
		    $state++;
		    break;
		case 7:
		    // Comment mood - we can't translate it, but it's not always present, so we need to parse it
		    if( !preg_match( "|^<img width='15' height='15' src='http://www.israblog.co.il//moodicons/|i",
				$line ) )
			$repeat=true;
		    $state++;
		    break;
		case 8:
		    // Comment body
		    if( !preg_match('|</p>|i', $line) ) {
			$comment['comment_content'].=iconv( $this->FILEENC, $this->DSTENC, $line );
		    } else {

			/*
			# Comment printing code:
			array_push( $this->comments, $comment );

			$comment_display_nesting=$this->aligncomment( $comment_display_nesting,
				$comment['comment_nesting_index'] );
			print "<li>".$comment['comment_author'].
			    (isset($comment['comment_author_email'])?
				sprintf("&#x200f; &lt;%s&gt;",$comment['comment_author_email']):"").
			    (isset($comment['comment_author_url'])?
				sprintf("&#x200f; (%s)",$comment['comment_author_url']):"").
			    "</li>\n";
			*/
			
			if( $comment['comment_nesting_index']>0 ) {
			    $comment['comment_parent']=
				$comment_parents[$comment['comment_nesting_index']-1];
			}

			// Need to escape the comment content to avoid SQL problems
			$comment['comment_content']=$wpdb->escape($comment['comment_content']);
			$comment['comment_author']=$wpdb->escape($comment['comment_author']);
			$comment_parents[$comment['comment_nesting_index']]=wp_insert_comment($comment);

			$repeat=true;
			$state++;
		    }
		    break;
		case 9:
		    // Sometimes, there is a <hr> line after the comment
		    if( !preg_match('|</p><hr />$|i', $line ) ) {
			$repeat=true;
		    }
		    $state=5;
		    break;
		case 10:
		    // End of file?
		    if( preg_match('@^</(body)|(html)>$@i', $line) )
			$finished=true;
		    break;
		}

		if( $repeat ) {
		    // printf ("<br />\nRepeat on line %d, state %d ", $this->linenum, $state );
		}
	    } while( $repeat );
	    // echo "<li>".htmlspecialchars(iconv('windows-1255', 'utf-8', $line))."</li>\n";
	}

	$this->aligncomment( $comment_display_nesting, -1 );
	print "</ol></p>\n";
	printf ("<p>%s</p>\n", sprintf(__("Processed %d lines"), $this->linenum));

	fclose( $file );
    }

    // Functions for processing the different stages of the state machine
    function process_date( $line ) {
	// PHP 5.1 only option
	if( version_compare( phpversion(), '5.1.0' ) != '-1' )
	    date_default_timezone_set('Asia/Jerusalem');

	if( !preg_match('@>(\d+)/(\d+)/(\d+)(\s+(\d+):(\d+):(\d+))?<br>$@i', $line, $times) )
							return null;
	$time=mktime($times[5], $times[6], $times[7], $times[2], $times[1], $times[3]);

	return date( 'Y-m-d H:i:s', $time );
    }

    function process_title( $line ) {
	preg_match('@^(.*)<br>$@i', $line, $results) or self::_die();

	return iconv( $this->FILEENC, $this->DSTENC, $results[1] );
    }

    // Return TRUE if this is the last line
    // Strip the "comments" epilouge if found
    function process_body( &$line ) {
	if( substr($line, -23 ) != '<br /><br />תגובות:</p>' ) {
	    return false;
	} else {
	    $line=preg_replace('|<br /><br />תגובות:</p>$|', '', $line);
	    return true;
	}
    }

    function process_comment1( $line )
    {
	if( !preg_match(
		    "|<p class=MsoNormal dir=RTL lang=HE style='font-size:10.0pt; font-family: Arial; ".
		    "margin-right:([0-9\\.]+)in'>(.*?)&nbsp;(.*?)(&nbsp;\\((.*)\\))?$|i", $line, $results ) ) {
	    //print ("New post line $this->linenum<br />\n");
	    return null;
	}
	// 1 - indent extent
	// 2 - commenter name
	// 3 - commenter email (if any)
	// 5 - commenter site

	//print "Matched: $results[1], $results[2], $results[3], $results[4], $results[5]<br>\n";
	$comment['comment_author']=iconv( $this->FILEENC, $this->DSTENC, $results[2] );
	$results[3] and $comment['comment_author_email']=iconv( $this->FILEENC, $this->DSTENC, $results[3] );
	$results[5] and $comment['comment_author_url']=iconv( $this->FILEENC, $this->DSTENC, $results[5] );
	$comment['comment_nesting_index']=$results[1]*5;
	//printf ("<br />\nFound comment. reported %s, which translated to %d", $results[1], $comment['comment_nesting_index'] );

	return $comment;
    }

    function process_comment2( $line )
    {
	preg_match( '|^, (\d+):(\d+) (\d+)/(\d+)/(\d+):<br />$|i', $line, $results ) || self::_die();

	$time=mktime($results[1], $results[2], 0, $results[4], $results[3], $results[5]);

	return date( 'Y-m-d H:i:s', $time );
    }

    function import_posts() {
	// wp_insert_post
	// wp_insert_comment 
    }

    // Figures out what to do, then does it.
    function start() {
	if ( isset($_GET['step']) ) {
	    $file = wp_import_handle_upload();
	    if( isset($file['error']) ) {
		echo $file['error'];
		return;
	    }

	    $this->file = $file['file'];
	    $this->get_posts();
	    $this->import_posts();
	    wp_import_cleanup($file['id']);

	    echo '<h3>';
	    printf(__('All done. <a href="%s">Have fun!</a>'), get_option('home'));
	    echo '</h3>';
	} else {
	    $this->greet();
	}
    }

    function Israblog_Import() {
	load_plugin_textdomain('israblog', 'wp-admin/import');
    }
}

$israblog_import = new Israblog_Import();

register_importer('israblog', __('Israblog'), __('Import posts and comments from an Israblog backup file'), array ($israblog_import, 'start'));

?>
