#!/usr/bin/env ruby
#
# $Id: find_slot,v 1.12 2004/12/14 03:13:56 ianmacd Exp $
#
# simple program to find the first free slot on a given agenda
#
# Copyright (C) 2002-2004 Ian Macdonald
#
#   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, 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.

begin
  require 'password'
rescue LoadError
  $stderr.puts "This program requires Ruby/Password: http://www.caliban.org/ruby/"
  exit 1
end

require 'ctime'
require 'date'
require 'getoptlong'

def usage(code = 0)
  prog_name = File::basename($0)
  $stderr.print "
Usage: #{prog_name} [-d|--duration <duration>] <agenda>
       #{prog_name} -h|--help

-d, --duration    find a slot for at least this number of minutes (default: 60)
-h, --help        show this usage message
"
  exit code
end

server = nil; line_nr = __LINE__
user = nil
passwd = nil

duration = 60

dot_mycal = ENV['HOME'] + '/.mycal'

if File.stat(dot_mycal).mode & 2 == 2
  $stderr.printf("%s is world-writable. Please fix this.\n", dot_mycal)
  exit 1
end

if FileTest.readable?(dot_mycal)
  File.open(dot_mycal) do |file|
    while line = file.gets
      eval line
    end
  end
end

if server.nil?
  $stderr.puts "Please define a CorporateTime server in either line " +
	       "#{line_nr} of this program or in a ~/.mycal file."
  exit 1
end

opt = GetoptLong.new(
  ['--duration',	'-d', GetoptLong::REQUIRED_ARGUMENT],
  ['--help',		'-h', GetoptLong::NO_ARGUMENT])

begin
  opt.each_option do |name,arg|
    case name
    when '--duration'
      duration = arg.to_i
    when '--help'
      usage
    end
  end
rescue
  usage 1
end

agenda = ARGV[0]
usage 1 if agenda.nil?

user ||= ( print "Username: "; gets.chomp )
passwd ||= Password.getc("Calendar password: ")

start_date = Time.now
end_date = start_date + 86400 * 60 # search the next 60 days

CTime.new.connect(server, user, passwd) do |ct|

  ct.open_agenda(agenda) do |ag|
    puts "Fetching agenda..."
    end_time = start_date

    ag.get_events(start_date, end_date) do |e|

      start_time = e.start_time

      if (end_time + duration * 60) <= start_time &&
         end_time.localtime.wday != 0 && end_time.localtime.wday != 6

        printf("The next available %d minute slot is on\n%s", duration,
        end_time.localtime.strftime("%A, %B %d, %Y at %H:%M"))

        print "\nBook it, keep looking or quit? (b/l/q) "
        response = $stdin.gets.chomp

        exit if response =~ /^q/i

        if response !~ /^b/i
          end_time += duration * 60
          puts
          redo
        end

        massage = CTime::Agenda::Event.new(end_time, duration * 60,
    				       "Massage for " + user, nil, nil)

        u = ct.open_agenda(user)
        if u.set_event(massage)
          puts "Booked!"
          ct.quit

          exit 0
        else
          puts "Booking failed!"
          ct.quit

          exit 1
        end

      end

      new_end_time = e.end_time

      if new_end_time > end_time
        end_time = new_end_time
      end

    end

    printf("I didn't look any further than %s\n",
           end_time.localtime.strftime("%A, %B %d, %Y"))

  end
end
