#!/usr/bin/env jruby
if ARGV.include?("--quiet")
  STDIN.reopen("/dev/null", "r")
  STDOUT.reopen("/dev/null", "w")
  STDERR.reopen("/dev/null", "w")
end
require 'rubygems'
require 'rubygems/gem_runner'
require 'rubygems/exceptions'
#
module Gem::UserInteraction
  def terminate_interaction(exit_code = 0)
		# Suppress the instruction to exit ruby:
		# ui.terminate_interaction exit_code
  end
end
#
class Object
	private
	def gem_command(commands=nil)
		if commands.is_a?(::String)
			Gem::GemRunner.new.run commands.split(" ")
		end
	end
	public
end
#
require 'gxg-framework'
# ### Define Directory Layout for Server
::GxG::SYSTEM.gxg_root = File.expand_path("../",File.dirname(__FILE__))
module GxG
  # Define Server directories, ensure directories are present
  SYSTEM_PATHS = ::GxG::SYSTEM.server_paths()
end
::GxG::SYSTEM_PATHS.values.each do |a_path|
  if a_path
    unless Dir.exist?(a_path)
      begin
        FileUtils.mkpath(a_path)
      rescue Exception => error
        log_error({:error => error, :parameters => a_path})
      end
    end
  end
end
# Ensure specs dir is present
if Dir.exist?(GxG::SYSTEM_PATHS[:gems])
  unless Dir.exist?("#{GxG::SYSTEM_PATHS[:gems]}/specs")
    begin
      FileUtils.mkpath("#{GxG::SYSTEM_PATHS[:gems]}/specs")
    rescue Exception => error
      log_error({:error => error, :parameters => "#{GxG::SYSTEM_PATHS[:gems]}/specs"})
    end
  end
else
  begin
    FileUtils.mkpath("#{GxG::SYSTEM_PATHS[:gems]}/specs")
  rescue Exception => error
    log_error({:error => error, :parameters => "#{GxG::SYSTEM_PATHS[:gems]}/specs"})
  end
end
# Setup Rubygems paths
ENV['GEM_HOME']=GxG::SYSTEM_PATHS[:gems]
ENV['GEM_SPEC_CACHE']="#{GxG::SYSTEM_PATHS[:gems]}/specs"
ENV['GEM_PATH']=[(GxG::SYSTEM_PATHS[:gems]), (Gem.paths.path)].flatten.join(":")
Gem.clear_paths
Gem.paths = ENV
#
class Object
	private
	def gem_install(gem_name=nil,version_info=nil)
		if gem_name.is_any?(::String, ::Symbol) && version_info.is_any?(::String, ::NilClass)
			if version_info
        gem_command("install --install-dir #{GxG::SYSTEM_PATHS[:gems]} --version #{version_info.to_s} #{gem_name.to_s}")
      else
        gem_command("install --install-dir #{GxG::SYSTEM_PATHS[:gems]} #{gem_name.to_s}")
      end
    else
      raise Exception, "Invalid gem or version specifier"
    end
	end
	public
end
# ### Mount Databases by role
if ::File.exist?("#{::GxG::SYSTEM_PATHS[:configuration]}/databases.json")
    handle = ::File.open("#{::GxG::SYSTEM_PATHS[:configuration]}/databases.json", "rb")
    db_config = ::JSON::parse(handle.read(), {:symbolize_names => true})
    handle.close
    # ### Set DB Roles, and other details
    ::GxG::DB[:roles] = {}
    if db_config[:databases].is_a?(::Array)
      #
      mounted = []
      db_config[:databases].each do |entry|
        entry[:roles].each do |the_role|
          if the_role.downcase == "users"
            #
            if ::URI::parse(entry[:url]).scheme.downcase == "ldap"
              # TODO: ExternalAuthority
              mounted << {:url => entry[:url].to_s, :db => nil, :roles => [:user]}
            else
              if ::URI::parse(entry[:url]).scheme.downcase == "sqlite"
                  if ::URI::parse(entry[:url]).hostname.to_s[0] == "/" || ::URI::parse(entry[:url]).path.to_s[0] == "/"
                      # absolute path
                      the_db_url = entry[:url]
                  else
                      # relative path
                      the_db_url = "sqlite://#{GxG::SYSTEM_PATHS[:databases]}/#{::URI::parse(entry[:url]).hostname}"
                  end
              else
                  the_db_url = entry[:url]
              end
              the_db = ::GxG::Database::connect(the_db_url)
              if the_db
                the_db.clear_all_element_locks
                the_db.empty_trash
                ::GxG::DB[:authority] = the_db
                ::GxG::DB[:roles][:users] = ::GxG::DB[:authority]
                mounted << {:url => entry[:url].to_s, :db => the_db, :roles => [:users]}
                break
              end
            end
            #
          end
        end
        if ::GxG::DB[:authority].is_any?(::GxG::Database::Database, ::GxG::Database::ExternalAuthority)
          break
        end
      end
      #
      if ::GxG::DB[:authority].is_any?(::GxG::Database::Database, ::GxG::Database::ExternalAuthority)
        db_config[:databases].each do |entry|
          log_info "Mounting or creating a database ..."
          if (mounted.map {|item| item[:url]}).include?(entry[:url].to_s)
            # Flesh out other roles : {:url => entry[:url].to_s, :db => the_db, :roles => [:user]}            
            mounted.each do |the_mount|
              #
              if entry[:url] == the_mount[:url]
                entry[:roles].each do |the_role|
                  unless the_mount[:roles].include?(the_role)
                    ::GxG::DB[:roles][(the_role.to_sym)] = the_mount[:db]
                    the_mount[:roles] << the_role.to_sym
                  end
                end
              end
              #
            end
          else
            # Mount fresh
            if ::URI::parse(entry[:url]).scheme.downcase == "sqlite"
                if ::URI::parse(entry[:url]).hostname.to_s[0] == "/" || ::URI::parse(entry[:url]).path.to_s[0] == "/"
                    # absolute path
                    the_db_url = entry[:url]
                else
                    # relative path
                    the_db_url = "sqlite://#{GxG::SYSTEM_PATHS[:databases]}/#{::URI::parse(entry[:url]).hostname}"
                end
            else
                the_db_url = entry[:url]
            end
            the_db = ::GxG::Database::connect(the_db_url, {:authority => ::GxG::DB[:authority]})
            if the_db
              # house cleaning:
              the_db.clear_all_element_locks
              the_db.empty_trash
              mounted_roles = []              
              entry[:roles].each do |the_role|
                unless ::GxG::DB[:roles][(the_role.to_sym)]
                  ::GxG::DB[:roles][(the_role.to_sym)] = the_db
                  mounted_roles << the_role.to_sym
                end
              end
              mounted << {:url => entry[:url].to_s, :db => the_db, :roles => mounted_roles}
            end
            #
          end
        end
      else
        # Error - no authority db found, unable to proceed.
        log_error "No Authority Database Found : Unable to proceed."
        exit 1
      end
      #
      unless ::GxG::DB[:roles][:formats].is_a?(::GxG::Database::Database)
        # Error - no format db found, unable to proceed.
        log_error "No Format Database Found : Unable to proceed."
        exit 1
      end
      #
    end
    # Set Administrator/Members credential for system use.
    ::GxG::DB[:administrator] = ::GxG::DB[:authority][:system_credentials][:administrator]
    ::GxG::DB[:administrators] = ::GxG::DB[:authority][:system_credentials][:administrators]
    ::GxG::DB[:developers] = ::GxG::DB[:authority][:system_credentials][:developers]
    ::GxG::DB[:designers] = ::GxG::DB[:authority][:system_credentials][:designers]
    ::GxG::DB[:users] = ::GxG::DB[:authority][:system_credentials][:users]
else
    log_warn "No Database Configuration found: run setup.rb from the shell."
end
# ### Populate the Mandatory VFS with GxG::SYSTEM_PATHS
::GxG::VFS.mount(::GxG::Storage::Volume.new({:directory => ::GxG::SYSTEM_PATHS[:system]}), "/System")
::GxG::VFS.mount(::GxG::Storage::Volume.new({:directory => ::GxG::SYSTEM_PATHS[:services]}), "/Services")
::GxG::VFS.mount(::GxG::Storage::Volume.new({:directory => ::GxG::SYSTEM_PATHS[:installers]}), "/Installers")
::GxG::VFS.mount(::GxG::Storage::Volume.new({:directory => ::GxG::SYSTEM_PATHS[:temporary]}), "/Temporary")
::GxG::VFS.mount(::GxG::Storage::Volume.new({:directory => ::GxG::SYSTEM_PATHS[:logs]}), "/Logs")
::GxG::VFS.mount(::GxG::Storage::Volume.new({:directory => ::GxG::SYSTEM_PATHS[:public]}), "/Public")
# Populate Optional VFS mount points
if GxG::valid_uuid?(GxG::DB[:administrator])
    if File.exist?("#{GxG::SYSTEM_PATHS[:configuration]}/mounts.json")
        handle = File.open("#{GxG::SYSTEM_PATHS[:configuration]}/mounts.json", "rb")
        mount_config = ::JSON::parse(handle.read(), {:symbolize_names => true})
        handle.close
        #
        volume = nil
        mount_config[:mount_points].each do |entry|
            if entry[:db_role]
                the_db = ::GxG::DB[:roles][(entry[:db_role].to_sym)]
                if the_db
                  volume = ::GxG::Storage::Volume.new({:database => the_db, :credential => GxG::DB[:administrator]})
                end
            end
            if entry[:file_system]
              if ["./", ".."].include?(entry[:file_system][0..1])
                # Relative Path - to GXGROOT
                fs_path = File.expand_path(entry[:file_system],::GxG::SYSTEM.gxg_root())
              else
                # Absolute Path
                fs_path = entry[:file_system]
              end
              unless Dir.exist?(fs_path)
                  FileUtils.mkdir_p(fs_path)
              end
              if entry[:path] == "/Users"
                ::GxG::SYSTEM_PATHS[:users] = fs_path
                unless Dir.exist?(fs_path + "/Shared")
                    FileUtils.mkdir_p((fs_path + "/Shared"))
                end
              else
                ::GxG::SYSTEM_PATHS[(File.basename(entry[:path]).downcase.to_sym)] = fs_path 
              end
              volume = ::GxG::Storage::Volume.new({:directory => fs_path})
            end
            if volume
              GxG::VFS.mount(volume, entry[:path])
              volume = nil
            end
        end
    else
        log_warn "No VFS Optional Configuration found: run setup.rb from the shell."
    end
end
# ### Services Framework
module GxG
  SERVICES = {}
  module Services
    # ### Service Management
    def self.start_order()
      # Calculate service startup order based upon interdepenedencies
      # Review : Research a REAL dep tree calculator - See: https://stackoverflow.com/questions/21108109/how-do-i-find-out-all-the-dependencies-of-a-gem
      deps = {}
      ::GxG::SERVICES.each_pair do |moniker, service|
        unless moniker == :core
          unless deps[(moniker)]
            deps[(moniker)] = 0
          end
          service.required_services().each do |the_dep|
            if deps[(the_dep.to_sym)]
              deps[(the_dep.to_sym)] -= 1
            else
              deps[(the_dep.to_sym)] = 0
            end
          end
        end
      end
      boot_queue = []
      (deps.sort_by {|key,value| value}).to_h.keys.each do |the_service_moniker|
        ::GxG::SERVICES[(the_service_moniker)].required_services.each do |moniker|
          unless boot_queue.include?(moniker)
            boot_queue << moniker
          end
        end
        unless boot_queue.include?(the_service_moniker)
          boot_queue << the_service_moniker
        end
      end
      #
      boot_queue
    end
    #
    def self.stop_order()
      ::GxG::Services::start_order().reverse!
    end
    #
    def self.start_service(moniker=nil)
      if moniker.is_a?(::Symbol)
        if ::GxG::SERVICES[(moniker)]
          # ::GxG::SERVICES[(moniker)].start
          ::GxG::SERVICES[(moniker)].call_event({:start => nil})
        end
      end
    end
    #
    def self.stop_service(moniker=nil)
      if moniker.is_a?(::Symbol)
        if ::GxG::SERVICES[(moniker)]
          # ::GxG::SERVICES[(moniker)].stop
          ::GxG::SERVICES[(moniker)].call_event({:stop => nil})
        end
      end
    end
    #
    def self.install_service(moniker=nil)
      if moniker.is_a?(::Symbol)
        configuration = ::GxG::SERVICES[:core].configuration
        unless configuration[:available].is_a?(::Array)
          configuration[:available] = []
        end
        unless configuration[:available].include?(moniker.to_s)
          configuration[:available] << moniker.to_s
        end
        ::GxG::SERVICES[:core].save_configuration
        #
        true
      else
        false
      end
    end
    #
    def self.service_available?(moniker=nil)
      if moniker.is_a?(::Symbol)
        configuration = ::GxG::SERVICES[:core].configuration
        if configuration[:available].is_a?(::Array)
          if configuration[:available].include?(moniker.to_s)
            true
          else
            false
          end
        else
          false
        end
      else
        false
      end
    end
    #
    def self.enable_service(moniker=nil)
      if moniker.is_a?(::Symbol)
        configuration = ::GxG::SERVICES[:core].configuration
        unless configuration[:disabled].is_a?(::Array)
          configuration[:disabled] = []
        end
        unless configuration[:enabled].is_a?(::Array)
          configuration[:enabled] = []
        end
        if configuration[:disabled].include?(moniker.to_s)
          configuration[:disabled].delete_at(configuration[:enabled].find_index(moniker.to_s))
        end
        unless configuration[:enabled].include?(moniker.to_s)
          configuration[:enabled] << moniker.to_s
        end
        ::GxG::SERVICES[:core].save_configuration
        #
        true
      else
        false
      end
      #
    end
    #
    def self.disable_service(moniker=nil)
      if moniker.is_a?(::Symbol)
        configuration = ::GxG::SERVICES[:core].configuration
        unless configuration[:disabled].is_a?(::Array)
          configuration[:disabled] = []
        end
        unless configuration[:enabled].is_a?(::Array)
          configuration[:enabled] = []
        end
        if configuration[:enabled].include?(moniker.to_s)
          configuration[:enabled].delete_at(configuration[:enabled].find_index(moniker.to_s))
        end
        unless configuration[:disabled].include?(moniker.to_s)
          configuration[:disabled] << moniker.to_s
        end
        ::GxG::SERVICES[:core].save_configuration
        #
        true
      else
        false
      end
    end
    #
    def self.register_service(moniker=:unspecified, service_harness=nil)
      if moniker
        unless moniker == :unspecified
          if service_harness.is_a?(GxG::Services::Service)
            GxG::SERVICES[(moniker)] = service_harness
          end
        end
      end
    end
    # ### Service Class Definition
    class Service
      # Class-level toolbox:
      # Instance toolbox:
      def initialize(moniker=:unspecified, options={:event_interval => 0.333})
        if moniker.is_a?(::Symbol)
          if moniker == :unspecified || (::GxG::SERVICES[:core] && moniker == :core)
            raise Exception, "You MUST provide a unique, specific Symbol as your service moniker. This becomes the system-wide service name other services will need provided."
          else
            # Service Initialization code
            @provides = moniker
            @requirements = [:core]
            @thread_safety = ::Mutex.new
            @heap = {}
            @status = :stopped
            @state = nil
            @configuration = {}
            @dispatcher = ::GxG::Events::EventDispatcher.new((options[:event_interval] || 0.333))
            @interface = {}
            #
            self.load_configuration
            #
            self.on(:interface, {:description => "Available Commands", :usage => "{ :interface => nil }", :public => true}) do
              self.interface()
            end
            #
            ::GxG::Services::register_service(moniker, self)
            #
          end
        else
          raise Exception, "You MUST provide a unique service name as a Symbol for your service moniker."
        end
        self
      end
      #
      def inspect()
        "<Service #{@provides.inspect}>"
      end
      # ### FS & VFS
      def vfs_root()
        if @provides == :core
          "/Services"
        else
          "/Services/#{@provides.to_s}"
        end
      end
      #
      def fs_root()
        ::File.expand_path("#{::GxG::SYSTEM.gxg_root()}/#{self.vfs_root()}")
      end
      # ### API Support
      def publish_route(the_method=:get, path="", options={}, &block)
        if ::GxG::Services::service_available?(:www)
          ::GxG::SERVICES[:www].call_event({:publish_route => {:http_method => the_method, :path => path, :options => options, :code => block}}, ::GxG::DB[:administrator])
        end
      end
      #
      def publish_api()
        if ::GxG::Services::service_available?(:www)
          ::GxG::SERVICES[:www].call_event({:publish_api => {:service => self, :path => "/#{@provides.to_s}"}}, ::GxG::DB[:administrator])
        end
      end
      #
      def unpublish_api()
        if ::GxG::Services::service_available?(:www)
          ::GxG::SERVICES[:www].call_event({:unpublish_api => {:path => "/#{@provides.to_s}"}}, ::GxG::DB[:administrator])
        end
      end
      # ### Service Management
      def provides()
        @provides
      end
      #
      def required_services()
        @requirements.clone
      end
      #
      def require_service(moniker=:unspecified)
        if moniker.is_a?(::Symbol)
          unless moniker == :unspecified
            unless @requirements.include?(moniker)
              @requirements << moniker
            end
          end
        end
      end
      # ### Configuration Management
      def configuration()
        @configuration
      end
      #
      def save_configuration(options={})
        result = false
        config_path = ::File.expand_path(::GxG::SYSTEM_PATHS[:configuration] + "/" + "#{@provides.to_s}.json")
        if File.exist?(config_path)
          File.delete(config_path)
        end
        begin
          handle = File.open(config_path, "w+b", 0664)
          handle.write(::JSON::pretty_generate(@configuration))
          handle.close
          result = true
        rescue Exception => the_error
          log_warn("Failed to save configuration for #{@provides.inspect} --> #{the_error.to_s}")
        end
        result
      end
      #
      def load_configuration(options={})
        result = false
        config_path = ::File.expand_path(::GxG::SYSTEM_PATHS[:configuration] + "/" + "#{@provides.to_s}.json")
        if File.exist?(config_path)
          handle = File.open(config_path, "rb", 0664)
          begin
            @configuration =::JSON::parse(handle.read(), {:symbolize_names => true})
            result = true
          rescue Exception => the_error
            log_warn("Failed to load configuration for #{@provides.inspect} --> #{the_error.to_s}")
          end
          handle.close
          #
          if result == true
            if ::GxG::valid_uuid?(@configuration[:state_uuid])
              unless @state.is_a?(::GxG::Database::PersistedHash)
                @state = ::GxG::DB[:roles][:data].retrieve_by_uuid(@configuration[:state_uuid].to_s.to_sym, ::GxG::DB[:administrator])
                if @state.is_a?(::GxG::Database::PersistedHash)
                  @state.get_reservation
                else
                  # This means the db was blown out and this must be reconstructed.
                  @state = ::GxG::DB[:roles][:data].try_persist({}, ::GxG::DB[:administrator])
                  @state.get_reservation
                  @state.set_title("#{@provides.to_s} State Data")
                  @state.save
                  @configuration[:state_uuid] = @state.uuid.to_s
                end
              end
            else
              orphaned_state_record = GxG::DB[:roles][:data].uuid_list(GxG::DB[:administrator],{:title => "#{@provides.to_s} State Data"}).first
              if orphaned_state_record
                @state = ::GxG::DB[:roles][:data].retrieve_by_uuid((orphaned_state_record[:uuid]),::GxG::DB[:administrator])
              end
              unless @state.is_a?(::GxG::Database::PersistedHash)
                @state = ::GxG::DB[:roles][:data].try_persist({}, ::GxG::DB[:administrator])
                @state.get_reservation
                @state.set_title("#{@provides.to_s} State Data")
                @state.save
              end
              @configuration[:state_uuid] = @state.uuid.to_s
            end
          end
        else
          if @state.is_a?(::GxG::Database::PersistedHash)
            unless ::GxG::valid_uuid?(@configuration[:state_uuid])
              @configuration[:state_uuid] = @state.uuid.to_s
            end
          else
            if ::GxG::valid_uuid?(@configuration[:state_uuid])
              @state = ::GxG::DB[:roles][:data].retrieve_by_uuid(@configuration[:state_uuid].to_s.to_sym, ::GxG::DB[:administrator])
              @state.get_reservation
            else
              orphaned_state_record = GxG::DB[:roles][:data].uuid_list(GxG::DB[:administrator],{:title => "#{@provides.to_s} State Data"}).first
              if orphaned_state_record
                @state = ::GxG::DB[:roles][:data].retrieve_by_uuid((orphaned_state_record[:uuid]),::GxG::DB[:administrator])
              end
              unless @state.is_a?(::GxG::Database::PersistedHash)
                @state = ::GxG::DB[:roles][:data].try_persist({}, ::GxG::DB[:administrator])
                @state.get_reservation
                @state.set_title("#{@provides.to_s} State Data")
                @state.save
              end
              @configuration[:state_uuid] = @state.uuid.to_s
            end
          end
          self.save_configuration
          result = true
        end
        result
      end
      # ### Heap & State Data
      def keys()
        @thread_safety.synchronize { @heap.keys }
      end
      #
      def [](key=nil)
        if key.is_any?(::String, ::Symbol)
          @thread_safety.synchronize { @heap[(key)] }
        else
          nil
        end
      end
      #
      def []=(key=nil,value=nil)
        if key.is_any?(::String, ::Symbol)
          @thread_safety.synchronize { @heap[(key)] = value }
        else
          nil
        end
      end
      #
      def delete(key=nil)
        if key.is_any?(::String, ::Symbol)
          @thread_safety.synchronize { @heap.delete(key) }
        else
          nil
        end
      end
      #
      def state_keys()
        @state.keys()
      end
      #
      def state_get(state_key=nil)
        result = nil
        if state_key.is_a?(::Symbol)
          if @state.is_a?(::GxG::Database::PersistedHash)
            result = @state[(state_key)]
          end
        end
        result
      end
      #
      def state_set(state_key=nil, state_value=nil)
        if state_key.is_a?(::Symbol)
          if @state.is_a?(::GxG::Database::PersistedHash)
            @state[(state_key)] = state_value
            @state.save
          end
        end
      end
      #
      def state_delete(key)
        result = nil
        if state_key.is_a?(::Symbol)
          if @state.is_a?(::GxG::Database::PersistedHash)
            result = @state.delete(state_key)
          end
        end
        result
      end
      # ### Activity and Status Management
      def is_running?()
        @status == :running || @status == :paused
      end
      #
      def status()
        @status
      end
      #
      def start(options={:timeout => 30000.0})
        # start entire service, load configuration
        @status = :starting
        if self.load_configuration() == true
          timeout = Time.now.to_f + (options[:timeout] || 30000.0)
          all_loaded = false
          #
          if @provides == :core
            all_loaded = true
          else
            # wait until all requirements load until timeout
            requirement_count = @requirements.size
            while (Time.now.to_f < timeout) do
              started_count = 0
              @requirements.each do |moniker|
                if ::GxG::SERVICES[(moniker)].is_running? == true
                  started_count += 1
                end
              end
              if requirement_count == started_count
                all_loaded = true
                break
              else
                sleep 1.0
              end
            end
            unless all_loaded == true
              log_warn("Aborted service startup for #{@provides.inspect} because other required services did not start in time.")
            end
          end
          #
          if all_loaded == true
            if self.respond_to_event?(:before_start)
              self.call_event({:before_start => self}, ::GxG::DB[:administrator])
            end
            # start event dispatcher
            @dispatcher.startup
            @status = :running
            if self.respond_to_event?(:at_start)
              self.call_event({:at_start => self}, ::GxG::DB[:administrator])
            end
            if self.respond_to_event?(:after_start)
              self.call_event({:after_start => self}, ::GxG::DB[:administrator])
            end
            true
          else
            @status = :stopped
            false
          end
          #
        else
          @status = :stopped
          false
        end
        #
      end
      #
      def stop(options={})
        # stop entire service
        if self.respond_to_event?(:before_stop)
          self.call_event({:before_stop => self}, ::GxG::DB[:administrator])
        end
        @status = :stopping
        #
        if self.respond_to_event?(:at_stop)
          self.call_event({:at_stop => self}, ::GxG::DB[:administrator])
        end
        @dispatcher.shutdown
        #
        @status = :stopped
        if self.respond_to_event?(:after_stop)
          self.call_event({:after_stop => self}, ::GxG::DB[:administrator])
        end
        true
      end
      #
      def restart(options={})
        # restart entire service, reloading configuration
        if self.respond_to_event?(:before_restart)
          self.call_event({:before_restart => self}, ::GxG::DB[:administrator])
        end
        if self.stop(options) == true
          self.start(options)
          if self.respond_to_event?(:at_restart)
            self.call_event({:at_restart => self}, ::GxG::DB[:administrator])
          end
          if self.respond_to_event?(:after_restart)
            self.call_event({:after_restart => self}, ::GxG::DB[:administrator])
          end
          true
        else
          false
        end
        #
      end
      #
      def pause(options={})
        # pause dispatcher
        if self.respond_to_event?(:before_pause)
          self.call_event({:before_pause => self}, ::GxG::DB[:administrator])
        end
        @dispatcher.shutdown
        @status = :paused
        if self.respond_to_event?(:at_pause)
          self.call_event({:at_pause => self}, ::GxG::DB[:administrator])
        end
        if self.respond_to_event?(:after_pause)
          self.call_event({:after_pause => self}, ::GxG::DB[:administrator])
        end
        true
      end
      #
      def resume(options={})
        # resume dispatcher
        if self.respond_to_event?(:before_resume)
          self.call_event({:before_resume => self}, ::GxG::DB[:administrator])
        end
        @dispatcher.startup
        @status = :running
        if self.respond_to_event?(:at_resume)
          self.call_event({:at_resume => self}, ::GxG::DB[:administrator])
        end
        if self.respond_to_event?(:after_resume)
          self.call_event({:after_resume => self}, ::GxG::DB[:administrator])
        end
        true
      end
      # ### Command Interface:
      def dispatcher()
        @dispatcher
      end
      #
      def on(the_event, options={}, &block)
        unless the_event.is_a?(::Symbol)
          raise ArgumentError, "You must specify an event listener with a unique Symbol."
        end
        unless block.respond_to?(:call)
          raise ArgumentError, "You must provide an event code block to execute."
        end
        unless options[:description]
          options[:description] = "Event : :#{the_event.to_s}"
        end
        unless options[:usage]
          options[:usage] = "{ :#{the_event.to_s} => (your_data_payload / nil) }"
        end
        unless options[:public] == true
          options[:public] = false
        end
        @interface[(the_event)] = {:description => options[:description], :usage => options[:usage], :public => (options[:public] || false), :users => (options[:users] || false), :administrators => true, :procedure => block}
        true
      end
      #
      def call_event(operation_envelope=nil, credential=(::GxG::DB[:administrator] || :"00000000-0000-4000-0000-000000000000"))
        result = nil
        if operation_envelope.is_a?(::Hash)
          the_event = operation_envelope.keys[0]
          if the_event
            data = operation_envelope[(the_event)]
            if @interface[(the_event)]
              begin
                can_call = false
                if credential == :"00000000-0000-4000-0000-000000000000" && @interface[(the_event)][:public] == true
                  can_call = true
                else
                  if  ::GxG::DB[:authority].role_member?(GxG::DB[:authority][:system_credentials][:administrators].to_s.to_sym, credential)
                    if @interface[(the_event)][:administrators] == true
                      can_call = true
                    end
                  else
                    if ::GxG::valid_uuid?(credential) && @interface[(the_event)][:users] == true && credential != :"00000000-0000-4000-0000-000000000000"
                      can_call = true
                    end
                  end
                end
               #
                if can_call
                  result = {:result => @interface[(the_event)][:procedure].call(data, credential)}
                else
                  result = {:result => nil, :error => "You Do Not Have Sufficient Permissions for Command #{the_event.inspect}"}
                end
              rescue Exception => the_error
                log_error({:error => the_error, :parameters => {:data => data, :credential => credential}})
                result = {:result => nil, :error => the_error.to_s}
              end
            else
              result = {:result => nil, :error => "Command #{the_event.inspect} Not Found"}
            end
          end
        end
        result
      end
      #
      def interface(credential=:"00000000-0000-4000-0000-000000000000")
        result = {}
        is_administrator = ::GxG::DB[:authority].role_member?(::GxG::DB[:authority][:system_credentials][:administrators].to_s.to_sym, credential)
        @interface.each_pair do |the_event, the_record|
          can_view = false
          if credential == :"00000000-0000-4000-0000-000000000000" && the_record[:public] == true
            can_view = true
          else
            if  is_administrator == true
              if the_record[:administrators] == true
                can_view = true
              end
            else
              if ::GxG::valid_uuid?(credential) && the_record[:users] == true && credential != :"00000000-0000-4000-0000-000000000000"
                can_view = true
              end
            end
          end
         #
          if can_view == true
            result[(the_event)] = (the_record[:description] + ", Usage : " + the_record[:usage])
          end
        end
        result
      end
      #
      def respond_to_event?(the_event=nil)
        result = false
        if the_event.is_a?(::Symbol)
          if @interface[(the_event)]
            result = true
          end
        end
        result
      end
      #
    end
    # ### Universal Resource Access (URA) for Services
    class UniversalResourcesAccess
      # ???
      def initialize()
        # VFS Lock format: {:path => "", :resource => File/DB_Object}
        @thread_safety_read = ::Mutex.new
        @read_locks = {}
        @thread_safety_write = ::Mutex.new
        @write_locks = {}
        self
      end
      #
      def busy?(the_path="")
        result = false
        # @thread_safety_read.synchronize {
        #   @read_locks.keys.each do |the_token|
        #     if @read_locks[(the_token)][:path] == the_path
        #       result = true
        #       break
        #     end
        #   end
        # }
        unless result == true
          @thread_safety_write.synchronize {
            @write_locks.keys.each do |the_token|
              if @write_locks[(the_token)][:path] == the_path
                result = true
                break
              end
            end
          }
        end
        result
      end
      #
      def exist?(the_path="")
        ::GxG::VFS.exist?(the_path)
      end
      #
      def profile(the_path="", credential=:"00000000-0000-4000-0000-000000000000", options={})
        ::GxG::VFS.profile(the_path, options.merge({:with_credential => credential}))
      end
      #
      def entries(the_path="", credential=:"00000000-0000-4000-0000-000000000000", options={})
        ::GxG::VFS.entries(the_path, credential)
      end
      #
      def permissions(the_path="", credential=:"00000000-0000-4000-0000-000000000000")
        the_profile = self.profile(the_path, credential)
        if the_profile
          the_profile[:permissions][:effective]
        else
          {:execute => false, :rename => false, :move => false, :destroy => false, :create => false, :write => false, :read=>false}
        end
      end
      #
      def get_permissions(the_path="", credential=:"00000000-0000-4000-0000-000000000000")
        ::GxG::VFS.get_permissions(the_path, credential)
      end
      #
      def set_permissions(the_path="", credential=:"00000000-0000-4000-0000-000000000000", permissions={})
        ::GxG::VFS.set_permissions(the_path, credential, permissions)
      end
      #
      def set_permissions_recursive(the_path="", credential=:"00000000-0000-4000-0000-000000000000", permissions={})
        ::GxG::VFS.set_permissions_recursive(the_path, credential, permissions)
      end
      #
      def revoke_permissions(the_path="", credential=:"00000000-0000-4000-0000-000000000000")
        GxG::VFS.revoke_permissions(the_path, credential)
      end
      #
      def rename(the_path="", credential=:"00000000-0000-4000-0000-000000000000", new_name="")
        result = nil
        if self.busy?(the_path)
          result = {:result => false, :error => "Busy", :error_code => :busy}
        end
        unless result
          if self.permissions(the_path, credential)[:rename] == false
            result = {:result => false, :error => "Permission Error", :error_code => :permission}
          end
        end
        unless result
          result = {:result => ::GxG::VFS.rename(the_path, new_name)}
        end
        result
      end
      #
      def copy(the_path="", credential=:"00000000-0000-4000-0000-000000000000", new_path="")
        result = nil
        if self.busy?(the_path)
          result = {:result => false, :error => "Busy", :error_code => :busy}
        end
        unless result
          if self.permissions(File.dirname(new_path), credential)[:create] == false
            result = {:result => false, :error => "Permission Error", :error_code => :permission}
          end
        end
        unless result
          result = {:result => ::GxG::VFS.copy(the_path, new_path)}
        end
        result
      end
      #
      def move(the_path="", credential=:"00000000-0000-4000-0000-000000000000", new_path="")
        result = nil
        if self.busy?(the_path)
          result = {:result => false, :error => "Busy", :error_code => :busy}
        end
        unless result
          if self.permissions(the_path, credential)[:move] == false
            result = {:result => false, :error => "Permission Error", :error_code => :permission}
          end
        end
        unless result
          result = {:result => ::GxG::VFS.move(the_path, new_path)}
        end
        result
      end
      #
      def destroy(the_path="", credential=:"00000000-0000-4000-0000-000000000000")
        result = nil
        if self.busy?(the_path)
          result = {:result => false, :error => "Busy", :error_code => :busy}
        end
        unless result
          if self.permissions(the_path, credential)[:destroy] == false
            result = {:result => false, :error => "Permission Error", :error_code => :permission}
          end
        end
        unless result
          the_profile = self.profile(the_path, credential)
          if [:virtual_directory, :directory, :persisted_array].include?(the_profile[:type])
            result = {:result => ::GxG::VFS.rmdir(the_path)}
          else
            result = {:result => ::GxG::VFS.rmfile(the_path)}
          end
          # xxx
        end
        result
      end
      #
      def create(the_path="", credential=:"00000000-0000-4000-0000-000000000000", options={})
        result = nil
        if self.busy?(the_path)
          result = {:result => false, :error => "Busy", :error_code => :busy}
        end
        unless result
          if self.permissions(File.dirname(the_path), credential)[:create] == false
            result = {:result => false, :error => "Permission Error", :error_code => :permission}
          end
        end
        unless result
          handle = ::GxG::VFS.mkfile(the_path, options)
          if handle
            if handle.is_a?(::GxG::Database::PersistedHash)
              handle.set_permissions(credential, {:execute => false, :rename => true, :move => true, :destroy => true, :create => true, :write => true, :read=>true})
              handle.deactivate
              result = {:result => true}
            else
              # FS
              # Review : Create a extra layer of permission tracking (by path) of files and directories on the actual file system. This puts it at parity with DB Objects.
              if handle.is_a?(::File)
                handle.close
              end
              result = {:result => true}
            end
          else
            result = {:result => false, :error => "Creation Error", :error_code => :create_fail}
          end
        end
        result
      end
      #
      def create_directory(the_path="", credential=:"00000000-0000-4000-0000-000000000000", options={})
        #result = {:result => false}
        result = nil
        if self.permissions(File.dirname(the_path), credential)[:create] == false
          result = {:result => false, :error => "Permission Error", :error_code => :permission}
        end
        unless result
          if ::GxG::VFS.mkdir(the_path)
            the_profile = self.profile(the_path)
            if the_profile[:uuid]
              handle = ::GxG::DB[:roles][:data].retrieve_by_uuid(the_profile[:uuid], ::GxG::DB[:administrator])
              if handle.is_a?(::GxG::Database::PersistedArray)
                handle.set_permissions(credential, {:execute => false, :rename => true, :move => true, :destroy => true, :create => true, :write => true, :read=>true})
                result = {:result => true}
              else
                result = {:result => false, :error => "Creation Error", :error_code => :create_fail}
              end
            else
              # FS
              # Review : Create a extra layer of permission tracking (by path) of files and directories on the actual file system. This puts it at parity with DB Objects.
              result = {:result => true}
            end
          else
            result = {:result => false, :error => "Creation Error", :error_code => :create_fail}
          end
        end
        result
      end
      #
      def open(the_path="", credential=:"00000000-0000-4000-0000-000000000000", flags=[:read, :binary])
        result = nil
        if ::GxG::valid_uuid?(credential) && flags.is_a?(::Array)
          if self.permissions(the_path, credential)[:read] == true
            the_flags = []
            flags.each do |a_flag|
              unless [:readwrite, :write].include?(a_flag)
                the_flags << a_flag
              end
            end
            supplimental_flags = []
            unless the_flags.include?(:read)
              supplimental_flags << :read
            end
            unless the_flags.include?(:binary)
              supplimental_flags << :binary
            end
            the_resource = ::GxG::VFS.open(the_path, {:flags => [(the_flags),(supplimental_flags)].flatten})
            if the_resource
              the_token = ::GxG::uuid_generate.to_sym
              @thread_safety_read.synchronize {
                @read_locks[(the_token)] = {:path => the_path, :resource => the_resource}
              }
              result = {:token => the_token, :path => the_path, :resource => the_resource}
            end
          end
        end
        result
        #
      end
      #
      def open_writable(the_path="", credential=:"00000000-0000-4000-0000-000000000000", flags=[:readwrite, :binary])
        result = nil
        if ::GxG::valid_uuid?(credential) && flags.is_a?(::Array)
          if self.permissions(the_path, credential)[:write] == true
            someone_else_locked = false
            @thread_safety_write.synchronize {
              @write_locks.keys.each do |the_write_token|
                if @write_locks[(the_write_token)][:path] == the_path
                  someone_else_locked = true
                  break
                end
              end
            }
            #
            unless someone_else_locked == true
              supplimental_flags = []
              unless flags.include?(:readwrite)
                supplimental_flags << :readwrite
              end
              unless flags.include?(:binary)
                supplimental_flags << :binary
              end
              the_resource = ::GxG::VFS.open(the_path, {:flags => [(flags),(supplimental_flags)].flatten})
              if the_resource
                the_token = ::GxG::uuid_generate.to_sym
                @thread_safety_write.synchronize {
                  @write_locks[(the_token)] = {:path => the_path, :resource => the_resource}
                }
                result = {:token => the_token, :path => the_path, :resource => the_resource}
              end
            end
            #
          end
          #
        end
        result
      end
      #
      def mark_busy(the_path="")
        the_token = ::GxG::uuid_generate.to_sym
        @thread_safety_write.synchronize {
          @write_locks[(the_token)] = {:path => the_path, :resource => true}
        }
        {:token => the_token, :path => the_path, :resource => true}
      end
      #
      def reopen_writable(the_token="", credential=:"00000000-0000-4000-0000-000000000000", flags=[])
        result = nil
        if ::GxG::valid_uuid?(the_token)
          details = nil
          someone_else_locked = false
          @thread_safety_read.synchronize {
            if @read_locks[(the_token.to_sym)]
              details = @read_locks.delete(the_token.to_sym)
            end
          }
          if details
            # ONLY converts read-locks to write-locks. Be sure to use open first.
            @thread_safety_write.synchronize {
              @write_locks.keys.each do |the_write_token|
                if @write_locks[(the_write_token)][:path] == details[:path] && the_token.to_sym != the_write_token
                  someone_else_locked = true
                  break
                end
              end
            }
            unless someone_else_locked == true
              if details[:resource].is_any?(::GxG::Database::PersistedArray, ::GxG::Database::PersistedHash)
                details[:resource].wait_for_reservation(5.0)
                if details[:resource].write_reserved?()
                  @thread_safety_write.synchronize {
                    @write_locks[(the_token.to_sym)] = details
                  }
                  result = details
                else
                  @thread_safety_read.synchronize {
                    @read_locks[(the_token.to_sym)] = details
                  }
                end
              else
                if details[:resource].is_a?(::Dir)
                  if self.permissions(details[:path], credential)[:write] == true
                    @thread_safety_write.synchronize {
                      @write_locks[(the_token.to_sym)] = details
                    }
                    result = details
                  else
                    @thread_safety_read.synchronize {
                      @read_locks[(the_token.to_sym)] = details
                    }
                  end
                else
                  if details[:resource].is_a?(::File)
                    if self.permissions(details[:path], credential)[:write] == true
                      details[:resource].close
                      details[:resource] = ::GxG::VFS.open(details[:path], {:flags => [:readwrite, :binary]})
                      @thread_safety_read.synchronize {
                        @write_locks[(the_token.to_sym)] = details
                      }
                      result = details
                    else
                      @thread_safety_read.synchronize {
                        @read_locks[(the_token.to_sym)] = details
                      }
                    end
                  end
                end
              end
            end
          end
        end
        result
      end
      #
      def reopen_readonly(the_token="", credential=:"00000000-0000-4000-0000-000000000000", flags=[])
        result = nil
        if ::GxG::valid_uuid?(the_token) && ::GxG::valid_uuid?(credential) && flags.is_a?(::Array)
          the_flags = []
          flags.each do |a_flag|
            unless [:readwrite, :write].include?(a_flag)
              the_flags << a_flag
            end
          end
          supplimental_flags = []
          unless the_flags.include?(:read)
            supplimental_flags << :read
          end
          unless the_flags.include?(:binary)
            supplimental_flags << :binary
          end
          details = nil
          @thread_safety_write.synchronize {
            if @write_locks[(the_token.to_sym)]
              details = @write_locks.delete(the_token.to_sym)
            end
          }
          if details
            if self.permissions(details[:path], credential)[:read] == true
              if details[:resource].is_any?(::GxG::Database::PersistedArray, ::GxG::Database::PersistedHash)
                details[:resource].release_reservation()
                @thread_safety_read.synchronize {
                  @read_locks[(the_token.to_sym)] = details
                }
                result = details
              else
                if details[:resource].is_a?(::Dir)
                  @thread_safety_read.synchronize {
                    @read_locks[(the_token.to_sym)] = details
                  }
                  result = details
                else
                  if details[:resource].is_a?(::File)
                    details[:resource].close
                    details[:resource] = ::GxG::VFS.open(details[:path], {:flags => [:read, :binary]})
                    @thread_safety_read.synchronize {
                      @read_locks[(the_token.to_sym)] = details
                    }
                    result = details
                  end
                end
              end
            else
              @thread_safety_write.synchronize {
                @write_locks[(the_token.to_sym)] = details
              }
            end
          end
        end
        result
      end
      #
      def close(the_token="")
        result = false
        if ::GxG::valid_uuid?(the_token)
          details = nil
          @thread_safety_read.synchronize {
            if @read_locks[(the_token.to_sym)]
              details = @read_locks.delete(the_token.to_sym)
            end
          }
          unless details
            @thread_safety_write.synchronize {
              if @write_locks[(the_token.to_sym)]
                details = @write_locks.delete(the_token.to_sym)
              end
            }
          end
          if details
            # VFS Lock format: {:path => "", :resource => File/DB_Object}
            if details[:resource]
              if details[:resource].is_a?(::Dir)
                # Review : ??
              else
                if details[:resource].is_a?(::File)
                  details[:resource].close
                else
                  if details[:resource].is_any?(::GxG::Database::PersistedArray, ::GxG::Database::PersistedHash)
                    details[:resource].deactivate
                  else
                    # err
                  end
                end
              end
              result = true
            end
          end
        end
        result
      end
      # ### User Home Directory Supports
      def home_mounted?(credential=nil)
        result = false
        if GxG::valid_uuid?(credential)
          if GxG::VFS.exist?(("/Users/" + credential.to_s))
            result = true
          end
        end
        result
      end
      #
      def home_mount(credential=nil)
        result = false
        if self.home_mounted?(credential)
          unless GxG::VFS.mounted?("/User/#{credential.to_s}/Database")
            volume_stub = GxG::DB[:roles][:vfs].search_database(credential, {:title => ("volume-" + credential.to_s)}).first
            if volume_stub
              volume_uuid = volume_stub[:uuid]
            else
              volume_persisted_array = GxG::DB[:roles][:vfs].try_persist([], credential)
              volume_uuid = volume_persisted_array.uuid
              volume_persisted_array.get_reservation()
              volume_persisted_array.set_title("volume-" + credential.to_s)
              volume_persisted_array.save
              volume_persisted_array.deactivate
            end
            volume_handle = GxG::Storage::Volume.new({:database => GxG::DB[:roles][:vfs], :credential => credential, :root_uuid => volume_uuid})
            GxG::VFS.mount(volume_handle, "/User/#{credential.to_s}/Database")
          end
          result = true
        else
          home_path = ("/Users/" + credential.to_s)
          manifest = [(home_path)]
          ["Preferences", "Documents", "Pictures", "Music", "Videos", "Books", "Resources", "Volumes", "Database", "ApplicationData"].each do |subdir|
            manifest << (home_path + "/" + subdir)
          end
          while manifest.size > 0 do
            entry = manifest.shift
            GxG::VFS.mkpath(entry)
            if entry == home_path
              GxG::VFS.set_permissions(home_path, GxG::DB[:authority][:system_credentials][:administrators], {:execute => false, :rename => true, :move => true, :destroy => true, :create => true, :write => true, :read=>true})
              GxG::VFS.set_permissions(home_path, credential, {:execute => false, :rename => false, :move => false, :destroy => false, :create => true, :write => true, :read=>true})
            else
              # {:execute => false, :rename => false, :move => false, :destroy => false, :create => false, :write => false, :read=>false}
              if ["Preferences","Volumes", "Database", "ApplicationData"].include?(File.basename(entry))
                # disallow delete
                GxG::VFS.set_permissions(entry, GxG::DB[:authority][:system_credentials][:administrators], {:execute => false, :rename => true, :move => true, :destroy => true, :create => true, :write => true, :read=>true})
                GxG::VFS.set_permissions(entry, credential, {:execute => false, :rename => false, :move => false, :destroy => false, :create => true, :write => true, :read=>true})
              else
                # allow delete ??
                GxG::VFS.set_permissions(entry, GxG::DB[:authority][:system_credentials][:administrators], {:execute => false, :rename => true, :move => true, :destroy => true, :create => true, :write => true, :read=>true})
                GxG::VFS.set_permissions(entry, credential, {:execute => false, :rename => false, :move => false, :destroy => false, :create => true, :write => true, :read=>true})
              end
            end
          end
          # mount Objects DB root
          volume_persisted_array = GxG::DB[:roles][:vfs].try_persist([], credential)
          volume_uuid = volume_persisted_array.uuid
          volume_persisted_array.get_reservation()
          volume_persisted_array.set_title("volume-" + credential.to_s)
          volume_persisted_array.save
          volume_persisted_array.deactivate
          volume_handle = GxG::Storage::Volume.new({:database => GxG::DB[:roles][:vfs], :credential => credential, :root_uuid => volume_uuid})
          GxG::VFS.mount(volume_handle, "/User/#{credential.to_s}/Database")
          result = true
        end
        result
      end
      #
      def home_path(credential=nil)
        if credential == :"00000000-0000-4000-0000-000000000000"
          result = "/Public/www"
        else
          # if GxG::DB[:authority].role_member?(GxG::DB[:authority][:system_credentials][:administrators], credential) || GxG::DB[:authority].role_member?(GxG::DB[:authority][:system_credentials][:developers], credential) || GxG::DB[:authority].role_member?(GxG::DB[:authority][:system_credentials][:designers], credential)
          #   result = "/"
          # else
          #   self.home_mount(credential)
          #   result = ("/Users/" + credential.to_s)
          # end
          self.home_mount(credential)
          result = ("/Users/" + credential.to_s)
        end
        result
      end
      # ###
      #
    end
    # ### Installer Support
    class SoftwareInstaller
      #
      def initialize(archive_name=nil)
        #
        unless archive_name.is_a?(::String)
          raise "You MUST provide a valid installer archive name as a String."
        end
        unless ::GxG::SERVICES[:core][:resources].exist?("/Installers/#{archive_name}")
          raise "Archive #{archive_name} does not exist."
        end
        if ::GxG::SERVICES[:core][:resources].busy?("/Installers/#{archive_name}")
          raise "Archive #{archive_name} is in use currently."
        end
        #
        @manifest = nil
        @database = nil
        @archive_token = ::GxG::SERVICES[:core][:resources].open("/Installers/#{archive_name}", GxG::DB[:administrator])
        if @archive_token
          @database = ::GxG::Database::connect(::URI.parse("sqlite://#{::GxG::SYSTEM_PATHS[:installers]}/#{archive_name}"), {:read_only => true})
          unless @database.is_a?(::GxG::Database::Database)
            ::GxG::SERVICES[:core][:resources].close(@archive_token[:token])
            raise "Unable to open #{archive_name}"
          end
          @installer_path = "/Installers/#{::GxG::uuid_generate()}"
          @manifest = ::JSON::parse(@database[:installation_manifest].to_s.decode64, {:symbolize_names => true})
          @manifest[:formats].each_pair do |format_uuid, format_record|
            format_record[:content] = ::Hash::gxg_import(format_record[:content])
          end
          ::GxG::VFS.mount(::GxG::Storage::Volume.new({:database => @database, :credential => GxG::DB[:administrator]}), @installer_path)
        else
          raise "Unable to secure a read-access token for: #{archive_name}"
        end
        #
        self
      end
      #
      def open?()
        if @database.is_a?(::GxG::Database::Database)
          true
        else
          false
        end
      end
      #
      def close()
        if @archive_token.is_a?(::Hash)
          ::GxG::SERVICES[:core][:resources].close(@archive_token[:token])
          ::GxG::VFS.unmount(@installer_path)
          @archive_token = nil
          if @database.is_a?(::GxG::Database::Database)
            @database.close
            @database = nil
          end
        end
        true
      end
      #
      def perform_install(options={})
        begin
          if self.open?() && @manifest.is_a?(::Hash)
            # flesh out manifest
            # manifest format: {:package => "", :version => "0.0", :gems => {}, :formats => {}, objects => {:"path/to/file" => [{:users => {:read => true}}]}}
            # Install Gems
            @manifest[:gems].each_pair do |gem_name, version_info|
              gem_install(gem_name, version_info)
            end
            # copy formats
            ::GxG::DB[:roles][:formats].sync_import(GxG::DB[:administrator], {:formats => (@manifest[:formats] || {}), :records => []})
            # copy files into place, setting permissions          
            if @manifest[:objects].is_a?(::Hash)
              @manifest[:objects].each_pair do |the_path, the_permissions|
                if ::GxG::SERVICES[:core][:resources].exist?(the_path.to_s)
                  existing_permissions = ::GxG::VFS.get_permissions(the_path.to_s)
                else
                  existing_permissions = nil
                end
                ::GxG::SERVICES[:core][:resources].copy("#{@installer_path}#{the_path.to_s}", GxG::DB[:administrator], the_path.to_s)
                if the_permissions.is_a?(::Array)
                  ::GxG::SERVICES[:core][:resources].set_permissions(the_path.to_s, :"00000000-0000-4000-0000-000000000000", {:write => false, :read => false})
                  ::GxG::SERVICES[:core][:resources].revoke_permissions(the_path.to_s, :"00000000-0000-4000-0000-000000000000")
                  #
                  the_permissions.each do |the_entry|
                    if the_entry.is_a?(::Hash)
                      #
                      the_credential = nil
                      case the_entry.keys[0]
                      when :public
                        the_credential = :"00000000-0000-4000-0000-000000000000"
                      when :users
                        the_credential = ::GxG::DB[:users]
                      when :designers
                        the_credential = ::GxG::DB[:designers]
                      when :developers
                        the_credential = ::GxG::DB[:developers]
                      when :administrators
                        the_credential = ::GxG::DB[:administrators]
                      end
                      if the_credential
                        ::GxG::SERVICES[:core][:resources].set_permissions(the_path.to_s, the_credential, (the_entry.values[0] || {:read => true}))
                      end
                      #
                    end
                  end
                  #
                  if existing_permissions.is_a?(::Array)
                    existing_permissions.each do |entry|
                      ::GxG::SERVICES[:core][:resources].set_permissions(the_path.to_s, entry[:credential], entry[:permissions])
                    end
                  end
                  #
                end
              end
            end
            result = true
          else
            result = false
          end
        rescue Exception => the_error
          log_error({:error => the_error})
          result = false
        end
        result
      end
      #
    end
    #
    class SoftwareInstallerMaker
      private
      #
      def portable_format(the_format_record=nil)
        result = nil
        if the_format_record.is_any?(::Hash, ::GxG::Database::DetachedHash, ::GxG::Database::PersistedHash)
          if the_format_record.is_any?(::GxG::Database::DetachedHash, ::GxG::Database::PersistedHash)
            the_format_record = the_format_record.unpersist
          end
          if (the_format_record[:uuid] && the_format_record[:type] && the_format_record[:ufs] && the_format_record[:version] && the_format_record[:mime_types])
            #
            result = {:uuid => (the_format_record[:uuid]), :type => (the_format_record[:type]), :ufs => (the_format_record[:ufs]), :title => (the_format_record[:title].to_s), :version => (the_format_record[:version]), :mime_types => (the_format_record[:mime_types] || []), :content => the_format_record[:content].gxg_export}
            #
          else
            raise "Malformed format record"
          end
        else
          raise "Malformed format record"
        end
        result
      end
      #
      def portable_permission(credential=nil, permissions=nil)
        result = nil
        if ::GxG::valid_uuid?(credential) && permissions.is_a?(::Hash)
          if credential == :"00000000-0000-4000-0000-000000000000"
            the_role = :public
          else
            the_role = nil
            [:administrators, :developers, :designers, :users].each do |entry|
              if credential == ::GxG::DB[(entry)]
                the_role = entry
                break
              end
            end
          end
          if the_role
            result = {}
            result[(the_role)] = permissions
          end
        end
        result
      end
      #
      public
      #
      def initialize()
        @manifest = {:package => nil, :version => "0.0", :gems => {}, :formats => {}, :objects => {}}
        self
      end
      #
      def package()
        @manifest[:package]
      end
      #
      def package=(package_name=nil)
        if package_name
          @manifest[:package] = package_name.to_s[0..127]
        end
      end
      #
      def version()
        ::BigDecimal.new(@manifest[:version])
      end
      #
      def version=(the_version=nil)
        if the_version.is_any?(::String, ::BigDecimal)
          @manifest[:version] = the_version.to_s
        else
          raise "You MUST provide a String or BigDecimal as version number"
        end
        #
        def add_gem(gem_name=nil, version_info=nil)
          if gem_name.is_any?(::String, ::Symbol) && version_info.is_any?(::String, ::NilClass)
            @manifest[:gems][gem_name.to_s.to_sym] = version_info
            true
          else
            false
          end
        end
        #
        def add_format_from_uuid(the_uuid=nil)
          the_format_record = ::GxG::DB[:roles][:formats].format_load({:uuid => the_uuid})
          unless the_format_record
            the_format_record = ::GxG::DB[:formats][(the_uuid.to_s.to_sym)]
          end
          if the_format_record.is_a?(::Hash)
            portable_record = portable_format(the_format_record)
            if portable_record
              @manifest[:formats][(the_format_record[:uuid].to_s.to_sym)] = portable_record
              true
            else
              false
            end
          else
            false
          end
        end
        #
        def add_format_from_ufs(the_ufs=nil)
          the_format_record = ::GxG::DB[:roles][:formats].format_load({:ufs => the_ufs})
          unless the_format_record
            ::GxG::DB[:formats].values.each do |entry|
              if entry[:ufs] == the_ufs
                the_format_record = entry
                break
              end
            end
          end
          if the_format_record.is_a?(::Hash)
            portable_record = portable_format(the_format_record)
            if portable_record
              @manifest[:formats][(the_format_record[:uuid].to_s.to_sym)] = portable_record
              true
            else
              false
            end
          else
            false
          end
        end
        #
        def add_format_from_record(the_format_record=nil)
          if (the_format_record[:uuid] && the_format_record[:type] && the_format_record[:ufs] && the_format_record[:version] && the_format_record[:mime_types])
            portable_record = portable_format(the_format_record)
            if portable_record
              @manifest[:formats][(the_format_record[:uuid].to_s.to_sym)] = portable_record
              true
            else
              false
            end
          else
            raise "Malformed format record"
          end
        end
        #
        def add_path(the_path=nil)
          if the_path.is_a?(::String)
            the_profile = ::GxG::SERVICES[:core][:resources].profile(the_path, ::GxG::DB[:administrator])
            #
            if [:virtual_directory, :directory, :persisted_array].include?(the_profile[:type])
              processing_db = [(the_path)]
              while processing_db.size > 0
                item = processing_db.shift
                if item
                  subitems = ::GxG::SERVICES[:core][:resources].entries(item, ::GxG::DB[:administrator])
                  #
                  if subitems.size == 0
                    @manifest[:objects][(item.to_s.to_sym)] = []
                    ::GxG::VFS.get_permissions(item).each do |entry|
                      the_permission = portable_permission(entry[:credential], entry[:permissions])
                      if the_permission
                        @manifest[:objects][(item.to_s.to_sym)] << the_permission
                      end
                    end
                  end
                  #
                  if subitems.size > 0
                    subitems.each do |profile|
                      subpath = (item + "/" + profile[:title])
                      if [:virtual_directory, :directory, :persisted_array].include?(profile[:type])
                        processing_db << subpath
                      else
                        @manifest[:objects][(subpath.to_s.to_sym)] = []
                        ::GxG::VFS.get_permissions(subpath).each do |entry|
                          the_permission = portable_permission(entry[:credential], entry[:permissions])
                          if the_permission
                            @manifest[:objects][(subpath.to_s.to_sym)] << the_permission
                          end
                        end
                      end
                    end
                  end
                  #
                end
              end
            else
              @manifest[:objects][(the_path.to_s.to_sym)] = []
              ::GxG::VFS.get_permissions(the_path).each do |entry|
                the_permission = portable_permission(entry[:credential], entry[:permissions])
                if the_permission
                  @manifest[:objects][(the_path.to_s.to_sym)] << the_permission
                end
              end
            end
            #
            true
          else
            raise "Malformed path String"
          end
        end
        #
        def make_installer()
          result = false
          #
          if @manifest[:package]
            archive_name = (@manifest[:package].to_s.gsub(" ","-") + "_" + @manifest[:version].to_s.gsub(".","-") + ".gxg_installer")
            installer_path = "/Installers/#{::GxG::uuid_generate()}"
            database = ::GxG::Database::connect(::URI.parse("sqlite://#{::GxG::SYSTEM_PATHS[:installers]}/#{archive_name}"))
            unless database.is_a?(::GxG::Database::Database)
              raise "Unable to open #{archive_name}"
            end
            archive_token = ::GxG::SERVICES[:core][:resources].mark_busy("/Installers/#{archive_name}")
            ::GxG::VFS.mount(::GxG::Storage::Volume.new({:database => database, :credential => GxG::DB[:administrator]}), installer_path)
            begin
              database[:installation_manifest] = @manifest.to_json.encode64
              @manifest[:objects].keys.each do |the_path|
                ::GxG::SERVICES[:core][:resources].copy(the_path.to_s, GxG::DB[:administrator], "#{installer_path}#{the_path.to_s}")
                ::GxG::SERVICES[:core][:resources].set_permissions("#{installer_path}#{the_path.to_s}", :"00000000-0000-4000-0000-000000000000", {:read => true})
              end
              @manifest[:objects].keys.each do |the_path|
                ::GxG::SERVICES[:core][:resources].revoke_permissions("#{installer_path}#{the_path.to_s}", ::GxG::DB[:users])
                ::GxG::SERVICES[:core][:resources].revoke_permissions("#{installer_path}#{the_path.to_s}", ::GxG::DB[:designers])
                ::GxG::SERVICES[:core][:resources].revoke_permissions("#{installer_path}#{the_path.to_s}", ::GxG::DB[:developers])
                ::GxG::SERVICES[:core][:resources].revoke_permissions("#{installer_path}#{the_path.to_s}", ::GxG::DB[:administrators])
              end
              #
              ::GxG::VFS.unmount(installer_path)
              database.close
              ::GxG::SERVICES[:core][:resources].close(archive_token[:token])
              result = true
            rescue Exception => the_error
              ::GxG::VFS.unmount(installer_path)
              database.close
              ::GxG::SERVICES[:core][:resources].close(archive_token[:token])
              ::GxG::SERVICES[:core][:resources].destroy(("/Installers/#{archive_name}"), ::GxG::DB[:administrator])
              log_error({:error => the_error})
              raise the_error
            end
          else
            raise "You MUST first set the package name"
          end
          #
          result
        end
        #
      end
      #
    end
    #
  end
end
# ### Define The Core Service:
core_service = ::GxG::Services::Service.new(:core)
# ### Provide Universal Resource Access
core_service[:resources] = ::GxG::Services::UniversalResourcesAccess.new()
#
# ### Define Public Command Interface:
core_service.on(:start, {:description => "System Service Layer Start", :usage => "{ :start => nil }", :users => false}) do
  ::GxG::SERVICES[:core].start
end
core_service.on(:stop, {:description => "System Service Layer Shutdown", :usage => "{ :stop => nil }", :users => false}) do
  ::GxG::SERVICES[:core].stop
end
core_service.on(:restart, {:description => "System Service Layer Restart", :usage => "{ :restart => nil }", :users => false}) do
  ::GxG::SERVICES[:core].restart
end
core_service.on(:pause, {:description => "System Service Pause", :usage => "{ :pause => nil }", :users => false}) do
  ::GxG::SERVICES[:core].pause
end
core_service.on(:resume, {:description => "System Service Resume", :usage => "{ :resume => nil }", :users => false}) do
  ::GxG::SERVICES[:core].resume
end
# ### Define Internal Service Control Events:
core_service.on(:at_start, {:description => "System Service Layer Startup", :usage => "{ :at_start => (service-object) }", :users => false}) do |service, credential|
  # ### Set Engine Monitors
  service.dispatcher.every("1 second") do
    ::GxG::Engine::determine_event_allocations()
    ::GxG::Engine::determine_loads()
  end
  # ### Load Services
  if service.configuration()[:available]
    service.configuration()[:available].each do |moniker|
      unless service.configuration()[:disabled].include?(moniker)
        service_file_path = ::File.expand_path("#{File.dirname(__FILE__)}/#{moniker}/#{moniker}.rb")
        puts "Loading : #{service_file_path}"
        if ::File.exist?(service_file_path)
          begin
            require (service_file_path)
          rescue Exception => the_error
            log_error({:error => the_error, :parameters => {:service => moniker}})
          end
        else
          log_warn("WARNING: /Services/#{moniker.to_s}/#{moniker.to_s}.rb NOT FOUND -- skipping service")
        end
      end
    end
    # ### Start Services
    ::GxG::Services::start_order().each do |the_service_moniker|
      unless the_service_moniker == :core
        if service.configuration()[:enabled].include?(the_service_moniker.to_s)
          log_info("Starting Service: #{the_service_moniker.inspect} ...")
          ::GxG::Services::start_service(the_service_moniker)
        end
      end
    end
    #
  end
end
core_service.on(:at_stop, {:description => "System Service Layer Shutdown", :usage => "{ :at_stop => (service-object) }", :public => false}) do |service, credential|
  # ### Stop Services
  ::GxG::Services::stop_order().each do |the_service_moniker|
    unless the_service_moniker == :core
      log_info("Stopping Service: #{the_service_moniker.inspect} ...")
      ::GxG::Services::stop_service(the_service_moniker)
    end
  end
  #
end
#
unless core_service.configuration()[:available]
  core_service.configuration()[:available] = []
  core_service.configuration()[:enabled] = []
  core_service.configuration()[:disabled] = []
  core_service.save_configuration
  ::GxG::VFS.entries("/Services").each do |the_profile|
    if the_profile[:type] == :directory
      ::GxG::Services::install_service(the_profile[:title].to_sym)
      ::GxG::Services::enable_service(the_profile[:title].to_sym)
    end
  end
end
core_service.start
# ### Trap for exit signals
unless RUBY_ENGINE == "jruby"
  Signal.trap("QUIT") do
    ::GxG::Services::stop_service(:core)
    exit(0)
  end
end
Signal.trap("INT") do
  ::GxG::Services::stop_service(:core)
  exit(0)
end
Signal.trap("TERM") do
  ::GxG::Services::stop_service(:core)
  exit(0)
end
# ### Review : USR1 in use by JVM/JRuby and won't work.
# Signal.trap("USR1") do
#   ::GxG::Services::stop_service(:core)
# end
Signal.trap("HUP") do
  ::GxG::Services::stop_service(:core)
  exit(0)
end
#
# ### Startup Scripts
Dir.entries("#{::GxG::SYSTEM_PATHS[:system]}/Startup").each do |entry|
  if File.extname(entry) == ".rb"
    begin
      require "#{::GxG::SYSTEM_PATHS[:system]}/Startup/#{entry}"
    rescue Exception => the_error
      log_error({:error => the_error})
    end
  end
end
#
unless ($0 == "irb" || $0 == "jirb" || Module.constants.include?(:IRB))
  # ### Place-holder loop for running in the background
  while true do
    sleep 5
  end
end
