# encoding: utf-8

# dash.rb : Implements stroke dashing
#
# Contributed by Daniel Nelson. October, 2009
#
# This is free software. Please see the LICENSE and COPYING files for details.
#
module Prawn
  module Graphics
    module Dash
      # @group Stable API

      # Sets the dash pattern for stroked lines and curves or return the
      # current dash pattern setting if +length+ is nil.
      #
      # There are two ways to set the dash pattern:
      #
      # * If the parameter +length+ is an Integer/Float, it specifies
      #   the length of the dash and of the gap. The length of the gap
      #   can be customized by setting the :space option.
      #
      #   Examples:
      #
      #     length = 3
      #       3 on, 3 off, 3 on, 3 off, ...
      #     length = 3, :space =2
      #       3 on, 2 off, 3 on, 2 off, ...
      #
      # * If the parameter +length+ is an array, it specifies the
      #   lengths of alternating dashes and gaps. The :space option is
      #   ignored in this case.
      #
      #   Examples:
      #
      #     length = [2, 1]
      #       2 on, 1 off, 2 on, 1 off, ...
      #     length = [3, 1, 2, 3]
      #       3 on, 1 off, 2 on, 3 off, 3 on, 1 off, ...
      #
      # Options may contain the keys :space and :phase
      #
      # :space:: The space between the dashes (only used when +length+
      #          is not an array)
      #
      # :phase:: The distance into the dash pattern at which to start
      #          the dash. For example, a phase of 0 starts at the
      #          beginning of the dash; whereas, if the phase is equal
      #          to the length of the dash, then stroking will begin at
      #          the beginning of the space. Default is 0.
      #
      # Integers or Floats may be used for length and the option values.
      # Dash units are in PDF points (1/72 inch).
      #
      def dash(length = nil, options = {})
        return current_dash_state if length.nil?

        if length == 0 || length.kind_of?(Array) && length.any? { |e| e == 0 }
          fail ArgumentError,
               "Zero length dashes are invalid. Call #undash to disable dashes."
        end

        self.current_dash_state = { :dash  => length,
                                    :space => length.kind_of?(Array) ? nil : options[:space] || length,
                                    :phase => options[:phase] || 0 }

        write_stroke_dash
      end

      alias_method :dash=, :dash

      # Stops dashing, restoring solid stroked lines and curves
      #
      def undash
        self.current_dash_state = undashed_setting
        write_stroke_dash
      end

      # Returns when stroke is dashed, false otherwise
      #
      def dashed?
        current_dash_state != undashed_setting
      end

      private

      def write_stroke_dash
        renderer.add_content dash_setting
      end

      def undashed_setting
        { :dash => nil, :space => nil, :phase => 0 }
      end

      def current_dash_state=(dash_options)
        graphic_state.dash = dash_options
      end

      def current_dash_state
        graphic_state.dash
      end

      def dash_setting
        graphic_state.dash_setting
      end
    end
  end
end
