The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
=head1 NAME

WWW::Kontent::Class::Kiki - Kiki page class for Kontent

=head1 SYNOPSIS

	# Attributes
	kontent:class=kiki
	kontent:version=1
	kiki:content=Page's content
	kiki:type=text/x-kolophon

=head1 DESCRIPTION

Kiki is a page class for a general-purpose text page.  Besides the title, it 
contains only a single body of text, which is parsed of markup (as Kolophon by 
default).  It does not attempt to block anyone from editing; an access control 
system such as L<WWW::Kontent::Magic::Fidelius> can be used to limit editing 
privileges.

=head2 Attributes

Kontent pages are sensitive to the following attributes:

=over 4

=item C<kiki:content>

The text of the page.

=item C<kiki:type>

The MIME type of the text.  Defaults to text/x-kolophon.

=back 4

Kiki's behavior is also affected by standard attributes, such as 
C<kontent:title>, and attributes controlling the behavior of any magic modules 
enabled in your Kontent instance.

=head2 MODES

view, history, create, edit

=head1 SEE ALSO

L<WWW::Kontent>, L<WWW::Kontent::Foundation>

=cut

class WWW::Kontent::Class::Kiki is WWW::Kontent::Class;
WWW::Kontent::register_class('kiki', $?CLASS);

has $.draftrev;

submethod BUILD() {
	my $r=.revision;
	$r.attributes<kontent:version> == 1 or die "Can't handle a version {$r.attributes<kontent:version>} Kiki page";
}

method create_(Str $name is copy) {
	my $draftpage = $_.WWW::Kontent::Class::create_($name);
	my $rev = $draftpage.draft_revision;
	
	$rev.attributes<kontent:class>   = 'kiki';
	$rev.attributes<kontent:version> = 1;
	
	return $draftpage;
}

method driver_(WWW::Kontent::Request $request) {
	# This method is Complicated because, if we're processing a 'create' or 
	# 'edit' mode request, we want to allocate a draft revision or page, and 
	# let the draft revision handle the actual processing.  (This allows a 
	# subclass's create() override to say 
	# `$rev.attributes<kontent:class>='somethingelse'` and DTRT.)
	
	unless $.revision.isa(WWW::Kontent::DraftRevision) {
		# This is a normal revision...
		if $request.mode eq 'create' | 'edit' {
			# which is about to acquire an inner revision it should dispatch 
			# to.  Create the inner revision and call its driver.
			.:inner_driver($request);
		}
	}
	else {
		# This is a draft revision of some sort, so we need to build it from 
		# a combination of user parameters, stuff the revision it's based on 
		# knew, and defaults.
		my $p=$request.parameters;
		
		$.revision.revno = $p<revno> // $.revision.revno;
		$.revision.attributes<kiki:type>     = 'text/x-kolophon';
		$.revision.attributes<rev:author>    = $request.user_pathstr;
		$.revision.attributes<rev:log>       = $p<log> // '';
		
		$.revision.attributes<kontent:title> =
			$p<title>   // $.revision.attributes<kontent:title>;
		$.revision.attributes<kiki:content>  =
			$p<content> // $.revision.attributes<kiki:content>;
		
		my $page=$.revision.page;
		unless defined $page.name {
			# Derive the default name from the title, but normalized to 
			# lowercase, spaces replaced by underscores and repeated sequences 
			# squashed, and everything else deleted entirely.
			my $name = lc $.revision.attributes<kontent:title>;
			$name ~~ s:g/<[ _]>+/_/;
			$name ~~ s:g/\W//;
			$page.name = $name;
		}
		
		if $request.mode eq 'create' | 'edit' and $p<action> eq 'save' {
			$.revision.attributes<kiki:content> ~~ s:g{\n}{\n};		#Get rid of \r
			# Save all that hard work!
			$.revision.commit;
		}
	}
}

method :inner_driver($request) {
	if $request.mode eq 'create' {
		# Create the draft page and retrieve the draft revision from it.
		my $draftpage = $.revision.create(undef);
		$.draftrev = $draftpage.draft_revision;
	}
	else {
		# Create the draft revision.  (The current revision's revno has 
		# to be used here, but the current revision is the one being 
		# revised.)
		my $page = $.revision.page;			# XXX pugsbug
		my $cur  = $page.cur;
		$.draftrev = $.revision.revise($cur.revno + 1);
	}
	
	my $draftrev=$.draftrev;
	$.draftrev.driver($request);
}

method adapter_(WWW::Kontent::Request $request) {
	my $rev=.revision;
	my $page=$rev.page;
	
	if $.draftrev {
		return $.draftrev.adapter($request);
	}
	else {
		my $skel=WWW::Kontent::Skeleton.new();
		given $request.mode {
			when 'create' | 'edit' {
				my $ing = $request.mode eq 'create' ?? 'creating' :: 'editing';
				
				$skel.add_node('header', :level<0>);
				$skel.children[-1].add_text("{$rev.attributes<kontent:title> // 'Unnamed'} ($ing)");
				
				if $request.parameters<action> eq 'save' {
					$skel.add_node('paragraph');
					$skel.children[-1].add_text("Your revisions have been saved.  ");
					$skel.children[-1].add_node('link', :location($page.path));
					$skel.children[-1].children[-1].add_text("View the revised page...");
				}
				else {
					if $request.parameters<action> eq 'preview' {
						$skel.add_node('header', :level(1));
						$skel.children[-1].add_text("Preview changes");
						
						if $request.mode eq 'create' {
							$skel.add_text("Page name: $page.name()\n");
						}
						
						$skel.children.push(
							WWW::Kontent::parse(
								$request.parameters<content>, 
								$.revision.attributes<kiki:type>, $request
							)
						);
					}
					
					$skel.add_node('header', :level(1));
					$skel.children[-1].add_text(
						$request.mode eq 'create'
					??  "Create Kiki page"
					::  "Edit Kiki page");
					
					my $f=$skel.add_node('form');
					$f.add_node('paragraph');
					$f.add_node('paragraph');
					
					$f.children[0].add_node('textfield', :name<title>, :label<Title>,
						:value($rev.attributes<kontent:title>)
					);
					$f.children[0].add_text("\n");
					$f.children[0].add_node('textfield', :name<content>, 
						:value($rev.attributes<kiki:content>), :type<multiline>);
					
					$f.children[1].add_node('textfield', :name<log>, :label("Log message"),
						:value($rev.attributes<rev:log>)
					);
					$f.children[1].add_text("\n");
					
					my $c=$f.children[1].add_node('choicefield', :type<action>);
					
					$c.add_node('choice', :value<save>);
					$c.children[0].add_text("Save changes");
					
					$c.add_node('choice', :value<preview>);
					$c.children[1].add_text("Preview changes");
				
					$f.add_node('metafield', :name<revno>, :value($rev.revno));
				}
			}
			default {
				$skel.add_node('header', :level<0>);
				$skel.children[-1].add_text(~$rev.attributes<kontent:title>);
				$skel.children.push(WWW::Kontent::parse(~$rev.attributes<kiki:content>, ~$rev.attributes<kiki:type>, $request));
			}
		}
		return $skel;
	}
}

method modelist_(WWW::Kontent::Request $request) {
	return <view history create edit>
}