#!/usr/bin/env python3
#
# (C) 2019-22 - ntop.org
#
# missing_localization.py
# A tool to find missing localization strings
#
# Sample invocation:
#   tools/localization/missing_localization.py scripts/locales/en.lua pro/scripts/locales/de.lua | grep -v ".nedge." | awk '{ $2 = ""; print $0; }'

import sys
import difflib

def extract_table_key(x):
  if x.startswith('["') and x.endswith('"]'):
    return x[2:-2]
  return x

class LocalizationFile(object):
  def __init__(self, name):
    self.f = open(name, "r", encoding='UTF-8')
    self.next_skip = False
    self.cur_section = []
    self.line_no = 0

  def __iter__(self):
    return self

  # Iterates on localization ids
  def __next__(self):
    while True:
      line = next(self.f).strip()
      self.line_no += 1
      is_section_start = line.endswith("{") and line.find(" = ") != None
      is_section_end = line.startswith("}")

      if is_section_start:
        self.cur_section.append(extract_table_key(line.split(" = ", 1)[0].split()[-1]))
      elif is_section_end:
        self.cur_section.pop()
      elif not line.startswith("--") and self.cur_section:
        if not self.next_skip:
          value = line.split("=", 1)

          if len(value) == 2:
            localized_id, localized_str = value
            localized_id = extract_table_key(localized_id.strip())
            localized_str = localized_str.strip().strip(",").strip('"')

            if localized_str.endswith(".."):
              # String continues on next line
              self.next_skip = True

            return ".".join(self.cur_section) + "." + localized_id, self.line_no, localized_str
        else:
          self.next_skip = line.endswith("..")
  
  def close(self):
    self.f.close()

# Wrapper to provide len and indexing on the LocalizationFile
class LocalizationReaderWrapper(object):
  def __init__(self, localization_file_obj):
    self.localiz_obj = localization_file_obj
    self.lines = []
    self.line_id_to_line = {}
    self.populateLines()

  def __len__(self):
    return len(self.lines)

  def __getitem__(self, idx):
      return self.lines[idx]

  def __iter__(self):
    return self.lines.__iter__()

  def populateLines(self):
    for line in self.localiz_obj:
      self.lines.append(line[0])
      self.line_id_to_line[line[0]] = line

  def getLineInfo(self, line_id):
    return self.line_id_to_line[line_id]

def doCompare(base_file, cmp_file):
  difftool = difflib.Differ()
  base_file = LocalizationReaderWrapper(base_file)
  cmp_file = LocalizationReaderWrapper(cmp_file)
  diff = difftool.compare(base_file, cmp_file)

  for line in diff:
    if not line.startswith(" "):
      if line.startswith("-"):
        wrapper = base_file
      elif line.startswith("+"):
        wrapper = cmp_file
      else:
        print(line)
        continue

      line_info = wrapper.getLineInfo(line.split()[-1])

      print(u"%d) %s = \"%s\"" % (
        line_info[1],
        line,
        line_info[2].encode("utf8"),
      ))

def doMissing(base_file, cmp_file):
    existing = set([line[0] for line in base_file])

    for line in cmp_file:
      stringid = line[0]

      if not stringid in existing:
        print(stringid)

if __name__ == "__main__":
  def usage():
    print("Usage: " + sys.argv[0] + " [cmp|missing] base_file cmp_file")
    exit(1)

  if len(sys.argv) != 4:
    usage()

  mode = sys.argv[1]
  if not mode in ("cmp", "missing"):
    usage()

  base_file = LocalizationFile(sys.argv[2])
  cmp_file = LocalizationFile(sys.argv[3])

  if mode == "cmp":
    doCompare(base_file, cmp_file)
  elif mode == "missing":
    doMissing(base_file, cmp_file)

  base_file.close()
  cmp_file.close()
