package	mmt;

=pod

=head1 NAME

mmt.pm - マスターメンテツールモジュール

=head1 概要

マスタメンテ用CGI作成の為のモジュール

部品マスタメンテ　サンプル

 #!/usr/local/bin/perl
 
 package mymmt;
 @ISA = qw(mmt);
 
 package main;
 
 use strict;
 use mmt;
 use vars qw($mmt);
 $mmt = new mymmt({'table'=>'部品マスタ'});
 my @key = qw(部品コード);
 my @item = qw(部品名称);
 $mmt->{m}->{key} = \@key;
 $mmt->{m}->{item} = \@item;
 
 $mmt->action();


=head1 サブルーチン

=cut

#use CGI qw/:standard :html3 -no_xhtml/;
use CGI qw/:standard :xhtml/;
use CGI::Carp qw(fatalsToBrowser);
use Data::Dumper;
use webdb;
use myconstant;
#---------------------------------------------------------------#
sub new{
#---------------------------------------------------------------#

=head2 new コンストラクタ

$mmt = new mmt({'table'=>'テーブル名称'});

メンテナンスしたいテーブル名をtableにセットして呼び出す。

=cut

	my $class = shift;
	my $self = {};
	$self->{'m'} = shift;
	bless $self,$class;
	$self->{'dbh'} = new webdb;
	$self->{'in'} = new CGI;
	$self->{'cons'} = new myconstant;
	$self->{'m'}->{table} ||= $self->{in}->param('table');
	$self->{m}->{-explain} ||= $self->{m}->{table};
	$self->desc_table();
	$self->initialize();
	$self->{dbh}->secure($self->{in});
	return $self;
}
#---------------------------------------------------------------#
sub initialize{
#---------------------------------------------------------------#

=head2 initialize 初期設定

=cut

	my $s = shift;
	$s->{msg}->{action}->[0] = 'ENTER';
	$s->{msg}->{action}->[1] = '登録';
	$s->{msg}->{action}->[2] = '修正';
	$s->{msg}->{action}->[3] = '削除';
	$s->{msg}->{action}->[4] = 'クリア';
	$s->{msg}->{action}->[5] = '検索';
	$s->{msg}->{action}->[6] = '読込';
	$s->{msg}->{action}->[7] = 'excel';
	$s->{msg}->{action}->[8] = '更新';
	$s->{next} = $s->{home_p}||"key0";
}
#---------------------------------------------------------------#
sub desc_table{
#---------------------------------------------------------------#

=head2 desc_table テーブル情報取得

=cut

	my $s = shift;
	my $m = shift || 'm';
	my $f;
	$s->{$m}->{key} = [];
	$s->{$m}->{item} = [];
	my $sth = $s->{dbh}->{dbh}->prepare($s->desc_param($m));
	$sth->execute();
	my $flag = 0;
	while(my $ref = $sth->fetchrow_hashref()){
		$f = $ref->{Field};
		$s->{$m}->{$f}->{Type} = $ref->{Type};
		$s->{$m}->{$f}->{Null} = $ref->{Null};
		$s->{$m}->{$f}->{Key} = $ref->{Key};
		$s->{$m}->{$f}->{Default} = $ref->{Default};
		$s->{$m}->{$f}->{Extra} = $ref->{Extra};
		$s->{$m}->{$f}->{Size} = $s->size($ref->{Type});
		if($ref->{Key} eq 'PRI'){
			push @{$s->{$m}->{key}},$f;
		}elsif($ref->{Type} =~ /timestamp/){
			$s->{$m}->{timestamp} = $f;
		}else{	push @{$s->{$m}->{item}},$f;
		}
		$flag = 1;
	}
	$sth->finish();
	return $flag;
}
sub desc_param{
	my $s = shift;
	my $m = shift;
	return "desc $s->{$m}->{table}";
}
sub keys_get{
	my $s =shift;
}
#---------------------------------------------------------------#
sub size{
#---------------------------------------------------------------#

=head2 size 項目桁数取得

フィールドタイプより桁数を計算する

=over 2

=item C<$ret = $mmt->size($ref->{Type})>

 $ref->{Type}: データベースより取得したフィールドのタイプ
 $ret: フィールドタイプより計算した項目の桁数を返す

=back

=cut

	my $s = shift;
	my $type = shift;
	my ($t1,$t2,$t3);
	$type =~ /\w+\((\d+)\,{0,1}(\d{0,1})\)/;
	$t1 = $1;
	$t1++ if($2);
	$t1++ if($s->type_numeric2($type));
	if($type eq 'date'){
		$t1 = 10;
	}elsif($type eq 'time'){
		$t1 = 8;
	}elsif($type eq 'datetime'){
		$t1 = 20;
	}
	return $t1;
}
#---------------------------------------------------------------#
sub display{
#---------------------------------------------------------------#

=head2 display メンテナンス画面作成

キー項目画面とデータ画面を表示する

=cut

	my $s = shift;
	$s->key_display();
	$s->data_display();
	$s->up_load_form();
	$s->sub_window();
}
sub sub_window{
}
#---------------------------------------------------------------#
sub key_display{
#---------------------------------------------------------------#

=head2 key_display キー項目画面作成

キー項目の入力用画面を作成する。

=cut

	my $s = shift;
	my $onLoadsub = "onloadsub();";
	if($s->{in}->param('action') eq '検索'){
		$onLoadsub = '';
	}
	$s->{m}->{title} = $s->{m}->{table} unless(exists $s->{m}->{title});
	print $s->{in}->header(-type=>"text/html; charset=utf-8"),
		$s->{in}->start_html(-title=>$s->{m}->{title} ." - ".
				$s->{in}->url(),
			-style=>[{'src'=>$s->{cons}->{css}.'sne.css'},
						{'src'=>$s->{cons}->{css}.'calendar.css'},
					],
			-script=>[{-language=>'JavaScript',
					-src=>$s->{cons}->{js}.'prototype.js'},
				{-language=>'JavaScript',
					-src=>$s->{cons}->{js}.'sortable_ja.js'},
			{-language=>'JavaScript',-src=>"$s->{cons}->{js}dateformat.js"},
			{-language=>'JavaScript',-src=>"$s->{cons}->{js}yahoo.js"},
			{-language=>'JavaScript',-src=>"$s->{cons}->{js}dom.js"},
			{-language=>'JavaScript',-src=>"$s->{cons}->{js}event.js"},
			{-language=>'JavaScript',-src=>"$s->{cons}->{js}calendar.js"},
			{-language=>'JavaScript',-src=>"$s->{cons}->{js}initcompletion.js"},
			{-language=>'JavaScript',-src=>"$s->{cons}->{js}complete.js"},
			{-language=>'JavaScript',-src=>"$s->{cons}->{js}ecl_new.js"},
			],
#			-head=>meta({-http_equiv=>'Pragma',
#					-content=>'no-cache'}),
			-onLoad=>$onLoadsub."document.form.$s->{next}.focus();document.form.$s->{next}.select();");
	my $rand = $s->{dbh}->random_str() . "=1";
	my $url = $s->{in}->url();
	$url =~ s/\.cgi/\.cgi\?$rand/;
	print $s->{in}->start_form(-name=>'form',-method=>'post',
			-onSubmit=>"submitsub();return false;",
			-action=>$s->{in}->url());
	print qq{<input type="hidden" name="table" value=$s->{m}->{table}>};
	print $s->{in}->hidden(-name=>'next'),"\n";
	if(defined $s->{m}->{timestamp}){
		print $s->{in}->hidden(-name=>'timestamp');
	}
	print h2($s->{m}->{title});
	print $s->formScript({'a5'=>$s->{m}->{editA5},
				'f1'=>$s->{m}->{editF1}});
#	print Dump($s->{m});
	print "<table border=1>\n";
	$s->key_form();
	print "</table>",
		$s->{in}->submit(-name=>'action',
			-value=>$s->{msg}->{action}->[0]),
		$s->{in}->submit(-name=>'action',
			-value=>$s->{msg}->{action}->[6],
			-onFocus=>qq{document.form.next.value="action[1]"});
	my @item_list = (@{$s->{m}->{key}},@{$s->{m}->{item}});
	if(exists $s->{m}->{serch_item}){
		@item_list = (@{$s->{m}->{serch_item}});
	}
	print	$s->{in}->popup_menu(-name=>'serch_item',
			-values=>\@item_list,
			-labels=>$s->{m}->{label}),
		$s->{in}->popup_menu(-name=>'serch_op',
			-values=>[qw(like = <> <= < > >= between regexp)]),
		$s->{in}->textfield(-name=>'serch_value'),
		$s->{in}->submit(-name=>'action',
			-value=>$s->{msg}->{action}->[5],
			-onFocus=>qq{document.form.next.value="action[2]"}),
		$s->{in}->button(-name=>'Oprion:',-onClick=>
			"Add_Option();"),
		$s->{in}->textfield(-name=>'serch_opt'),
		$s->serch_items,
		$s->{dbh}->menu(),
		"[<span -class=err id=errstr>$s->{errstr}</span>]",
		"<hr>\n";
}
sub key_form{
	my $s = shift;
	my $i = 0;
	for(@{$s->{m}->{key}}){
		print Tr(th("<div id=_l_key$i>" . $s->Label($_) . "</div>"),
			td([$s->{in}->textfield(-name=>"key$i",
				-size=>int($s->{m}->{$_}->{Size}*1.3)+1,
				-maxlength=>$s->{m}->{$_}->{Size},
				-tabindex=>'1',
				-onFocus=>qq{document.form.next.value="key$i"}).
			$s->{cons}->{explain}->{$s->{m}->{-explain}}->{$_},
			"<div id=kdisp$i>".
			$s->{m}->{d}->{$_}."</div>"])),
			"\n";
		$i++;
	}
}
sub key_input_field{
	my $s = shift;
	my $name = shift;
	my $n = $s->input_names();
	return $s->{in}->textfield(-name=>"$n->{$name}",
			-size=>int($s->{m}->{$name}->{Size}*1.3)+1,
			-tabindex=>1,
			-onFocus=>qq{\$("next").value=$n->{$name}}
	);
}	
sub serch_items{
	my $s = shift;
	my $txt;
	my @item_list = (@{$s->{m}->{key}},@{$s->{m}->{item}});
	if(exists $s->{m}->{serch_item}){
		@item_list = (@{$s->{m}->{serch_item}});
	}
	my $line =
		$s->{in}->popup_menu(-name=>'serch_and__No_',
			-values=>[qw(and or)]) .
		$s->{in}->popup_menu(-name=>'serch_item__No_',
			-values=>\@item_list,
			-labels=>$s->{m}->{label}) .
		$s->{in}->popup_menu(-name=>'serch_op__No_',
			-values=>[qw(like = <> <= < > >= between regexp)]) .
		$s->{in}->textfield(-name=>'serch_value__No_');
	$line =~ s/\n//g;
	for my $i (1 .. $s->{in}->param('OpCnt')){
		$txt .= "<br>\n".
		$s->{in}->popup_menu(-name=>"serch_and$i",
			-values=>[qw(and or)]) .
		$s->{in}->popup_menu(-name=>"serch_item$i",
			-values=>\@item_list,
			-labels=>$s->{m}->{label}) .
		$s->{in}->popup_menu(-name=>"serch_op$i",
			-values=>[qw(like = <> <= < > >= between regexp)]) .
		$s->{in}->textfield(-name=>"serch_value$i");
	}
	$txt .= <<End_Script;
<input type=hidden name=OpCnt value=@{[$s->{in}->param('OpCnt')||0]}>
<br><div id="AddSerch"></div>
<script language=JavaScript>
var OptionLine = '';
//for(i=1;i<=\$('OpCnt').value;i++){
//	line = '$line';
//	line2 = line.replace(/__No_/g,i);
//	OptionLine = OptionLine + line2 + '<br>';
//}
//\$('AddSerch').innerHTML = OptionLine;

function Add_Option(){
	No = \$('OpCnt').value;
	No++;
	\$('OpCnt').value = No;
	line = '$line';
	line2 = line.replace(/__No_/g,No);
	OptionLine = OptionLine + line2 + '<br>';
	\$('AddSerch').innerHTML = OptionLine;
}
</script>
End_Script
	return $txt;
}
#---------------------------------------------------------------#
sub data_display{
#---------------------------------------------------------------#

=head2 data_display データ項目画面作成

データ項目入力用の画面を作成する。

=cut

	my $s = shift;
	print "<table border=1>\n";
	$i = 0;
	$ii = 0;
	$j = 0;
	$k = 1;
	if($s->{m}->{linemax} =~ /^\d+$/){
		print "<tr>";
	}
	for(@{$s->{m}->{item}}){
		if($s->{m}->{linemax} =~ /^\d+$/){
			if($ii%$s->{m}->{linemax} == 0){
				print "</table></td>" if($i != 0);
				if($s->{m}->{-column} > 1 and 
				   $s->{m}->{-column} == $j){
					print "</tr><tr>";
					$j = 0;
				}
				print '<td style="vertical-align:top;"><table border=1>';
				print "<caption>".
					$s->{m}->{-caption}->{$k}.
					"</caption>"
					if($s->{m}->{-caption}->{$k});
				$j++;
				$k++;
			}
		}
		if($s->{m}->{-ctl}->{$_} eq 'hidden'){
			print "<input type=hidden name=item$i value=".
				$s->input_data($_).">";
		}else{	print Tr(th("<div id=_l_item$i>" . $s->Label($_) .
						"</div>"),
				td([$s->input_field($i,$_).'&nbsp'.
					$s->{cons}->{explain}->
					{$s->{m}->{-explain}}->{$_},
				"<div id=disp$i>".
				$s->{m}->{d}->{$_}."</div>"])),
				"\n";
		}
		$i++;$ii++;
		$ii = $s->{m}->{linemax} if($s->{m}->{-ctl}->{$_} eq 'feed');
	}
	if($s->{m}->{linemax} =~ /^\d+$/){
		print "</table></td></tr>";
	}
	print "</table>";
	$s->syori_button();
}
sub input_field{
	my $s = shift;
	my $i = shift;
	my $name = shift;
	my $j = shift || 0;
	my $style = 'text-align: left';
	my $addComma = ';';
	if($s->type_numeric($name)){
		$style = 'text-align: right';
	}
	if(grep {"item$i" eq $_} @{$s->{m}->{editA5}}){
		$addComma = "this.value=addComma(this.value)";
	}
	if(grep {"item$i" eq $_} @{$s->{m}->{editF1}}){
		$addComma = "this.value=edit_F1(this.value)";
	}
	if($s->{m}->{$name}->{Type} eq 'text'){
		return $s->{in}->textarea(-name=>"item$i",-rows=>5,-cols=>70,
			-tabindex=>1,
			-onFocus=>qq{document.form.next.value="item$i"});
	}elsif($s->{m}->{$name}->{Type} =~ /enum\((.*)\)/){
		return $s->{in}->popup_menu(-name=>"item$i",
			-tabindex=>1,
			-values=> [map {s/'//g;$_} split /,/,$1],
			-onFocus=>qq{document.form.next.value="item$i"});
	}else{	return $s->{in}->textfield(-name=>"item$i",
			-size=>int($s->{m}->{$name}->{Size}*1.3)+1,
			-maxlength=>$s->{m}->{$name}->{Size},
			-default=>@{[$s->{in}->param("item$i")]}[$j],
			-override=>1,
			-tabindex=>1,
			-style=>$style,
			-onChange=>$addComma,
			-onFocus=>qq{document.form.next.value="item$i"});
	}
}
sub disp_field{
	my $s = shift;
	my $name = shift;
	my $style = 'text-align: left';
	my $override = 0;
	if($s->type_numeric($name)){
		$style = 'text-align: right';
	}
	if($s->{in}->param('action') eq $s->{msg}->{action}->[6] or
		$s->{in}->param('action') eq "get"){
		$override = 1;
		$s->{in}->param($name,$s->{m}->{ref}->{$name});
	}
	return $s->{in}->textfield(-name=>"$name",
			-size=>int($s->{m}->{$name}->{Size}*1.3)+1,
			-default=>$s->{m}->{ref}->{$name},
			-override=>$override,
			-tabindex=>-1,
			-readonly=>"true",
			-style=>$style
	);
}
sub syori_button{
	my $s = shift;
	print	$s->{in}->submit(-name=>'action2',
			-tabindex=>1,
			-value=>$s->{msg}->{action}->[0]),
		$s->{in}->submit(-name=>'action',
			-tabindex=>1,
			-value=>$s->{msg}->{action}->[1],
			-onFocus=>qq{document.form.next.value="action[4]"}),
		$s->{in}->submit(-name=>'action',
			-tabindex=>1,
			-value=>$s->{msg}->{action}->[2],
			-onFocus=>qq{document.form.next.value="action[5]"}),
		$s->{in}->submit(-name=>'action',
			-tabindex=>1,
			-value=>$s->{msg}->{action}->[3],
			-onFocus=>qq{document.form.next.value="action[6]"}),
		$s->{in}->submit(-name=>'action',
			-tabindex=>1,
			-value=>$s->{msg}->{action}->[4],
			-onFocus=>qq{document.form.next.value="action[7]"}),
		"<br>\n";
	print 	"</form>\n";
#	$s->up_load_form();
}
sub up_load_form{
	my $s = shift;
	print "<hr>\n";
	print $s->{in}->start_multipart_form(-name=>'form2',-method=>'post',
			-action=>$s->{in}->url(),
			-target=>'_blank');
	print "アップロードファイル：";
	print	$s->{in}->filefield(-name=>'upload_file',-size=>70);
	print	$s->{in}->submit(-name=>action,-value=>
					$s->{msg}->{action}->[8]);
	print	$s->{in}->hidden('table');
	print	$s->{in}->hidden('_truncate_');
	print	$s->{in}->hidden('_opt_');
	print	"</form>\n";
}
sub up_load_upd_opt{
	my $s = shift;
	my @x = @_;
	print qq{$x[0]<br>$x[1]<br>\n};
	return @x;
}
sub up_load_upd{
	my $s = shift;
	print $s->{in}->header(-type=>"text/html; charset=utf-8"),
		$s->{in}->start_html(-title=>$s->{m}->{title} ." - ".
				$s->{in}->url(),
			-style=>{'src'=>$s->{cons}->{css}.'sne.css'});
	$filename = $s->{in}->upload('upload_file');
	my $FileName = $s->{in}->param('upload_file');
	my (@title,@data);
	my (@key,@item);
	my ($sql,$sql2);
	my $i;
	while(<$filename>){
		s/\x0D//;
		s/\x0A//;
		if($FileName =~ /.csv$/){
			@title = $s->{dbh}->csv_split($s->{dbh}->sj2euc($_));
		}else{	@title = split '\t',$s->{dbh}->sj2euc($_);
		}
#		print [$#title];
		for $i (0..$#title){
			if(grep {$title[$i] eq $_} @{$s->{m}->{key}}){
				push @key,$i;
			}elsif(grep {$title[$i] eq $_} @{$s->{m}->{item}}){
				push @item,$i;
			}else{
			}
		}
		$sql = "update " . $s->{m}->{table} . " set ";
		$sql .= join ',',map {"$title[$_] = ?"} @item ;
		$sql .= " where ";
		$sql .= join ' and ',map {"$title[$_] = ?"} @key ;
		$sql2 = "insert into " . $s->{m}->{table} ."(";
		$sql2 .= join ',',map {"$title[$_]"} @item,@key;
		$sql2 .= ") values (";
		$sql2 .= join ",",map {'?'} @item,@key;
		$sql2 .= ")";
		last;
	}
	($sql,$sql2) = $s->up_load_upd_opt($sql,$sql2);
	my $error_flag = 0;
	unless(defined $key[0]){
		print "キー項目がありません";
		$error_flag = 1;
	}
	if($#key != $#{$s->{m}->{key}}){
		print "キー項目の個数が違います";
		$error_flag = 1;
	}
	print "<table border=1>\n";
	print Tr(th([@title])),"\n";
	my $count = 0;
	my $count2 = 0;
	my $line = 1;
	if($error_flag == 0){
		if($s->{in}->param('_truncate_') eq 'on'){
			$s->{dbh}->{dbh}->do("truncate table $s->{m}->{table}");
		}
		my $sth = $s->{dbh}->{dbh}->prepare($sql);
		my $sth2 = $s->{dbh}->{dbh}->prepare($sql2);
		my @prepare;
		my $ret;
		while(<$filename>){
			$line++;
			s/\x0D//;
			s/\x0A//;
			next if(/^$/);
			s/\t$/\t /;
			@prepare = ();
			if($FileName =~ /.csv$/){
				@data =
				$s->{dbh}->csv_split($s->{dbh}->sj2euc($_));
			}else{	@data = split '\t',$s->{dbh}->sj2euc($_);
			}
			if($#data != $#title){
				print Tr(td({-colspan=>$#title+1},
					["$line行は項目数が違うためスキップ"]))
					,"\n";
				print Tr(td([@data])),"\n";
				next ;
			}
			push @prepare,map{$data[$_]} @item,@key;
			if(($ret = $sth->execute(@prepare)) < 1){
				$ret = $sth2->execute(@prepare);
				$count2 += $ret;
			}else{	$count += $ret;}
		}
	}
#			print Tr(td([@item]));
	print "</table>\n";
	print "$line 行中 $count 件更新 $count2 件追加しました。<br>\n";
	print end_html();
}
#---------------------------------------------------------------#
sub action{
#---------------------------------------------------------------#

=head2 action 処理判断

メンテナンス画面でどのボタンが押されたか判断し
各処理を行う。

単純なメンテナンス処理はB<new>とB<action>のみでマスタメンテ処理が出来る。

 #!/usr/local/bin/perl
 
 use mmt;
 $mmt = new mmt({'table'=>'ＰＮマスタ'});
 $mmt->action();

=cut

	my $s = shift;
	$s->{next} = $s->next_set($s->{in}->param('next')) ||$s->{home_p}|| 'key0';
	$s->{errorflag} = 0;
	if($s->{in}->param('action') eq $s->{msg}->{action}->[1]){
		if($s->data_check0() == 0){
			$s->data_insert();
			$s->AFTER_PROC();
		}
	}elsif($s->{in}->param('action') eq $s->{msg}->{action}->[2]){
		if($s->data_check0() == 0){
			$s->data_update();
			$s->AFTER_PROC();
		}
	}elsif($s->{in}->param('action') eq $s->{msg}->{action}->[3]){
		$s->data_delete();
		$s->AFTER_PROC();
	}elsif($s->{in}->param('action') eq $s->{msg}->{action}->[4]){
		$s->data_cancel();
		$s->{next} = $s->{home_p}||"key0";
	}elsif($s->{in}->param('action') eq $s->{msg}->{action}->[6] or
		$s->{in}->param('action') eq "get"){
		$s->data_get();
		if($s->{errorflag}){
			$s->{next} = $s->{home_p}||"key0";
			if($s->{m}->{-act} eq 'input'){
				$s->{next} = $s->check_name($s->{item_s}||"item0",0);
			}
		}else{	$s->data_check0();
			$s->{next} = $s->check_name($s->{item_s}||"item0",0);
		}
	}elsif($s->{in}->param('action') eq $s->{msg}->{action}->[0]){
		if($s->{in}->param('next') =~ /key/){
			$s->data_check_key();
		}else{	$s->data_check0();
		}
	}else{	;
	}
	if($s->{in}->param('action') eq $s->{msg}->{action}->[5]){
		$s->{next} = $s->{home_p}||"key0";
		$s->data_serch();
	}elsif($s->{in}->param('action') eq $s->{msg}->{action}->[7]){
		$s->excel_put();
	}elsif($s->{in}->param('action') eq $s->{msg}->{action}->[8]){
		$s->up_load_upd();
	}elsif($s->{in}->param('action') eq 'Updater'){
		$s->Updater();
	}elsif($s->{in}->param('action') eq 'JSON'){
		$s->JSON();
	}elsif($s->{in}->param('action') eq 'sub_list'){
		$s->sub_list();
	}else{	$s->display();
	}
	
}
sub New_Updater{
	my $s = shift;
	my @n = @_;
	my $p = '';
	for(@n){
		$p .= q{+'&p='+encodeURIComponent($F("}. $s->input_names->{$_} . '"))';
	}
	return qq{new Ajax.Updater('@{[$s->disp_names->{$n[0]}]}','} .
	$s->{in}->url(-relative=>1) .'?action=Updater&n='.
	$s->input_names->{$n[0]} . "'$p,{method: 'get'});\n";
}
sub Updater{
	my $s = shift;
	print header(-type=>"text/html; charset=utf-8");
	my $sth = $s->set_sql();
	while(my $ref = $sth->fetchrow_arrayref()){
		print $ref->[0];
		$sth->finish();
		last;
	}
}
sub set_sql{
	my $s = shift;
	$s->{in}->param('n') =~ /^(\D+)(\d+)$/;
	my ($Name,$No) = ($1,$2);
	my $sth = $s->{dbh}->{dbh}->prepare(
		$s->{m}->{$s->{m}->{$Name}[$No]}->{LOOK_UP}->[0]);
	$sth->execute($s->{in}->param('p'));
	return $sth;
}
sub JSON{
	my $s = shift;
	print header(-type=>"text/html; charset=utf-8");
	my $sth = $s->json_sql();
	print '{"item":[' ."\n";
	my @a = ();
	my @b = ();
	while(my $ref = $sth->fetchrow_hashref()){
		@b = ();
		for(@{$sth->{NAME}}){
			$ref->{$_} =~ s/\x00//g;
			push @b,qq{"$_":"$ref->{$_}"};
		}
		push @a,"{\n" . join(",\n",@b) ."}\n";
	}
	print join(',',@a);
	print "]\n}\n";
}
sub json_sql{
	my $s = shift;
	$sth = $s->{dbh}->{dbh}->prepare("select 'SELECT_EXPRESSION'");
	$sth->execute($s->{in}->param('p'));
	return $sth;
}
#---------------------------------------------------------------#
sub next_set{
#---------------------------------------------------------------#

=head2 next_set 入力項目サーチ

次の入力項目を探し出す。

=cut

	my $s = shift;
	my $next = shift;
	my $tmp;
	$next =~ /^(\D+)(\d+)$/;
	my $name = $1;
	my $no = $2;
	my $i = 1;
	if($no < $#{$s->{m}->{$name}}){
		$tmp = $next;
		for(;$no+$i <= $#{$s->{m}->{$name}};$i++){
			next if($s->{m}->{-ctl}->
					{$s->{m}->{$name}->[$no + $i]}
					 eq 'hidden');
			if($no+$i > $#{$s->{m}->{$name}}){return $tmp;}
			$tmp = "$name" . ($no + $i);
			last;
		}
	}elsif($name eq "key"){
		$tmp = "item0";
	}elsif($no == $#{$s->{m}->{$name}}){
		$tmp = $s->{home_p}||"item0";
	}else{	$tmp = $next;
	}
	my $i = 0;
	if($s->{m}->{-ctl}->{$s->{m}->{$name}->[$no]}
					 =~ /next:\s*([^\s]*)/){
		$tmp = $1;$i++;
	}
	return $s->check_name($tmp,$i);
#	my @arr = $s->{in}->param($tmp);
#	if(@arr > 1){$tmp .= "[$i]";}
#	return $tmp;
}
sub check_name{
	my $s = shift;
	my $name = shift;
	my $i = shift||0;
	my @arrye = $s->{in}->param($name);
	if(@arrye > 1) {$name .= "[$i]";}
	return $name;
}
#---------------------------------------------------------------#
sub data_insert{
#---------------------------------------------------------------#

=head2 data_insert データ追加処理

登録ボタン投下後の処理で入力データを追加登録する。

=cut

	my $s = shift;
	$s->_data_insert(0);
}
sub _data_insert{
	my $s = shift;
	my $i = shift;
	$s->{sql} = "insert into $s->{m}->{table} (";
	$s->{sql} .= join(",",@{$s->{m}->{key}},@{$s->{m}->{item}});
	$s->{sql} .= ") values(";
	my $cnt = @{$s->{m}->{key}}+@{$s->{m}->{item}};
	my $tmp = "?," x $cnt;
	$tmp =~ s/,$//;
	$s->{sql} .= $tmp .")";
	$s->{m}->{where} = [];
	for (0..$#{$s->{m}->{key}}){
		push @{$s->{m}->{where}},$s->{in}->param("key$_");
	}
	for (0..$#{$s->{m}->{item}}){
		push @{$s->{m}->{where}},
			(@{[$s->{in}->param("item$_")]}[$i]||
				$s->{in}->param("item$_"));
	}
	$s->INSERT_SUB;
	my $sth = $s->{dbh}->{dbh}->prepare($s->{sql});
	my $ret = $sth->execute(@{$s->{m}->{where}});
	$s->{errstr} = $s->err_str($sth->errstr) || "登録しました";
	if($s->{in}->param('key0') eq ''){
		$s->{next} = $s->{home_p}||"item0";
	}else{	$s->{next} = $s->{home_p}||"key0";
	}
}
sub err_str{
	my $s = shift;
	return $s->{dbh}->utf2euc(shift);
}
#---------------------------------------------------------------#
sub INSERT_SUB{
#---------------------------------------------------------------#

=head2 INSERT_SUB 登録前処理

DATAがINSERTされる直前のルーチンです。何か処理がある時には
オーバーライドして下さい。

=cut

}
#---------------------------------------------------------------#
sub data_update{
#---------------------------------------------------------------#

=head2 data_update データ更新処理

修正ボタン投下後の処理で入力データを修正する。

=cut

	my $s = shift;
	$s->_data_update(0);
}
sub _data_update{
	my $s = shift;
	my $i = shift||0;
	$s->{sql} = "update $s->{m}->{table} set ";
	for(@{$s->{m}->{item}}){
		$s->{sql} .= "$_ = ?,";
	}
	$s->{sql} =~ s/,$/ /;
	$s->{sql} .= $s->where();
	$s->{m}->{where} = [];
	for (0..$#{$s->{m}->{item}}){
		push @{$s->{m}->{where}},
			(@{[$s->{in}->param("item$_")]}[$i]||
				$s->{in}->param("item$_"));
	}
	for (0..$#{$s->{m}->{key}}){
		push @{$s->{m}->{where}},$s->{in}->param("key$_");
	}
	if(defined $s->{m}->{timestamp}){
		$s->{sql} .= " and $s->{m}->{timestamp} = ? ";
		push @{$s->{m}->{where}},$s->{in}->param("timestamp");
	}
	$s->UPDATE_SUB;
	my $sth = $s->{dbh}->{dbh}->prepare($s->{sql});
	my $ret = $sth->execute(@{$s->{m}->{where}});
	$s->{errstr} = $sth->errstr || "修正しました";
	if ($ret < 1){ $s->{errstr} =
		 "修正データありません（キー項目修正しましたか？または他のユーザーに修正された可能性が有ります。もう１度読み込んでください。）";}
	$s->{next} = $s->{home_p}||"key0";
}
#---------------------------------------------------------------#
sub UPDATE_SUB{
#---------------------------------------------------------------#

=head2 UPDATE_SUB 更新前処理

DATAがUPDATEされる直前のルーチンです。何か処理がある時には
オーバーライドして下さい。

=cut

}
#---------------------------------------------------------------#
sub data_delete{
#---------------------------------------------------------------#

=head2 data_delete データ削除処理

削除ボタン投下後の処理で入力データを削除する。

=cut

	my $s = shift;
	$s->{sql} = "delete from $s->{m}->{table} ";
	$s->{sql} .= $s->where();
	$s->DELETE_SUB;
	my $sth = $s->{dbh}->{dbh}->prepare($s->{sql});
	my $ret = $sth->execute(@{$s->{m}->{where}});
	$s->{errstr} = $sth->errstr||"削除しました";
	if ($ret < 1){ $s->{errstr} =
		 "削除データありません（キー項目修正しましたか？または他のユーザーに修正された可能性が有ります。もう１度読み込んでください。）";}
	$s->{next} = $s->{home_p}||"key0";
}
#---------------------------------------------------------------#
sub DELETE_SUB{
#---------------------------------------------------------------#

=head2 DELETE_SUB 削除前処理

DATAがDELETEされる直前のルーチンです。何か処理がある時には
オーバーライドして下さい。

=cut

}
#---------------------------------------------------------------#
sub AFTER_PROC{
#---------------------------------------------------------------#

=head2 AFTER_PROC 更新処理後ルーチン

登録、修正、削除の各々の処理後に処理されるルーチン

=cut

}
#---------------------------------------------------------------#
sub data_cancel{
#---------------------------------------------------------------#

=head2 data_cancel 画面キャンセル処理

クリアボタン投下後の処理で画面をクリアーする。

=cut

	my $s = shift;
	my $tmp = $s->{in}->param('table');
	$s->{in}->delete_all();
	$s->{in}->param('table',$tmp);
}
#---------------------------------------------------------------#
sub data_check0{
#---------------------------------------------------------------#

=head2 data_check0 データチェック処理

データチェックルーチン　全てのチェックはdata_chekルーチン移行で
処理しここでは何もしない

=cut

	my $s = shift;
	$s->data_check_key();
	$s->data_check_item();
	return $s->{errorflag};
}
#---------------------------------------------------------------#
sub data_check_key{
#---------------------------------------------------------------#

=head2 data_check_key キー部データチェック処理

キー項目の入力内容をチェックする。

=cut

	my $s = shift;
	for(0..$#{$s->{m}->{key}}){
		$s->data_check1('key',$_);
	}
}
#---------------------------------------------------------------#
sub data_check_item{
#---------------------------------------------------------------#

=head2 data_check_item データ部データチェック処理

データ項目の入力内容をチェックする。

=cut

	my $s = shift;
	for(0..$#{$s->{m}->{item}}){
		$s->data_check1('item',$_);
	}
}
#---------------------------------------------------------------#
sub data_check1{
#---------------------------------------------------------------#

=head2 data_check1 入力データチェック処理

入力項目の内容チェックを行う。

数値項目はB<numeric_chk>ルーチンにてニューメリックチェックを行い、
日付項目はB<date_chk>ルーチンにて日付チェックを行う。

ユーザー指定項目チェック：各項目別に設定したチェック内容にて
データチェックを行う。newの後でチェック内容をセットする事。

B<$mmt->{m}->{項目名}->{チェック処理}> 

=over 2

=item チェック処理：OK

$mmt->{m}->{項目名}->{OK} = [qw(A B C)]

入力値が"A","B","C"の時ＯＫとする

=item チェック処理：BETWEEN

$mmt->{m}->{項目名}->{BETWEEN} = [10,500]

入力値が10〜500の時ＯＫとする

=item チェック処理：LOOK_UP

$mmt->{m}->{項目名}->{LOOK_UP} = ["select 名称 from 参照テーブル where キー項目 = ?",[sub {$mmt->input_data('項目名Ａ')}]]

項目名Ａで参照テーブルを参照する

=item チェック処理：SUB

$mmt->{m}->{'親部品コード'}->{SUB} = sub {$mmt->oyacheck()};

ユーザー定義メソッド oyacheckを実行する

=back

 use strict;
 package main;
 
 $mmt = new mymmt({'table'=>'ＰＳマスタ'});
 
 $mmt->{m}->{'親部品コード'}->{SUB} = $mmt->oyacheck();
 $mmt->{m}->{'子部品コード'}->{LOOK_UP} = [
         "select concat(部品名称,機種名) from ＰＮマスタ
                 where 部品コード = ?",
         [sub {$mmt->input_data('子部品コード')}]];
 $mmt->{m}->{'処理区分'}->{OK} = [qw(A C D)];
 $mmt->{m}->{'乗数'}->{BETWEEN} = [qw(-7 7)];
 $mmt->{m}->{'内外作'}->{OK} = ['N','G',''];
 
 $mmt->action();


=cut

	my $s = shift;
	my $k = shift;
	my $i = shift;
	my ($ref,$tmp,@tmp);
	my $ii = -1;
	for $tmp ($s->{in}->param("$k$i")){
	 $ii++;
	 if(defined $tmp){
		if(defined $s->{m}->{$s->{m}->{$k}[$i]}->{SUB}){
			unless($s->{m}->{$s->{m}->{$k}[$i]}->{SUB}()){
				$s->error_set("$k$i",$ii);
			}
		}
		if(defined $s->{m}->{$s->{m}->{$k}[$i]}->{OK}){
			unless(grep {$tmp eq $_} 
				@{$s->{m}->{$s->{m}->{$k}[$i]}->{OK}}){
				$s->{m}->{d}->{$s->{m}->{$k}[$i]} = "範囲外";
				$s->error_set("$k$i",$ii);
			}
		}
		if(defined $s->{m}->{$s->{m}->{$k}[$i]}->{BETWEEN}){
		 if($s->{m}->{$s->{m}->{$k}[$i]}->{Type} =~ /char/){
			unless($tmp ge  
				$s->{m}->{$s->{m}->{$k}[$i]}->{BETWEEN}[0] and
				$tmp le  
				$s->{m}->{$s->{m}->{$k}[$i]}->{BETWEEN}[1]){
				$s->{m}->{d}->{$s->{m}->{$k}[$i]} = "範囲外";
				$s->error_set("$k$i",$ii);
			}
		 }else{	unless($tmp >=  
				$s->{m}->{$s->{m}->{$k}[$i]}->{BETWEEN}[0] and
				$tmp <=  
				$s->{m}->{$s->{m}->{$k}[$i]}->{BETWEEN}[1]){
				$s->{m}->{d}->{$s->{m}->{$k}[$i]} = "範囲外";
				$s->error_set("$k$i",$ii);
			}
		 }
		}
		if(defined $s->{m}->{$s->{m}->{$k}[$i]}->{LOOK_UP}){
			if($ref = $s->look_up($s->{m}->{$s->{m}->{$k}[$i]}->
						{LOOK_UP}[0],
					$s->{m}->{$s->{m}->{$k}[$i]}->
						{LOOK_UP}[1]
				)){
				$s->{m}->{d}->{$s->{m}->{$k}[$i]} = $ref->[0];
			}else{	$s->{m}->{d}->{$s->{m}->{$k}[$i]} = "未登録";
				$s->error_set("$k$i");
			}
		}
			
	 }
	}
	if($s->type_numeric($s->{m}->{$k}[$i])){
		my $ii = -1;
		for($s->{in}->param("$k$i")){
		 $ii++;
		 unless($s->numeric_chk2($k,$i,$ii)){
			$s->{errstr} .= "$s->{m}->{$k}[$i]:numeric err ";
			$s->{m}->{d}->{$s->{m}->{$k}[$i]} = "数値エラー";
			$s->error_set("$k$i",$ii);
		 }
		}
	}elsif($s->type_date($s->{m}->{$k}[$i])){
		@tmp = ();
		my $ii = -1;
		for($s->{in}->param("$k$i")){
			$ii++;
			if($_ eq ''){push @tmp,'';next;}
			if($tmp = $s->date_chk($_)){
				push @tmp,$tmp;	
			}else{	$s->{m}->{d}->{$s->{m}->{$k}[$i]} =
							"日付エラー";
				$s->error_set("$k$i",$ii);
				push @tmp,$_;
			}
		}
		$s->{in}->param("$k$i",@tmp);
	}
}
#---------------------------------------------------------------#
sub error_set{
#---------------------------------------------------------------#

=head2 error_set エラーフラグセット

=cut

	my $s = shift;
	my $tmp = shift;
	my $i = shift || 0;
	unless($s->{errorflag}){
		$s->{errorflag} = 1;
		$s->{next} = $s->check_name($tmp,$i);
	}
}
#---------------------------------------------------------------#
sub type_numeric{
#---------------------------------------------------------------#

=head2 type_numeric

フィールドタイプが数値項目かチェックする

=cut

	my $s = shift;
	my $f = shift;
	return($s->type_numeric2($s->{m}->{$f}->{Type}));
}
#---------------------------------------------------------------#
sub type_numeric2{
#---------------------------------------------------------------#

=head2 type_numeric2

フィールドタイプが数値項目かチェックする

=cut

	my $s = shift;
	my $type = shift;
	return($type =~ /(numeric|int|deci|double|float|real)/);
}
sub numeric_chk2{
	my $s = shift;
	my $k = shift;
	my $i = shift;
	my $ii = shift || 0;
	$s->{m}->{$s->{m}->{$k}[$i]}->{Type} =~ /\((\d+)\,?(\d)?\)/;
	my $n = $1-$2 ; $n2 = $2;
	my @tmp = $s->{in}->param("$k$i");
	return ($tmp[$ii] =~ /^[+-]{0,1}\d{0,$n}\.{0,1}\d{0,$n2}$/);
}
#---------------------------------------------------------------#
sub numeric_chk{
#---------------------------------------------------------------#

=head2 numeric_chk

データ内容がが数値かチェックする

=cut

	my $s = shift;
	my $num = shift;
	return ($num =~ /^[+-]{0,1}\d+\.{0,1}\d*$/);
}
#---------------------------------------------------------------#
sub type_date{
#---------------------------------------------------------------#

=head2 type_date

フィールドタイプが日付項目かチェックする

=cut

	my $s = shift;
	my $f = shift;
	return($s->{m}->{$f}->{Type} =~ /^date$/);
}
#---------------------------------------------------------------#
sub date_chk{
#---------------------------------------------------------------#

=head2 date_chk

データ内容が日付かチェックする

=cut

	my $s = shift;
	my $num = shift;
	if($num eq ''){return '0000-00-00';}
	if($num =~ /^0000\D*00\D*00$/){return $num;}
	$num =~ /^(\d{2,4})\D*(\d{1,2})\D*(\d{1,2})$/;
	if($2 < 1 or $2 > 12){ return 0;}
	if($3 < 1 or $3 > 31){ return 0;}
	return "$1-$2-$3";
}
#---------------------------------------------------------------#
sub data_serch{
#---------------------------------------------------------------#

=head2 data_serch データ検索処理

検索ボタン投下後の処理でテーブル内容を一覧表示する。

=cut

	my $s = shift;
	my ($i,$url,@param);
	my $next = $s->{in}->param(next_line) || 0;
	my $max = defined $s->{m}->{maxline} || 2000;
	my $get = $max + 1;
	my $order ;
	my $serch_opt ;
	my @OpParam;
	if ($s->{in}->param('serch_opt') ne ''){
		$serch_opt = " and ".$s->{in}->param('serch_opt');
	}
	($serch_opt,@OpParam) = $s->option_add($serch_opt);
	$order = join(",",@{$s->{m}->{key}});
	$order = "order by $order" if($order);
	$order = $s->{in}->param('OrderBy') if($s->{in}->param('OrderBy'));
	$s->key_display();
	print qq{<table border=1 class="sortable" id="foo">\n};
	print "<thead>";
	$s->head_line_disp;
	print "</thead><tbody>";
	$s->{sql} = <<END;
select m.* from $s->{m}->{table} m where  
m.@{[$s->{in}->param(serch_item)]} @{[$s->{in}->param(serch_op)]} ?
$serch_opt
$order
limit $next,$get
END
	@param = ($s->{in}->param("serch_value"));
	$param[0] .= '%' if $s->{in}->param("serch_op") eq "like";

	if($s->{in}->param(serch_op) eq 'between'){
		$s->{sql} = <<END;
select m.* from $s->{m}->{table} m where
m.@{[$s->{in}->param(serch_item)]} between ? and ?
$serch_opt
$order
limit $next,$get
END
		@param = split ",",$s->{in}->param("serch_value");
	}
	push @param,@OpParam;
	$s->serch_param_set(\@param);
#	print "[$s->{sql}] @param ";
	my $sth = $s->mmt_init_prepare($s->{sql});
	$sth->execute(@param);
	my $count = 0;
	while(my $ref = $sth->fetchrow_hashref()){
		$s->{rwt}->{rskip} = 0;
		$s->mmt_tisel($ref);
		next if($s->{rwt}->{rskip} == 1);
		$count++;
		last if $count > $max; 
		print "<tr>";
		$url=$s->{in}->url() . "?table=" .
			$s->{dbh}->urlencode($s->{in}->param('table'));
		$url .= "&action=get";
		$i=0;
		for(@{$s->{m}->{key}}){
			$url .= "&key$i=@{[$s->{dbh}->urlencode($ref->{$_})]}";
			$i++;
		}
		$s->{url} = $url;
		$s->line_disp($ref);
		print "</tr>\n";
	}
	print "</tbody>";
	print "</table>\n";
	$sth->finish();
	if($count >$max){
		$s->{in}->param('next_line',$next+$max);
		print "<A href=" . $s->{in}->self_url() . ">Next</a> \n";
		$s->{in}->param('next_line',$next-$max);
		print "<A href=" . $s->{in}->self_url() . ">back</a> \n";
	}else{	$s->{in}->param('next_line',0);
		print "<A href=" . $s->{in}->self_url() . ">Top</a> \n";
		$s->{in}->param('next_line',$next-$max);
		print "<A href=" . $s->{in}->self_url() . ">back</a> \n";
	}
	$s->{in}->param('next_line',0);
	$s->{in}->param('action',$s->{msg}->{action}->[7]);
	print "<a href=".$s->{in}->self_url()." target=_blank>excel</a>\n";
}
sub option_add{
	my $s = shift;
	my $serch_opt = shift;
	my @OpParam;
	for my $i(1 .. $s->{in}->param('OpCnt')){
		next if($s->{in}->param("serch_value$i") eq '');
		$serch_opt .= qq{ @{[$s->{in}->param("serch_and$i")]} 
	m.@{[$s->{in}->param("serch_item$i")]} @{[$s->{in}->param("serch_op$i")]} ? };
		if($s->{in}->param("serch_op$i") eq 'between'){
			$serch_opt .= " and ? ";
			push @OpParam,split(',',$s->{in}->param("serch_value$i"));
		}elsif($s->{in}->param("serch_op$i") eq like){
			push @OpParam,$s->{in}->param("serch_value$i")."%";
		}else{
			push @OpParam,$s->{in}->param("serch_value$i");
		}
	}
	return $serch_opt,@OpParam;
}
#---------------------------------------------------------------#
sub excel_put{
#---------------------------------------------------------------#

=head2 excel_put excel用データ出力

excelボタン投下後の処理でテーブル内容をTAB区切りで出力する。

=cut

	my $s = shift;
	my ($i,$url,@param);
#
#	print "Window-Target: _blank\n";
	print "Content-type: application/vnd.ms-excel\n";
	print "ContentDisposition: filename=output.xls\n\n";
#
	my $order ;
	my $serch_opt ;
	my @OpParam;
	if ($s->{in}->param('serch_opt') ne ''){
		$serch_opt = " and ".$s->{in}->param('serch_opt');
	}
	($serch_opt,@OpParam) = $s->option_add($serch_opt);
	$order = join(",",@{$s->{m}->{key}});
	$order = "order by $order" if($order);
	$order = $s->{in}->param('OrderBy') if($s->{in}->param('OrderBy'));
	$s->head_line_disp1;
	$s->{sql} = <<END;
select m.* from $s->{m}->{table} m where  
m.@{[$s->{in}->param(serch_item)]} @{[$s->{in}->param(serch_op)]} ?
$serch_opt
$order
END
	@param = ($s->{in}->param("serch_value"));
	$param[0] .= '%' if $s->{in}->param("serch_op") eq "like";

	if($s->{in}->param(serch_op) eq 'between'){
		$s->{sql} = <<END;
select m.* from $s->{m}->{table} m where
m.@{[$s->{in}->param(serch_item)]} between ? and ?
$serch_opt
$order
END
		@param = split ",",$s->{in}->param("serch_value");
	}
	push @param,@OpParam;
	$s->serch_param_set(\@param);
#	print "[$s->{sql}] @param";
	my $sth = $s->mmt_init_prepare($s->{sql});
	$sth->execute(@param);
	my $count = 0;
	while(my $ref = $sth->fetchrow_hashref()){
		$s->mmt_tisel($ref);
		$s->line_disp2($ref);
	}
	$sth->finish();
}
sub mmt_init_prepare{
	my $s = shift;
	return $s->{dbh}->{dbh}->prepare($s->{sql});
}
sub mmt_tisel{
}
#---------------------------------------------------------------#
sub serch_param_set{
#---------------------------------------------------------------#

=head2 serch_param_set 検索パラメータセット

検索処理用パラメータセット用メソッド$->{sql}にsql文、配列リファレンス
paramにプレースフォルダーの値をセット

=cut

	my $s = shift;
	my $param = shift;
}
#---------------------------------------------------------------#
sub head_line_disp{
#---------------------------------------------------------------#

=head2 head_line_disp 検索行タイトル表示

=cut

	my $s = shift;
	if(defined $s->{m}->{disp_line}){
		print Tr(th([$s->labels(@{$s->{m}->{disp_line}})]),
			th({-class=>"unsortable"},["選択"])),"\n";
	}else{	print Tr(th([$s->labels(@{$s->{m}->{key}},@{$s->{m}->{item}})]),
			th({-class=>"unsortable"},["選択"])),"\n";
	}
}
#---------------------------------------------------------------#
sub head_line_disp1{
#---------------------------------------------------------------#

=head2 head_line_disp1 excelタイトル表示

=cut

	my $s = shift;
	my @title;
	if(defined $s->{m}->{disp_line}){
		print join("\t",map {$s->{dbh}->euc2sj($_)}
					@{$s->{m}->{disp_line}}),
				"\n";
	}else{	print join("\t",map {$s->{dbh}->euc2sj($_)}
					@{$s->{m}->{key}},
					@{$s->{m}->{item}}),"\n";
	}
}
#---------------------------------------------------------------#
sub line_disp{
#---------------------------------------------------------------#

=head2 line_disp 検索１行表示

検索画面の１明細表示ルーチン

=cut

	my $s = shift;
	my $ref = shift;
	if(defined $s->{m}->{disp_line}){
		for(@{$s->{m}->{disp_line}}){
			print "<td>",$ref->{$_},"</td>\n";
		}
	}else{	for(@{$s->{m}->{key}}){
			print "<td><a href=$s->{url}>",$ref->{$_},"</a></td>\n";
		}
		for(@{$s->{m}->{item}}){
			print "<td>",$ref->{$_},"</td>\n";
		}
	}
	print "<td><a href=$s->{url}>選択</a></td>\n";
}
#---------------------------------------------------------------#
sub line_disp2{
#---------------------------------------------------------------#

=head2 line_disp2 excel用１行出力

excel用１明細表示ルーチン

=cut

	my $s = shift;
	my $ref = shift;
	my @items;
	if(defined $s->{m}->{disp_line}){
		for(@{$s->{m}->{disp_line}}){
			push @items,$s->{dbh}->euc2sj($ref->{$_});
		}
	}else{	for(@{$s->{m}->{key}}){
			push @items,$s->{dbh}->euc2sj($ref->{$_});
		}
		for(@{$s->{m}->{item}}){
			push @items,$s->{dbh}->euc2sj($ref->{$_});
		}
	}
	print join("\t",@items),"\n";
}
#---------------------------------------------------------------#
sub data_get{
#---------------------------------------------------------------#

=head2 data_get データ読込処理

読込ボタン投下後のでKEY項目入力内容にてテーブルを参照する。

=cut

	my $s = shift;
	$s->{sql} = "select * from $s->{m}->{table} " . $s->where();
	my $sth = $s->{dbh}->{dbh}->prepare($s->{sql});
	$sth->execute(@{$s->{m}->{where}});
	$s->{_itemcount} = 0;
	my $ref = $sth->fetchrow_hashref();
	if($ref){
		for(0..$#{$s->{m}->{key}}){
			$s->{in}->param("key$_",$ref->{$s->{m}->{key}[$_]});
		}
		$s->{_itemcount}++;
	}else{	$s->{errstr} = "未登録です";
		$s->{errorflag} = 1;
		$s->itemClear();
	}
	for(0..$#{$s->{m}->{item}}){
		$s->{in}->param("item$_",$ref->{$s->{m}->{item}[$_]});
	}
	if(defined $s->{m}->{timestamp}){
		$s->{in}->param("timestamp",$ref->{$s->{m}->{timestamp}});
	}
	$s->{m}->{ref} = $ref;
	if($s->{errorflag} == 0){
	 while($ref = $sth->fetchrow_hashref()){
		for(0..$#{$s->{m}->{item}}){
			$s->{in}->append("item$_",$ref->{$s->{m}->{item}[$_]});
		}
		$s->{_itemcount}++;
	 }
	}
	$s->GET_AF_CHECK();
}
sub GET_AF_CHECK(){
	$s = shift;
}
sub itemClear{
	my $s = shift;
	for(0..$#{$s->{m}->{item}}){
		$s->{in}->param("item$_",'');
	}
}
#---------------------------------------------------------------#
sub where {
#---------------------------------------------------------------#

=head2 where

KEY項目入力内容にてテーブルを参照する条件を組み立てる。

=cut

	my $s = shift;
	my $tmp = "where ";
	$s->{m}->{where} = [];
	for (0..$#{$s->{m}->{key}}){
		$tmp .= $s->{m}->{key}[$_] . " = ? and ";
		push @{$s->{m}->{where}},$s->{in}->param("key$_");
	}
	$tmp =~ s/and $/ /;
	$tmp .= $s->{orderby};
	return $tmp;
}
#---------------------------------------------------------------#
sub look_up{
#---------------------------------------------------------------#

=head2 look_up

参照テーブルを参照する。

=cut

	my $s =shift;
	my ($sql,$para) = @_;
	my @para;
	for (@$para){
		if(ref($_) eq 'CODE'){
			push @para,&$_;
		}else{ push @para,$_;
		}
	}
	my $sth = $s->{dbh}->{dbh}->prepare(qq{$sql});
	$sth->execute(@para);
	my $ref = $sth->fetchrow_arrayref();
	return $ref;
}
#---------------------------------------------------------------#
sub input_data{
#---------------------------------------------------------------#

=head2 input_data 入力値読み出し

フィールド名にて入力データを取り出す。

=cut

	my $s = shift;
	my $k = shift;
	for(0..$#{$s->{m}->{key}}){
		return $s->{in}->param("key$_")
			if($k eq $s->{m}->{key}[$_]);
	}
	for(0..$#{$s->{m}->{item}}){
		return $s->{in}->param("item$_")
			if($k eq $s->{m}->{item}[$_]);
	}
	return undef;
}
#---------------------------------------------------------------#
sub input_names{
#---------------------------------------------------------------#

=head2 input_names 入力フィールド名読み出し

入力フィールド名のhashを返す

=cut

	my $s = shift;
	my $n = {};
	for(0..$#{$s->{m}->{key}}){
			$n->{$s->{m}->{key}[$_]} = "key$_";
	}
	for(0..$#{$s->{m}->{item}}){
			$n->{$s->{m}->{item}[$_]} = "item$_";
	}
	return $n;
}
#---------------------------------------------------------------#
sub disp_names{
#---------------------------------------------------------------#

=head2 disp_names 表示領域読み出し

表示領域のhashを返す

=cut

	my $s = shift;
	my $n = {};
	for(0..$#{$s->{m}->{key}}){
			$n->{$s->{m}->{key}[$_]} = "kdisp$_";
	}
	for(0..$#{$s->{m}->{item}}){
			$n->{$s->{m}->{item}[$_]} = "disp$_";
	}
	return $n;
}
#---------------------------------------------------------------#
sub set_data{
#---------------------------------------------------------------#

=head2 set_data 入力値セット

フィールド名にて入力フィールドにデータをセットする

=cut

	my $s = shift;
	my $k = shift;
	my @v = @_;
	for(0..$#{$s->{m}->{key}}){
		return $s->{in}->param("key$_",@v)
			if($k eq $s->{m}->{key}[$_]);
	}
	for(0..$#{$s->{m}->{item}}){
		return $s->{in}->param("item$_",@v)
			if($k eq $s->{m}->{item}[$_]);
	}
	return undef;
}
#---------------------------------------------------------------#
sub delete_item{
#---------------------------------------------------------------#

=head2 delete_item

メンテ項目を削除する

=cut

	my $s = shift;
	my @k = @_;
	my $tmp = [];
	my $k;
	for $k (@{$s->{m}->{item}}){
		next	if(grep {$k eq $_} @k);
		push @$tmp,$k;
	}
	$s->{m}->{item} = $tmp;
	return $tmp;
}

#---------------------------------------------------------------#
sub formScript{
#---------------------------------------------------------------#
	my $s = shift;
	my $r = shift;
	my $ent2tab;
	my $editA5 = join(',', map {'"'.$_.'"'} @{$r->{a5}});
	my $editF1 = join(',', map {'"'.$_.'"'} @{$r->{f1}});
	my $TabIndex = join(',', map {'"'.$_.'"'} @{$r->{num}});
	$TabIndex =~ s/\[\d+\]//;
	my $ime;
	for(@{$r->{num}}){
		$ime .= "document.form.$_.style.imeMode = 'inactive';\n";
	}
	for(@{$r->{char}}){
		$ime .= "document.form.$_.style.imeMode = 'active';\n";
	}
	if($s->{m}->{-ent2tab} eq 'on'){
		$ent2tab = <<END;
window.document.onkeydown = nextForm;
var ent = 1;
function nextForm(e){
	e = e || window.event;
	var target = e.target || e.srcElement;
	if((window.event ? event.keyCode : e.which) == 13){
//		alert(document.form.next.value + ent);
		if((document.form.next.value.match(/action/) == 'action')&&
			(ent == 1)){
			ent = 0;
		}else{
			if(target.type != 'textarea'){
				window.event.keyCode = 0x09;
			}
		}
	}
}
END
	}
	my $script = <<end;
<script type="text/javascript">
<!--
$s->{script}
$ent2tab
editA5 = new Array($editA5);
editF1 = new Array($editF1);
TabIndex = new Array($TabIndex);
end
	$script .= <<'end';
function onloadsub(){
	for(i = 0;i < editA5.length;i++){
		var someNodeList = document.getElementsByName(editA5[i]);
		var nodes = $A(someNodeList);
		nodes.each(function(node){
			node.value = addComma(node.value);
		});
	}
	for(i = 0;i < editF1.length;i++){
		var someNodeList = document.getElementsByName(editF1[i]);
		var nodes = $A(someNodeList);
		nodes.each(function(node){
			node.value = edit_F1(node.value);
		});
	}
end
	$script .= $ime;
	$script .= $s->serch_button;
	$script .= <<'end';
}
function addComma(str) {
	var num = new String(str).replace(/,/g, "");
	while(num != (num = num.replace(/^(-?\d+)(\d{3})/, "$1,$2")));
	return num;
}
function edit_F1(str) {
	var num = new String(str).replace(/[\/]/g, "");
	num = num.replace(/^(.*)(\d{2})(\d{2})$/, "$1-$2-$3");
	return num;
}
function delComma(str){
	var num = new String(str).replace(/[,\/]/g, "");
	return num;
}
function submitsub(){
	for(i = 0;i < editA5.length;i++){
		var someNodeList = document.getElementsByName(editA5[i]);
		var nodes = $A(someNodeList);
		nodes.each(function(node){
			node.value = delComma(node.value);
		});
	}
	for(i = 0;i < editF1.length;i++){
		document.getElementsByName(editF1[i])[0].value = delComma(document.getElementsByName(editF1[i])[0].value);
	}
	submit();
}
end
	$script .= $s->serch_button_Script;
	$script .= <<'end';
// -->
</script>
end
	return $script;
}
sub serch_button{
	my $s = shift;
	my $button = '';
	my $name ;
	for(keys %{$s->{subwin}}){
		$name = $s->input_names->{$_};
		$button .= qq{\t\$('_l_$name').innerHTML = }.
			qq{'<input type="button" value="@{[$s->Label($_)]}" }.
			qq{onclick="sub_win(&#39;$name&#39;)" tabindex=-1>';\n};
	}
	return $button;
}
sub sub_list{
	my $s = shift;
	print $s->{in}->header(-type=>"text/html; charset=utf-8"),
		$s->{in}->start_html(-title=>$s->{m}->{title} ." - ".
				$s->{in}->url(),
			-style=>{'src'=>$s->{cons}->{css}.'sne.css'},
			-script=>[{-language=>'JavaScript',
					-src=>$s->{cons}->{js}.'prototype.js'
			}],
			-onLoad=>'focus();');

	$s->{in}->param('n') =~ /^(\D+)(\d+)$/;
	my ($Name,$No) = ($1,$2);
	my $sth = $s->{dbh}->{dbh}->prepare(
		$s->{subwin}->{$s->{m}->{$Name}[$No]}->[0]);
	print $s->{dbh}->{dbh}->errstr;
	$sth->execute($s->{in}->param('p'));
	my $ref;
	print "<table border=1>\n";
	print Tr(th([@{$sth->{'NAME'}}]));
	my $i;
	while($ref = $sth->fetchrow_arrayref()){
		print "<tr>";
		for ($i = 0;$i <= $#{$ref};$i++){
			if($i == 0){
				print qq{
<td><a href=close.cgi onClick="window.opener.document.form.${Name}$No.value='$ref->[$i]';window.opener.document.form.${Name}$No.select();">$ref->[$i]</a></td>};
			}else{	print td($ref->[$i]);
			}
		}
		print "</tr>\n";
	}
	print "</table>";
}
sub serch_button_Script{
	my $s = shift;
	my $Script;
	my ($name,$name2,$n3);
	my $p = "var p = '';\n";
	$p .= <<END;
	var win = 'sublist';
	var opt = 'width=400,height=600,scrollbars=yes,statusbar=yes';
END
	for $n3 (keys %{$s->{subwin}}){
		$name = $s->input_names->{$n3};
		$p .= qq/\tif(name == "$name"){\n\t\tp="&n=$name";\n/;
		for(keys %{$s->{subwin}->{$n3}->[1]}){
			if($_ eq 'in'){
				for(@{$s->{subwin}->{$n3}->[1]->{in}}){
					$name2 = $s->input_names->{$_};
					$p .= qq/\t\tp+="&p="+\$F('$name2');\n/;
				}
			}
			if($_ eq 'win'){
				$p .= qq/\t\tp+= '$s->{subwin}->{$n3}->[1]->{win}';\n/;
			}
			if($_ eq 'opt'){
				$p .= qq/\t\tp+= '$s->{subwin}->{$n3}->[1]->{opt}';\n/;
			}
		}
		$p .= qq/\t}\n/;
	}
	$w .= qq/"end_hash":"end"\n};\n/;
	$script = <<END;
function sub_win(name){
	$p
	window.open('@{[$s->{in}->url()]}?action=sub_list'+p,win,opt);
}
END
	return $script;
}

=head1 rwt (ReportWriterTool module群)

帳票出力用モジュール群

=head2 rwt

rwt用コンストラクタ

変数

 $obj->{in} : CGI.pmのオブジェクト
 $obj->{dbh} : webdb.pmのオブジェクト
 $obj->{dbh}->{dbh} : DBI.pmのオブジェクト
 $obj->{cons} : myconstant.pmのオブジェクト
 $obj->{rwt}->{maxline} : 1頁のＭＡＸ行数(default:39)
 $obj->{rwt}->{lcnt} : 現在印字行数
 $obj->{rwt}->{headPrint} : 見出し印字直後に1になる
 $obj->{rwt}->{-title} : htmlと帳票のタイトル
 $obj->{rwt}->{-p_id} :
 $obj->{rwt}->{sql} : 印刷用データセレクトＳＱＬ文
 $obj->{rwt}->{rskip} : ＝1の時データをリードスキップする
 $obj->{rwt}->{endsw} : ≠0の時eof処理を行う
 $obj->{m}->{item} : 印刷用項目（rwt_initにて$obj->{rwt}->{sql}より取得）
 $obj->{rwt}->{key}[0 ..] : 各レベルのキー項目設定
 $obj->{rwt}->{group} : グループ印字項目とレベル指定
      $obj->{rwt}->{group} = {'科目コード' => 1,
				'科目名' => 1,
				'部門コード' => 0,
				'部門名' => 0};
 $obj->{rwt}->{sum}->{0 ..} : サマリー項目指定
      $obj->{rwt}->{sum}->{0} = {'数量' => 0,
					'金額' =>0};
      $obj->{rwt}->{sum}->{99} = {'金額' => 0};
 $obj->{rwt}->{break_level} : 現在のブレークレベル


=cut

sub rwt{
	my $class = shift;
	my $self = {};
	$self->{'rwt'} = shift;
	$self->{rwt}->{-css} = 'print.css';
	bless $self,$class;
	$self->{'dbh'} = new webdb;
	$self->{'in'} = new CGI;
	$self->{'cons'} = new myconstant;
	$self->{rwt}->{maxline} = 39;
	$self->{rwt}->{lcnt} = 0;
	$self->{rwt}->{page} = 0;
	$self->{rwt}->{headPrint} = 0;
	$self->{rwt}->{RestartPage} = 1;
	$self->{rwt}->{RestartPage_E} = 10000;
	if($self->{in}->param('maxline') =~ /^\d+$/){
		$self->{rwt}->{maxline} = $self->{in}->param('maxline');
	}
	if($self->{in}->param('action') =~ /(nonpage|excel|ftp)/){
		$self->{rwt}->{maxline} = 9999999;
	}
	if($self->{in}->param('action') =~ /(ftp)/){
		open CSV,">/tmp/rwt$$.csv";
		$self->{CVS} = \*CSV;
	}
	return $self;
}
sub rwt_init{
	my $s = shift;
	if($s->{in}->param('action') =~ /excel/){
		print "Content-type: application/vnd.ms-excel\n";
		print "ContentDisposition: filename=output.xls\n\n";
		print '<meta http-equiv="Content-Type" content="text/html;charset=utf-8">',"\n";
	}else{
		$s->prtSetting();
		print header(-type=>"text/html; charset=utf-8"),
		start_html(-title=>"$s->{rwt}->{-title} - $s->{rwt}->{-p_id}",
			-style=>{src=>$s->{cons}->{css}.$s->{rwt}->{-css}},
			#-style=>{'code'=>$style},
			-script=>$s->{cons}->{printSetting},
			-onLoad=>'focus();prtSetting();');
		print $s->{cons}->{printObject};
	}
	$s->{rwt}->{sth} = $s->rwt_init_prepare($s->{rwt}->{sql});
	print $s->{dbh}->utf2euc($s->{dbh}->{dbh}->errstr);
	$s->{rwt}->{sth}->execute();
	print $s->{dbh}->utf2euc($s->{rwt}->{sth}->errstr);
	$s->{m}->{item} = \@{$s->{rwt}->{sth}->{'NAME'}};
#	print "<pre>";
	if($s->{in}->param('action') =~ /(nonpage|excel|ftp)/){
		$s->{rwt}->{maxline} = 9999999;
	}
	return $s;
}
sub prtSetting{
	my $s = shift;
	my @arg = @_;
	if($#arg == -1){
		@arg = (0,5,0,5);
	}
	if($#arg == 3){
		$s->{cons}->{printSetting} =~ s/leftMargin = 0;/leftMargin = $arg[3];/;
		$s->{cons}->{printSetting} =~ s/rightMargin = 0;/rightMargin = $arg[1];/;
		$s->{cons}->{printSetting} =~ s/topMargin = 0;/topMargin = $arg[0];/;
		$s->{cons}->{printSetting} =~ s/bottomMargin = 0;/bottomMargin = $arg[2];/;
	}
}
sub rwt_init_prepare{
	my $s = shift;
	return $s->{dbh}->{dbh}->prepare($s->{rwt}->{sql});
}
sub printout{
	my $s = shift;
	if($s->{rwt}->{page} < $s->{rwt}->{RestartPage}){
		return;
	}
	if($s->{rwt}->{page} > $s->{rwt}->{RestartPage_E}){
		return;
	}
	print @_;
}
sub rwt_start{
	my $s = shift;
	my $level;
	$s->{rwt}->{break_level} = -1;
	while($s->{rwt}->{ref} = $s->rwt_dataget()){
		$s->{rwt}->{line} = [];
		$s->{rwt}->{rskip} = 0;
		$s->{rwt}->{endsw} = 0;
		$s->rwt_tisel($s);
		if($s->{rwt}->{endsw} != 0
		or $s->{rwt}->{page} > $s->{rwt}->{RestartPage_E}){
			$ref = undef;
			last;
		}
		next if($s->{rwt}->{rskip} == 1);
		unless($s->{rwt}->{oref}){
			$s->rwt_data_save();
		}
		$s->break_check($s);
		$s->rwt_dtail($s);
		$s->rwt_dtail_opt($s);
		$s->rwt_print_dt($s);
		$s->rwt_sumry($s);
		$s->rwt_sumcomp($s);
		$s->{rwt}->{headPrint} = 0;
	}
	$s->{rwt}->{break_level} = 99;
#	$s->break_check(99);
	$s->break_routine(99);
	$s->bottom_print();
#	print "</pre>";
	return $s;
}
sub bottom_print{
	my $s = shift;
	$s->printout( "</table>");
	$s->printout( $s->{rwt}->{BOTTOM}) if($s->{rwt}->{BOTTOM});
}

=head2 rwt_dataget １件リード

データ１件リードしハッシュのリファレンスを返す

=cut

sub rwt_dataget{
	my $s = shift;
	return $s->{rwt}->{sth}->fetchrow_hashref();
}
sub rwt_data_save{
	my $s = shift;
	for(@{$s->{rwt}->{sth}->{'NAME'}}){
		$s->{rwt}->{oref}->{$_} = $s->{rwt}->{ref}->{$_};
	}
}

=head2 rwt_tisel １件リード後のサブルーチン

データ読み飛ばしや終了の判断を行う。
データ読み飛ばしたい時は$obj->{rwt}->{rskip}に1をセット。
終了したい時は$obj->{rwt}->{endsw}に1をセット。

=cut

sub rwt_tisel{
	my $s = shift;
}
sub break_check{
	my $s = shift;
	my $level = shift;
	my $i = 0;
	$s->{rwt}->{break_level} = -1;
	for ($i = $s->key_count;$i>=0;$i--){
		if($s->{rwt}->{ref}->{$s->{rwt}->{key}[$i]} ne
				$s->{rwt}->{okey}[$i]){
			$s->{rwt}->{break_level} = $i;
			$s->break_routine($i);
			last;
		}
	}
	for ($i = $s->key_count;$i>=0;$i--){
		$s->{rwt}->{okey}[$i] =
			$s->{rwt}->{ref}->{$s->{rwt}->{key}[$i]};
	}
	$s->rwt_data_save();
	if($level != 99){
		if($s->{rwt}->{lcnt} > $s->{rwt}->{maxline} or
			$s->{rwt}->{lcnt} == 0){
			$s->rwt_head_print();
		}
	}
}
sub key_count{
	my $s = shift;
	my $count = 0;
	for(@{$s->{rwt}->{key}}){$count++;}
	return --$count;
}
sub break_routine{
	my $s = shift;
	my $i = shift;
	my $j;
	my $tmp ;
	if($s->{rwt}->{page} != 0){
		for $j (0 .. $i){
			$tmp = "level$j";
			$s->rwt_print_levelset($j);
			eval{
				$s->$tmp($i);
			};
			$s->rwt_print_level($j);
		}
	}
}

=head2 level0,level1 .. level99 キー項目ブレーク処理

キー項目($obj->{rwt}->{Key}[0 ..])に設定した項目がブレーク
した時に処理するルーチン

level99はeof後処理（総合計印字用）

=cut

sub level0{ my $s = shift; my $break = shift; }
sub level1{ my $s = shift; my $break = shift; }
sub level2{ my $s = shift; my $break = shift; }
sub level3{ my $s = shift; my $break = shift; }
sub level4{ my $s = shift; my $break = shift; }
sub level5{ my $s = shift; my $break = shift; }
sub level99{ my $s = shift; my $break = shift; }

=head2 rwt_dtail 明細印字前ルーチン

明細を印字前に処理されるルーチン
独自に明細を編集したい時には'rwt_dtail'をオーバーライドする。

$self->{rwt}->{line}[0..] :明細内容をこの配列にセット

=cut

sub rwt_dtail_opt{
	my $s = shift;
}
sub rwt_dtail_bef{
	my $s = shift;
}
sub rwt_dtail{
	my $s = shift;
	$s->rwt_dtail_bef();
	my $i = 0;
	$s->{rwt}->{line}[0] = "<tr>";
	for(@{$s->{m}->{item}}){
		if($s->{rwt}->{edit}->{$_} =~ /^[0-9a-f][0-9a-f]$/i){
			$s->{rwt}->{line}[0] .= td({-align=>right,
						$s->{rwt}->{opt}->{$_}},
							$s->group_inji($_));
		}else{	$s->{rwt}->{line}[0] .= td(
						{$s->{rwt}->{opt}->{$_}},
							$s->group_inji($_));
		}
	}
	$s->{rwt}->{line}[0] .= "</tr>\n";
	if($s->{in}->param('action') =~ /ftp/){
#		$s->{rwt}->{line}[0] = '';
		my @array;
		for(@{$s->{m}->{item}}){
#			$s->{rwt}->{line}[0] .= $s->{rwt}->{ref}->{$_}.',';
#			$s->{rwt}->{line}[0] .=
#				$s->{dbh}->euc2sj($s->{rwt}->{ref}->{$_}).',';
			push @array,$s->{rwt}->{ref}->{$_};
		}
#		$s->{rwt}->{line}[0] =~ s/,$//;
		$s->{rwt}->{line}[0] = 
			join ',',map {(s/"/""/g or /[\r\n,]/) ?
					qq("$_") : $_} @array;
	}
}
sub group_inji{
	my $s = shift;
	my $tmp = shift;
	my $data = $s->{rwt}->{ref}->{$tmp};
	my $edt = $s->{rwt}->{edit}->{$_};
	my $tuuka ='';
	if($edt =~ /^(E)(.)$/i){
		$edt = 'a'.$2;
		$tuuka = $s->{tuuka};
	}
	if($edt eq 'a5'){
		$data = $tuuka . $s->{dbh}->place3($data);
	}elsif($edt eq 'a7'){
		if($data == 0){$data = '&nbsp';
		}else{	$data = $tuuka . $s->{dbh}->place3($data);
		}
	}elsif($s->{rwt}->{edit}->{$_} eq 'f8'){
		$data = sprintf("%4d:%02d",int($data/60),$data%60);
	}
	return $data if($s->{rwt}->{headPrint} == 1);
	return $data unless($s->{rwt}->{group}->{$tmp} =~ /^\d+$/);
	return $data if($s->{rwt}->{group}->{$tmp} <= $s->{rwt}->{break_level});
	return undef;
}

=head2 rwt_sumry 明細印字後処理ルーチン

明細を印字後に処理されるルーチン
独自に集計処理をしたい時には'rwt_sumry'をオーバーライドする。

この後に$self->{rwt}->{ref}->{'サマリー指定した項目'}を集計

=cut

sub rwt_sumry{
	my $s = shift;
}
sub rwt_sumcomp{
	my $s = shift;
	my ($i,$j);
	for $i (keys %{$s->{rwt}->{sum}}){
		for $j (keys %{$s->{rwt}->{sum}->{$i}}){
			if($s->{rwt}->{sum}->{$i}->{$j} =~ /^[+-]*\d+\.?\d*$/){
				$s->{rwt}->{sum}->{$i}->{$j} +=
						$s->{rwt}->{ref}->{$j};
			}
		}
	}
}
sub rwt_print_dt{
	my $s = shift;
	for(@{$s->{rwt}->{line}}){
		if($s->{rwt}->{pagechk} == 1){
			if($s->{rwt}->{lcnt} > $s->{rwt}->{maxline} or
				$s->{rwt}->{lcnt} == 0){
				$s->rwt_head_print();
			}
		}
		if($s->{in}->param('action') =~ /excel/){
			#print $s->{dbh}->euc2sj($_),"\n";
			$s->printout( $_,"\n");
		}elsif($s->{in}->param('action') =~ /ftp/){
			print CSV $s->{dbh}->euc2sj($_),"\n";
#			print CSV $_,"\n";
		}else{	$s->printout($_);
		}
		$s->{rwt}->{lcnt}++;
	}
}
sub rwt_feed{
	my $s = shift;
	$s->{rwt}->{lcnt} = $s->{rwt}->{maxline} + 1;
}
sub rwt_head_print{
	my $s = shift;
	my $i;
	$s->{rwt}->{page}++;
	my $columnopt = 'width=100%';
	my $colwidth; 
	if($s->{rwt}->{-columnopt} eq 'compact'){
			$columnopt = '';
	}elsif($s->{rwt}->{-columnopt} ne ''){
			$columnopt = $s->{rwt}->{-columnopt};
	}
	if($s->{rwt}->{-column} =~ /^\d+$/ and $s->{rwt}->{-column} > 1){
		$colwidth = sprintf("width=%d%%",int(100/$s->{rwt}->{-column}));
		$s->{rwt}->{lcnt} = 0;
		if($s->{rwt}->{page} == 1){
			$s->printout(qq{<p><table $columnopt><tr><td colspan=$s->{rwt}->{-column}>});
		}elsif($s->{rwt}->{page} % $s->{rwt}->{-column} != 1){
			$s->printout(qq{</table></td><td $colwidth style="vertical-align:top;">});
		}else{	$s->printout('</table></td></tr></table>');
			$s->page_break();
			$s->printout(qq{<table $columnopt><tr><td colspan=$s->{rwt}->{-column}>});
		}
		$s->rwt_header($s);
		$i = 0;
		for(@{$s->{rwt}->{hdline}}){
			if($i == 0){
			 if($s->{rwt}->{page} % $s->{rwt}->{-column} == 1){
				$s->printout("$_</td></tr><tr>");
				$s->printout(qq{<td $colwidth style="vertical-align:top;">});
			 }
			}else{	$s->printout($_);}
			$s->{rwt}->{lcnt}++;
			$i++;
		}
		$s->{rwt}->{headPrint} = 1;
		return;
	}
	if($s->{in}->param('action') =~ /ftp/){
		$s->{rwt}->{lcnt} = 0;
		$s->rwt_header($s);
		print CSV $s->{dbh}->euc2sj($s->{rwt}->{hdline}[1]);
		$s->{rwt}->{headPrint} = 1;
		return;
	}
	if($s->{in}->param('action') =~ /excel/){
		$s->{rwt}->{lcnt} = 0;
		$s->rwt_header($s);
		for(@{$s->{rwt}->{hdline}}){
			#print $s->{dbh}->euc2sj($_),"\n";
			$s->printout($_,"\n");
			$s->{rwt}->{lcnt}++;
		}
		$s->{rwt}->{headPrint} = 1;
		return;
	}
	if($s->{rwt}->{page} != $s->{rwt}->{RestartPage}){
		$s->{rwt}->{page}--;
		$s->bottom_print();
		$s->{rwt}->{page}++;
		$s->page_break();
	}else{	$s->printout('<p>');
	}
	$s->{rwt}->{lcnt} = 0;
	$s->rwt_header($s);
	for(@{$s->{rwt}->{hdline}}){
		$s->printout( $_);
		$s->{rwt}->{lcnt}++;
	}
	$s->{rwt}->{headPrint} = 1;
}
sub page_break{
	my $s = shift;
	$s->printout('<div style="page-break-before:always;"><br style="height:0; line-height:0"></div><p>');
}
sub rwt_print_levelset{
	my $s = shift;
	my $i = shift;
	my $tmp = "level$i";
	my $j;
	my $edt;
	my $tuuka ='';
	if(exists $s->{rwt}->{sum}->{$i}){
		$s->{rwt}->{$tmp}[0] = "<tr>";
		for(@{$s->{m}->{item}}){
			$edt = $s->{rwt}->{edit}->{$_};
			if($edt =~ /^(E)(.)$/i){
				$edt = 'a'.$2;
				$tuuka = $s->{tuuka};
			}else{
				$tuuka = '';
			}
			if($s->{rwt}->{edit2}->{$_} ne '' and
				$s->{rwt}->{sum}->{$i}->{$_} ne ''){
				$s->{rwt}->{sum}->{$i}->{$_} =
				sprintf(
					$s->{rwt}->{edit2}->{$_},
					$s->{rwt}->{sum}->{$i}->{$_});
			}
			if($edt eq 'f8'){
				$s->{rwt}->{$tmp}[0] .= td({-align=>right,
						$s->{rwt}->{opt}->{$_}},
					sprintf("%4d:%02d",
					int($s->{rwt}->{sum}->{$i}->{$_}/60),
					$s->{rwt}->{sum}->{$i}->{$_}%60));
			}elsif($edt eq 'a7'){
				if($s->{rwt}->{sum}->{$i}->{$_} == 0){
				$s->{rwt}->{$tmp}[0] .= td({-align=>right,
						$s->{rwt}->{opt}->{$_}},'');
				}else{
				$s->{rwt}->{$tmp}[0] .= td({-align=>right,
						$s->{rwt}->{opt}->{$_}},
						$tuuka .
						$s->{dbh}->place3(
						$s->{rwt}->{sum}->{$i}->{$_}));
				}
			}elsif($edt =~ /^[0-9a-f][0-9a-f]$/i){
				$s->{rwt}->{$tmp}[0] .= td({-align=>right,
						$s->{rwt}->{opt}->{$_}},
						$tuuka .
						$s->{dbh}->place3(
						$s->{rwt}->{sum}->{$i}->{$_}));
			}else{	$s->{rwt}->{$tmp}[0] .= td(
						{$s->{rwt}->{opt}->{$_}},
						$s->{rwt}->{sum}->{$i}->{$_});
			}
		}
		$s->{rwt}->{$tmp}[0] .= "</tr>\n";
	}
}
sub rwt_print_level{
	my $s = shift;
	my $i = shift;
	my $tmp = "level$i";
	for(@{$s->{rwt}->{$tmp}}){
		if($s->{rwt}->{lcnt} > $s->{rwt}->{maxline} or
			$s->{rwt}->{lcnt} == 0){
			$s->rwt_head_print();
		}
		#if($s->{in}->param('action') =~ /(excel|ftp)/){
		if($s->{in}->param('action') =~ /(ftp)/){
			$_ = $s->{dbh}->euc2sj($_);
		}
		$s->printout( $_,"\n");
		$s->{rwt}->{lcnt}++;
	}
	if(exists $s->{rwt}->{sum}->{$i}){
		for $j (keys %{$s->{rwt}->{sum}->{$i}}){
			if($s->{rwt}->{sum}->{$i}->{$j} =~ /^[+-]*\d+(\.\d*)?$/){
				$s->{rwt}->{sum}->{$i}->{$j} = 0;
			}
		}
	}
	for(@{$s->{rwt}->{$tmp}}){
		pop @{$s->{rwt}->{$tmp}};
	}
}
sub rwt_header{
	my $s = shift;
	my $i = 0;
	my $page;
	if($s->{rwt}->{-column} =~ /^\d+$/ and $s->{rwt}->{-column} > 1){
		$page = int($s->{rwt}->{page} / $s->{rwt}->{-column})+1;
	}else{	$page = $s->{rwt}->{page};}
	$s->{rwt}->{hdline}[$i++] =
		sprintf("<pre>%60s%40s Page.%4d</pre>",
			"$s->{rwt}->{-title1}" .
			"<font size=+2><b>$s->{rwt}->{-title}</b></font>",
			"$s->{rwt}->{-title2}" .
			webdb::date_format(),
			$page);
	if($s->{rwt}->{-newstyle} eq 'ON'){
		$s->{rwt}->{hdline}[0] =
			table({-width=>'100%'},Tr(
			td({-width=>'30%',-align=>'left'},
				["$s->{rwt}->{-title1}"]),
			td({-width=>'40%',-align=>'center'},[
			"<font size=+1><b>$s->{rwt}->{-title}</b></font>"]),
			td({-width=>'30%',align=>'right'},[
			"$s->{rwt}->{-title2}" .
			webdb::date_format(). " Page. ".
			$page])));
	}
	$s->{rwt}->{hdline}[$i++] = ($s->{rwt}->{-table}||"<table border=1>") .
		Tr($s->headlabel())."\n";
	if($s->{in}->param('action') =~ /ftp/){
		$s->{rwt}->{hdline}[1] = $s->headlabel()."\n";
	}
	$s->rwt_head($s);
}

=head2 rwt_head 見出し印字前ルーチン

見出しを印字前に処理されるルーチン帳票固有の
見出しを印字したい時には'rwt_head'をオーバーライドする。

$self->{rwt}->{hdline}[0..] :見出し内容をこの配列にセット

=cut

sub rwt_head{
	my $s = shift;
}
sub headlabel{
	my $s = shift;
	my $label = '';
	for(@{$s->{m}->{item}}){
		if($s->{in}->param('action') =~ /ftp/){
			$label .= $s->Label($_).",";
		}else{	$label .= th({$s->{rwt}->{opt}->{$_}},[$s->Label($_)]);
		}
	}
	$label =~ s/,$//;
	return $label;
}
sub labels{
	my $s = shift;
	my @array = @_;
	for(@array){
		$_ = $s->Label($_);
	}
	return @array;
}
sub Label{
	my $s = shift;
	my $tmp = shift;
	return ($s->{m}->{label}->{$tmp}) ? $s->{m}->{label}->{$tmp} : $tmp ;
}
sub final{
	my $s = shift;
	if($s->{in}->param('action') =~ /(ftp)/){
		close CSV;
		print "ftp start<br>\n";
		use Net::FTP;
		my ($ftp);
		print "connect $s->{rwt}->{-ftphost}<br>\n";
		$ftp = Net::FTP->new($s->{rwt}->{-ftphost}||'localhost'
				,Debug=>0);
		if(!$ftp){
			print "Connect Error $s->{rwt}->{-ftphost}";
		}else{
			$ftp->login($s->{rwt}->{-ftpusr}||'anonimus',
				$s->{rwt}->{-ftppass}||'password')
					or print "login error $!<br>\n";
			$ftp->put("/tmp/rwt$$.csv",
				$s->{rwt}->{-ftpout}||"/tmp/ftp.data")
					or print"ERR put $!<br>\n";
			$ftp->quit;
			print $s->{dbh}->sj2euc($s->{rwt}->{-ftpout}),
				"に転送しました<br>\n";
		}
		unlink ("/tmp/rwt$$.csv");
		print $s->{dbh}->menu();
	}
	$s->final_opt();
	$s->{dbh}->{dbh}->disconnect;
}
sub final_opt{
	my $s = shift;
	if($s->{in}->param('action') =~ /excel/
	or $s->{in}->param('action') =~ /JSON/){
	}else{
		if($s->{rwt}->{page} eq '0'){
			print qq{<h1 style="line-height: 200%;">該当データなし</h1>};
		}
		print "\n</body></html>\n";
	}
	if($s->{in}->param('action') =~ /excel/){
		if($s->{rwt}->{page} eq '0'){
			print table(Tr(td("該当データなし")));
		}
	}
}
1;

=head1 AUTHOR INFORMATION

 ;######################################################################
 ;#
 ;# mmt.pm: Master Maintenance Tool perl module.
 ;#
 ;# Copyright (c) 2004 Masashi Hori <hori@japannet.co.jp>
 ;# JapanNet. All Rights Reserved.
 ;#
 ;#
 ;######################################################################

=cut
