#!/usr/bin/env ruby -w
# encoding: UTF-8
#
# = DaemonConnector.rb -- The TaskJuggler III Project Management Software
#
# Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014
#               by Chris Schlaeger <cs@taskjuggler.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of version 2 of the GNU General Public License as
# published by the Free Software Foundation.
#

require 'drb'
require 'drb/acl'
require 'taskjuggler/MessageHandler'

class TaskJuggler

  module DaemonConnectorMixin

    include MessageHandler

    def connectDaemon
      unless @authKey
        error('missing_auth_key', <<'EOT'
You must set an authentication key in the configuration file. Create a file
named .taskjugglerrc or taskjuggler.rc that contains at least the following
lines. Replace 'your_secret_key' with some random character sequence.

_global:
  authKey: your_secret_key
EOT
             )
      end

      uri = "druby://#{@host}:#{@port}"
      if @port == 0
        # If the @port is configured to 0, we need to read the URI to connect
        # to the server from the .tj3d.uri file that has been generated by the
        # server.
        begin
          uri = File.read(@uriFile).chomp
        rescue
          error('tjc_port_0',
                'The server port is configured to be 0, but no ' +
                ".tj3d.uri file can be found: #{$!}")
        end
      end
      debug('', "DRb URI determined as #{uri}")

      # We try to play it safe here. The client also starts a DRb server, so
      # we need to make sure it's constricted to localhost only. We require
      # the DRb server for the standard IO redirection to work.
      $SAFE = 1 unless @unsafeMode
      DRb.install_acl(ACL.new(%w[ deny all
                                  allow 127.0.0.1 ]))
      DRb.start_service('druby://127.0.0.1:0')
      debug('', 'DRb service started')

      broker = nil
      begin
        # Get the ProjectBroker object from the tj3d.
        broker = DRbObject.new_with_uri(uri)
        # Client and server should always come from the same Gem. Since we
        # restict communication to localhost, that's probably not a problem.
        if (check = broker.apiVersion(@authKey, 1)) < 0
          error('tjc_too_old',
                'This client is too old for the server. Please ' +
                'upgrade to a more recent version of the software.')
        elsif check == 0
          error('tjc_auth_fail',
                'Authentication failed. Please check your authentication ' +
                'key to match the server key.')
        end
        debug('', "Connection with report broker on #{uri} established")
      rescue => e
        # If we ended up here due to a previously reported TjRuntimeError, we
        # just pass it through.
        if e.is_a?(TjRuntimeError)
          raise TjRuntimeError, $!
        end
        error('tjc_srv_not_responding',
              "TaskJuggler server (tj3d) on URI '#{uri}' is not " +
              "responding:\n#{$!}")
      end

      broker
    end

    def disconnectDaemon
      DRb.stop_service
    end

  end

  class DaemonConnector

    include DaemonConnectorMixin

    def initialize(authKey, host, port, uri)
      @authKey = authKey
      @host = host
      @port = port
      @uri = uri
      @unsafeMode = true

      @broker = connectDaemon
    end

    def disconnect
      disconnectDaemon
      @broker = nil
    end

    def getProject(projectId)
      @broker.getProject(@authKey, projectId)
    end

    def getProjectList
      @broker.getProjectList(@authKey)
    end

  end

end

