#!/bin/sh

##########################################################################
#
#  tzset.sh - script that validates, parses and compiles TZ env string.
#             Added routine to convert env.global TZ to /etc/localtime
#  Mike Goins
#  Adtec, Inc.
#  Sept 11, 2006
#
##########################################################################

: ${AWK=awk}    


declare -i OFS

function fix_tz
{
   TZNAME="[^-+,0-9]\{,4\}"    #eg EST PST HK
   TIME="[0-2]\{0,1\}[0-9](:[0-5][0-9](:[0-5][0-9])\{0,1\})\{0,1\}"
   OFFSET="[-+]\{0,1\}${TIME}"                 

   # if /etc/TZ does not exist then copy it from env.global
   if [ ! -e /etc/TZ ]; then 
      tz=`grep "export TZ" /etc/env.global | cut -d= -f2 | sed -e 's/\"//g'`
      if [ $tz ]; then 
         STD_NAME=`expr "$tz" : "\(${TZNAME}\)${OFFSET}.*"`
         OSF=`expr "$tz" : "${TZNAME}\(${OFFSET}\).*"`  
         let "new_osf=OSF * -1"
	 if [ "$STD_NAME" == "UTC" ]; then
	    echo $new_osf > /etc/TZ
         else
	    new_tz=`echo $tz | sed -e "s/$OSF/$new_osf/"`
	    echo $new_tz > /etc/TZ 
	 fi    
      else  # not exist so create it as UTC
         echo 0 > /etc/TZ
      fi
   fi      
   # remove it from env.global.
   sed -i '/export TZ*/d' /etc/env.global   # could probably remove this line eventually.
   # if localtime file not exist, then create it
   if [ ! -e /etc/localtime ]; then
      tzset.sh `cat /etc/TZ`
   fi
}


function set_localtime 
{
   if [ ! -e /usr/local/sbin/zic ]; then
      exit 5  # need to set to adtec err nums
   fi

   TZ="$1"

   if [ -e /bin/awk ]; then
      $AWK -v TZ="$TZ" 'BEGIN {
         tzname = "([^-+,0-9][^-+,0-9][^-+,0-9]+)?"
         time = "[0-2]?[0-9](:[0-5][0-9](:[0-5][0-9])?)?"
         offset = "[-+]?" time
         date = "(J?[0-9]+|M[0-9]+.[0-9]+.[0-9]+)"
         datetime = "," date "(/" time ")?"
         tzpattern = "^(:.*|" tzname offset "(" tzname \
           "(" offset ")?(" datetime datetime ")?)?)$"
           if (TZ ~ tzpattern) exit 1
           exit 0
      }'

      if [ $? -eq 0 ]; then
         exit 2   # data not valid
      fi
   fi

   # begin parsing TZ here
   TZNAME="[^-+,0-9]\{0,4\}"    #eg EST PST HK
   TIME="[0-2]\{0,1\}[0-9]:\{0,1\}[0-5]\{0,1\}[0-9]\{0,1\}"                   
   OFFSET="[-+]\{0,1\}${TIME}"                   #eg 05 +5 -05
   SAVE="${TIME}"                   #eg 1, 1:30
   DATE="M[0-9]\{1,\}.[0-9]\{1,\}.[0-9]\{1,\}"   #eg M4.0.1
   DATETIME=${DATE}/${TIME}
   MO=([1]=Jan [2]=Feb [3]=Mar [4]=Apr [5]=May [6]=Jun [7]=Jul [8]=Aug [9]=Sep [10]=Oct [11]=Nov [12]=Dec)
   DY=([0]=Sun [1]=Mon [2]=Tue [3]=Wed [4]=Thu [5]=Fri [6]=Sat)


   STD_NAME=`expr "$TZ" : "\(${TZNAME}\)${OFFSET}.*"`  #${TZNAME}\{0,1\}.*"
   if [ ! ${STD_NAME} ]; then
      STD_NAME="UTC"
   fi
   OSF=`expr "$TZ" : "${TZNAME}\(${OFFSET}\).*"`  #${TZNAME}\{0,1\}.*"
   DST_NAME=`expr "$TZ" : "${TZNAME}${OFFSET}\(${TZNAME}\).*"`
   DST_SAVE=`expr "$TZ" : "${TZNAME}${OFFSET}${TZNAME}\(${SAVE}\),${DATETIME}.*"`
   #echo "SV $DST_SAVE"
   if [ -z "$DST_SAVE" ]; then
      DST_SAVE="1"
      DST_FROM=`expr "$TZ" : "${TZNAME}${OFFSET}${TZNAME},\(${DATETIME}\).*"`
      DST_TO=`expr "$TZ" : "${TZNAME}${OFFSET}${TZNAME},${DATETIME},\(${DATETIME}\)"`
   else
      DST_FROM=`expr "$TZ" : "${TZNAME}${OFFSET}${TZNAME}${SAVE},\(${DATETIME}\).*"`
      DST_TO=`expr "$TZ" : "${TZNAME}${OFFSET}${TZNAME}${SAVE},${DATETIME},\(${DATETIME}\)"`
   fi
   MONTH_FROM=`expr "$DST_FROM" : "M\([0-9]\{1,\}\).[0-9]\{1,\}.[0-9]\{1,\}/${TIME}"`
   WEEK_FROM=`expr "$DST_FROM" : "M[0-9]\{1,\}.\([0-9]\{1,\}\).[0-9]\{1,\}/${TIME}"`
   DAY_FROM=`expr "$DST_FROM" : "M[0-9]\{1,\}.[0-9]\{1,\}.\([0-9]\{1,\}\)/${TIME}"`
   TIME_FROM=`expr "$DST_FROM" : "M[0-9]\{1,\}.[0-9]\{1,\}.[0-9]\{1,\}/\(${TIME}\)"`

   MONTH_TO=`expr "$DST_TO" : "M\([0-9]\{1,\}\).[0-9]\{1,\}.[0-9]\{1,\}/${TIME}"`
   WEEK_TO=`expr "$DST_TO" : "M[0-9]\{1,\}.\([0-9]\{1,\}\).[0-9]\{1,\}/${TIME}"`
   DAY_TO=`expr "$DST_TO" : "M[0-9]\{1,\}.[0-9]\{1,\}.\([0-9]\{1,\}\)/${TIME}"`
   TIME_TO=`expr "$DST_TO" : "M[0-9]\{1,\}.[0-9]\{1,\}.[0-9]\{1,\}/\(${TIME}\)"`

   #echo $WEEK_FROM

   # figure out day
   if [ ${WEEK_FROM} ]; then   # means they at least supplied a rule
      case "${WEEK_FROM}" in
         5) # first specified day  of the month:  Sun>=1
            FRULE="last${DY[$DAY_FROM]}"
            ;;
         *)
         #let FRULEA=7*${WEEK_FROM}+1
         let FRULEA=(${WEEK_FROM}-1)*7+1
         FRULE="${DY[${DAY_FROM}]}>=${FRULEA}"
      esac
      case "${WEEK_TO}" in
         5) # first specified day  of the month:  Sun>=1
            TRULE="last${DY[$DAY_TO]}"
            ;;
         *)
            #let TRULEA=7*${WEEK_TO}+1
            let TRULEA=(${WEEK_TO}-1)*7+1
            TRULE="${DY[${DAY_TO}]}>=${TRULEA}"
      esac

      RULE1="Rule ADTEC 2006 max - ${MO[$MONTH_FROM]} ${FRULE} ${TIME_FROM} $DST_SAVE ${DST_NAME}"  
      RULE2="Rule ADTEC 2006 max - ${MO[$MONTH_TO]} ${TRULE} ${TIME_TO} 0 ${STD_NAME}"   
      ZONE="Zone localtime ${OSF} ADTEC %s"  
   else  # no rules
      ZONE="Zone localtime ${OSF} - ${STD_NAME}"  
   fi   
   rm -f /etc/localtime
   echo $TZ > /etc/TZ
   #echo -e "${RULE1}\n${RULE2}\n${ZONE}"
   echo -e "${RULE1}\n${RULE2}\n${ZONE}" | zic -d /etc - 

}


# main routine
if [ $# -ne 1 ]; then
   fix_tz
else
   set_localtime "$1"
   # make syslog re-read /etc/localtime
   pkill -HUP syslogd
fi