#!/usr/local/bin/perl -w

use strict;
use Simple; # corrected LJ::Simple
use POSIX;

my $DEBUG=1;

# error codes (TODO: move to an include file)
my $E_NOLOGIN = 1;
my $E_NOTIMPLEMENTED = 2;
my $E_DAYCOUNTS = 3;
my $E_GETENTRY = 4;
my $E_CANTPOST = 5;
my $E_GETGROUPS = 6;

# constraints
my $REMOTE_MAX_GET = 50; # livejournal.com let us download no more than 50 event at a time

# test it!
import_journal(
  0,                        # throttle_speed (seconds)
  "www.livejournal.com",    # remote_site
  "flat",                   # remote_protocol
  "nofate",                    # remote_user
  "up",           # remote_pass
  "lj.rossia.org",                     # local_site
  "flat",                   # local_protocol
  "lenushka2",                   # local_user
  "down",           # local_pass
  "0",                      # overwrite entries
  "0"                       # import comments
  );

print $?;


# do the actual import
sub import_journal {
  my (
    $throttle_speed,
    $remote_site, $remote_protocol, $remote_user, $remote_pass,
    $local_site, $local_protocol, $local_user, $local_pass,
    $overwrite, $import_comments
  ) = @_;

  my %gdc_hr;
  my $tvar;

  if ($remote_protocol ne "flat") {
    print "Unsupported protocol $remote_protocol\n";
    exit($E_NOTIMPLEMENTED);
  }
  if ($local_protocol ne "flat") {
    print "Unsupported protocol $local_protocol\n";
    exit($E_NOTIMPLEMENTED);
  }

  # login to the remote site
  my $remote_lj = new LJ::Simple ({
      site => $remote_site,
      user => $remote_user,
      pass => $remote_pass,
      });
  if (! defined $remote_lj) {
    print "Can't login to remote site.\n$LJ::Simple::error\n";
    exit($E_NOLOGIN);
  }

  # login to the local site
  my $local_lj = new LJ::Simple ({
      site => $local_site,
      user => $local_user,
      pass => $local_pass,
      });
  if (! defined $local_lj) {
    print "Can't login to local site.\n$LJ::Simple::error\n";
    exit($E_NOLOGIN);
  }
  # get local friend groups
  my %lfg=();
  if (! defined $local_lj->GetFriendGroups(\%lfg)) {
    print "Failed to get groups on the local site.\n$LJ::Simple::error\n";
    exit($E_GETGROUPS);
  }

  # get remote days with entries
  if (! defined $remote_lj->GetDayCounts(\%gdc_hr, undef)) {
    print "Can't get day counts.\n$LJ::Simple::error\n";
    exit($E_DAYCOUNTS);
  }

  # process them, day by day, sleeping a little
  foreach (sort {$a<=>$b} keys %gdc_hr) {
    my $timestamp = $_;

    # download all the entries for a day
    if ($gdc_hr{$timestamp} < $REMOTE_MAX_GET) {
      $DEBUG && print "getting entries for $timestamp :" . localtime($timestamp);

      my %r_entries=(); # remote entries

      while (1) {
        if (! defined $remote_lj->GetEntries(\%r_entries,undef,"day",($timestamp))) {
          if ($LJ::Simple::error =~ /Connection reset by peer/) {
            next;
          }
  
          print "Can't get remote entries.\n$LJ::Simple::error\n";
          exit($E_GETENTRY);
        }
        else {
          last;
        }
      }

      my %l_entries=(); # local entries
      if (! defined $local_lj->GetEntries(\%l_entries,undef,"day",($timestamp))) {
        print "Can't get local entries.\n$LJ::Simple::error\n";
        exit($E_GETENTRY);
      }

      my $rkey=undef;
      my $rentry=undef;
      my $lkey=undef;
      my $lentry=undef;

      while (($rkey, $rentry) = each(%r_entries)) {
        my $remote_date = $remote_lj->GetDate($rentry);

        # delete local entry if needed
        $tvar = 0;
        while (($lkey, $lentry) = each(%l_entries)) {
          if ($local_lj->GetDate($rentry) == $remote_date) {
            $tvar = 1;
            if ($overwrite eq "1") {
              $local_lj->DeleteEntry($lkey);
              delete $l_entries{$lkey};
            }
          }
        }
        if ($tvar == 1 && $overwrite eq "0") {
          next;
        }
        
        # prepare new local entry from remote entry
        my %lentry=();
        $local_lj->NewEntry(\%lentry);
        $local_lj->SetEntry(\%lentry, ($remote_lj->GetEntry($rentry)));
        $local_lj->SetSubject(\%lentry, $remote_lj->GetSubject($rentry));
        $local_lj->SetDate(\%lentry, $remote_lj->GetDate($rentry));
        #TODO: Setprop_taglist
        $local_lj->Setprop_current_mood(\%lentry, $remote_lj->Getprop_current_mood($rentry));
        $local_lj->Setprop_current_music(\%lentry, $remote_lj->Getprop_current_music($rentry));
        $local_lj->Setprop_preformatted(\%lentry, $remote_lj->Getprop_preformatted($rentry));
        $local_lj->Setprop_nocomments(\%lentry, $remote_lj->Getprop_nocomments($rentry));
        #TODO: Setprop_picture_keyword
        $local_lj->Setprop_noemail(\%lentry, $remote_lj->Getprop_noemail($rentry));
        $local_lj->Setprop_unknown8bit(\%lentry, $remote_lj->Getprop_unknown8bit($rentry));
        $local_lj->Setprop_backdate(\%lentry, 1);

        #TODO: create friend groups
        my @r_protection = $remote_lj->GetProtect($rentry);
        if ($r_protection[0] ne "groups") {
          $local_lj->SetProtect(\%lentry, $r_protection[0]);
        }
        else {
          shift @r_protection;
          $local_lj->SetProtect(\%lentry, "groups", @r_protection);
        }

        my ($item_id,$anum,$html_id)=$local_lj->PostEntry(\%lentry);
        if (! defined $item_id) {
          print "Can't post to local server.\n$LJ::Simple::error\n";
          exit($E_CANTPOST);
        }

        $DEBUG && print ".";
      }

      print "\n";
      sleep($throttle_speed);
    }
    else { # TODO: download one entry at a time for a given day
      print "More than 50 entries a day. Skipping day " . localtime($_);
      next;
    }
  }
}
