#!/usr/bin/perl
#

use strict;
package LJ::S2;

sub EntryPage
{
    my ($u, $remote, $opts) = @_;

    my $get = $opts->{'getargs'};

    my $p = Page($u, $opts);
    $p->{'_type'} = "EntryPage";
    $p->{'view'} = "entry";
    $p->{'comments'} = [];
    $p->{'comment_pages'} = undef;

    # setup viewall options
    my ($viewall, $viewsome) = (0, 0);
    if ($get->{viewall} && LJ::check_priv($remote, 'canview')) {
        # we don't log here, as we don't know what entry we're viewing yet.  the logging
        # is done when we call EntryPage_entry below.
        $viewall = LJ::check_priv($remote, 'canview', '*');
        $viewsome = $viewall || LJ::check_priv($remote, 'canview', 'suspended');
    }

    my ($entry, $s2entry) = EntryPage_entry($u, $remote, $opts);
    return if $opts->{'suspendeduser'};
    return if $opts->{'handler_return'};

    $p->{'multiform_on'} = $remote &&
        ($remote->{'userid'} == $u->{'userid'} ||
         $remote->{'userid'} == $entry->{'posterid'} ||
         LJ::can_manage($remote, $u));

    my $itemid = $entry->{'itemid'};
    my $ditemid = $entry->{'itemid'} * 256 + $entry->{'anum'};
    my $permalink = LJ::journal_base($u) . "/$ditemid.html";
    my $stylemine = $get->{'style'} eq "mine" ? "style=mine" : "";

    if ($u->{'journaltype'} eq "R" && $u->{'renamedto'} ne "") {
        $opts->{'redir'} = LJ::journal_base($u->{'renamedto'}, $opts->{'vhost'}) .
            "/$ditemid.html" . $opts->{'pathextra'};
        return 1;
    }

    if ($u->{'opt_blockrobots'}) {
        $p->{'head_content'} .= LJ::robot_meta_tags();
    }
    if ($LJ::UNICODE) {
        $p->{'head_content'} .= '<meta http-equiv="Content-Type" content="text/html; charset='.$opts->{'saycharset'}."\" />\n";
    }

    $p->{'entry'} = $s2entry;

    # add the comments
    my %userpic;
    my %user;
    my $copts = {
        'thread' => ($get->{'thread'} >> 8),
        'page' => $get->{'page'},
        'view' => $get->{'view'},
        'userpicref' => \%userpic,
        'userref' => \%user,
        # user object is cached from call just made in EntryPage_entry
        'up' => LJ::load_user($s2entry->{'poster'}->{'username'}),
        'viewall' => $viewall,

	# Okuklivanie tredov - daem upravlenie pol'zovatelyu -
        'page_size' => $get->{'page_size'},
        'max_subjects' => $get->{'max_subjects'},
        'threading_point' => $get->{'threading_point'},
        'uncollapse' => $get->{'uncollapse'},
    };

    my $userlite_journal = UserLite($u);

    my @comments = LJ::Talk::load_comments($u, $remote, "L", $itemid, $copts);

    my $pics = LJ::Talk::get_subjecticons()->{'pic'};  # hashref of imgname => { w, h, img }
    my $convert_comments = sub {
        my ($self, $destlist, $srclist, $depth) = @_;

        foreach my $com (@$srclist) {
            my $dtalkid = $com->{'talkid'} * 256 + $entry->{'anum'};
            my $text = $com->{'body'};
            if ($get->{'nohtml'}) {
                # quote all non-LJ tags
                $text =~ s{<(?!/?lj)(.*?)>} {&lt;$1&gt;}gi;
            }
            LJ::CleanHTML::clean_comment(\$text, { 'preformatted' => $com->{'props'}->{'opt_preformatted'}, 
                                                   'anon_comment' => !$com->{posterid}});

            # local time in mysql format to gmtime
	    my $datetime = DateTime_unix(LJ::mysqldate_to_time($com->{'datepost'}));
	    if ($datetime == 0) {
	      $datetime = "Invalid date";
	    }
	    
            my $subject_icon = undef;
            if (my $si = $com->{'props'}->{'subjecticon'}) {
                my $pic = $pics->{$si};
                $subject_icon = Image("$LJ::IMGPREFIX/talk/$pic->{'img'}",
                                      $pic->{'w'}, $pic->{'h'}) if $pic;
            }

            my $comment_userpic;
            if (my $pic = $userpic{$com->{'picid'}}) {
                $comment_userpic = Image("$LJ::USERPIC_ROOT/$com->{'picid'}/$pic->{'userid'}",
                                         $pic->{'width'}, $pic->{'height'});
            }

            my $reply_url = LJ::Talk::talkargs($permalink, "replyto=$dtalkid", $stylemine);

            my $par_url;
            if ($com->{'parenttalkid'}) {
                my $dparent = ($com->{'parenttalkid'} << 8) + $entry->{'anum'};
                $par_url = LJ::Talk::talkargs($permalink, "thread=$dparent", $stylemine) . "#t$dparent";
            }

            my $poster;
            if ($com->{'posterid'}) {
                if ($user{$com->{'posterid'}}) {
                    $poster = UserLite($user{$com->{'posterid'}});
                } else {
                    $poster = {
                        '_type' => 'UserLite',
                        'username' => $com->{'userpost'},
                        'name' => $com->{'userpost'},  # we don't have this, so fake it
                        'journal_type' => 'P',         # fake too, but only people can post, so correct
                    };
                }
            }

            my $s2com = {
                '_type' => 'Comment',
                'journal' => $userlite_journal,
                'metadata' => {
                    'picture_keyword' => $com->{'props'}->{'picture_keyword'},
                },
                'permalink_url' => "$permalink?thread=$dtalkid#t$dtalkid",
                'reply_url' => $reply_url,
                'poster' => $poster,
                'replies' => [],
                'subject' => LJ::ehtml($com->{'subject'}),
                'subject_icon' => $subject_icon,
                'talkid' => $dtalkid,
                'text' => $text,
                'userpic' => $comment_userpic,
                'time' => $datetime,
                'tags' => [],
                'full' => $com->{'_loaded'} ? 1 : 0,
                'depth' => $depth,
                'parent_url' => $par_url,
                'screened' => $com->{'state'} eq "S" ? 1 : 0,
                'frozen' => $com->{'state'} eq "F" ? 1 : 0,
                'link_keyseq' => [ 'delete_comment' ],
                'anchor' => "t$dtalkid",
                'dom_id' => "ljcmt$dtalkid",
            };

            # don't show info from suspended users
            # FIXME: ideally the load_comments should only return these
            # items if there are children, otherwise they should be hidden entirely
            my $pu = $com->{'posterid'} ? $user{$com->{'posterid'}} : undef;
            if ($pu && $pu->{'statusvis'} eq "S" && !$viewsome) {
                $s2com->{'text'} = "";
                $s2com->{'subject'} = "";
                $s2com->{'full'} = 0;
                $s2com->{'subject_icon'} = undef;
                $s2com->{'userpic'} = undef;
            }

            # Conditionally add more links to the keyseq
            my $link_keyseq = $s2com->{'link_keyseq'};
            push @$link_keyseq, $s2com->{'screened'} ? 'unscreen_comment' : 'screen_comment';
            push @$link_keyseq, $s2com->{'frozen'} ? 'unfreeze_thread' : 'freeze_thread';

            if (@{$com->{'children'}}) {
                $s2com->{'thread_url'} = LJ::Talk::talkargs($permalink, "thread=$dtalkid", $stylemine) . "#t$dtalkid";
            }                    

            # add the poster_ip metadata if remote user has 
            # access to see it.
            $s2com->{'metadata'}->{'poster_ip'} = $com->{'props'}->{'poster_ip'} if 
                ($com->{'props'}->{'poster_ip'} && $remote &&
                 ($remote->{'userid'} == $entry->{'posterid'} ||
                  LJ::can_manage($remote, $u) || $viewall));
            
            push @$destlist, $s2com;

            $self->($self, $s2com->{'replies'}, $com->{'children'}, $depth+1);
        }
    };
    $p->{'comments'} = [];
    $convert_comments->($convert_comments, $p->{'comments'}, \@comments, 1);

    # prepare the javascript data structure to put in the top of the page
    # if the remote user is a manager of the comments
    my $do_commentmanage_js = $p->{'multiform_on'};
    if ($LJ::DISABLED{'commentmanage'}) {
        if (ref $LJ::DISABLED{'commentmanage'} eq "CODE") {
            $do_commentmanage_js = $LJ::DISABLED{'commentmanage'}->($remote);
        } else {
            $do_commentmanage_js = 0;
        }
    }

    if ($do_commentmanage_js) {
        my $js = "<script>\n// don't crawl this.  read http://www.livejournal.com/developer/exporting.bml\n";
        $js .= "var LJ_cmtinfo = {\n";
        my $canAdmin = LJ::can_manage($remote, $u) ? 1 : 0;
        $js .= "\tjournal: '$u->{user}',\n";
        $js .= "\tcanAdmin: $canAdmin,\n";
        $js .= "\tremote: '$remote->{user}',\n" if $remote;
        my $recurse = sub {
            my ($self, $array) = @_;
            foreach my $i (@$array) {
                my $has_threads = scalar @{$i->{'replies'}};
                my $poster = $i->{'poster'} ? $i->{'poster'}{'username'} : "";
                my $child_ids = join(',', map { $_->{'talkid'} } @{$i->{'replies'}});
                $js .= "\t$i->{'talkid'}: { rc: [$child_ids], u: '$poster' },\n";
                $self->($self, $i->{'replies'}) if $has_threads;
            }
        };
        $recurse->($recurse, $p->{'comments'});
        chop $js; chop $js;  # remove final ",\n".  stupid javascript.
        $js .= "\n};\n" .
            "var LJVAR;\n".
            "if (!LJVAR) LJVAR = new Object();\n".
            "LJVAR.imgprefix = \"$LJ::IMGPREFIX\";\n".
            "</script>\n";
        $p->{'head_content'} .= $js;
        $p->{'head_content'} .= "<script src='$LJ::SITEROOT/js/commentmanage.js'></script>\n";
        
    }


    $p->{'viewing_thread'} = $get->{'thread'} ? 1 : 0;

    # default values if there were no comments, because
    # LJ::Talk::load_comments() doesn't provide them.
    if ($copts->{'out_error'} eq 'noposts') {
        $copts->{'out_pages'} = $copts->{'out_page'} = 1;
        $copts->{'out_items'} = 0;
        $copts->{'out_itemfirst'} = $copts->{'out_itemlast'} = undef;
    }

    $p->{'comment_pages'} = ItemRange({
        'all_subitems_displayed' => ($copts->{'out_pages'} == 1),
        'current' => $copts->{'out_page'},
        'from_subitem' => $copts->{'out_itemfirst'},
        'num_subitems_displayed' => scalar @comments,
        'to_subitem' => $copts->{'out_itemlast'},
        'total' => $copts->{'out_pages'},
        'total_subitems' => $copts->{'out_items'},
        '_url_of' => sub { return "$permalink?page=" . int($_[0]) .
                               ($stylemine ? "&$stylemine" : ''); },
    });

    return $p;
}

sub EntryPage_fast_check
{
    my ($u, $view, $remote, $opts) = @_;
    
    return  unless ($view eq "entry" || $view eq "reply");

    my $get = $opts->{'getargs'};

    my $r = $opts->{'r'};
    my $uri = $r->uri;

    my ($ditemid, $itemid, $anum);
    unless ($uri =~ /(\d+)\.html/) {
        $opts->{'handler_return'} = 404;
        return;
    }

    $ditemid = $1;
    $anum = $ditemid % 256;
    $itemid = $ditemid >> 8;

    my $entry = LJ::Talk::get_journal_item($u, $itemid, "props_only");
    unless ($entry && $entry->{'anum'} == $anum) {
        $opts->{'handler_return'} = 404;
        return;
    }
    my $props = $entry->{'props'};

    # do they have the viewall priv?
    my $viewall = 0;
    my $viewsome = 0;
    if ($get->{'viewall'} && LJ::check_priv($remote, "canview")) {
        LJ::statushistory_add($u->{'userid'}, $remote->{'userid'}, 
                              "viewall", "entry: $u->{'user'}, itemid: $itemid, statusvis: $u->{'statusvis'}");
        $viewall = LJ::check_priv($remote, 'canview', '*');
        $viewsome = $viewall || LJ::check_priv($remote, 'canview', 'suspended');
    }

    # check using normal rules
    unless (LJ::can_view($remote, $entry) || $viewall) {
        $opts->{'handler_return'} = 403;
        return;
    }

    my $pu = $u;
    if ($entry->{'posterid'} != $entry->{'ownerid'}) {
        $pu = LJ::load_userid($entry->{'posterid'});
    }
    if (($pu && $pu->{'statusvis'} eq 'S') && !$viewsome) {
        $opts->{'suspendeduser'} = 1;
        return;
    }

    # check If-Modified-Since
    my $lastmod = $props->{'commentalter'};
    my $revisiontime = $props->{' revtime'};
    $lastmod = $revisiontime  if $revisiontime && $revisiontime > $lastmod;

    my $ims = $r->header_in('If-Modified-Since');
    if ($ims) {
        my $theirtime = LJ::http_to_time($ims);
        if ($theirtime >= $lastmod && !$remote) {
            # only for anonymous: logged users will be checked by Etag for exact match
            # reply special: uniq challange string for regular users
            if ($view eq "entry" || ($view eq "reply" && $r->header_in('User-Agent') =~ /$LJ::ROBOTS_REGEXP/)) {

                $opts->{'notmodified'} = 1;
                return;
            }
        }
    }
    $r->header_out("Last-Modified", LJ::time_to_http($lastmod));
}

sub EntryPage_entry
{
    my ($u, $remote, $opts) = @_;

   ### NB!  EntryPage_fast_check was previously called, so all checks passed.

    my $get = $opts->{'getargs'};

    my $r = $opts->{'r'};
    my $uri = $r->uri;

    my ($ditemid, $itemid, $anum);
    unless ($uri =~ /(\d+)\.html/) {
        $opts->{'handler_return'} = 404;
        return;
    }

    $ditemid = $1;
    $anum = $ditemid % 256;
    $itemid = $ditemid >> 8;

    my $entry = LJ::Talk::get_journal_item($u, $itemid);
    unless ($entry && $entry->{'anum'} == $anum) {
        $opts->{'handler_return'} = 404;
        return;
    }
    ### more checks skipped ###

    my $props = $entry->{'props'};

    my $userlite_journal = UserLite($u);
    my $userlite_poster = $userlite_journal;
    my $pu = $u;
    if ($entry->{'posterid'} != $entry->{'ownerid'}) {
        $pu = LJ::load_userid($entry->{'posterid'});
        $userlite_poster = UserLite($pu);
    }

    my $replycount = $props->{'replycount'};
    my $nc = "";
    $nc .= "nc=$replycount" if $replycount; # && $remote && $remote->{'opt_nctalklinks'};

    my $stylemine = $get->{'style'} eq "mine" ? "style=mine" : "";

    my $userpic = Image_userpic($pu, 0, $props->{'picture_keyword'});

    my $permalink = LJ::journal_base($u) . "/$ditemid.html";
    my $readurl = LJ::Talk::talkargs($permalink, $nc, $stylemine);
    my $posturl = LJ::Talk::talkargs($permalink, "mode=reply", $stylemine);

    my $comments = CommentInfo({
        'read_url' => $readurl,
        'post_url' => $posturl,
        'count' => $replycount,
        'maxcomments' => ($replycount >= LJ::get_cap($u, 'maxcomments')) ? 1 : 0,
        'enabled' => ($u->{'opt_showtalklinks'} eq "Y" && ! 
                      $props->{'opt_nocomments'}) ? 1 : 0,
        'screened' => ($props->{'hasscreened'} && $remote &&
                       LJ::can_manage($remote, $u)) ? 1 : 0,
    });

    # format it
    if ($opts->{'getargs'}->{'nohtml'}) {
        # quote all non-LJ tags
        $entry->{'subject'} =~ s{<(?!/?lj)(.*?)>} {&lt;$1&gt;}gi;
        $entry->{'event'}   =~ s{<(?!/?lj)(.*?)>} {&lt;$1&gt;}gi;
    }
    my $raw_subj = $entry->{'subject'};
    LJ::CleanHTML::clean_subject(\$entry->{'subject'});
    LJ::CleanHTML::clean_event(\$entry->{'event'}, $props->{'opt_preformatted'});
    LJ::expand_embedded($u, $ditemid, $remote, \$entry->{'event'});

    my $s2entry = Entry($u, {
        '_rawsubject' => $raw_subj,
        'subject' => $entry->{'subject'},
        'text' => $entry->{'event'},
        'dateparts' => $entry->{'alldatepart'},
        'security' => $entry->{'security'},
        'props' => $props,
        'itemid' => $ditemid,
        'comments' => $comments,
        'journal' => $userlite_journal,
        'poster' => $userlite_poster,
        'new_day' => 0,
        'end_day' => 0,
        'userpic' => $userpic,
        'permalink_url' => $permalink,
        'enable_tags_compatibility' => [$opts->{enable_tags_compatibility}, $opts->{ctx}],
    });
    
    return ($entry, $s2entry);
}

1;
