#!/usr/bin/env ruby

# Timer Daemon

# $Id: timer.rb,v 1.9 2002/05/20 16:40:47 makeinu Exp $

# 2002/4/30  Ken-ichi HASHIMOTO <ken@po.ganseki.ne.jp>
# Copyright (C) 2002 Ken-ichi HASHIMOTO <ken@po.ganseki.ne.jp>
# This is free software with ABSOLUTELY NO WARRANTY.

# 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, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.


require "thread"
require "socket"

class SharedInformation
	 def initialize
			@starttime		= nil				#Time
			@endtime			= nil				#Time
			@recordingime = nil				#Int
			@command			= ""				#String
			@pid					= nil				#Int
			@state				= nil				#Bool
	 end

	 # attr_reader :starttime 		 #Time
	 # attr_reader :endtime 			 #Time
	 # attr_reader :recordingtime  #Int
	 attr_accessor :starttime 		 #Time
	 attr_accessor :endtime 			 #Time
	 attr_accessor :recordingtime  #Int
	 attr_accessor :command 			 #String
	 attr_accessor :pid 					 #Int
	 attr_accessor :state 				 #Bool

	 def setStarttime (aTime)
			@starttime = aTime
			calcRecTime()
	 end

	 def setEndtime (aTime)
			@endtime = aTime
			calcRecTime()
	 end

	 def setRectime (aTime)
			@recordingtime = aTime
	 end

	 # FIXME!!
	 def calcRecTime ()
			if @starttime && @endtime then
				 the_time = Time.now < starttime ? starttime : Time.now
				 @recordingtime = @endtime.to_i - the_time.to_i
			end
	 end
end

class System
	def debugPrint(aString)
	# 	puts aString
	# 	STDOUT.flush
	end
	def printUsage()
		 printf "Usage : %s <start time> <end time> <command>\n", $0
		 printf "  start time: time to start command\n"
		 printf "    end time: time to end command\n"
		 printf "     command: command to be executed\n"
	end

	def checkArgs()
		if !ARGV[0] || !ARGV[1] || !ARGV[2] then
			 printUsage ()
			 exit
		end
	end


	def run()
		###############################################################################
		#
		# 	Initialize
		#
		###############################################################################
		## check args

		checkArgs()

		$sharedInformation = SharedInformation.new
		$sharedInformation.state = true

		# get time
		$sharedInformation.starttime = convertToTimeFrom(ARGV[0])
		$sharedInformation.endtime   = convertToTimeFrom(ARGV[1])
		if !$sharedInformation.starttime || !$sharedInformation.endtime then
			printUsage ()
			exit
		end

		if $sharedInformation.starttime > $sharedInformation.endtime then
			printf "starttime = #{$sharedInformation.starttime}\n"
			printf "endttime  = #{$sharedInformation.endtime}\n"
			printf "Go home!! XD\n"
			exit
		end

		if $sharedInformation.endtime < Time.now then
			printf "endttime  = #{$sharedInformation.endtime}\n"
			printf "Now       = #{Time.now}\n"
			printf "Already ended\n"
			exit
		end

		$sharedInformation.calcRecTime

		# get command string
		$sharedInformation.command = ""

		for i in 2..(ARGV.length - 1)
			 $sharedInformation.command += ARGV[i] + " "
		end

		@mutex  = Mutex.new
		@timer  = nil
		@server = nil

		main
	end

	def main()
		startTimer		# thread create in this function
		startServer		# this code contain loop. Then this code is blocked
	end


	###############################################################################
	#
	# 	Timer Proccess
	#
	###############################################################################


	def waitStart
		loop do
			now = Time.now
			st = $sharedInformation.starttime

			if (now > st) then
				debugPrint ("Start #{now}")
				$sharedInformation.pid = Process::fork do
					## new process(child)
					command = $sharedInformation.command
					exec command
					## Here does not reach.
					## Because EXEC.
				end
				return
			end

			sleep 1

			debugPrint ("waiting start")
		end
	end

	def waitEnd()
		loop do
			now = Time.now.to_i
			rectime = $sharedInformation.recordingtime
			st = $sharedInformation.starttime.to_i
			debugPrint ("now = #{now} : endtime = #{st + rectime}")

			if (now > (st + rectime)) then
				debugPrint ("End")

				@mutex.synchronize do
					$sharedInformation.state = false
					Process::kill ("SIGINT", $sharedInformation.pid)
				end

				if @server then
					@server.shutdown
				end

				Proccess::waitpid($sharedInformation.pid)

				return
			end

			sleep 1

			debugPrint("waiting end")
		end
	end

	def startTimer()
		print "Now #{Time.now}\n"
		print "will start #{$sharedInformation.starttime}\n"

		## Cretate New thread.
		@timer = Thread.new do
			waitStart		# Long running function
			st = $sharedInformation.starttime.to_i
			waitEnd			# Long running function
			exit
		end
		
	end

	###############################################################################
	#
	# 	Server Process
	#
	###############################################################################
	def startServer()
		@server = TCPServer.open(10000)
		#socks = [gs]
		#addr = gs.addr
		#addr.shift
		#print ("server is on %d\n", addr.join(":"))


		debugPrint("loop")

		while $sharedInformation.state do
			Thread.new (@server.accept) do |s| 
				debugPrint( "connected" )
				s.write ("Wellcome to Video server\r\n")
				s.flush

				while s.gets do 
					debugPrint( "#{$_}" )

					case $_
					when /^status/
						printStatus (s)

					when /^starttime/
						printStatus (s)

					when /^rectime\s+(\d+)/
						s.write ("set rectime=#{$1}\r\n")
						@mutex.synchronize do
							 $sharedInformation.recordingtime = $1.to_i
						end
						printstatus (s)

					else
						s.write ("Error #{$_}")
					end
				end

				print (s, "Goodbye\n")

				s.close
			end
		end
	end

	def printStatus( aSocket )
		info = $sharedInformation
		aSocket.write ( "starttime = #{info.starttime}\r\n" )
		aSocket.write ( "endttime  = #{info.endtime}\r\n" )
		aSocket.write ( "recordingtime = #{info.recordingtime}\r\n" )
	end


	def convertToTimeFrom(aString)
		unless aString then
			return nil
		end

		# SS:MM:HH:DD:MM:YY
		if (aString =~ /(\d+):(\d+):(\d+):(\d+):(\d+):(\d+)/)
			return Time.local ($6, $5.to_i, $4.to_i,$3.to_i, $2.to_i, $1.to_i)
		 else
			return nil
		 end
	end
end

theSystem = System.new
theSystem.run
