# Classes for translating text similar to GNU gettext
# Translator class: translate text to another language

# for debug REMOVE BEFORE COMMITTING / BUILDING
# require "zlib"

class Language
  FONT_WESTERN = 'Terminus (TTF)'
  FONT_J = 'HigashiOme Gothic regular'
  LANGUAGES = []
  class << self
    def set(lc)
      @data = nil
      @tr = nil
      [lc.full, lc.lang].each do |name|
        path = "Languages/#{name}.po"
        if File.exist?(path)
          load_pot(path)
          loadFontMap
          Font.default_name = @languageFontMap[name]
          Journal.setLang(name)
          break
        end
      end
      reset_fonts(@text_sprites)
      Oneshot.set_yes_no(tr('Yes'), tr('No'))
    end
	  
    def unescape_string(str)
      unescaped = []
      
      string_began = false
      escape = false
      str.chars.each do |c|
        if not string_began
          string_began = true if c == '"'
          next
        end

        next if c == "\n"
        next if c == "\r"

        if not escape
          break if c == '"'
          if c == '\\'
          	escape = true
            next
          end
        else
          escape = false
          case c
          when 'n'
            unescaped.push("\n")
          when 'r'
            unescaped.push("\r")
          else
            unescaped.push(c)
          end
          next
        end

        unescaped.push(c)
      end

      return unescaped.join('')
    end

    def load_pot(path)
      msgid = nil
      msgstr = nil
      @data = Hash.new
      lastLineWasMsgId = false
      lastLineWasMsgStr = false
      if File.exist?(path)
        File.readlines(path, encoding: "UTF-8").each do |line|
          if line.start_with?("msgid ")
            line = line[6..-1]
            #unescape the string
			#note that I tried using undump here instead before, but it doesn't play nicely with non-ascii characters
            msgid = unescape_string(line)
            lastLineWasMsgId = true
            lastLineWasMsgStr = false
      
          elsif line.start_with?("msgstr ")
            line = line[7..-1]
            #unescape the string
            msgstr = unescape_string(line)
            lastLineWasMsgId = false
            lastLineWasMsgStr = true
      
          elsif line.start_with?("\"")
            if lastLineWasMsgId
              msgid += unescape_string(line)
              lastLineWasMsgId = true
              lastLineWasMsgStr = false
        
            elsif lastLineWasMsgStr
              msgstr += unescape_string(line)
              lastLineWasMsgId = false
              lastLineWasMsgStr = true
        
            else #ignore
              lastLineWasMsgId = false
              lastLineWasMsgStr = false
        
            end
      
          else
            lastLineWasMsgId = false
            lastLineWasMsgStr = false
      
            if !(msgid.nil? || msgid.empty?)
              @data[Oneshot::crc32(msgid)] = msgstr
              msgid = nil
              msgstr = nil
            end
          end
        end
      end
    
      # make sure we cleared out the last one stored
      if !(msgid.nil? || msgid.empty?)
        @data[Oneshot::crc32(msgid)] = msgstr
        msgid = nil
        msgstr = nil
      end
    end

    # Translate some text
    def tr(string)
      return string unless @data
      s = string.to_s.encode("UTF-8")
      rv = @data[Oneshot::crc32(s)] || s
      rv.nil? ? "NULL" : String.new(rv)
    end

    def loadFontMap
      if !@fontMapLoaded
        @languageFontMap = Hash.new
        path = "Languages/language_fonts.ini"
        if File.exist?(path)
          File.readlines(path, encoding: "UTF-8").each do |line|
            parts = line.split("=", 2)
            #print(parts[0].inspect)
            if parts.length == 2
              LANGUAGES.push(parts[0])
              @languageFontMap[parts[0]] = parts[1].strip
            end
          end
        end
        @fontMapLoaded = true
      end
    end

    # Turn all database items into translatable strings
    def initialize_database
      $data_actors.each do |i|
        i.name = TrString.new(i.name) if i && !i.name.empty?
      end
      $data_items.each do |i|
        if i && !i.name.empty?
          i.name = TrString.new(i.name)
          i.description = TrString.new(i.description)
        end
      end
    end

    def register_text_sprite(key, spr)
      if @text_sprites.nil?
        @text_sprites = Hash.new()
      end
      @text_sprites[key] = spr
      # we dont want memory leak
      @text_sprites.delete_if do |_, ispr|
        ispr.disposed?
      end
    end

    def reset_fonts(sprites)
      if sprites.kind_of?(Array)
        sprites.each do |spr|
          if spr.kind_of?(Sprite) and !spr.disposed?
            spr.bitmap.font.name = Font.default_name
          end
        end
      elsif sprites.kind_of?(Hash)
        sprites.each_value do |spr|
          if spr.kind_of?(Sprite) and !spr.disposed?
            spr.bitmap.font.name = Font.default_name
          elsif spr.kind_of?(Bitmap) and !spr.disposed?
            spr.font.name = Font.default_name
          end
        end
      elsif sprites.kind_of?(Sprite) and not sprites.disposed?
        sprites.bitmap.font.name = Font.default_name
      end
    end
  end
end

# Translatable string
class TrString
  def initialize(str)
    @str = str
  end

  def to_str
    Language.tr(@str)
  end
  alias :to_s :to_str

  def length
    to_str.length
  end

  def +(other)
    to_str + other
  end
end

def tr(text)
  TrString.new(text)
end
