# spittoon-compat.rb --- a compatibility shim so Spittoon (statico/
# spittoon, written in 2005 for RMagick 1.x/2.x) runs on modern
# RMagick (7.x) + Ruby 3.x, without touching the (root-owned) Spittoon
# tree. Loaded via `ruby -r /path/to/spittoon-compat.rb` ahead of
# bin/make_comic.rb (see qdb-comic).
#
# Two incompatibilities are bridged here:
#
# 1. The RMagick "configuration block" idiom. Spittoon writes
#
#        Magick::Image.new(w, h) do
#          self.background_color = '...'
#        end
#
#    where the block was instance_eval'd against the object being
#    configured (an Image::Info, or a Montage for ImageList#montage),
#    so a bare `self.background_color =` worked. Modern RMagick *yields*
#    that object to the block instead, leaving `self` as the caller ---
#    so those blocks raise NoMethodError. Every such block in
#    spittoon.rb is pure `self.<setter> = ...` (no instance variables),
#    so re-instating instance_eval semantics fixes them all at once:
#    Image.new / Image.read (8 sites), ImageList#montage (4 sites in
#    spittoon.rb), and Image#write (the final write in make_comic.rb).
#
# 2. File.exists?. Ruby 3.2 removed the plural form; Spittoon still
#    calls it. Alias it back to File.exist?.

require 'rmagick'

# --- (2) Ruby 3.2+ removed File.exists? -------------------------------------
unless File.respond_to?(:exists?)
  class << File
    alias_method :exists?, :exist?
  end
end

# --- (1) RMagick configuration-block idiom ----------------------------------
# Wrap a method so that, when given a block, the object RMagick yields
# is the block's `self` (old instance_eval semantics) instead of its
# argument (new yield semantics).
module Magick
  class Image
    # Class methods: Image.new, Image.read.
    class << self
      [:new, :read].each do |name|
        orig = :"_spittoon_orig_#{name}"
        next if method_defined?(orig) || private_method_defined?(orig)
        alias_method orig, name
        define_method(name) do |*args, &block|
          return send(orig, *args) unless block
          send(orig, *args) { |cfg| cfg.instance_eval(&block) }
        end
      end
    end

    # Instance method: image.write(file) { self.quality = ... }.
    unless method_defined?(:_spittoon_orig_write)
      alias_method :_spittoon_orig_write, :write
      def write(file, &block)
        return _spittoon_orig_write(file) unless block
        _spittoon_orig_write(file) { |cfg| cfg.instance_eval(&block) }
      end
    end
  end

  class ImageList
    unless method_defined?(:_spittoon_orig_montage)
      alias_method :_spittoon_orig_montage, :montage
      def montage(&block)
        return _spittoon_orig_montage unless block
        _spittoon_orig_montage { |cfg| cfg.instance_eval(&block) }
      end
    end
  end
end

# --- (3) RMagick 5+/IM7 removed the matte (alpha) API -----------------------
# Spittoon's "open" panel style (generate_background, the random
# alternative to "closed") fades a background's bottom third out via:
#
#     bg.matte = true; mask.matte = false
#     bg.composite!(mask, 0, stop_y, Magick::CopyOpacityCompositeOp)
#
# `Image#matte=`/`#matte` were deprecated aliases for the alpha channel,
# removed in RMagick 5.0 (now `#alpha`/`#alpha?`); `CopyOpacityCompositeOp`
# was renamed `CopyAlphaCompositeOp` for ImageMagick 7. Without these the
# open style raises NoMethodError / NameError and the whole strip render
# aborts --- so roughly half of all panels (style is chosen at random)
# fail, which on RMagick 7 means effectively every multi-panel quote.
module Magick
  class Image
    unless method_defined?(:matte=)
      def matte=(flag)
        alpha(flag ? Magick::ActivateAlphaChannel : Magick::DeactivateAlphaChannel)
        flag
      end
    end
    unless method_defined?(:matte)
      def matte
        alpha?
      end
    end
  end

  unless const_defined?(:CopyOpacityCompositeOp)
    CopyOpacityCompositeOp = CopyAlphaCompositeOp
  end
end
