#!/bin/sh
# makealias: make alias compressed dic and aff files
# Author: László Németh
# Version: 2019-05-10

export LC_ALL=C

usage()
{
echo 'makealias: make alias compressed dic and aff files for faster load and smaller memory footprint
Usage: makealias [--minimize-diff old_file_without_file_extension] file.dic file.aff' >/dev/stderr
exit
}

filecheck()
{
  if [ ! -f $1 ]; then
    echo File not found: $1
    exit
  fi
}

case $# in
0|1|3) usage;;
esac

if [ "$1" = "--minimize-diff" ]; then
  filecheck $2.aff
  AWK_ARG="-v mindiff=$2.aff"
  shift; shift
fi

case $1 in
*.dic) filecheck $1;;
*) usage;;
esac

case $2 in
*.aff) filecheck $2;;
*) usage;;
esac

DIC=`basename $1 .dic`
AFF=`basename $2 .aff`

# Alias definitions must be between FLAG type definition and SFX/PFX lines.
# copy aff content before SFX/PFX lines
sed '/^[SP]FX/,$d;s/\s\+$//' $2 >"${AFF}_alias.aff"

awk $AWK_ARG '
# Mirror HashMgr::load_tables: a morph-field section is introduced by
# a tab, or by a (whitespace + 2 chars + colon) marker like " po:".
# Headwords may legitimately contain spaces, so a plain space cannot
# be assumed to terminate the headword.
function find_morph_start(line,    tab_pos, code_pos) {
    tab_pos = index(line, "\t")
    code_pos = match(line, /[ \t]..:/) ? RSTART : 0
    if (tab_pos == 0) return code_pos
    if (code_pos == 0) return tab_pos
    return (tab_pos < code_pos) ? tab_pos : code_pos
}
# Split a .dic line into headword / flag-vector / morph-field. The first
# unescaped slash that is not at column 1 separates the word from its
# flags; everything from the morph boundary on is the morph field.
function parse_dic(line, parts,    morph_pos, head, i, c) {
    morph_pos = find_morph_start(line)
    if (morph_pos > 0) {
        head = substr(line, 1, morph_pos - 1)
        parts["morph"] = ltrim(substr(line, morph_pos))
    } else {
        head = line
        parts["morph"] = ""
    }
    parts["word"] = head
    parts["flags"] = ""
    for (i = 2; i <= length(head); i++) {
        c = substr(head, i, 1)
        if (c == "/" && substr(head, i-1, 1) != "\\") {
            parts["word"] = substr(head, 1, i - 1)
            parts["flags"] = substr(head, i + 1)
            break
        }
    }
}
BEGIN{
  n=1;m=1
  # make smaller and more readable diff for LibreOffice git
  if (mindiff != "") {
      n=0;m=0
      # load old AF and AM fields
      while ((getline var < mindiff) > 0) {
          if (var~/^AF /) {
                  b[n] = gensub(" #.*$", "", 1, substr(var, 4))
                  a[b[n]] = n
                  n = n + 1
          }
          if (var~/^AM /) {
                  c[m] = substr(var, 4)
                  a2[c[m]] = m
                  m = m + 1
          }
     }
     # reuse unused AF and AM items
     # first load dic
     while ((getline line < ARGV[1]) > 0) {
       parse_dic(line, dp)
       if (length(dp["flags"]) > 0) {
           if(a[dp["flags"]]) {
               used[dp["flags"]] = 1
           } else if (!not_used_registered[dp["flags"]]) {
               not_used[un] = dp["flags"]
               not_used_registered[dp["flags"]] = 1
               un++
           }
       }
       if (length(dp["morph"]) > 0) {
               mfld = dp["morph"]
               if(a2[mfld] || not_used2[mfld]) {
                   used2[mfld] = 1
               } else if (!not_used2_registered[mfld]) {
                   not_used2[um] = mfld
                   not_used2_registered[mfld] = 1
                   um++
               }
       }
     }
     # load aff file
     while ((getline $0 < ARGV[2]) > 0) {
       if ($0 ~ /^[PS]FX/ && NF > 4) {
         if ($4 ~ /\/[^  \t]/) {
            split($4,t,"/")
            if(a[t[2]]){
                 used[t[2]] = 1
            } else {
                 not_used[un++] = t[2]
            }
         }
         if ($6 != "") {
           $1 = $2 = $3 = $4 = $5 = ""
           $0 = ltrim($0)
           if(a2[$0]) {
             used2[$0] = 1
           } else {
             not_used2[um++] = $0
           }
         }
       }
     }
     # reuse unused items
     j = 0
     for (i=0; i < n && j < un; i++) {
        if (!(b[i] in used)) {
           b[i] = not_used[j]
           a[b[i]] = i
           used[b[i]] = 1
           j++
        }
     }
     j = 0
     for (i=0; i < m && j < um; i++) {
        if (!(c[i] in used2)) {
           c[i] = not_used2[j]
           a2[c[i]] = i
           used2[c[i]] = 1
           j++
        }
     }
  }
}
function cutslash(st) {
    if (split(st,t,"/") > 1) return t[1]
    return st
}
function ltrim(st) {
    sub(/^ +/,"",st)
    gsub("[ \t]+"," ",st)
    return st
}

FILENAME ~ /.dic$/ {
    parse_dic($0, dp)
    flags = ""
    if(length(dp["flags"]) > 0) {
        if (!a[dp["flags"]]) {
            a[dp["flags"]]=n
            b[n]=dp["flags"]
            n++
        }
        flags = "/" a[dp["flags"]]
    }
    end = ""
    if (length(dp["morph"]) > 0) {
        mfld = dp["morph"]
        if(!a2[mfld]){
            a2[mfld]=m
            c[m]=mfld
            m++
        }
        end = "\t" a2[mfld]
    }
    print dp["word"] flags end
    next
}

FILENAME ~ /.aff$/ && /^[PS]FX/ && NF > 4 {
    if ($4 ~ /\/[^  \t]/) {
        split($4,t,"/")
        if(!a[t[2]]){
            a[t[2]]=n
            b[n]=t[2]
            n++
        }
        begin = $1 " " $2 " " $3 " " (t[1]"/"a[t[2]]) " " $5
    } else {
        begin = $1 " " $2 " " $3 " " cutslash($4) " " $5
    }
    end = ""
    if ($6 != "") {
        $1 = $2 = $3 = $4 = $5 = ""
        $0 = ltrim($0)
        if(!a2[$0]) {
            a2[$0]=m
            c[m]=$0
            m++
        }
        end = " " a2[$0]
    }
    print begin end >>"/dev/stderr"
    next
}
FILENAME ~ /.aff$/ { print $0 >>"/dev/stderr" }
END {
    if (n>1) {
        print "AF", n-1 >>"'${AFF}_alias.aff'"
        for(i=1;i<n;i++) print "AF", b[i],"#",i >>"'${AFF}_alias.aff'"
    }
    if (m>1) {
        print "AM", m-1 >>"'${AFF}_alias.aff'"
        for(i=1;i<m;i++) print "AM " ltrim(c[i]) >>"'${AFF}_alias.aff'"
    }
}' $1 $2 >"${DIC}_alias.dic" 2>"${AFF}_alias.$$"
sed -n '/^[SP]FX/,$p' "${AFF}_alias.$$" | sed 's/\s\+$//' >>"${AFF}_alias.aff"
echo "output: ${DIC}_alias.dic, ${AFF}_alias.aff"

rm ${AFF}_alias.$$
