#!/usr/bin/perl

#┌─────────────────────────────────
#│ WEB CALEN : calen.cgi - 2015/05/02
#│ copyright (c) KentWeb, 1997-2015
#│ http://www.kent-web.com/
#└─────────────────────────────────

# モジュール宣言
use strict;
use CGI::Carp qw(fatalsToBrowser);
use lib "./lib";
use CGI::Minimal;
use File::ReadBackwards;

# 設定ファイル認識
require "./init.cgi";
my %cf = set_init();

# データ受理
CGI::Minimal::max_read_size($cf{maxdata});
my $cgi = CGI::Minimal->new;
error('容量オーバー') if ($cgi->truncated);
my %in = parse_form($cgi);

# 処理分岐
if ($in{mode} eq "note") { note_page(); }
main_page();

#-----------------------------------------------------------
#  メイン画面
#-----------------------------------------------------------
sub main_page {
	# 年月モード
	my $date_mode;
	
	# 現在の年月
	my ($mday,$mon,$year) = (localtime())[3 .. 5];
	$mon = sprintf("%02d",++$mon);
	$year += 1900;
	
	# datepicker
	if ($in{warp} =~ m|^(\d{4})/(\d{2})|) {
		$date_mode++;
		$in{y} = $1;
		$in{m} = $2;
	
	# カレンダ指定
	} elsif ($in{read} =~ /^(\d{4})(\d{2})(\d{2})$/) {
		$date_mode++;
		$in{y} = $1;
		$in{m} = $2;
		$in{d} = $3;
		
	} else {
		# 年月引数
		$in{y} =~ s/\D//g;
		$in{m} =~ s/\D//g;
		
		if ($in{y} < 1970 or $in{m} < 1 or $in{m} > 12) {
			$in{y} = $year;
			$in{m} = $mon;
		} else {
			$in{m} = sprintf("%02d",$in{m});
			$date_mode++;
		}
	}
	
	# データ読み込み
	my ($ttl,$log,$ym,$pgs) =
			$in{mode} eq 'news' ? read_news() :
			$in{y} && $in{m} && $in{d} ? read_data($in{y},$in{m},$in{d}) :
			$date_mode ? read_data($in{y},$in{m}) :
			read_news();
			
	# ペイジャー
	my $pager = $pgs ? make_pager($pgs,$in{pg}) : '';
	
	# 前月・翌月を求める
	my ($bk_y,$bk_m,$nx_y,$nx_m) = get_ym($in{y},$in{m});
	
	# ログ読み込み
	my %ico;
	my $data = sprintf("%04d%02d",$in{y},$in{m});
	open(IN,"$cf{datadir}/$data.txt");
	while(<IN>) {
		my ($day,$sub,$msg,$ico,$wico,$im1,$im2,$im3) = split(/<>/);
		
		if ($msg) { $ico{$day} = $wico; }
	}
	close(IN);
	
	# カレンダ生成
	my $calen = calen_tbl($year,$mon,$mday,$in{y},$in{m},\%ico);
	
	# テンプレート読込
	open(IN,"$cf{tmpldir}/calen.html") or error("open err: calen.html");
	my $tmpl = join('',<IN>);
	close(IN);
	
	# 文字置き換え
	$tmpl =~ s/!ttl-name!/$ttl/g;
	$tmpl =~ s/!cgi_title!/$cf{cgi_title}/g;
	$tmpl =~ s/!([a-z]+_cgi)!/$cf{$1}/g;
	$tmpl =~ s/!homepage!/$cf{homepage}/g;
	$tmpl =~ s/!calendar!/$calen/;
	$tmpl =~ s/!year!/$in{y}/g;
	$tmpl =~ s/!month!/$in{m}/g;
	$tmpl =~ s/!cmnurl!/$cf{cmnurl}/g;
	$tmpl =~ s/!pager!/$pager/g;
	$tmpl =~ s|!icon:(\w+\.\w+)!|<img src="$cf{cmnurl}/$1" class="icon" alt="" />|g;
	$tmpl =~ s|!back_btn!|<a href="$cf{calen_cgi}?y=$bk_y&amp;m=$bk_m"><img src="$cf{cmnurl}/back.png" alt="前月" class="icon" /></a>|;
	$tmpl =~ s|!this_btn!|<a href="$cf{calen_cgi}?y=$year&amp;m=$mon"><img src="$cf{cmnurl}/this.png" alt="今月" class="icon" /></a>|;
	$tmpl =~ s|!next_btn!|<a href="$cf{calen_cgi}?y=$nx_y&amp;m=$nx_m"><img src="$cf{cmnurl}/next.png" alt="翌月" class="icon" /></a>|;
	
	# テンプレート分割
	my ($head,$loop,$foot) = $tmpl =~ /(.+)<!-- loop_begin -->(.+)<!-- loop_end -->(.+)/s
			? ($1,$2,$3)
			: error("テンプレート不正");
	
	# ヘッダ
	print "Content-type: text/html; charset=utf-8\n\n";
	print $head;
	
	my $i = 0;
	foreach (@{$log}) {
		my ($day,$sub,$msg,$ico,$wico,$img1,$img2,$img3) = split(/<>/);
		
		$i++;
		my ($y,$m) = $$ym{$i} =~ /^(\d{4})(\d{2})$/ && ($1,$2);
		
		# 日付フォーマット
		my $week = holiday::get_week($y,$m,$day);
		my $date = "$y年$m月$day日（$cf{week}[$week]）";
		
		# アイコン
		$msg  = qq|<div class="f-l"><img src="$cf{cmnurl}/$ico" alt="" /></div>$msg<br class="f-c" />| if ($ico);
		
		# アップ画像
		my ($image,$n);
		foreach my $img ($img1,$img2,$img3) {
			$n++;
			my ($ex,$w,$h) = split(/:/,$img);
			next if (!$ex);
			$image .= image($n,"$y$m$day",$ex,$w,$h);
		}
		
		my $tmp = $loop;
		$tmp =~ s|!icon!|<img src="$cf{cmnurl}/$cf{w_icon}[$wico]" class="icon" alt="" />|g;
		$tmp =~ s/!subject!/$sub/g;
		$tmp =~ s/!date!/$date/g;
		$tmp =~ s/!comment!/chg_tag($msg)/eg;
		$tmp =~ s|<!-- image -->|<p>$image</p>|g if ($image);
		print $tmp;
	}
	
	# フッタ
	footer($foot);
}

#-----------------------------------------------------------
#  カレンダ表示
#-----------------------------------------------------------
sub calen_tbl {
	my ($year,$mon,$mday,$y,$m,$ico) = @_;
	$in{y} = $y;
	$in{m} = $m;
	my $log = sprintf("%04d%02d",$in{y},$in{m});
	
	# テンプレート読込
	open(IN,"$cf{tmpldir}/calendar.html") or error("open err: calendar.html");
	my $tmpl = join('',<IN>);
	close(IN);
	
	my ($head,$loop,$foot) = $tmpl =~ /(.+)<!-- loop_begin -->(.+)<!-- loop_end -->(.+)/s
			? ($1,$2,$3)
			: error('テンプレート不正');
	
	# 祝日ライブラリ
	require $cf{holiday_pl};
	
	my $cal = $head;
	
	# 1日の曜日を求める
	my $week = holiday::get_week($in{y},$in{m},1);
	
	# 末日を求める
	my $last = holiday::last_day($in{y},$in{m});
	
	# 祝日を認識
	my %holi = holiday::holi_mon($in{y},$in{m});
	
	my ($day,$end);
	foreach my $k (1 .. 6) {
		# 週のテンプレート情報
		my $tmp = $loop;
		
		# 末日のフラグが立った場合はループを終了
		last if ($end);
		
		# 日から土まで7日分をループ
		foreach my $i (0 .. 6) {
			# 第１週で初日の週より小のとき、又は終了フラグが立ったときは「空き枠」
			if (($k == 1 && $i < $week) || $end) {
				$tmp =~ s/!$i!/&nbsp;/;
			
			# 実枠あり
			} else {
				# 日を数える
				$day++;
				
				# 本日のときは背景色を変える
				if ($in{y} == $year && $in{m} == $mon && $day == $mday) {
					$tmp =~ s/<td>!$i!/<td style="background:$cf{week_col}[8]">!$i!/;
				}
				
				# 枠処理
				my $d = sprintf("%02d",$day);
				my $cday;
				if (defined($holi{$d})) {
					$cday = qq|<span style="color:$cf{week_col}[7]" title="$holi{$d}">$day</span>|;
				} else {
					$cday = qq|<span style="color:$cf{week_col}[$i]">$day</span>|;
				}
				if (defined($$ico{$d})) {
					$cday .= qq|<br /><a href="$cf{calen_cgi}?read=$log$d"><img src="$cf{cmnurl}/$cf{w_icon}[$$ico{$d}]" alt="" /></a>|;
				}
				$tmp =~ s/!$i!/$cday/;
			}
			
			# 末日に達した場合フラグを立てる
			if ($day >= $last) { $end = 1; }
		}
		$cal .= $tmp;
	}
	
	# フッタ
	$cal .= $foot;
	
	return $cal;
}

#-----------------------------------------------------------
#  特定記事読み込み
#-----------------------------------------------------------
sub read_data {
	my ($y,$m,$d) = @_;
	
	# ページ数定義
	my $pg = $in{pg} || 0;
	
	# 月次データ読み込み
	my ($i,$n,@log,%ym);
	my $bw = File::ReadBackwards->new("$cf{datadir}/$y$m.txt")
						or return("$y年$m月 一覧",undef,undef,undef);
	while( defined( my $line = $bw->readline ) ) {
		my ($day,$sub,$msg,undef,undef,undef,undef,undef) = split(/<>/,$line);
		
		# 日指定のとき
		if ($d) {
			if ($day == $d) {
				$i++;
				$ym{$i} = "$y$m";
				push(@log,$line);
				last;
			}
			
		# 一括表示
		} else {
			if ($msg ne '') {
				$i++;
				next if ($i < $pg + 1);
				next if ($i > $pg + $cf{max_page});
				
				$n++;
				$ym{$n} = "$y$m";
				push(@log,$line);
			}
		}
	}
	
	my $ttl = $d ? "$y年$m月$d日 記事" : "$y年$m月 一覧";
	return ($ttl,\@log,\%ym,$i);
}

#-----------------------------------------------------------
#  新着記事読み込み
#-----------------------------------------------------------
sub read_news {
	# 月次ファイル読み取り
	my @tmp;
	opendir(DIR,"$cf{datadir}");
	while( my $dir = readdir(DIR) ) {
		next if ($dir !~ /^(\d{6})\.txt$/);
		
		push(@tmp,$1);
	}
	closedir(DIR);
	
	# データ順次読み込み
	my ($i,$flg,@log,%ym);
	for my $log ( sort{ $b <=> $a } @tmp ) {
		my $bw = File::ReadBackwards->new("$cf{datadir}/$log.txt") or next;
		while( defined( my $line = $bw->readline ) ) {
			my ($day,$sub,$msg,undef,undef,undef,undef,undef) = split(/<>/,$line);
			next if ($msg eq '');
			
			$i++;
			$ym{$i} = $log;
			push(@log,$line);
			
			# 最大記事
			if ($i >= $cf{new_data}) {
				$flg++;
				last;
			}
		}
		last if ($flg);
	}
	
	return('新着記事',\@log,\%ym);
}

#-----------------------------------------------------------
#  前後の年月を求める
#-----------------------------------------------------------
sub get_ym {
	my ($y,$m) = @_;
	
	# 前月
	my ($b_y,$b_m);
	if ($m == 1) {
		$b_y = $y - 1;
		$b_m = 12;
	} else {
		$b_y = $y;
		$b_m = sprintf("%02d",$m-1);
	}
	
	# 翌月
	my ($n_y,$n_m);
	if ($m == 12) {
		$n_y = $y + 1;
		$n_m = '01';
	} else {
		$n_y = $y;
		$n_m = sprintf("%02d",$m+1);
	}
	return ($b_y,$b_m,$n_y,$n_m);
}

#-----------------------------------------------------------
#  利用方法
#-----------------------------------------------------------
sub note_page {
	open(IN,"$cf{tmpldir}/note.html") or error("open err: note.html");
	my $tmpl = join('',<IN>);
	close(IN);
	
	# 文字置き換え
	$tmpl =~ s/!cgi_title!/$cf{cgi_title}/g;
	$tmpl =~ s/!([a-z]+_cgi)!/$cf{$1}/g;
	$tmpl =~ s/!cmnurl!/$cf{cmnurl}/g;
	$tmpl =~ s|!icon:(\w+\.\w+)!|<img src="$cf{cmnurl}/$1" class="icon" alt="" />|g;
	
	print "Content-type: text/html; charset=utf-8\n\n";
	print $tmpl;
	exit;
}

#-----------------------------------------------------------
#  フッター
#-----------------------------------------------------------
sub footer {
	my $foot = shift;
	
	# 著作権表記（削除・改変禁止）
	my $copy = <<EOM;
<p style="margin-top:2.5em;text-align:center;font-family:Verdana,Helvetica,Arial;font-size:10px;">
	- <a href="http://www.kent-web.com/" target="_top">WebCalen</a> -
</p>
EOM

	if ($foot =~ /(.+)(<\/body[^>]*>.*)/si) {
		print "$1$copy$2\n";
	} else {
		print "$foot$copy\n";
		print "</body></html>\n";
	}
	exit;
}

#-----------------------------------------------------------
#  画像表示
#-----------------------------------------------------------
sub image {
	my ($i,$no,$ex,$w,$h) = @_;
	
	my $image;
	if (-f "$cf{upldir}/$no-s-$i$ex") {
		$image = qq|<img src="$cf{uplurl}/$no-s-$i$ex" class="img" alt="" />|;
	} else {
		($w,$h) = resize($w,$h);
		$image = qq|<img src="$cf{uplurl}/$no-$i$ex" width="$w" height="$h" class="img" alt="" />|;
	}
	return qq|<a href="$cf{uplurl}/$no-$i$ex" target="_blank">$image</a>\n|;
}

#-----------------------------------------------------------
#  タグ復元
#-----------------------------------------------------------
sub chg_tag {
	my $msg = shift;
	
	$msg =~ s/&amp;/&/g;
	$msg =~ s/&lt;/</g;
	$msg =~ s/&gt;/>/g;
	$msg =~ s/&quot;/"/g;
	$msg =~ s/&#39;/'/g;
	
	return $msg;
}

#-----------------------------------------------------------
#  ページ送り作成
#-----------------------------------------------------------
sub make_pager {
	my ($i,$pg) = @_;
	
	# 引数
	my $param = $in{y} && $in{m} ? "&amp;y=$in{y}&amp;m=$in{m}" : '';
	
	# ページ繰越数定義
	my $next = $pg + $cf{max_page};
	my $back = $pg - $cf{max_page};
	
	# ページ繰越ボタン作成
	my @pg;
	if ($back >= 0 || $next < $i) {
		my $flg;
		my ($w,$x,$y,$z) = (0,1,0,$i);
		while ($z > 0) {
			if ($pg == $y) {
				$flg++;
				push(@pg,qq!<li><span>$x</span></li>\n!);
			} else {
				push(@pg,qq!<li><a href="$cf{bbs_cgi}?pg=$y$param">$x</a></li>\n!);
			}
			$x++;
			$y += $cf{max_page};
			$z -= $cf{max_page};
			
			if ($flg) { $w++; }
			last if ($w >= 5 && @pg >= 10);
		}
	}
	while( @pg >= 11 ) { shift(@pg); }
	my $ret = join('', @pg);
	if ($back >= 0) {
		$ret = qq!<li><a href="$cf{calen_cgi}?pg=$back$param">prev</a></li>\n! . $ret;
	}
	if ($next < $i) {
		$ret .= qq!<li><a href="$cf{calen_cgi}?pg=$next$param">next</a></li>\n!;
	}
	
	# 結果を返す
	return $ret ? qq|<ul class="pager">\n$ret</ul>| : '';
}

