#! /usr/bin/env ruby

require 'optparse'
require 'orocos'

search_for = []

debug = false
save_configuration = nil
parser = OptionParser.new do |opt|
    opt.banner = <<-EOT
usage: oroinspect <search term>"
 Searches for <search term> in installed oroGen projects
 and displays the definition of the matching objects
 it searches for: task context, types and deployments
    EOT

    opt.on('--help') do
        puts self
        exit(0)
    end
    opt.on('-t', '--tasks', 'if given, will search only for tasks. Can be combined with --deployments and --types to search for the other categories as well.') do
        search_for << :tasks
    end
    opt.on('-T', '--types', 'if given, will search only for types. Can be combined with --deployments and --tasks to search for the other categories as well.') do
        search_for << :types
    end
    opt.on('-d', '--deployments', 'if given, will search only for deployments. Can be combined with --tasks and --types to search for the other categories as well.') do
        search_for << :deployments
    end
    opt.on('-C', 'invalid option. This functionality is now moved to oroconf') do
        STDERR.puts "the configuration display mode of oroinspect has been moved to oroconf"
        STDERR.puts "  see http://rock-robotics.org/documentation/runtime/configuration.html for more information"
        exit 1
    end
    opt.on('--debug') do
        debug = true
    end
    opt.on('--help') do
        puts parser
        exit 0
    end
end

remaining = parser.parse(ARGV)

pattern = remaining
if pattern.empty?
    puts parser
    exit(1)
end

if search_for.empty?
    search_for = [:tasks, :types, :deployments]
end

regexp = /#{pattern.first}/i

Orocos.load

def load_orogen_project(loader, name, debug)
    loader.project_model_from_name(name)
rescue Exception => e
    if debug
        raise
    end
    STDERR.puts "WARN: cannot load the installed oroGen project #{name}"
    STDERR.puts "WARN:     #{e.message}"
end

if search_for.include?(:tasks)
    found = []
    Orocos.default_pkgconfig_loader.available_task_models.each do |name, project_name|
        if name =~ regexp || project_name =~ regexp
            if tasklib = load_orogen_project(Orocos.default_loader, project_name, debug)
                if task = tasklib.self_tasks.find { |_, t| t.name == name }
                    found << [task.last, project_name]
                end
            end
        end
    end

    found.sort_by { |t, _| t.name }.each do |tasklib, project_name|
        puts
        puts "===== #{tasklib.name} is a task context defined in #{project_name}"
        pp tasklib
    end
end

if search_for.include?(:deployments)
    found = []
    Orocos.default_pkgconfig_loader.available_deployments.each do |name, pkg|
        project_name = pkg.project_name
        if name =~ regexp || project_name =~ regexp
            if tasklib = load_orogen_project(Orocos.default_loader, project_name, debug)
		if deployer = tasklib.deployers.find { |_, n| n.name == name }
		    found << [deployer.last, project_name]
		end
            end
        end
    end

    found.sort_by { |d, _| d.name }.each do |deployment, project_name|
        puts
        puts "===== #{deployment.name} is a deployment defined in #{project_name}"
        pp deployment
    end
end

if search_for.include?(:types)
    Orocos.default_loader.each_available_project_name do |project_name|
        seen = Set.new
        found = Array.new
        next if !Orocos.default_loader.has_typekit?(project_name)

        typekit = Orocos.default_loader.typekit_model_from_name(project_name)
        matching_types = typekit.typelist.grep(regexp)
        if !matching_types.empty?
            matching_types.each do |type_name|
                if !seen.include?(type_name)
                    found << [Orocos.default_loader.registry.get(type_name), project_name]
                    seen << type_name
                end
            end
        end

        found.to_a.sort_by { |t, _| t.name }.each do |type, project_name|
            puts
            puts "===== #{type.name} is a type defined in #{project_name}"
            pp type
        end
    end
end
