package NDWeb::Controller::Wiki;

use strict;
use warnings;
use parent 'Catalyst::Controller';

use Text::MediawikiFormat prefix => '/wiki/';

=head1 NAME

NDWeb::Controller::Wiki - Catalyst Controller

=head1 DESCRIPTION

Catalyst Controller.

=head1 METHODS

=cut


=head2 index

=cut

sub auto : Priate {
	my ( $self, $c ) = @_;

	$c->stash(wikiformat => \&wikiformat);
}

sub index :Path :Args(0) {
	my ( $self, $c ) = @_;

	push @{$c->req->captures}, ('Info','Main');
	$c->forward('page');
	$c->stash(template => 'wiki/page.tt2');
}

sub page : LocalRegex(^(?:([A-Z]\w*)(?::|%3A))?([A-Z]\w*)$) {
	my ( $self, $c ) = @_;
	my $dbh = $c->model;

	$c->forward('findPage');
	$c->acl_access_denied('test',$c->action,'No edit access for this page')
		if defined $c->stash->{page}->{view} && !$c->stash->{page}->{view};
	$c->forward('loadText');

	unless ($c->stash->{page}->{wpid}){
		$c->stash->{page}->{namespace} = $c->req->captures->[0];
		$c->stash->{page}->{name} = $c->req->captures->[1];
		$c->stash->{page}->{fullname} = ($c->stash->{page}->{namespace} ? $c->stash->{page}->{namespace}.':' : '')
			. $c->stash->{page}->{name};
		$c->stash->{page}->{post} = $dbh->selectrow_array(q{SELECT post
				FROM wiki_namespace_access
				WHERE namespace = COALESCE($1,'') AND post AND gid IN (SELECT groups($2))
			},undef,$c->stash->{page}->{namespace}, $c->stash->{UID});
	}
	$c->stash(title => $c->stash->{page}->{fullname});
}

sub edit : LocalRegex(^edit/(?:([A-Z]\w*)(?::|%3A))?([A-Z]\w*)$) {
	my ( $self, $c ) = @_;
	my $dbh = $c->model;

	$c->forward('findPage');
	$c->acl_access_denied('test',$c->action,'No edit access for this page')
		if defined $c->stash->{page}->{edit} && !$c->stash->{page}->{edit};
	$c->forward('loadText');
	$c->forward('findNamespaces');

	unless ($c->stash->{page}->{wpid}){
		$c->acl_access_denied('test',$c->action,'No edit access for this page')
			unless @{$c->stash->{namespaces}};
		$c->stash->{page}->{namespace} = $c->req->captures->[0];
		$c->stash->{page}->{name} = $c->req->captures->[1];
	}
}

sub history : LocalRegex(^history/(?:([A-Z]\w*)(?::|%3A))?([A-Z]\w*)$) {
	my ( $self, $c ) = @_;
	my $dbh = $c->model;

	$c->forward('findPage');

	my $query = $dbh->prepare(q{SELECT wprev,time,username,comment
		FROM wiki_page_revisions JOIN users u USING (uid)
		WHERE wpid = $1
		ORDER BY time DESC
		});
	$query->execute($c->stash->{page}->{wpid});
	$c->stash(revisions => $query->fetchall_arrayref({}) );
	$c->stash(title => 'History for ' . $c->stash->{page}->{fullname});
}

sub postedit : Local {
	my ( $self, $c, $p ) = @_;
	my $dbh = $c->model;

	eval {
		$dbh->begin_work;

		my $wpid = $c->req->param('wpid');
		if ( $wpid eq 'new'){
			my $namespace = $dbh->selectrow_array(q{SELECT namespace
				FROM wiki_namespace_access
				WHERE namespace = $1 AND post AND gid IN (SELECT groups($2))
			},undef,$c->req->param('namespace'), $c->stash->{UID});

			my $query = $dbh->prepare(q{INSERT INTO wiki_pages (namespace,name) VALUES($1,$2) RETURNING wpid});
			$query->execute($namespace,$c->req->param('name'));
			$wpid = $query->fetchrow;
		}
		$c->forward('findPage',[$wpid]);
		$c->acl_access_denied('test',$c->action,'No edit access for this page')
			if defined $c->stash->{page}->{edit} && !$c->stash->{page}->{edit};

		my $query = $dbh->prepare(q{INSERT INTO wiki_page_revisions
			(wpid,parent,text,comment,uid) VALUES($1,$2,$3,$4,$5)
			RETURNING wprev
			});
		$c->req->params->{parent}||= undef;
		$query->execute($wpid,$c->req->param('parent'),$c->req->param('text')
			,$c->req->param('comment'),$c->stash->{UID});
		my $rev = $query->fetchrow;
		$dbh->do(q{UPDATE wiki_pages SET wprev = $1 WHERE wpid = $2}
			,undef,$rev,$wpid);

		$dbh->commit;
		$c->res->redirect($c->uri_for($c->stash->{page}->{fullname}));
		return;
	} if ($c->req->param('cmd') eq 'Submit');

	if ($@){
		if ($@ =~ /duplicate key value violates unique constraint "wiki_pages_namespace_key"/){
			$c->stash(error => "Page does already exist");
		}elsif ($@ =~ /value too long for type character varying\(255\)/){
			$c->stash(error => 'The name is too long, keep it to max 255 characters');
		}else{
			$c->stash(error => $@);
		}
		$dbh->rollback;
	}

	$c->forward('findPage') if $p;
	$c->forward('findNamespaces');

	$c->stash->{page}->{namespace} = $c->req->param('namespace');
	$c->stash->{page}->{name} = $c->req->param('name');

	$c->stash(text => $c->req->param('text'));
	$c->stash(template => 'wiki/edit.tt2');
}

sub findPage : Private {
	my ( $self, $c, $p ) = @_;
	my $dbh = $c->model;

	my @arguments = ($c->stash->{UID});
	my $where;
	if ($p){
		$where =  q{AND wpid = $2};
		push @arguments, $p;
	}else{
		$where = q{AND (namespace = COALESCE($2,'') AND name = $3)};
		push @arguments, @{$c->req->captures};
	}

	my $query = q{SELECT wpid,namespace,name,wprev
		,(CASE WHEN namespace <> '' THEN namespace || ':' ELSE '' END) || name AS fullname
		,bool_or(COALESCE(wpa.edit,wna.edit)) AS edit
		,bool_or(wna.post) AS post
		,bool_or(wpa.moderate OR wna.moderate) AS moderate
		,bool_or(wpa.wpid IS NOT NULL OR wna.namespace IS NOT NULL) AS view
		FROM wiki_pages wp
			LEFT OUTER JOIN (SELECT * FROM wiki_namespace_access
				WHERE gid IN (SELECT groups($1))) wna USING (namespace)
			LEFT OUTER JOIN (SELECT * FROM wiki_page_access
				WHERE uid =  $1) wpa USING (wpid)
		WHERE TRUE
	} . $where . q{ GROUP BY wpid,namespace,name,wprev};
	$query = $dbh->prepare($query);
	$query->execute(@arguments);

	my $page = $query->fetchrow_hashref;
	$c->stash(page => $page);
}

sub loadText : Private {
	my ( $self, $c, $p ) = @_;
	my $dbh = $c->model;

	my $text = $dbh->selectrow_array(q{SELECT text
		FROM wiki_page_revisions WHERE wprev = $1
		},undef,$c->stash->{page}->{wprev});
	$c->stash(text => $text);
}

sub findNamespaces : Private {
	my ( $self, $c, $p ) = @_;
	my $dbh = $c->model;

	my $query = $dbh->prepare(q{SELECT namespace FROM wiki_namespaces
		WHERE namespace IN (SELECT namespace FROM wiki_namespace_access WHERE post AND gid IN (SELECT groups($1)))
		ORDER BY namespace
		});
	$query->execute($c->stash->{UID});
	$c->stash(namespaces => $query->fetchall_arrayref({}) );
}


=head1 AUTHOR

Michael Andreen (harv@ruin.nu)

=head1 LICENSE

GPL 2.0, or later

=cut

1;
