#!/usr/bin/env ruby
#--
# Last Change: Tue May 16 18:13:36 2006
#++
=begin rdoc

== pldiff -- show the differences between two (v)pl files.
  
  Usage: pldiff [options] file file
  file can be tfm, pl, vpl or vf files.
      -d, --delta DELTA                Don't report differences whithin +/- DELTA percent
      -c, --ignore-comments            ignore comments
      -k, --ignore-kern                ignore difference in kerning information
      -m, --mapenc ENC                 assume encoding ENC for destination encoding
      -t, --texenc ENC                 assume encoding ENC for source encoding (TeX side)
      -e, --encoding ENC               assume encoding ENC for both in and out
      -s, --skip-characters            only look at fontdimen and main data
  
      -h, --help                       Show this help
    

---
Author:: Patrick Gundlach <patrick@gundla.ch>
License::  Copyright (c) 2005 Patrick Gundlach.
           Released under the terms of the GNU General Public License

=end

# :enddoc:

require 'optparse'
require 'ostruct'

require 'rfil/tex/kpathsea'
require 'rfil/tex/enc'
require 'rfil/tex/tfm'
require 'rfil/tex/vf'

include RFIL


def showmap(mapary)
  str = ""
  if mapary
    mapary.each { |entry|
      str << "  |  " << entry.join(" ") << "\n"
    }
  end
  str
end

def plopen(filename)
  case filename
  when /\.tfm$/
    return TFM.new.read_tfm(filename)
  when /\.vf$/
    # change to that dir first
    currentdir=Dir.getwd
    dirname=File.dirname(filename)
    Dir.chdir(dirname)
    fn=File.basename(filename)
    vf=VF.new.read_vf(filename)
    Dir.chdir(currentdir)
    return vf
  when /\.pl$/
    return TFM.new.read_pl(filename)
  when /\.vpl$/
    return TFM.new.read_pl(filename)
  else
    puts "Unknown format: #{filename}"
    exit 1
  end
end

include TeX
options=OpenStruct.new
kpse=Kpathsea.new

ARGV.options { |opts|
  opts.banner = "Usage: #{File.basename($0)} [options] file file"
  opts.separator "file can be tfm, pl, vpl or vf files."
  
  opts.on("--delta","-d DELTA", Float,
         "Don't report differences whithin +/- DELTA percent") { |d|
    options.delta=d
  }
  opts.on("--ignore-comments", "-c", "ignore comments") { |i|
    options.ignore_comments=true
  }
  opts.on("--ignore-kern", "-k", "ignore difference in kerning information") { |k|
    options.ignore_kern=true
  }

  opts.on("--mapenc", "-m ENC",
          "assume encoding ENC for destination encoding") {|e|
    options.mapencoding=e
  }

  opts.on("--texenc", "-t ENC",
          "assume encoding ENC for source encoding (TeX side)") {|e|
    options.texencoding=e
  }
    
  opts.on("--encoding", "-e ENC",
          "assume encoding ENC for both in and out") {|e|
    options.encoding=e
  }
  opts.on("--skip-characters", "-s", "only look at fontdimen and main data") {|s|
    options.skip=true
  }
  opts.on_tail("--help", "-h", "Show this help") { puts opts; exit 0 }
  opts.separator  ""
  opts.parse!
}

# untested:
if options.encoding
  kpse.open_file(options.encoding,"enc") { |f|
    options.encoding = ENC.new(f)
  }
  options.mapencoding=options.encoding
  options.texencoding=options.encoding
end

if options.mapencoding.instance_of?(String)
  kpse.open_file(options.mapencoding,"enc") { |f|
    options.mapencoding = ENC.new(f)
  }
end

if options.texencoding.instance_of?(String)
  kpse.open_file(options.texencoding,"enc") { |f|
    options.texencoding = ENC.new(f)
  }
end

if ARGV.size != 2
  puts "#{File.basename($0)}: Need exactly two file arguments."
  puts "Try `#{File.basename($0)} --help' for more information."
  exit 0
end


p1 = plopen(ARGV[0])
p2 = plopen(ARGV[1])

percent = options.delta ? options.delta/50.0 : 0

[:fontfamily,:codingscheme,:designsize].each { |sym|
  if p1.send(sym) != p2.send(sym)
    puts "#{sym} differ: #{p1.send(sym)} vs #{p2.send(sym)}"
  end
}


fd1 = p1.params
fd2 = p2.params
str = ""
if fd1.size != fd2.size
  str << "Difference in number of parameters (fontdimen)"
end

paramname=%w( X SLANT SPACE STRETCH SHRINK XHEIGHT QUAD EXTRASPACE )
if p1.codingscheme=="TeX math symbols"
  paramname += %w(NUM1 NUM2 NUM3 DENOM1 DENOM2 SUP1 SUP2 SUP3
                      SUB1 SUB2 SUPDROP)
elsif p1.codingscheme=="TeX math extension"
  paramname += %w(DEFAULT_RULE_THICKNESS BIG_OP_SPACING1
      BIG_OP_SPACING2 BIG_OP_SPACING3 BIG_OP_SPACING4 BIG_OP_SPACING5) 
end

for i in 1..fd1.size
  next if fd1[i] == fd2[i]
  if fd1[i]==nil
    str << "Difference in #{paramname[i]}: nil vs. #{fd2[i]}" << "\n"
  elsif
    fd2[i]==nil
    str << "Difference in #{paramname[i]}: #{fd1[i]} vs. nil"  << "\n"
  elsif (fd1[i] - fd2[i] ).abs > fd1[i] * percent
    str << "Difference in #{paramname[i]}: #{fd1[i]} vs. #{fd2[i]}" << "\n" 
  end
end

if str.size > 0
  puts "--------------------"
  puts "fondimen difference:"
  puts str
  puts "--------------------"
end

exit if options.skip==true
str= ""
0.upto(255) do |i|
  a=p1.chars[i]
  b=p2.chars[i]
  next unless a and b
  l1=a[:lig_kern] ? p1.lig_kern[a[:lig_kern]] : nil
  l2=b[:lig_kern] ? p2.lig_kern[b[:lig_kern]] : nil

  next if a==b and l1==l2

  if a==nil
    str << "#{i}: no character at this slot in font 1" << "\n"
  elsif b==nil
    str << "#{i}: no character at this slot in font 2" << "\n"
  else
    chr=""
    [:charwd, :charht, :chardp, :charic].each { |dim|
      next if a[dim].to_f==b[dim].to_f
      if a[dim]==nil 
        chr << "  Difference in #{dim}: nil vs. #{b[dim]}" << "\n"
      elsif b[dim]==nil
        chr << "  Difference in #{dim}: #{b[dim]} vs. nil" << "\n"
      elsif (a[dim]  - b[dim]).abs > a[dim] * percent
        chr << "  Difference in #{dim}: #{a[dim]} vs. #{b[dim]}" << "\n"
      end
    }
    if  l1 != l2  and options.ignore_kern != true
      chr << "  Difference in kern information" << "\n"
      if l1==nil
        str << "  no lig/kern information for first font \n"
      elsif l2==nil
        str << "  no lig/kern information for second font \n"
      else
        chr << "  in font1 but not in font 2:" << (l1 - l2).join(" ").to_s << "\n"
        chr << "  in font2 but not in font 1:" << (l2 - l1).join(" ").to_s << "\n"
      end
    end
      
#     if a[:ligkern] and b[:ligkern]
#       if a[:ligkern][:lig] != b[:ligkern][:lig]
#         chr << "  Difference in lig information"  << "\n"
#         if a[:ligkern][:lig]  
#           a[:ligkern][:lig].each { |lig|
#             chr << "  | " << lig.inspect << "\n"
#           }
#         else
#           chr << "nil"
#         end
#         chr << "  vs.\n"
#         if b[:ligkern][:lig]
#           b[:ligkern][:lig].each { |lig|
#             chr << "  | " << lig.inspect << "\n"
#           }
#         else
#           chr << "nil"
#         end
#       end
#         if a[:ligkern][:krn]
#           (a[:ligkern][:krn] - b[:ligkern][:krn]).each { |lig|
#             if options.mapencoding
#               chr <<  "  | [#{options.mapencoding[lig[0]]} #{lig[1]}]\n"
#             else
#               chr << "  | " << lig.inspect << "\n"
#             end
#           }
#         else
#           chr << "nil"
#         end
#         chr << "  vs.\n"
#         if b[:ligkern][:krn]
#           (b[:ligkern][:krn] - a[:ligkern][:krn]).each { |lig|
#             if options.mapencoding
#               chr <<  "  | [#{options.mapencoding[lig[0]]} #{lig[1]}]\n"
#             else
#               chr << "  | " << lig.inspect << "\n"
#             end
#           }
#         else
#           chr << "nil"
#         end
    #end
#    end
    if  a[:dvi] != b[:dvi] 
      chr << "  Difference in map\n"
      chr << showmap(a[:map])
      chr << "  vs.\n"
      chr << showmap(b[:map])
    end

    if chr.length > 0
      str << "#{i}: "
      if options.texencoding
        str << options.texencoding[i]
      end
      str << "\n"
      str << chr
    end
  end
end
if str.length > 0
  puts "Character entries:"
  puts "------------------"
  puts str
end