require 'nitro/controller'
require 'nitro/server/runner'

module Nitro

class Server

  # The server listening address. 

  setting :address, :default => '0.0.0.0', :doc => 'The server listening address'

  # The server listening port.

  setting :port, :default => 9999, :doc => 'The server listening port'

  # The map.
  
  setting :map, :default => { '/' => Controller }, :doc => 'The server map'

  # The public files root directory.
  
  setting :public_root, :default => 'public', :doc => 'The public files root directory'

  # The access log, can be a path to a file or an IO object.
  
  setting :access_log, :default => nil, :doc => 'The access log'

  # Additional server options. Useful to pass options to 
  # Webrick for example.
  
  setting :options, :default => {}, :doc => "Additional server options"

  # The name of the application.

  attr_accessor :name
  
  # The sitemap. Defines how controller objects are published.
  
  attr_accessor :map

  # The public files root directory.
  
  attr_accessor :public_root

  # The server listening address. 

  attr_accessor :address

  # The server listening port.

  attr_accessor :port

  # The dispatcher
  
  attr_accessor :dispatcher

  # Additional server options. Useful to pass options to 
  # Webrick for example.
  
  attr_accessor :options  

  # The access_log for this server, used by Webrick.

  attr_accessor :access_log   

  def initialize(name = 'Nitro', options = {})
    @name = name
    @map = self.class.map.dup
    @address, @port = self.class.address, self.class.port
    @public_root = self.class.public_root
    @access_log = self.class.access_log
    @options = self.class.options.dup
    @options.update(options)
  end
  
  # Return the dispatcher.
  
  def dispatcher
    unless @dispatcher
      @dispatcher = Dispatcher.new(self.map)
    end
    @dispatcher
  end
  
  # Start the server.
  
  def start(options = {})    
    @map['/'] = options[:controller] if options[:controller]
    @dispatcher = options[:dispatcher] || Dispatcher.new(@map)
    return self
  end

  def root=(controller)
    @map['/'] = controller
  end
  
  def root
    Mounter.new(self)
  end

  # Helper method.
  #
  # Available options: 
  #
  # :dispatcher, :controller
  #
  # Altetnatively you can pass a single Controller class instead
  # of the options hash.

  def self.run(options = {})
    unless options.is_a?(Hash)
      options = { :controller => options }
    end
    
    runner = Runner.new
    runner.setup_options
    runner.setup_mode
    runner.daemonize if runner.daemon  
    
    server = Server.new
    server.start(options)
    
    runner.invoke(server) unless $NITRO_NO_INVOKE 
    
    return server
  end

  # A Helper class used for CherryPy-style publishing.
  
  class Mounter # :nodoc: all
    def initialize(parent, base = '')
      @parent, @base = parent, base
    end
    
    def method_missing(sym, *args)
      sym = sym.to_s
      if sym =~ /=$/
        @parent.map["#@base/#{sym.gsub(/=/, '')}"] = args.first
      else
        Mounter.new(@parent, "#@base/#{sym}")
      end
    end
  end
    
end

end

# Alias for the Server class.

App = Nitro::Server unless Object.const_defined?(:App)