# This file is part of the Gentium package for TeX.
# It is licensed under the Expat License, see doc//README for details.
#
# This is just helper file for the main script generate-support-files.rb.
# It is not intended to be run directly
#
# TODO: Make it work with current version of Ruby! It works with version
#       1.8.7, but not with version as old as 1.9.1.

require 'fileutils'

$TDS_ROOT = File.expand_path('../../../')
$package_name = "gentium-tug"

$path_source  = File.join($TDS_ROOT, "source", "fonts",              $package_name)
$path_ttf     = File.join($TDS_ROOT, "fonts",  "truetype", "public", $package_name)
$path_type1   = File.join($TDS_ROOT, "fonts",  "type1",    "public", $package_name)
$path_tfm     = File.join($TDS_ROOT, "fonts",  "tfm",      "public", $package_name)
$path_afm     = File.join($TDS_ROOT, "fonts",  "afm",      "public", $package_name)
$path_map_ttf = File.join($TDS_ROOT, "fonts",  "map",      "pdftex", $package_name)
$path_map     = File.join($TDS_ROOT, "fonts",  "map",      "dvips",  $package_name)
$path_enc     = File.join($TDS_ROOT, "fonts",  "enc",      "dvips",  $package_name)
$path_fd      = File.join($TDS_ROOT, "tex",    "latex",              $package_name)
$path_tmp     = File.join($TDS_ROOT, "tmp")

class Font
	def initialize(filename, name_something, filename_tex)
		@filename     = filename
		@filename_tex = filename_tex
		@name_something = name_something # TODO
		if filename =~ /Plus/ then
			@is_plus = true
		else
			@is_plus = false
		end
	end
	def is_plus?
		return @is_plus
	end

	def filename_ttf
		return "#{@filename}.ttf"
	end
	def filename_type1
		return "#{@filename}.pfb"
	end
	def filename_afm
		return "#{@filename}.afm"
	end
	def filename_pl
		return "#{@filename}.pl"
	end

	def generate_type1_with_ttf2pt1
		puts "#"
		puts "# generating type1 version of #{@filename}"
		puts "#"
		pwd = Dir.pwd()
		Dir.chdir($path_ttf)
		command = "ttf2pt1 -a -b #{filename_ttf}"
		puts "> #{command}"
		if system(command) then
			if File.exists?(filename_type1) then
				File.rename(filename_type1, File.join($path_type1, filename_type1))
			else
				stderr.puts "ERROR: '#{filename_type1}' doesn't exist"
			end
			if File.exists?(filename_afm) then
				File.rename(filename_afm, File.join($path_afm, filename_afm))
			else
				stderr.puts "ERROR: '#{filename_afm}' doesn't exist"
			end
		end
		Dir.chdir(pwd)
	end

	def generate_type1
		generate_type1_with_ttf2pt1
	end

	def generate_tfms(encoding)
		# normal
		if is_plus? or encoding.has_bold? then
			generate_tfm(encoding, false)
		end
		# small caps
		if is_plus? and encoding.has_smallcaps? then
			generate_tfm(encoding, true)
		end
	end

	def generate_tfm(encoding, smallcaps)
		pwd = Dir.pwd
		Dir.chdir($path_afm)
		smcp = ""
		if smallcaps then
			smcp = "-sc"
		end
		puts "#"
		puts "# Generating TFM file for font \"#{filename}\" in encoding \"#{encoding.name}#{smcp}\""
		puts "#"
		filename_enc = "gentium-#{encoding.name}#{smcp}.enc"
		filename_map = "#{filename}.map"
		filename_pl_new = "#{encoding.name}-#{filename_tex}#{smcp}.pl"
		filename_tfm    = "#{encoding.name}-#{filename_tex}#{smcp}.tfm"
		filename_lig = File.join(pwd, "lig", "gentium-#{encoding.name}#{smcp}.lig")

		# temporarily copy encoding file to current directory (absolute paths don't seem to work)
		FileUtils.cp(File.join($path_enc, filename_enc), filename_enc)
		# File.copy(File.join($path_enc, filename_enc), filename_enc)
		if File.exists?(filename_lig) then
			command = "afm2pl -p #{filename_enc} -l #{filename_lig} #{filename_afm}"
		else
			command = "afm2pl -p #{filename_enc} #{filename_afm}"
		end
		puts "> #{command}"
		system(command)
		# output = `#{command}`
		# if $?.success? then
			if File.exists?(filename_pl) then
				File.rename(filename_pl, filename_pl_new)
				command2 = "pltotf #{filename_pl_new}"
				puts "> #{command2}"
				if system(command2) then
					if File.exists?(filename_tfm) then
						File.rename(filename_tfm, File.join($path_tfm, filename_tfm))
					else
						$stderr.puts "ERROR: '#{filename_tfm}' doesn't exist"
					end
				else
					$stderr.puts "ERROR: unable to run #{command2}"
				end
			else
				$stderr.puts "ERROR: '#{filename_pl}' doesn't exist"
			end
		# else
		# 	$stderr.puts "ERROR: unable to run '#{command}'"
		# 	puts output
		# end
		File.delete(filename_pl_new)
		File.delete(filename_enc)
		# afm2pl creates filename.map that has to be removed
		File.delete(filename_map)

		Dir.chdir(pwd)
		# puts "   I'm now at #{Dir.pwd}"
	end

	def glyph_names
		if @glyph_names_hash == nil then
			@glyph_names_hash = Hash.new
			File.open(File.join($path_afm, filename_afm)).each_line.grep(/^C .*?; N ([^\s]*)/) do |line|
				name = $1
				@glyph_names_hash[name] = true
				# puts line
			end
		end

		return @glyph_names_hash
	end

	attr_reader :filename, :filename_tex, :name_something
end

class FontSet
	def initialize(font_rm, font_it, font_bf, font_bi)
		@rm = font_rm
		@it = font_it
		@bf = font_bf
		@bi = font_bi
		@list = [font_rm, font_it, font_bf, font_bi]
	end
	def each
		@list.each { |f| if f then yield f end }
	end
end

class Encoding
	def initialize(name, supported_by_basic_family)
		@name = name
		@supported_by_basic_family = supported_by_basic_family
	end
	def to_s
		@name
	end
	def name_context
		return @name
	end
	def name_latex
		if @name == "ec" then
			return "t1"
		elsif @name == "texnansi" then
			return "ly1"
		else
			return @name
		end
	end
	def name_latex_uppercase
		if @name == "l7x" then
			return "L7x"
		else
			return name_latex.upcase
		end
	end
	def name_truetype
		if ["ec", "t5"].include?(@name) then
			return "#{@name}-ttf"
		else
			return @name
		end
	end
	def name_truetype_sc
		if @name == "ec" then
			return "#{@name}-ttf-sc"
		else
			return "#{@name}-sc"
		end
	end

	def is_used_in_context?
		if ["ot1", "ts1", "lgr", "t2b", "t2c", "x2"].include?(@name) then
			return false
		else
			return true
		end
	end
	def is_used_in_latex?
		if ["agr"].include?(@name) then
			return false
		else
			return true
		end
	end
	def has_bold?
		# TODO: (Pavel) All fonts have bold weight. Refactor out the tests for bold.
		return true
	end
	def has_smallcaps?
		if ["ts1", "agr", "lgr"].include?(@name) then
			return false
		else
			return true
		end
	end

	def generate_enc_sc(font)
		file_enc_new = File.open(File.join($path_enc, "gentium-#{@name}-sc.enc"), 'w')
		File.open(File.join($path_enc, "gentium-#{@name}.enc")).each_line do |line|
			if line =~ /Encoding/ then
				file_enc_new.puts line.gsub(/Encoding/, "scEncoding")
			elsif line =~ /^\/([^\s%]*)/ then
				name = $1
				name_sc = "#{name}.sc"
				if not font.glyph_names[name] then
					puts "Warning: glyph '#{name}' in in encoding '#{@name}' doesn't exist."
				end
				if name == "uni0237" then
					name_sc = "j.sc"
				end
				if font.glyph_names[name_sc] then
					file_enc_new.puts "/#{name_sc}"
				elsif ["ff", "fi", "ffi", "fl", "ffl"].include?(name) then
					file_enc_new.puts "/.notdef"
				else
					file_enc_new.puts "/#{name}"
				end
			else
				file_enc_new.puts line
			end
		end
		file_enc_new.close
	end

	def declare_font_shape(width, shape, name)
		text = "\\DeclareFontShape{#{name_latex_uppercase}}{gentium}{#{width}}{#{shape}}{\n" +
			"            <->     \\gentium@@scale #{@name}-gentium#{name}\n" +
			"}{}\n\n"
		return text
	end
	def declare_font_shape_sub(width1, shape1, width2, shape2)
		return "\\DeclareFontShape{#{name_latex_uppercase}}{gentium}{#{width1}}{#{shape1}}{<->ssub * gentium/#{width2}/#{shape2}}{}"
	end
	def generate_fd
		date = Time.new.strftime("%Y/%m/%d")  # set creation date to current date

		filename = "#{name_latex}gentium.fd"
		File.open(File.join($path_fd,filename), 'w') do |file|
			file.puts "\\ProvidesFile{#{name_latex}gentium.fd}"
			file.puts "    [#{date} Font definitions for gentium.]"
			file.puts
			file.puts '\expandafter\ifx\csname gentium@scale\endcsname\relax'
			file.puts '    \let\gentium@@scale\@empty'
			file.puts '\else'
			file.puts '    \edef\gentium@@scale{s*[\csname gentium@scale\endcsname]}%'
			file.puts '\fi'
			file.puts
			file.puts "\\DeclareFontFamily{#{name_latex_uppercase}}{gentium}{}"
			file.puts
			file.puts declare_font_shape("m", "n",  "plus-regular")
			file.puts declare_font_shape("m", "it", "plus-italic")
			if has_bold? then
				file.puts declare_font_shape("b", "n",  "plus-bold")
				file.puts declare_font_shape("b", "it", "plus-bolditalic")
				# gentium book as additional weights (semi bold, extra bold)
				file.puts declare_font_shape("sb", "n",  "book-regular")
				file.puts declare_font_shape("sb", "it", "book-italic")
				file.puts declare_font_shape("eb", "n",  "book-bold")
				file.puts declare_font_shape("eb", "it", "book-bolditalic")
				# TODO: set the correct tfm names in the following two lines
				if has_smallcaps? then
					file.puts declare_font_shape("m", "sc",   "plus-regular-sc")
					file.puts declare_font_shape("m", "scit", "plus-italic-sc")
					file.puts declare_font_shape("b", "sc",   "plus-bold-sc")
					file.puts declare_font_shape("b", "scit", "plus-bolditalic-sc")
					# gentium book as additional weights (semi bold, extra bold)
					file.puts declare_font_shape("sb", "sc",   "book-regular-sc")
					file.puts declare_font_shape("sb", "scit", "book-italic-sc")
					file.puts declare_font_shape("eb", "sc",   "book-bold-sc")
					file.puts declare_font_shape("eb", "scit", "book-bolditalic-sc")
				end
				# TODO: a clever algorithm to do replacements instead
				# TODO: (Pavel) Look at substitutions (bold, small caps)
				file.puts declare_font_shape_sub("m",  "sl", "m", "it")
				file.puts declare_font_shape_sub("b",  "sl", "b", "it")
				file.puts declare_font_shape_sub("bx", "sl", "b", "it")
				file.puts declare_font_shape_sub("bx", "it", "b", "it")
				file.puts declare_font_shape_sub("bx", "n",  "b", "n")
				# substitutions for additional weights
				file.puts declare_font_shape_sub("sb",  "sl", "sb", "it")
				file.puts declare_font_shape_sub("sbx", "sl", "sb", "it")
				file.puts declare_font_shape_sub("sbx", "it", "sb", "it")
				file.puts declare_font_shape_sub("sbx", "n",  "sb", "n")
				file.puts declare_font_shape_sub("eb",  "sl", "eb", "it")
				file.puts declare_font_shape_sub("ebx", "sl", "eb", "it")
				file.puts declare_font_shape_sub("ebx", "it", "eb", "it")
				file.puts declare_font_shape_sub("ebx", "n",  "eb", "n")
			else
				file.puts declare_font_shape_sub("m",  "sl", "m", "it")
			end
			file.puts
			file.puts '\endinput'
		end
	end

	# TODO: (Pavel) Merge the following 3 methods with the previous 3 methods
	def declare_font_shape_book(width, shape, name)
		text = "\\DeclareFontShape{#{name_latex_uppercase}}{gentiumbook}{#{width}}{#{shape}}{\n" +
			"            <->     \\gentiumbook@@scale #{@name}-gentium#{name}\n" +
			"}{}\n\n"
		return text
	end
	def declare_font_shape_sub_book(width1, shape1, width2, shape2)
		return "\\DeclareFontShape{#{name_latex_uppercase}}{gentiumbook}{#{width1}}{#{shape1}}{<->ssub * gentiumbook/#{width2}/#{shape2}}{}"
	end
	def generate_fd_book
		date = Time.new.strftime("%Y/%m/%d")  # set creation date to current date

		filename = "#{name_latex}gentiumbook.fd"
		File.open(File.join($path_fd,filename), 'w') do |file|
			file.puts "\\ProvidesFile{#{name_latex}gentiumbook.fd}"
			file.puts "    [#{date} Font definitions for gentiumbook.]"
			file.puts
			file.puts '\expandafter\ifx\csname gentiumbook@scale\endcsname\relax'
			file.puts '    \let\gentiumbook@@scale\@empty'
			file.puts '\else'
			file.puts '    \edef\gentiumbook@@scale{s*[\csname gentiumbook@scale\endcsname]}%'
			file.puts '\fi'
			file.puts
			file.puts "\\DeclareFontFamily{#{name_latex_uppercase}}{gentiumbook}{}"
			file.puts
			file.puts declare_font_shape_book("m", "n",  "book-regular")
			file.puts declare_font_shape_book("m", "it", "book-italic")
			if has_bold? then
				file.puts declare_font_shape_book("b", "n",  "book-bold")
				file.puts declare_font_shape_book("b", "it", "book-bolditalic")
				# gentium plus as additional weights (semi light, semi bold)
				file.puts declare_font_shape_book("sl", "n",  "plus-regular")
				file.puts declare_font_shape_book("sl", "it", "plus-italic")
				file.puts declare_font_shape_book("sb", "n",  "plus-bold")
				file.puts declare_font_shape_book("sb", "it", "plus-bolditalic")
				# TODO: set the correct tfm names in the following two lines
				if has_smallcaps? then
					file.puts declare_font_shape_book("m", "sc",   "book-regular-sc")
					file.puts declare_font_shape_book("m", "scit", "book-italic-sc")
					file.puts declare_font_shape_book("b", "sc",   "book-bold-sc")
					file.puts declare_font_shape_book("b", "scit", "book-bolditalic-sc")
					# gentium plus as additional weights (semi light, semi bold)
					file.puts declare_font_shape_book("sl", "sc",   "plus-regular-sc")
					file.puts declare_font_shape_book("sl", "scit", "plus-italic-sc")
					file.puts declare_font_shape_book("sb", "sc",   "plus-bold-sc")
					file.puts declare_font_shape_book("sb", "scit", "plus-bolditalic-sc")
				end
				# TODO: a clever algorithm to do replacements instead
				# TODO: (Pavel) Look at substitutions (bold, small caps)
				file.puts declare_font_shape_sub_book("m",  "sl", "m", "it")
				file.puts declare_font_shape_sub_book("b",  "sl", "b", "it")
				file.puts declare_font_shape_sub_book("bx", "sl", "b", "it")
				file.puts declare_font_shape_sub_book("bx", "it", "b", "it")
				file.puts declare_font_shape_sub_book("bx", "n",  "b", "n")
				# substitutions for additional weights
				file.puts declare_font_shape_sub_book("sl",  "sl", "sl", "it")
				file.puts declare_font_shape_sub_book("sb",  "sl", "sb", "it")
				file.puts declare_font_shape_sub_book("sbx", "sl", "sb", "it")
				file.puts declare_font_shape_sub_book("sbx", "it", "sb", "it")
				file.puts declare_font_shape_sub_book("sbx", "n",  "sb", "n")
			else
				file.puts declare_font_shape_sub_book("m",  "sl", "m", "it")
			end
			file.puts
			file.puts '\endinput'
		end
	end

	attr_reader :name
end

class EncodingSet < Hash

	def generate_maps(fontlist)
		# initialize lines for map files, one array for each encoding
		map_lines_type1 = Hash.new
		map_lines_ttf   = Hash.new
		self.each_value do |encoding|
			map_lines_type1[encoding.name] = Array.new
			map_lines_ttf[encoding.name]   = Array.new
		end

		# fill data
		fontlist.each do |font|
			self.each_value do |encoding|
				# TODO: fix the last name (gentium) & encodings: this is another parameter that we have to introduce
				name_tfm     = "#{encoding.name}-#{font.filename_tex}".ljust(35)
				line_reenc   = "\"gentium-#{encoding.name}Encoding ReEncodeFont\"".ljust(42)
				name_enc     = "gentium-#{encoding.name}.enc"
				name_enc_ttf = "gentium-#{encoding.name_truetype}.enc"

				# normal
				if font.is_plus? or encoding.has_bold? then
					map_lines_type1[encoding.name].push("#{name_tfm} #{font.name_something.ljust(28)} #{line_reenc} <#{name_enc.ljust(24)} <#{font.filename_type1}")
					map_lines_ttf[encoding.name].push("#{name_tfm} #{font.name_something.ljust(28)} <#{font.filename_ttf.ljust(18)} #{name_enc_ttf}")
				end
				# small caps
				if font.is_plus? and encoding.has_smallcaps? then
					name_tfm    = "#{encoding.name}-#{font.filename_tex}-sc".ljust(35)
					line_reenc = "\"gentium-#{encoding.name}scEncoding ReEncodeFont\"".ljust(42)
					name_enc = "gentium-#{encoding.name}-sc.enc"
					name_enc_ttf = "gentium-#{encoding.name_truetype_sc}.enc"

					map_lines_type1[encoding.name].push("#{name_tfm} #{font.name_something.ljust(28)} #{line_reenc} <#{name_enc.ljust(24)} <#{font.filename_type1}")
					map_lines_ttf[encoding.name].push("#{name_tfm} #{font.name_something.ljust(28)} <#{font.filename_ttf.ljust(18)} #{name_enc_ttf}")
				end
			end
		end

		# write map files into files
		map_file_type1 = File.open(File.join($path_map,     "gentiumplus-type1.map"   ), 'w')
		map_file_ttf   = File.open(File.join($path_map_ttf, "gentiumplus-truetype.map"), 'w')
		self.sort.map do |k,encoding|
			# map file for Type1
			map_lines_type1[encoding.name].each do |line|
				map_file_type1.puts line
			end
			# map file fon TrueType
			map_lines_ttf[encoding.name].each do |line|
				map_file_ttf.puts line
			end
			# map file for TrueType for a single encoding (for ConTeXt)
			# if encoding.is_used_in_context? then
			if true then
				File.open(File.join($path_map_ttf, "gentiumplus-#{encoding.name}.map"), 'w') do |map_file_enc|
					map_lines_ttf[encoding.name].each do |line|
						map_file_enc.puts line
					end
				end
			end
		end
		map_file_type1.close
		map_file_ttf.close
	end

	# TODO: (Pavel) Merge methods "generate_maps" and "generate_maps_book"
	def generate_maps_book(fontlist)
		# initialize lines for map files, one array for each encoding
		map_lines_type1 = Hash.new
		map_lines_ttf   = Hash.new
		self.each_value do |encoding|
			map_lines_type1[encoding.name] = Array.new
			map_lines_ttf[encoding.name]   = Array.new
		end

		# fill data
		fontlist.each do |font|
			self.each_value do |encoding|
				# TODO: fix the last name (gentium) & encodings: this is another parameter that we have to introduce
				name_tfm     = "#{encoding.name}-#{font.filename_tex}".ljust(35)
				line_reenc   = "\"gentium-#{encoding.name}Encoding ReEncodeFont\"".ljust(42)
				name_enc     = "gentium-#{encoding.name}.enc"
				name_enc_ttf = "gentium-#{encoding.name_truetype}.enc"

				# normal
				if font.is_plus? or encoding.has_bold? then
					map_lines_type1[encoding.name].push("#{name_tfm} #{font.name_something.ljust(28)} #{line_reenc} <#{name_enc.ljust(24)} <#{font.filename_type1}")
					map_lines_ttf[encoding.name].push("#{name_tfm} #{font.name_something.ljust(28)} <#{font.filename_ttf.ljust(18)} #{name_enc_ttf}")
				end
				# small caps
				if font.is_plus? and encoding.has_smallcaps? then
					name_tfm    = "#{encoding.name}-#{font.filename_tex}-sc".ljust(35)
					line_reenc = "\"gentium-#{encoding.name}scEncoding ReEncodeFont\"".ljust(42)
					name_enc = "gentium-#{encoding.name}-sc.enc"
					name_enc_ttf = "gentium-#{encoding.name_truetype_sc}.enc"

					map_lines_type1[encoding.name].push("#{name_tfm} #{font.name_something.ljust(28)} #{line_reenc} <#{name_enc.ljust(24)} <#{font.filename_type1}")
					map_lines_ttf[encoding.name].push("#{name_tfm} #{font.name_something.ljust(28)} <#{font.filename_ttf.ljust(18)} #{name_enc_ttf}")
				end
			end
		end

		# write map files into files
		map_file_type1 = File.open(File.join($path_map,     "gentiumbook-type1.map"   ), 'w')
		map_file_ttf   = File.open(File.join($path_map_ttf, "gentiumbook-truetype.map"), 'w')
		self.sort.map do |k,encoding|
			# map file for Type1
			map_lines_type1[encoding.name].each do |line|
				map_file_type1.puts line
			end
			# map file fon TrueType
			map_lines_ttf[encoding.name].each do |line|
				map_file_ttf.puts line
			end
			# map file for TrueType for a single encoding (for ConTeXt)
			# if encoding.is_used_in_context? then
			if true then
				File.open(File.join($path_map_ttf, "gentiumbook-#{encoding.name}.map"), 'w') do |map_file_enc|
					map_lines_ttf[encoding.name].each do |line|
						map_file_enc.puts line
					end
				end
			end
		end
		map_file_type1.close
		map_file_ttf.close
	end
end