# PDF-O-Matic is copyright (c) 2009, Brett Neumeier.
#
# PDF-O-Matic may be used under the terms of the GPL.  See
# COPYING.GPL, provided in this distribution, for full details.
#
# DOJ and CompNet Design, Inc., are granted a perpetual license to
# use, extend, modify, and redistribute the PDF-O-Matic software as
# they wish, without restriction.

module PdfHelpers

  def primary_color
    c, m, y, k = @primary_color
    color(c, m, y, k)
  end

  def with_secondary_color
    c, m, y, k = @secondary_color
    color(c, m, y, k)
    yield
    primary_color
  end

  def color(c, m, y, k)
    pdf.fill_color(c, m, y, k)
    pdf.stroke_color(c, m, y, k)
  end

  def glyphs
    pdf.font.respond_to?(:ttf) ? pdf.font.ttf.cmap.unicode.first : {}
  end

  def font_size_for_all(strings, field_width)
    font_sizes = strings.map { |string|
      pdf.save_font {
        (pdf.font_size -= 0.5) while (width_of(string) > field_width)
        pdf.font_size
      }
    }
    font_sizes.min
  end

  def font_size_for(string, field_width)
    font_size_for_all([ string ], field_width)
  end

  def text_centered_at(string, x, y, field_width = 9999)
    s = cleanup_string(string)
    # kludge to handle two-line text
    s = s + ' ' if s.end_with?('/')
    primary, secondary = s.split('/')
    pdf.font_size(font_size_for(s, field_width)) {
      w = width_of(s)
      primary_pos = x - (w/2)
      pdf.text(primary, :at => [ primary_pos, y ])
      if secondary
        secondary_pos = primary_pos + width_of(primary)
        with_secondary_color {
          pdf.text('/' + secondary, :at => [ secondary_pos, y ])
        }
      else
        pdf.text(s, :at => [ x - (w/2), y ])
      end
    }
  end

  def text_centered_twolines_at(string, x, y, field_width)
    s = cleanup_string(string)
    if s =~ /[0-9].*\/.*[0-9]/
      primary, secondary = s.split('/')
      pdf.font_size(font_size_for_all([primary, secondary], field_width)) {
        text_centered_at(primary + '/', x, y + pdf.font_size, field_width)
        with_secondary_color{
          text_centered_at(secondary, x, y, field_width)
        }
      }
    else
      text_centered_at(s, x, y, field_width)
    end
  end

  def text_left_at(string, x, y, field_width = 9999)
    s = cleanup_string(string)
    pdf.font_size(font_size_for(s, field_width)) {
      pdf.text(s, :at => [ x, y ])
    }
  end

  def text_right_at(string, x, y, field_width = 9999)
    s = cleanup_string(string)
    pdf.font_size(font_size_for(s, field_width)) {
      pdf.text(s, :at => [ x - width_of(s), y ])
    }
  end

  def text_trimmed_at(string, x, y, field_width)
    s = cleanup_string(string)

    if width_of(s) <= field_width
      ellipsis = ''
    elsif glyphs[8230]
      ellipsis = [8230].pack('U')
    else
      ellipsis = '...'
    end

    while width_of(s + ellipsis) > field_width || s.end_with?(' ')
      s = remove_last_char_from(s)
    end
    pdf.text(s + ellipsis, :at => [ x, y ])
  end

  # Chop off the last character of string, which may be UTF-8
  # encoded.
  def remove_last_char_from(string)
    string.unpack('U*')[0..-2].pack('U*')
  end

  def height_of_text(string, width)
    wrapped_text(string, width).size
  end

  def wrapped_text(string, width)
    s = cleanup_string(string)
    pdf.naive_wrap(s, width, pdf.font_size).split("\n")
  end

  def wrapped_text_at(string, x, y, linedrop, width)
    lines = wrapped_text(string, width)
    lines.each_with_index { |l, i|
      text_left_at(l, x, y)
      y -= linedrop
      x += 5 if i == 0
    }
    return y + linedrop
  end

  def width_of(string)
    pdf.width_of(string.to_s, :kerning => true)
  end

  def whiteout(x1, y1, x2, y2)
    color(0, 0, 0, 0)
    pdf.move_to(x1, y1)
    pdf.line_to(x2, y1)
    pdf.line_to(x2, y2)
    pdf.line_to(x1, y2)
    pdf.fill
    primary_color
  end

  def cleanup_string(string)
    s = remove_hd_description_cruft(string.to_s)
    s = s.gsub(/  /,' ')
    s = s.gsub(/, ;/,';')
    s = s.gsub(/\.,/,',')
    s = fix_skill_roll_consistency(s)
    s = replace_fractions(s)
    s = replace_other_characters(s)
    s = s.strip
  end

  def replace_other_characters(string)
    if glyphs[8212]
      string = string.gsub(/--/,[8212].pack('U'))
    end
    if glyphs[8220]
      string = string.gsub(/``/,[8220].pack('U'))
    else
      string = string.gsub(/``/,'"')
    end
    if glyphs[8221]
      string = string.gsub(/\'\'/,[8221].pack('U'))
    else
      string = string.gsub(/\'\'/,'"')
    end
    string
  end

  def remove_hd_description_cruft(string)
    string.gsub(/\(Total: [0-9]* Active Cost, [0-9]* Real Cost\)/,'')
  end

  # When there are both primary and secondary values for rolls,
  # HD formats characteristic rolls as 11-/14-, and skill rolls
  # as 11- (14-). This makes them consistent.
  def fix_skill_roll_consistency(string)
    if (md = /^([0-9]+)- \(([0-9]+)-\)$/.match(string))
      return "#{md[1]}-/#{md[2]}-"
    else
      return string
    end
  end

  # Sometimes a slash indicates a primary/secondary value like
  # 11/21.  Other times it indicates a fraction like 1 1/2. We
  # wawnt to replace the fractions with the actual fraction
  # glyphs and leave the other ones alone.
  def includes_fraction(string, fraction)
    return string =~ /[^0-9]#{fraction}[^0-9]/ ||
      string =~ /[^0-9]#{fraction}$/ ||
      string == fraction
  end

  def replace_fractions(string)
    if includes_fraction(string, '1/4')
      string = string.gsub(/1\/4/,[188].pack('U'))
    end
    if includes_fraction(string, '1/2')
      string = string.gsub(/1\/2/,[189].pack('U'))
    end
    if includes_fraction(string, '3/4')
      string = string.gsub(/3\/4/,[190].pack('U'))
    end
    return string
  end

end
