# Application initialization/notification API.
# Rick Smereka, Copyright (C) 2005-2006.

# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with this program; if not, get a copy via the Internet at
# http://gnu.org/copyleft/gpl.html or write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
# MA 02111-1307 USA

# You can contact the author via email at rsmereka@future-lab.com

# This API notifies other applications that the running program
# is initializing. Notification is done through a lock file.
# This API should be used by any program that depends on other
# applications to be running before starting-up. This API also
# provides a storage location for the application name in case
# this name is required by another API outside of the main
# program module.

# Initial tcl version. Apr/2005, Rick Smereka

# Added exit log message to 'appinit_remove_name'. Apr/2006,
# Rick Smereka

# global application name
set appinit_apname ""

proc appinit_start {sname} {
   # Indicate that the application is starting up by creating
   # a zero byte lock file. The parameter 'sname' should be a
   # unique name to identify the application and is usually
   # the 'socloc' service name when dealing with a socket
   # server. Returns 1 upon success, 0 otherwise.
   set mname "appinit_start"
   
   logman "$mname:enter:sname=$sname"

   if {$sname == ""} {
      logman "$mname:exit:empty(sname)"
      return 0
   }

   if {![appinit_get_sname $sname nsname]} {
      logman "$mname:exit:bad rc(0) from appinit_get_sname"
      return 0
   }

   if {[exist $nsname]} {
      logman "$mname:exit:lock file $nsname already exists"
      return 0
   }

   if {![zcreate $nsname]} {
      logman "$mname:exit:bad rc(0) from zcreate"
      return 0
   }

   logman "$mname:normal exit(1)"
   return 1
}

proc appinit_stop {sname} {
   # Indicate that the application has completed its
   # initialization by deleting the zero byte lock file.
   # The parameter 'sname' must be the same name used to
   # call 'appinit_start'. Returns 1 upon success,
   # 0 otherwise.
   set mname "appinit_stop"

   logman "$mname:enter:sname=$sname"

   if {$sname == ""} {
      logman "$mname:exit:empty(sname)"
      return 0
   }

   if {![appinit_get_sname $sname nsname]} {
      logman "$mname:exit:bad rc(0) from appinit_get_sname"
      return 0
   }

   if {![exist $nsname]} {
      logman "$mname:exit:lock file $nsname not present"
      return 0
   }

   file delete $nsname
   logman "$mname:normal exit(1)"
   return 1
}

proc appinit_waitfor {sname min_timeout} {
   # Check for a lock file using the name 'sname'. Wait
   # up to 'min_timeout' minutes for the lock file to be
   # removed. Returns 1 if the lock file no longer exists,
   # 0 otherwise.
   set mname "appinit_waitfor"

   logman "$mname:enter:sname=$sname"

   if {$sname == ""} {
      logman "$mname:exit:empty(sname)"
      return 0
   }

   if {$min_timeout <= 0} {
      logman "$mname:exit:out of range(min_timeout)"
      return 0
   }

   if {![appinit_get_sname $sname nsname]} {
      logman "$mname:exit:bad rc(0) from appinit_get_sname"
      return 0
   }

   set nowtime [clock clicks -milliseconds]
   set target_time [expr $nowtime + ($min_timeout * 60 * 1000)]

   while {$nowtime < $target_time} {
      if {![exist $nsname]} {
         logman "$mname:normal exit(1),lock file $nsname is not present"
         return 1
      }

      sleep 2
      set nowtime [clock clicks -milliseconds]
   }

   logman "$mname:exit(0):time expired"
   return 0
}

proc appinit_register_name {apname} {
   # Load the passed 'apname' into the global
   # 'appinit_apname' Returns 1 upon success,
   # 0 otherwise.
   global appinit_apname
   set mname "appinit_register_name"

   logman "$mname:enter"

   if {$apname == ""} {
      logman "$mname:exit(0):empty(apname)"
      return 0
   }

   set appinit_apname $apname
   logman "$mname:normal exit(1)"
   return 1
}
 
proc appinit_get_name {} {
   # Obtain the application name which must already be defined
   # by calling 'appinit_register_name'. Returns the application
   # name.
   global appinit_apname
   set mname "appinit_get_name"

   logman "$mname:enter"
   set apname $appinit_apname
   logman "$mname:normal exit"
   return $apname
}

proc appinit_remove_name {} {
   # Set the current application name ('appinit_apname') to an
   # empty string. Returns 1 upon success, 0 otherwise.
   global appinit_apname
   set mname "appinit_remove_name"

   logman "$mname:enter"

   # it is an error if the application name is not set
   if {$appinit_apname == ""} {
      return 0
   }

   set appinit_apname ""
   logman "$mname:normal exit"
   return 1
}

proc appinit_get_sname {oldname newname} {
   # Translate an application name. The lock file extension
   # will be appended to the name. The the translated name
   # will be loaded into 'newname' upon success. Returns
   # 1 upon success, 0 otherwise.
   upvar $newname lk
   set mname "appinit_get_sname"
   set lk ""

   logman "$mname:enter:oldname=$oldname"

   if {$oldname == ""} {
      logman "$mname:exit:empty(oldname)"
      return 0
   }

   set lk [format "%s.lck" $oldname]
   logman "$mname:normal exit(1):newname=$lk"
   return 1
}  
