#!/usr/bin/ruby
# encoding: utf-8

# Copyright (C) 2012, HipByte SPRL. All Rights Reserved.
#
# This file is subject to the terms and conditions of the End User License
# Agreement accompanying the package this file is a part of.

# Monkey-patch gen_bridge_metadata

load '/usr/bin/gen_bridge_metadata'

module Bridgesupportparser
  class Parser
    # From /System/Library/BridgeSupport/ruby-1.8/bridgesupportparser.rb
    def recursivefuncptr(f)
      return nil if f.nil?
      func, rettype, retenc, retattrs, retfunc, fattrs, variadic, inline = f.info
      ret = Bridgesupportparser::RetvalPtrInfo.new(self, nil, rettype, retenc, retattrs, recursivefuncptr(retfunc))
      args = Bridgesupportparser::MergingSequence.new('recursivefuncptr')
      f.each_argument do |name, type, enc, attrs, funcptr|
        # RubyMotion change:
        #
        # In the original implementation the last argument is always nil,
        # but we need to enable recursive parsing.
        #
        # Related to: http://hipbyte.myjetbrains.com/youtrack/issue/RM-288
        args << Bridgesupportparser::ArgInfo.new(self, name, type, enc, attrs, recursivefuncptr(funcptr))
      end
      Bridgesupportparser::FuncInfo.new(self, func, ret, args, fattrs, variadic, inline)
    end
  end
end

# Because this is not a method, in the original implementation, we need to copy it verbatim.
if __FILE__ == $0
  g = BridgeSupportGenerator.new
  OptionParser.new do |opts|
    opts.banner = "Usage: #{File.basename(__FILE__)} [options] <headers...>"
    opts.separator ''
    opts.separator 'Options:'

    opts.on('-f', '--framework FRAMEWORK', 'Generate metadata for the given framework.') do |opt|
      g.frameworks << opt
    end

    opts.on('-p', '--private', 'Support private frameworks headers.') do
      g.private = true
    end

    formats = BridgeSupportGenerator::FORMATS
    opts.on('-F', '--format FORMAT', formats, {}, "Select metadata format.") do |opt|
      g.generate_format = opt
    end

    opts.on('-e', '--exception EXCEPTION', 'Use the given exception file.') do |opt|
      g.exception_paths << opt
    end
        
    # both 32 & 64 bit is now the default
    enable_32 = true
    enable_64 = true
    opts.on(nil, '--64-bit', 'Write 64-bit annotations (now the default).') do
      enable_64 = true
    end
    opts.on(nil, '--no-64-bit', 'Do not write 64-bit annotations.') do
      enable_64 = false
    end

    # 64-bit is now the only option
    no_32bit_support = `/usr/bin/sw_vers -productVersion`.strip.match(/^10\.(\d+)/)[1].to_i >= 9
    if no_32bit_support
      opts.on(nil, '--no-32-bit', 'Do not write 32-bit annotations.') do
        enable_32 = false
      end
    end

    opts.on('-c', '--cflags FLAGS', 'Specify custom compiler flags.') do |flags|
      g.compiler_flags ||= ''
      g.compiler_flags << ' ' + flags + ' '
    end

    compiler_flags_64 = nil
    opts.on('-C', '--cflags-64 FLAGS', 'Specify custom 64-bit compiler flags.') do |flags|
      compiler_flags_64 ||= ''
      compiler_flags_64 << ' ' + flags + ' '
    end

    opts.on('-o', '--output FILE', 'Write output to the given file.') do |opt|
      die 'Output file can\'t be specified more than once' if @out_file
      g.out_file = opt
    end

    # RubyMotion addition that allows us to overcome 'too many arguments' error
    # when passing many headers to this tool.
    opts.on('--headers FILE', 'Use headers listed in file as input.') do |file|
      File.open(file, 'r') do |io|
        io.each_line do |header|
          g.add_header(header.strip)
        end
      end
    end

    help_msg = "Use the `-h' flag or consult gen_bridge_metadata(1) for help."
    opts.on('-h', '--help', 'Show this message.') do
      puts opts, help_msg
      exit
    end

    opts.on('-d', '--debug', 'Turn on debugging messages.') do
      $DEBUG = true
    end

    opts.on('-v', '--version', 'Show version.') do
      puts BridgeSupportGenerator::VERSION
      exit
    end

    opts.separator ''

    if ARGV.empty?
      die opts.banner
    else
      begin
        opts.parse!(ARGV)
        ARGV.each { |header| g.add_header(header) }
        if no_32bit_support
          g.parse(enable_32, enable_64, compiler_flags_64)
        else
          g.parse(enable_64, compiler_flags_64)
        end
  #    g.collect
  #    if enable_64
  #        g2 = g.duplicate
  #        g2.enable_64 = true
  #        if compiler_flags_64 != g.compiler_flags
  #      g2.compiler_flags = compiler_flags_64
  #        end
  #        g2.collect
  #        g.merge_64_metadata(g2)
  #    end
      g.write
  #    g.cleanup
      rescue => e
        msg = e.message
        msg = 'Internal error' if msg.empty?
        $DEBUG = true #DEBUG
        if $DEBUG
            $stderr.puts "Received exception: #{e}:"
            $stderr.puts e.backtrace.join("\n")
        end
        die msg, opts.banner, help_msg
      end
    end
  end
end
