#!/usr/sbin/perl
###
### 季節イベントのスケジュールをつくる
###
###
#
$dbfile = "schedule_event.lst";
$deffile = "m_ev_sche_def.h";
$datfile = "m_ev_sche_dat.h";

$defmax = 32;
$commax = 26;

open(DBF, $dbfile)
     || die "データベースをオープンできません。 '$dbfile'\n";
$i = 0;
while(<DBF>){
    next if /^!/;
    ($comment, $label, $date, $time) = split;
    if($label ne ""){
        if($COMMENT{$label} eq ""){
            $COMMENT{$label} = $comment;
        }elsif(!($COMMENT{$label} =~  /etc$/)){
            $COMMENT{$label} = $COMMENT{$label}." etc";
        }
        $COMM[$i] = $comment;
        $LABEL[$i] = $label;
        $DATE[$i] = $date;
        $TIME[$i] = $time;
        $i++;
    }
}
close(DBF);
$max = $i;

#
##
##  定義ヘッダーファイル書き出し
##
#
open(DEF, ">".$deffile) 
    || die "ヘッダーファイルをオープンできません。 '$deffile'\n";
print DEF <<____DEF_HEAD;
/*
 ******************************************************************************
 *
 *	スケジュールイベント管理（定義）
 *
 ******************************************************************************
 */

#ifndef	__M_EV_SCHE_DEF_H__
#define	__M_EV_SCHE_DEF_H__

/*
** スケジュールイベント定義 ** */
____DEF_HEAD
$i = 0;
foreach $key (sort keys(%COMMENT)){
    $enum = "EV_".$key;
    printf(DEF "#define %-${defmax}s (%3d) /* %-${commax}s */\n",  $enum, $i, $COMMENT{$key});
    $i++;
}
printf(DEF "#define %-${defmax}s (%3d) /* %-${commax}s */\n\n", "EV_SCHEDULE_NO_END", $i, "以上");
printf(DEF "#define EV_SCHEDULE_TYPE_MAX   EV_SCHEDULE_NO_END\n\n\n");

printf(DEF "#if defined(USE_EVENT_COMMENT_4_DEBUG) && defined(__M_EVENT_C__)\n");
printf(DEF "/*\n** デバッグ用文字列 ** */\nconst char *event_comment[EV_SCHEDULE_TYPE_MAX] = {\n");
foreach $key (sort keys(%COMMENT)){
    printf(DEF "   \"%s\",\n",  $COMMENT{$key});
    $i++;
}
printf(DEF "};\n#endif\n\n");

print DEF <<____DEF_TAIL;

/*
** --- スケジュール管理オブジェクト --- 
*/
typedef struct _event_date_data_ {
    char  month, day, flag, hour;
} evdate_t;

typedef struct _event_schedule_ {
    union _event_schedule_date_ {
	evdate_t d;               /* 日付時間 */
	unsigned short v;         /* インテル互換なし */
	unsigned long lv;
    } from, to;
    int type;
} EvSchedule;

typedef union _event_schedule_date_ evdate_u;

#if defined(__M_EVENT_C__)
#define is_normalday_data(flag)   ((flag) == 0)      /* 月日型データ */
#define is_kyureki_data(flag)     ((flag) & 0x08)    /* 旧暦か？ */
#define is_week_data(flag)        ((flag) & 0x01)    /* 週曜日指定か？ */
#define is_every_data(flag)       ((flag) & 0x06)    /* 毎？データ */
#define is_everyweek_data(flag)   ((flag) & 0x02)    /* 毎週データ */
#define is_everymonth_data(flag)  ((flag) & 0x04)    /* 毎月データ */
#define day_of_week(day)          ((day) & 0x07)     /* 曜日ゲット */
#define cycle_of_week(day)        (((day) & 0xf8) >> 3) /* 何週目か？ */
#endif
/* flag */
#define EV_FLG_WDAY               (0x01)  /* 曜日 */
#define EV_FLG_WEEKLY             (0x02)  /* 毎週 */
#define EV_FLG_MONTHLY            (0x04)  /* 毎月 */
#define EV_FLG_JPOLD              (0x08)  /* 旧暦 */
#define EV_FLG_PROGRAM            (0x10)  /* プログラムでいれる */
#define EV_FLG_NDAYS              (0x40)  /* 継続時間指定 */
#define EV_FLG_DAILYTIME          (0x80)  /* 時間指定が日単位 */
#define EV_FLG_MASK_DATE          ~(EV_FLG_DAILYTIME)
/* alias */
#define EV_DATE_MONTH_DAY         (0x00)  /* ？月？日 */
#define EV_DATE_MONTH_N_WDAY      (0x01)  /* ？月第ｎ？曜日 */
#define EV_DATE_MONTH_WEEKLY      (0x03)  /* ？月毎週？曜日 */
#define EV_DATE_DAY               (0x04)  /* 毎月？日 */
#define EV_DATE_N_WDAY            (0x05)  /* 毎月第ｎ？曜日 */
#define EV_DATE_WEEKLY            (0x07)  /* 毎月毎週？曜日 */
#define EV_DATE_JP_MONTH_DAY      (0x08)  /* 旧暦？月？日 */
#define EV_DATE_PROGRAM_DAY       (0x10)  /* プログラムでいれる */
#define EV_DATE_NDAYS             (0x40)  /* 継続時間指定 */

/*
** 曜日 ** */
#define EV_WEEK_SUNDAY    (0)
#define EV_WEEK_MONDAY    (1)
#define EV_WEEK_TUESDAY   (2)
#define EV_WEEK_WEDNESDAY (3)
#define EV_WEEK_THURSDAY  (4)
#define EV_WEEK_FRIDAY    (5)
#define EV_WEEK_SATURDAY  (6)
#define EV_WEEK_ANYDAY    (7)  /* 何曜日でも */

/*
** 第？週 ** */
#define EV_WEEK_FIRST     (0x01)
#define EV_WEEK_SECOND    (0x02)
#define EV_WEEK_THIRD     (0x03)
#define EV_WEEK_FOURTH    (0x04)
#define EV_WEEK_FIFTH     (0x05)
#define EV_WEEK_LAST      (0x0f)  /* 最終？曜日 */
#define EV_WEEK_EVELY     (0x10)  /* 毎週 */


#endif /* __M_EV_SCHE_DEF_H__ */

____DEF_TAIL
close(DEF);

#
##
##  データヘッダーファイル書き出し
##
#
open(DAT, ">".$datfile) 
    || die "ヘッダーファイルをオープンできません。 '$datfile'\n";
print DAT <<____DAT_HEAD;
/*
 ******************************************************************************
 *
 *	スケジュールイベント管理（データ）
 *
 ******************************************************************************
 */

#ifndef	__M_EV_SCHE_DAT_H__
#define	__M_EV_SCHE_DAT_H__
#ifdef  __M_EVENT_C__ 
#include "$deffile"

____DAT_HEAD
printf(DAT "static EvSchedule event_schedule_data[] =  {\n");
for($i = 0; $i < $max; $i++){
    $enum = "EV_".$LABEL[$i];

    $from = &make_from_data($DATE[$i], $TIME[$i]);
    $to = &make_to_data($DATE[$i], $TIME[$i]);
    printf(DAT "  /* *** %s *** %s %s *** */\n", $COMM[$i], $DATE[$i], $TIME[$i]);
    printf(DAT "  { %s, %s, %s },\n", $from, $to, $enum);
}
printf(DAT "};\n#define EV_SCHEDULE_DATA_MAX  (%d)\n", $max);

print DAT <<____DAT_TAIL;
#endif /* __M_EVENT_C__ */
#endif /* __M_EV_SCHE_DAT_H__ */

____DAT_TAIL
close(DAT);

exit(0);

#
##
##  サブルーチン
##
#
sub make_from_data {
    local($date, $time) = @_;
    local($ss) = "{ ";
    if(($pos = index($date, "-")) >= $[){
        $ss .= &check_date(substr($date, 0, $pos), 1);
    }else{
        $ss .= &check_date($date, 1);
    }
    $ss .= ", ";
    if(($pos = index($time, "-")) >= $[){
        $ss .= &check_time(substr($time, 0, $pos), 1);
    }else{
        $ss .= &check_time($time, 1);
    }
    $ss .= " }";
    return  $ss;
}

sub make_to_data {
    local($date, $time) = @_;
    local($ss) = "{ ";
    if(($pos = index($date, "-")) >= $[){
        $ss .= &check_date(substr($date, $pos + 1), 0);
    }else{
        $ss .= &check_date($date, 0);
    }
    $ss .= ", ";
    if(($pos = index($time, "-")) >= $[){
        $ss .= &check_time(substr($time, $pos + 1), 0);
    }else{
        $ss .= &check_time($time, 0);
    }
    $ss .= " }";
    return  $ss;
}

sub check_time {
    local($time, $dir) = @_;
    local($ss) = "";
    if($time =~ /^終日$/){
	$ss .= sprintf("%d", ($dir ? 0 : 23));
    }elsif($time =~ /^午前$/){
	$ss .= sprintf("%d", ($dir ? 0 : 11));
    }elsif($time =~ /^午後$/){
	$ss .= sprintf("%d", ($dir ? 12 : 23));
    }elsif($time =~ /^([0-9][0-9])(:00|時)$/){
        $ss .= sprintf("%d", $1);
    }elsif($time =~ /^([0-9][0-9])(:|時)([0-9][0-9])(分)?$/){
        print STDERR "分はサポートしてません。時間単位にしてください。\n";
        $ss .= sprintf("%d", $1);
    }else{
        print STDERR "時間データがおかしいです。($time)\n";
        $ss .= "99";
    }
    return  $ss;
}

sub check_date {
    local($date, $dir) = @_;
    local(%weekd) = (
        "日", 0,        "月", 1,        "火", 2,
        "水", 3,        "木", 4,        "金", 5,
        "土", 6,        "全", 7
    );
    local (%weekn) = (
        "毎週", 0x10, "最終", 0x0f,
        "第１", 0x01, "第２", 0x02, "第３", 0x03, "第４", 0x04, "第５", 0x05
    );
    local (%weekf) = (
        "毎週", 3, "最終", 1,
        "第１", 1, "第２", 1, "第３", 1, "第４", 1, "第５", 1
    );
    local($ss) = "";
    if($date =~ /^年中$/){
	$ss .= sprintf("%d,%d, 0", ($dir ? 1 : 12), ($dir ? 1 : 31));
    }elsif($date =~ /^プログラム$/){
	$ss .= sprintf("%d,%d, 128", ($dir ? 1 : 12), ($dir ? 1 : 31));
    }elsif($date =~ /^([0-9][0-9])(\/|月)([0-9][0-9])(日)?$/){
        $ss .= sprintf("%d,%d, 0", $1, $3);
    }elsif($date =~ /^([0-9]+)日間$/){
        $ss .= sprintf("0,%d, 64", $1);
    }elsif($date =~ /^毎月([0-9][0-9])(日)?$/){
        $ss .= sprintf("%d,%d, 4", 15, $1);
    }elsif($date =~ /^旧(暦)?([0-9][0-9])(\/|月)([0-9][0-9])(日)?$/){
        $ss .= sprintf("%d,%d, 8", $2, $4);
   }elsif($date =~ /^([0-9][0-9])(月)?(毎週|最終|第１|第２|第３|第４|第５)(日|月|火|水|木|金|土|全)(曜日)?$/){
        $ss .= sprintf("%d,0x%02x, %d", $1, ($weekn{$3} << 3) | ($4 eq "全" ? ($dir ? $weekd{'日'} : $weekd{'土'}) : $weekd{$4}), $weekf{$3});
    }elsif($date =~ /^(毎月)?(毎週|最終|第１|第２|第３|第４|第５)(日|月|火|水|木|金|土|全)(曜日)?$/){
        $ss .= sprintf("%d,0x%02x, %d", 15, ($weekn{$2} << 3) | ($3 eq "全" ? ($dir ? $weekd{'日'} : $weekd{'土'}) : $weekd{$3}), $weekf{$2} | 4);
    }else{
        print STDERR "日付データがおかしいです。($date)\n";
        $ss .= "0x00, 99,99";
    }
    return  $ss;
}
