/Vector/Post.pm
package Vector::Post;
use CGI::Fast qw/:standard/;
use Vector::DB;
use Vector::User;
use Vector::Channel;
use Vector::Thread;
use Vector::Util qw/simplify_uri xmlescape/;
use Vector::Config qw/$webroot $thumbdir $datadir/;
use Vector::Notify;
use Vector::ReplyTag;
use Vector::HtmlFilter;
use strict;

sub new {
	my ($class, $user_id, $channel_id, $data, $file, $replyto) = @_;

	Vector::HtmlFilter::htmlfilter \$data;

	my $self = {
		type => 'post',
		user_id => $user_id,
		channel_id => $channel_id,
		data => $data,
		file => $file,
		replyto => $replyto,
		user => Vector::User->fetch_by_id($user_id),
		channel => Vector::Channel::name($channel_id),
		root => not defined $replyto,
	};

	return bless $self, $class;
}

sub load {
	my ($class, $post_id) = @_;
	my $dbh = Vector::DB::connect;

	my $self = $dbh->selectrow_hashref('SELECT user_id, channel_id, data, file, replyto FROM posts WHERE post_id = ?', undef, $post_id);

	$self->{type} = 'post';
	$self->{user} = Vector::User->fetch_by_id($self->{user_id});
	$self->{channel} = Vector::Channel::name($self->{channel_id});
	$self->{post_id} = $post_id;
	$self->{thread} = fetch Vector::Thread($self->{replyto} || $self->{post_id});
	$self->{root} = not defined $self->{replyto};

	return bless $self, $class;
}

sub save {
	my ($self) = @_;
	my $dbh = Vector::DB::connect;

	Vector::HtmlFilter::htmlfilter \$self->{data};

	if ($self->{post_id}) {
		$dbh->do('UPDATE posts set data, ts) VALUES (?,NOW())', undef, $self->{data})
			or die $dbh->errstr;
	} else {
		$dbh->do('INSERT INTO posts (user_id, channel_id, data, file, replyto, ts) VALUES (?,?,?,?,?,NOW())', undef, $self->{user_id}, $self->{channel_id}, $self->{data}, $self->{file}, $self->{replyto})
			or die $dbh->errstr;

		# Ick, MySQL-ism
		($self->{post_id}) = $dbh->selectrow_array('SELECT LAST_INSERT_ID()');

		if ($self->{replyto}) {
			$self->{thread} = fetch Vector::Thread($self->{replyto});
			$self->{thread}->update;
		} else {
			$self->{thread} = new Vector::Thread($self->{post_id});
		}
	}

	Vector::Channel::update($self->{channel_id});

	$self->notify;

	return $self->{post_id};
}

sub replies {
	my ($self, %opts) = @_;
	my $dbh = Vector::DB::connect;

	if (defined $opts{limit}) {
		$opts{offset} = 0 unless defined $opts{offset};
		return @{$dbh->selectcol_arrayref('SELECT post_id FROM posts WHERE replyto = ? ORDER BY ts DESC LIMIT ? OFFSET ?', undef, $self->{post_id}, $opts{limit}, $opts{offset})};
	} else {
		return @{$dbh->selectcol_arrayref('SELECT post_id FROM posts WHERE replyto = ? ORDER BY ts DESC', undef, $self->{post_id})};
	}
}

sub count_replies {
	my ($self) = @_;
	my $dbh = Vector::DB::connect;

	my ($n) = $dbh->selectrow_array('SELECT count(*) FROM posts WHERE replyto = ?', undef, $self->{post_id});

	return $n;
}

sub content {
	my ($self) = @_;

	my $r;

	if ($self->{file}) {
		my ($file_id, $filename) = split(m'/', $self->{file});

		if (-e "$datadir/$self->{file}") {
			my $thumburi;
			if (-d "$thumbdir/$file_id") {
				$thumburi = "${webroot}thumb/$file_id/thumbnail.jpg";
			} else {
				$thumburi = "${webroot}static/unknown-document.png";
			}
			$r .= a({href => "${webroot}data/$self->{file}", alt => $filename, title => $filename}, img({src => $thumburi, align => 'left'}));
			$r .= "\n";
		}
	}
	$r .= Vector::Util::linebreak($self->{data});

	return $r;
}

sub format {
	my ($self, $child_limit) = @_;
	my (@controls);

	my $shortname = simplify_uri $self->{user}->{username};
	my $user_url = $self->{user}->user_url;
	my $content = $self->content;
	
	if (defined $child_limit && $self->{root}) {
		push @controls, qq{<a href="${webroot}channel/$self->{channel}/$self->{post_id}">full thread</a>};
	}

	my $count_replies = $self->count_replies;
	my @replies = reverse $self->replies(limit => $child_limit);
	my @things;

	if ($count_replies > @replies) {
		push @things,  qq{<li><a href="${webroot}channel/$self->{channel}/$self->{post_id}">... }, $count_replies - @replies, ' more replies</a></li>';
	}

	for my $r (@replies) {
		my $post = load Vector::Post($r);
		push @things, $post->format;
	}

	if ($self->{root} && $main::login_id) {
		Delete('replyto');
		my @expando = (-onfocus => 'reply_expand(this.parentNode)', -onblur => 'reply_compact(this.parentNode)');

		my $form_options = {};
		if (defined $child_limit) {
			$form_options->{class} = 'compact';
		}

		push @things,
		     '<li>' .
		     start_form($form_options) .
		     hidden('replyto', $self->{post_id}) .
		     textarea(-name => 'data', @expando) . br .
		     filefield(-name => 'file', @expando) . br .
		     submit(-name => 'Reply', @expando) .
		     end_form .
		     '</li>';
	}

	return <<EOD;
<li><a name="post$self->{post_id}"></a>
  <div>
    <div class="controls">@controls</div>
    <h2><a href="$user_url">$shortname</a></h2>
    $content
    <div style="clear: both"></div>
  </div>
  @{[ @things ? "<ul>@things</ul>" : '' ]}
</li>
EOD
}

sub print {
	my ($self, $child_limit) = @_;

	print $self->format($child_limit);
}

sub notify {
	my ($self) = @_;

	my $replytag = Vector::ReplyTag::create($self);
	my $display_username = simplify_uri($self->{user}->{username});

	Vector::Notify::queue(<<EOD, $self->{channel_id}, $self->{thread}->{post_id});
From $display_username $replytag
$self->{data}
EOD
}

sub post_uri {
	my ($self) = @_;

	return "${webroot}channel/$self->{channel}/$self->{thread}->{post_id}#post$self->{post_id}";
}

sub thread_uri {
	my ($self) = @_;

	return "${webroot}channel/$self->{channel}/$self->{thread}->{post_id}";
}

1;