package Template_Basic;
use strict;
use warnings;
use Test::More;
use Test::Mojo;
use utf8;

	BEGIN {
		$ENV{MOJO_NO_BONJOUR} = $ENV{MOJO_NO_IPV6} = 1;
		$ENV{MOJO_IOWATCHER}  = 'Mojo::IOWatcher';
		$ENV{MOJO_MODE}       = 'development';
	}
    
	use Test::More tests => 56;
    
	{
		$ENV{MOJO_MODE} = 'production';
		my $t = Test::Mojo->new('SomeApp');
		$t->get_ok('/index')
			->status_is(200)
			->header_is('Content-length', 18)
			->content_is('original[filtered]');
		$t->get_ok('/css.css')
			->status_is(200)
			->header_is('Content-length', 13)
			->content_is('css[filtered]');
	}
    
	{
		$ENV{MOJO_MODE} = 'production';
		my $t = Test::Mojo->new('SomeApp');
		local $SIG{ALRM} = sub { die "timeout\n" }; alarm 2;
		$t->tx($t->ua->get('/index',
			{'Content-Type' => 'multipart/form-data; boundary="abcdefg"'},
			"\x0d\x0a\x0d\x0acontent\x0d\x0a--abcdefg--\x0d\x0a")
		);
		$t->content_is('original[filtered]');
	}
	
		{
			package SomeApp;
			use strict;
			use warnings;
			use base 'Mojolicious';
			
			sub startup {
				my $self = shift;
				
				$self->plugin('plack_middleware', [
					'TestFilter'
				]);
				
				$self->routes->route('/index')->to(cb => sub{
					$_[0]->render(text => 'original');
				});
			}
		}
    
    {
        $ENV{MOJO_MODE} = 'production';
        my $t = Test::Mojo->new('OnProcessTwice');
        $t->get_ok('/index1')
			->status_is(200)
			->content_is('index2');
    }
		{
			package OnProcessTwice;
			use strict;
			use warnings;
			use base 'Mojolicious';
			
			sub startup {
				my $self = shift;
				
				$self->plugin('plack_middleware', [
					'InvokeAppTwice'
				]);
				
				$self->routes->route('/index1')->to(cb => sub{
					$_[0]->render_not_found;
				});
				$self->routes->route('/index2')->to(cb => sub{
					$_[0]->render(text => 'index2');
				});
			}
		}
    
    {
        $ENV{MOJO_MODE} = 'production';
        my $t = Test::Mojo->new('FormData');
		$t->post_ok('/index' => form => {a => 'b'});
    }
		{
			package FormData;
			use strict;
			use warnings;
			use base 'Mojolicious';
			use Test::More;
			
			sub startup {
				my $self = shift;
				
				$self->plugin('plack_middleware', [
					'TestFilter'
				]);
				
				$self->routes->route('/index')->to(cb => sub{
					my $content_type = $_[0]->req->headers->header('content-type');
					is($content_type, 'application/x-www-form-urlencoded', 'right content type');
					is($_[0]->req->body, 'a=b', 'req body set');
					$_[0]->render(text => 'original');
				});
			}
		}
    
    {
        $ENV{MOJO_MODE} = 'development';
        my $t = Test::Mojo->new('FormDataMultipart');
		$t->post_ok('/index' => {'Content-Type' => 'multipart/form-data'} => form => {foo => 'bar'})
			->status_is(200);
    }
		{
			package FormDataMultipart;
			use strict;
			use warnings;
			use base 'Mojolicious';
			use Test::More;
			
			sub startup {
				my $self = shift;
				
				$self->plugin('plack_middleware', [
					'TestFilter'
				]);
				
				$self->routes->route('/index')->to(cb => sub{
					my $content_type = $_[0]->req->headers->header('content-type');
					like($content_type, qr{multipart/form-data}, 'right content type');
					is($_[0]->req->body_params->param('foo'), 'bar', 'right body param');
					$_[0]->render(text => 'original');
				});
			}
		}
    
    {
        $ENV{MOJO_MODE} = 'production';
        my $t = Test::Mojo->new('ReqModified');
        $t->get_ok('/index')
			->status_is(200)
			->content_is('ok');
    }
		{
			package ReqModified;
			use strict;
			use warnings;
			use base 'Mojolicious';
			
			sub startup {
				my $self = shift;
				
				$self->plugin('plack_middleware', [
					'TestFilter4'
				]);
				
				$self->routes->route('/index.html')->to(cb => sub{
					$_[0]->render(text => 'ok');
				});
			}
		}
	
    {
        $ENV{MOJO_MODE} = 'production';
        my $t = Test::Mojo->new('SomeApp2');
        $t->get_ok('/index')
			->status_is(200)
			->header_is('Content-length', 29)
			->content_is('original[filtered2][filtered]');
    }
	    {
			package SomeApp2;
			use strict;
			use warnings;
			use base 'Mojolicious';
			
			sub startup {
				my $self = shift;
				
				$self->plugin('plack_middleware', [
					'TestFilter',
					'TestFilter2',
				]);
				
				$self->routes->route('/index')->to(cb => sub{
					$_[0]->render(text => 'original');
				});
			}
		}
    
    {
        $ENV{MOJO_MODE} = 'production';
        my $t = Test::Mojo->new('SomeApp3');
        $t->get_ok('/index')
			->status_is(200)
			->header_is('Content-length', 13)
			->content_is('original[aaa]');
    }
		{
			package SomeApp3;
			use strict;
			use warnings;
			use base 'Mojolicious';
			
			sub startup {
				my $self = shift;
				
				$self->plugin('plack_middleware', [
					'TestFilter3' => {tag => 'aaa'},
				]);
				
				$self->routes->route('/index')->to(cb => sub{
					$_[0]->render(text => 'original');
				});
			}
		}
	
    {
        $ENV{MOJO_MODE} = 'production';
        my $t = Test::Mojo->new('GrowLarge');
        $t->get_ok('/index')
			->status_is(200)
			->header_is('Content-length', 100001)
			->content_like(qr/890$/);
    }
		{
			package GrowLarge;
			use strict;
			use warnings;
			use base 'Mojolicious';
			
			sub startup {
				my $self = shift;
				
				$self->plugin('plack_middleware', [
					'GrowLargeFilter',
				]);
				
				$self->routes->route('/index')->to(cb => sub{
					$_[0]->render(text => '1');
				});
			}
		}
	
	{
        $ENV{MOJO_MODE} = 'production';
        my $t = Test::Mojo->new('HeadModified');
        $t->get_ok('/index')
			->status_is(200)
			->header_is('Content-Type', 'text/html;charset=Shift_JIS')
			->header_is('Content-length', 6)
			->content_is('日本語');
	}
		{
			package HeadModified;
			use strict;
			use warnings;
			use base 'Mojolicious';
			
			sub startup {
				my $self = shift;
				
				$self->plugin('plack_middleware', [
					'ForceCharset', {charset => 'Shift_JIS'}
				]);
				
				$self->routes->route('/index')->to(cb => sub{
					$_[0]->render(text => '日本語');
				});
			}
		}
	
	{
        $ENV{MOJO_MODE} = 'production';
        my $t = Test::Mojo->new('EnableIfFalse');
        $t->get_ok('/index')
			->status_is(200)
			->header_is('Content-length', 8)
			->content_is('original');
	}
		{
			package EnableIfFalse;
			use strict;
			use warnings;
			use base 'Mojolicious';
			
			sub startup {
				my $self = shift;
				
				$self->plugin('plack_middleware', [
					'TestFilter', sub {0}
				]);
				
				$self->routes->route('/index')->to(cb => sub{
					$_[0]->render(text => 'original');
				});
			}
		}
	
	{
        $ENV{MOJO_MODE} = 'production';
        my $t = Test::Mojo->new('EnableIfTrue');
        $t->get_ok('/index')
			->status_is(200)
			->header_is('Content-length', 18)
			->content_is('original[filtered]');
	}
		{
			package EnableIfTrue;
			use strict;
			use warnings;
			use base 'Mojolicious';
			use Scalar::Util;
			use Test::More;
			
			sub startup {
				my $self = shift;
				
				$self->plugin('plack_middleware', [
					'TestFilter', sub {
						ok($_[0]->isa('Mojolicious::Controller'), 'cb gets controller'); 1
					}, {
						'arg1' => 'a',
					}
				]);
				
				$self->routes->route('/index')->to(cb => sub{
					$_[0]->render(text => 'original');
				});
			}
		}
	
	{
        $ENV{MOJO_MODE} = 'production';
		
        my $t = Test::Mojo->new('AppRejected');
        $t->get_ok('/index')
			->status_is(401)
			->header_is('Content-length', 22)
			->content_is('Authorization required');
		
        my $t2 = Test::Mojo->new('AppRejected');
        $t2->get_ok('/index', {Authorization => "Basic dXNlcjpwYXNz"})
			->status_is(200)
			->header_is('Content-length', 8)
			->content_is('original');
	}
		{
			package AppRejected;
			use strict;
			use warnings;
			use base 'Mojolicious';
			use Scalar::Util;
			use Test::More;
			
			sub startup {
				my $self = shift;
				
				$self->plugin(plack_middleware => ["Auth::Basic", {authenticator => sub {1}}]);
				
				$self->routes->route('/index')->to(cb => sub{
					$_[0]->render(text => 'original');
				});
			}
		}

package Plack::Middleware::TestFilter;
use strict;
use warnings;
use base qw( Plack::Middleware );
	
	sub call {
		
		my $self = shift;
		my $res = $self->app->(@_);
		$self->response_cb($res, sub {
			return sub {
				if (my $chunk = shift) {
					return $chunk. '[filtered]';
				}
			};
			$res;
		});
	}

package Plack::Middleware::TestFilter2;
use strict;
use warnings;
use base qw( Plack::Middleware );
	
	sub call {
		
		my $self = shift;
		my $res = $self->app->(@_);
		$self->response_cb($res, sub {
			return sub {
				if (my $chunk = shift) {
					return $chunk. '[filtered2]';
				}
			};
			$res;
		});
	}

package Plack::Middleware::TestFilter3;
use strict;
use warnings;
use base qw( Plack::Middleware );
	
	sub call {
		
		my $self = shift;
		my $res = $self->app->(@_);
		$self->response_cb($res, sub {
			return sub {
				if (my $chunk = shift) {
					return $chunk. "[$self->{tag}]";
				}
			};
			$res;
		});
	}

package Plack::Middleware::TestFilter4;
use strict;
use warnings;
use base qw( Plack::Middleware );
	
	sub call {
		
		my ($self, $env) = @_;
		$env->{PATH_INFO} .= '.html';
		my $res = $self->app->($env);
		return $res;
	}

package Plack::Middleware::GrowLargeFilter;
use strict;
use warnings;
use base qw( Plack::Middleware );
	
	sub call {
		
		my $self = shift;
		my $res = $self->app->(@_);
		$self->response_cb($res, sub {
			return sub {
				if (my $chunk = shift) {
					return $chunk. ("1234567890" x 10000);
				}
			};
			$res;
		});
	}

package Plack::Middleware::ForceCharset;
use strict;
use warnings;
use 5.008_001;
use parent qw(Plack::Middleware);
use Plack::Util;
use Plack::Util::Accessor qw(charset);
use Encode;

	our $VERSION = '0.02';
	
	sub call {
		my ($self, $env) = @_;
		$self->response_cb($self->app->($env), sub {
			my $res = shift;
			my $h = Plack::Util::headers($res->[1]);
			my $charset_from = 'UTF-8';
			my $charset_to = $self->charset;
			my $ct = $h->get('Content-Type');
			if ($ct =~ s{;?\s*charset=([^;\$]+)}{}) {
				$charset_from = $1;
			}
			if ($ct =~ qr{^text/(html|plain)}) {
				$h->set('Content-Type', $ct. ';charset='. $charset_to);
			}
			my $fixed_body = [];
			Plack::Util::foreach($res->[2], sub {
				Encode::from_to($_[0], $charset_from, $charset_to);
				push @$fixed_body, $_[0];
			});
			$res->[2] = $fixed_body;
			$h->set('Content-Length', length $fixed_body);
			return $res;
		});
	}

package Plack::Middleware::InvokeAppTwice;
use strict;
use warnings;
use base qw( Plack::Middleware );
	
	sub call {
		
		my ($self, $env) = @_;
		my $res = $self->app->($env);
		if ($res->[0] == 404) {
			local $env->{PATH_INFO} = 'index2';
			$res = $self->app->($env);
		}
		return $res;
	}

1;

__END__
