#!/usr/bin/perl
#------------------------------------------------------------------------------
# $Id:$
#------------------------------------------------------------------------------
# Report batch setting CGI
#
# Copyright (c) BAYBITS LLC. All rights reserved.
#------------------------------------------------------------------------------

use strict;
use utf8;
use HTTP::Request::Common qw(POST);
use XML::DOM;
use URI::Escape;
use CGI;
use HTML::Template;
use TF::XMLUtils;
use TF::SingleLock;
use TF::CommonUtils;
use Encode;

binmode STDOUT, ":utf8";	# 標準出力はUTF8

#
# global
#
my $HOSTNAME      = $ENV{'HTTP_HOST'} || '';
my $BRAND         = $ENV{'TF_BRANDNAME'} || '';
my $USERID        = $ENV{'REMOTE_USER'} || '';
my $PASSWD        = $ENV{'TF_USERPLAINPASSWORD'} || '';
my $LOCATION      = $ENV{'TF_LOCATION'} || '';
my $PATH_INFO     = $ENV{'PATH_INFO'} || '';
my $USERTYPE      = $ENV{'TF_USERTYPE'} || 'normal';
my $LANGPARAM     = TF::CommonUtils::getLangPriority();

my $SETTINGS_DIR  = $ENV{'TF_CONFIG_ROOT'}."/report" || '/usr/local/teamfile/www/conf/conf.d/report';
my $LOCATION_NAME = $LOCATION;
$LOCATION_NAME    =~ s/\///g;
my $LOCK_FILE     = $SETTINGS_DIR . "/.$LOCATION_NAME.reportsettings.lock";
my $pagetitle     = $ENV{'TF_FOLDER_REPORTSETTINGS'} || '';
my $PAGETITLE     = TF::CommonUtils::decodeUTF8($pagetitle);
my $PAGEIMG       = $ENV{'TF_FOLDER_REPORTSETTINGS_IMG'} || '';
my $SETTINGS_FILE = $SETTINGS_DIR . "/" . "$LOCATION_NAME" . '.set.xml';
my $SETTINGS_FILE_OLD = $SETTINGS_DIR . "/" . "$HOSTNAME.$LOCATION_NAME" . '.set.xml';
my $SETTINGS_FILE_BAK = $SETTINGS_FILE . '.bak';

my $TEMPLATE_FILE = './tmpl/reportsettings.tmpl.' . $LANGPARAM;
my $BACKURI       = $LOCATION . "/.cgi-bin/reportsettings";

my $ERRORTABLE_ja = {
					CGIError => "CGIエラーです",
					templateError => "テンプレートオブジェクトが生成できません",
					readTemplateError => "テンプレートファイルの読み込みに失敗しました",
					serverBusy => "サーバがビジーです。しばらく経ってからやり直してください",
					paramError => "正常な値を入力してください",
					nothing => "入力していない箇所があります",
					nodays => "日数に０は指定できません",
				};

my $ERRORTABLE_en = {
					CGIError => "CGI error found.",
					templateError => "Can not create template object.",
					readTemplateError => "Failed to read template file.",
					serverBusy => "The server is busy. Please retry this operation after a while.",
					paramError => "Please specify normal value.",
					nothing => "Please input all parameter.",
					nodays => "Can not input 0 to days.",
				};

my $ERRORTABLE = ($LANGPARAM eq 'ja') ? $ERRORTABLE_ja : $ERRORTABLE_en;

if (!$HOSTNAME || !$LOCATION || !$USERTYPE || $USERTYPE ne 'admin') {
	TF::CommonUtils::showAccessDeny();
	die '';
}

main();

#
#	メインルーチン
#
sub main {
	my $status = '';
	my $isActive = 0;
	my $hour;
	my $min;
	my $from;
	my $to;
	my $subject;
	my $datetimefmt;
	my $trigger;
	my $stg_limit;
	my $stg_limit_per;

	my $cgi = new CGI;
	my @fmtlist = (
					{ value => "default", name => "YYYY-MM-DD HH:mm:ss" },
					{ value => "yyyy-mm-dd", name => "YYYY-MM-DD hh:mm:ss A"},
					{ value => "mm/dd/yyyy", name => "MM/DD/YYYY hh:mm:ss A"},
					{ value => "dd/mm/yyyy", name => "DD/MM/YYYY hh:mm:ss A"}
				  );

	if( ! $cgi ) {
		TF::CommonUtils::showErrorPage($ERRORTABLE->{CGIError}, $LANGPARAM);
		print STDERR "CGI Object error";
		return;
	}

	if( $cgi->cgi_error ) {
		TF::CommonUtils::showErrorPage($ERRORTABLE->{CGIError} . '(' . $cgi->cgi_error . ')', $LANGPARAM);
		print STDERR "CGI Error (" . $cgi->cgi->error . ")";
		return;
	}

	my $cmd  = $cgi->param('hidCmd') || '';

	#
	# 排他処理
	#
	my $lock = TF::SingleLock->new($LOCK_FILE);
	if( ! $lock->waitForLocking(5) ) {
		showResponse( $cgi, $ERRORTABLE->{serverBusy}, '', undef);
		$lock->release();
		die "Server busy ($$)";
	}

	# 更新時
	if ($cmd eq 'set') {
		# 現在の設定値を読み込む
		my %read_params = readSettingsFile($SETTINGS_FILE);

		my $enc_hour   = $cgi->param('hour');
	    my $enc_min    = $cgi->param('min');
	    my $enc_from   = $cgi->param('from');
	    my $enc_to     = $cgi->param('to');
		my $enc_subject= $cgi->param('subject');
		my $enc_datetimefmt= $cgi->param('datetimefmt');
		my $enc_trigger    = $cgi->param('trigger');
		my $enc_stg_limit  = $cgi->param('stg_limit');
		my $enc_stg_limit_per = $cgi->param('stg_limit_per');

		$hour   = TF::CommonUtils::decodeUTF8($enc_hour);
		$min    = TF::CommonUtils::decodeUTF8($enc_min);
		$from   = TF::CommonUtils::decodeUTF8($enc_from);
		$to     = TF::CommonUtils::decodeUTF8($enc_to);
		$subject= TF::CommonUtils::decodeUTF8($enc_subject);
		$datetimefmt = TF::CommonUtils::decodeUTF8($enc_datetimefmt);
		$trigger= TF::CommonUtils::decodeUTF8($enc_trigger);
		$stg_limit= TF::CommonUtils::decodeUTF8($enc_stg_limit);
		$stg_limit_per= TF::CommonUtils::decodeUTF8($enc_stg_limit_per);

		# 空行を取り除く
		$from    =~ s/[\s ]+//g;
		$to      =~ s/[\s ]+//g;
		$stg_limit =~ s/[\s ]+//g;  
		$stg_limit_per =~ s/[\s ]+//g;  

		my $actv = $cgi->param('func') || 'off';
		$isActive = ($actv eq 'on') ? 1 : 0;

		# POSTデータを反映する
		$read_params{active} = $isActive;
		$read_params{hour}   = $hour;
		$read_params{min}    = $min;
		$read_params{from} = $from;
		$read_params{to} = $to;
		$read_params{hostname} = $HOSTNAME;
		$read_params{location} = $LOCATION_NAME;
		$read_params{subject}  = $subject;
		$read_params{datetimefmt} = $datetimefmt;
		$read_params{trigger} = $trigger;
		$read_params{stg_limit} = $stg_limit;
		$read_params{stg_limit_per} = $stg_limit_per;

		#空欄がある場合はエラー
		if($hour eq '' || $min eq '') {
			$status = $status . $ERRORTABLE->{nothing} . '<br/>';

			$lock->release();
			showResponse($cgi, $status, '', \%read_params);
			return;
		}

		#
		# 時、分の連結。if文を見やすくするため
		#
		my $check = $hour . $min;

		#
		#範囲外の値はエラー
		#
		if ( $check =~ /^[0-9]*[0-9]$/) {
			if ( !($hour >= 0 && $hour <= 23) || !($min >= 0 && $min <= 59) ) {
				$status = $status . $ERRORTABLE->{paramError} . '<br/>';
				$lock->release();
				showResponse($cgi, $status, '', \%read_params);
				return;
			}
		}
		else {
			$status = $status . $ERRORTABLE->{paramError} . '<br/>';
			$lock->release();
			showResponse($cgi, $status, '', \%read_params);
			return;
		}

		# ディスク容量の数値チェック
		if ($stg_limit ne "" && $stg_limit !~ /^[0-9]*[0-9]$/) {
			$status = $status . $ERRORTABLE->{paramError} . '<br/>';
			$lock->release();
			showResponse($cgi, $status, '', \%read_params);
			return;
		}

		# ディスク利用率の数値チェック
		if ($stg_limit_per ne "" && $stg_limit_per !~ /^[0-9]*[0-9]$/) {
			$status = $status . $ERRORTABLE->{paramError} . '<br/>';
			$lock->release();
			showResponse($cgi, $status, '', \%read_params);
			return;
		}

		# ディスク利用率の範囲チェック
		if ($stg_limit_per > 100 || $stg_limit_per < 0) {
			$status = $status . $ERRORTABLE->{paramError} . '<br/>';
			$lock->release();
			showResponse($cgi, $status, '', \%read_params);
			return;
		}

		# from mail address の簡易チェック
		if ($from && TF::CommonUtils::isMailAddress($from) == 0) {
			$status = $status . $ERRORTABLE->{paramError} . ' From Mail Address<br/>';
			$lock->release();
			showResponse($cgi, $status, '', \%read_params);
			return;
		}

		# to mail addrees の簡易チェック
		my @arrayTo = split(/,/, $to);
		foreach(@arrayTo) {
			if (TF::CommonUtils::isMailAddress($_) == 0) {
				$status = $status . $ERRORTABLE->{paramError} . ' To Mail Address<br/>';
				$lock->release();
				showResponse($cgi, $status, '', \%read_params);
				return;
			}
		}

		# バックアップ
	    unlink $SETTINGS_FILE_BAK;
	    rename $SETTINGS_FILE,$SETTINGS_FILE_BAK;

		# ファイルに出力する
		storeSettingsFile($SETTINGS_FILE, \%read_params);
	}
	# 設定ファイルの読み出し
	my %params = readSettingsFile($SETTINGS_FILE);

	$lock->release();
	showResponse($cgi, $status, $cmd, \%params, \@fmtlist);
}

#
# レスポンスの出力
#
sub showResponse {
	my %emptyhash = ();
	my $succeeded = 0;
	my $cgi       = shift || undef;
	my $status    = shift || '';
	my $cmd       = shift || '';
	my $params_ref= shift || \%emptyhash;
	my $fmtlist_ref=shift;

	my %params    = %{$params_ref};
	my $action1;
	my $action2;

	my $trigger_daily = "";
	my $trigger_match = "";

	if ($cmd eq 'set') {
		TF::CommonUtils::redirectPage($BACKURI, $LANGPARAM);
		return;
	}

	if ($params{active}) {
        $action1 = "checked";
        $action2 = "";
    }
	else {
        $action1 = "";
        $action2 = "checked";
    }

	if ($params{trigger} =~ /daily/) { $trigger_daily = "checked"};
	if ($params{trigger} =~ /match/) { $trigger_match = "checked"};

	# 日付フォーマットを設定する
	foreach my $fmt (@{$fmtlist_ref}) {
		if ($params{datetimefmt} eq $fmt->{value}) {
			$fmt->{isselected} = 1;
		}
	}

	if( $cgi ) {
		if( open TEMPLATE, "<", $TEMPLATE_FILE ) {
			binmode TEMPLATE, ":utf8";	# テンプレートファイルはUTF8扱いで読み込む	
			my $htmltmpl = HTML::Template->new( filehandle => *TEMPLATE,
												case_sensitive => 1,
												die_on_bad_params => 0);

			#パラメータの受け渡し
			if( $htmltmpl ) {
				$htmltmpl->param(	hour => $params{hour},
									min  => $params{min},
									from => $params{from},
									to   => $params{to},
									subject => $params{subject},
									phsubject => $params{phsubject},
									datetimefmt => $fmtlist_ref,
									chk1 => $action1,
									chk2 => $action2,
									trigger_daily => $trigger_daily,
									trigger_match => $trigger_match,
									stg_limit => $params{stg_limit},
									stg_limit_per => $params{stg_limit_per},
									status => $status,
									brandname => $BRAND,
									pagetitle => $PAGETITLE,
									pageimg   => $PAGEIMG,
									isWritable => ($USERTYPE eq 'admin') ? 1 : 0,
								);
				
				print $cgi->header( -charset => 'utf-8' );
				print $htmltmpl->output;
				$succeeded = 1;
			}
			else {
				$status = $status . $ERRORTABLE->{templateError} . '<br/>';
			}
			close TEMPLATE;
		}
		else {
			$status = $status . $ERRORTABLE->{readTemplateError} . '<br/>';
		}
	}
	else {
		$status = $status . $ERRORTABLE->{CGIError} . '<br/>';
	}

	if( ! $succeeded ) {
		TF::CommonUtils::showErrorPage($status, $LANGPARAM);
		return;
	}
}

#
# Read settings file
#
sub readSettingsFile {
	my $filepath   = shift || '';

	if (!$filepath) {
		return;
	}

	my $isActive = 0;
	my $hour     = '';
	my $min      = '';
	my $from     = '';
	my $to       = '';
	my $hostname = '';
	my $location = '';
	my $subject  = '';
	my $phsubject= '';
	my $datetimefmt = '';
	my $trigger = '';
	my $stg_limit = '';
	my $stg_limit_per = '';

	if (-f $SETTINGS_FILE_OLD) {
		rename($SETTINGS_FILE_OLD, $SETTINGS_FILE);
	}

	if (-f $filepath) {
		my $xml = new XML::DOM::Parser;
		my $doc = $xml->parsefile($filepath);

		for my $elem ( $doc->getElementsByTagName("state") ) {
			my $nodelist = $elem->getElementsByTagName("active");
			if ($nodelist && $nodelist->getLength > 0) {
				$isActive = 1;
			}
			else {
				$isActive = 0;
			}
		}

		for my $elem ( $doc->getElementsByTagName("starttime") ) {
			$hour = TF::XMLUtils::getText($elem,"hour");
			$min  = TF::XMLUtils::getText($elem,"minutes");
		}

		for my $elem ( $doc->getElementsByTagName("reportsetting") ) {
			$from        = TF::XMLUtils::getText($elem, "from");
			$to          = TF::XMLUtils::getText($elem, "to");
			$hostname    = TF::XMLUtils::getText($elem, "hostname");
			$location    = TF::XMLUtils::getText($elem, "location");
			$subject     = TF::XMLUtils::getText($elem, "subject");
			$phsubject   = TF::XMLUtils::getText($elem, "phsubject");
			$datetimefmt = TF::XMLUtils::getText($elem, "datetimefmt");
			$trigger     = TF::XMLUtils::getText($elem, "trigger");
			$stg_limit   = TF::XMLUtils::getText($elem, "stg-limit");
			$stg_limit_per = TF::XMLUtils::getText($elem, "stg-limit-per");
		}

		$doc->dispose;
	}

	if ($phsubject eq '') {
		$phsubject = "[" . $BRAND . "] Server daily report";
	}

	if ($datetimefmt eq '') {
		$datetimefmt = "default";
	}

	my %params =	(	active => $isActive,
						hour   => $hour,
						min    => $min,
						from   => $from,
						to     => $to,
						hostname => $hostname,
						location => $location,
						subject  => $subject,
						phsubject=> $phsubject,
						datetimefmt => $datetimefmt,
						trigger  => $trigger,
						stg_limit => $stg_limit,
						stg_limit_per => $stg_limit_per
					);
	return %params;
}

#
# Store data to settings file
#
sub storeSettingsFile {
	my $filepath   = shift || '';
	my $params_ref = shift || undef;

	if (!$filepath || !$params_ref) {
		return;
	}

	# 前ゼロ　　0時0分がファイルに書き込めないため
	my %params = %{$params_ref};
	my $hour = sprintf("%02d",$params{hour});
	my $min  = sprintf("%02d",$params{min});

	my $doc = new XML::DOM::Document;
    my $pi_decl = $doc->createXMLDecl('1.0','utf-8','yes');

	$doc->setXMLDecl($pi_decl);

	my $edit = $doc->createElement("reportsetting");
	my $editstate = $doc->createElement("state");

	if ($params{active}) {
		my $e = $doc->createElement("active");
		$editstate->appendChild($e);
	}
	else {
		my $e = $doc->createElement("inactive");
		$editstate->appendChild($e);
	}
	$edit->appendChild($editstate);

	my $editstime = $doc->createElement("starttime");

	TF::XMLUtils::appendTextElement($doc, $editstime, "hour",    $hour);
	TF::XMLUtils::appendTextElement($doc, $editstime, "minutes", $min);
	$edit->appendChild($editstime);

	my $mail = $doc->createElement("mail");

	TF::XMLUtils::appendTextElement($doc, $mail, "from", $params{from});
	TF::XMLUtils::appendTextElement($doc, $mail, "to", $params{to});
	$edit->appendChild($mail);

	TF::XMLUtils::appendTextElement($doc, $edit, "hostname", $params{hostname});
	TF::XMLUtils::appendTextElement($doc, $edit, "location", $params{location});
	TF::XMLUtils::appendTextElement($doc, $edit, "subject", $params{subject});
	TF::XMLUtils::appendTextElement($doc, $edit, "phsubject", $params{phsubject});
	TF::XMLUtils::appendTextElement($doc, $edit, "datetimefmt", $params{datetimefmt});
	TF::XMLUtils::appendTextElement($doc, $edit, "trigger", $params{trigger});
	TF::XMLUtils::appendTextElement($doc, $edit, "stg-limit", $params{stg_limit});
	TF::XMLUtils::appendTextElement($doc, $edit, "stg-limit-per", $params{stg_limit_per});
	$doc->appendChild($edit);


	$doc ->printToFile($filepath);
	$doc ->dispose;

}
