###############################################
# FILE: KBFuncs.pat
# SUBJ: Call the DumpKB function
# AUTH: Your Name
# CREATED: 2020-11-19 8:40:53
# MODIFIED:
###############################################

@DECL

###############################################
# General functions
###############################################

AddUniqueCon(L("concept"),L("name")) {
  L("con") = findconcept(L("concept"),L("name"));
  if (!L("con")) L("con") = makeconcept(L("concept"),L("name"));
  return L("con");
}

AddUniqueStr(L("concept"),L("attr"),L("value")) {
  if (L("value")) {
    L("val") = AttrValues(L("concept"),L("attr"));
    while (L("val")) {
      L("str") = getstrval(L("val"));
      if (L("str") == L("value"))
        return 0;
      L("val") = nextval(L("val"));
    }
    addstrval(L("concept"),L("attr"),L("value"));
    return 1;
  }
  return 0;
}

AddUniqueNum(L("concept"),L("attr"),L("value")) {
  if (L("value")) {
    L("val") = AttrValues(L("concept"),L("attr"));
    while (L("val")) {
      L("num") = getnumval(L("val"));
      if (L("num") == L("value"))
        return 0;
      L("val") = nextval(L("val"));
    }
    addnumval(L("concept"),L("attr"),L("value"));
    return 1;
  }
  return 0;
}

AddUniqueConVal(L("concept"),L("attr"),L("value")) {
  "unique.txt" << L("attr") << " " << conceptpath(L("concept")) << " ==> " << L("attr") << " -- " << conceptpath(L("value")) << "\n";
  L("val") = AttrValues(L("concept"),L("attr"));
  while (L("val")) {
    L("con") = getconval(L("val"));
    "unique.txt" << conceptname(L("con")) << "\n";
    if (conceptpath(L("con")) == conceptpath(L("value")))
      return 0;
    L("val") = nextval(L("val"));
  }
  addconval(L("concept"),L("attr"),L("value"));
  return 1;
}

PathToConcept(L("parent"),L("hier")) {
  L("cons") = split(L("hier")," ");
  L("i") = 0;
  L("con") = L("parent");
  while (L("cons")[L("i")]) {
    L("c") = L("cons")[L("i")];
    L("name") = strsubst(L("c"),"\"",0); if (L("name") != "concept") L("con") = AddUniqueCon(L("con"),L("name")); L("i")++; } return L("con"); } CopyAttr(L("from"),L("to"),L("attr")) { L("from value") = strval(L("from"),L("attr")); if (L("from value")) { L("to value") = strval(L("to"),L("attr")); if (L("from value") && !L("to value")) addstrval(L("to"),L("attr"),L("from value")); } } CopyAttrNew(L("from"),L("to"),L("attr from"),L("attr to")) { L("from value") = strval(L("from"),L("attr from")); if (L("from value")) { L("to value") = strval(L("to"),L("attr to")); if (L("from value") && !L("to value")) addstrval(L("to"),L("attr to"),L("from value")); } } CopyConAttr(L("from"),L("to"),L("attr")) { L("from value") = conval(L("from"),L("attr")); if (L("from value")) { L("to value") = conval(L("to"),L("attr")); if (L("from value") && !L("to value")) addconval(L("to"),L("attr"),L("from value")); } } CopyConAttrs(L("from"),L("to")) { L("attrs") = findattrs(L("from")); while (L("attrs")) { L("vals") = attrvals(L("attrs")); L("name") = attrname(L("attrs")); L("type") = attrtype(L("from"),L("name")); while (L("vals")) { if (L("type") == 1) { addnumval(L("to"),L("name"),getnumval(L("vals"))); } else if (L("type") == 2) { addconval(L("to"),L("name"),getconval(L("vals"))); } else if (L("type") == 3) { addnumval(L("to"),L("name"),getfltval(L("vals"))); } else { addstrval(L("to"),L("name"),getstrval(L("vals"))); } L("vals") = nextval(L("vals")); } L("attrs") = nextattr(L("attrs")); } } AttrValues(L("con"),L("attr")) { L("at") = findattr(L("con"),L("attr")); if (L("at")) return attrvals(L("at")); return 0; } ValCount(L("vals")) { while (L("vals")) { L("count")++; L("vals") = nextval(L("vals")); } return L("count"); } LastChild(L("parent")) { L("child") = down(L("parent")); while (L("child")) { L("last") = L("child"); L("child") = next(L("child")); } return L("last"); } MakeCountCon(L("con"),L("count name")) { L("count name") = CountName(L("con"),L("count name"),3); return makeconcept(L("con"),L("count name")); } MakeCountConPad(L("con"),L("count name"),L("pad")) { L("count name") = CountName(L("con"),L("count name"),L("pad")); return makeconcept(L("con"),L("count name")); } IncrementCount(L("con"),L("countname")) { L("countname") = L("countname") + "_count"; L("count") = numval(L("con"),L("countname")); if (L("count")) { L("count") = L("count") + 1; replaceval(L("con"),L("countname"),L("count")); } else { addnumval(L("con"),L("countname"),1); L("count") = 1; } return L("count"); } CountName(L("con"),L("root"),L("pad")) { L("count") = IncrementCount(L("con"),L("root")); if (L("pad")) { L("pad") = RepeatStr(L("pad")-strlength(str(L("count"))),"0"); } else { L("pad") = 0; } return L("root") + L("pad") + str(L("count")); } StripEndDigits(L("name")) { if (strisdigit(L("name"))) return 0; L("len") = strlength(L("name")) - 1; L("i") = L("len") - 1; L("str") = strpiece(L("name"),L("i"),L("len")); while (strisdigit(L("str")) && L("i")) { L("i")--; L("str") = strpiece(L("name"),L("i"),L("len")); } return strpiece(L("name"),0,L("i")); } ############################################### # KB Dump Functipns ############################################### DumpKB(L("con"),L("file")) { L("dir") = G("$apppath") + "/kb/"; L("filename") = L("dir") + L("file") + ".kb"; if (!kbdumptree(L("con"),L("filename"))) { "kb.txt" << "FAILED dump: " << L("filename") << "\n"; } else { "kb.txt" << "DUMPED: " << L("filename") << "\n"; } } TakeKB(L("filename")) { L("path") = G("$apppath") + "/kb/" + L("filename") + ".kb"; "kb.txt" << "Taking: " << L("path") << "\n"; if (take(L("path"))) { "kb.txt" << " Taken successfully: " << L("path") << "\n"; } else { "kb.txt" << " Taken FAILED: " << L("path") << "\n"; } } ChildCount(L("con")) { L("count") = 0; L("child") = down(L("con")); while (L("child")) { L("count")++; L("child") = next(L("child")); } return L("count"); } ############################################### # KBB DISPLAY FUNCTIONS ############################################### ############################################### # display type: # 0 compact with ellipses on long attr values # 1 full, more spread out # 2 compact without ellipses on long attr values ############################################### SaveToKB(L("con"),L("name")) { L("filepath") = G("$kbpath") + L("name") + ".kbb"; L("file") = openfile(L("filepath")); SaveKB(L("file"),L("con"),2); closefile(L("file")); } SaveKB(L("file"),L("top con"),L("display type")) { DisplayKBRecurse(L("file"),L("top con"),0,L("display type")); L("file") << "\n"; return L("top con"); } DisplayKB(L("top con"),L("display type")) { L("file") = DisplayFileName(); DisplayKBRecurse(L("file"),L("top con"),0,L("display type")); L("file") << "\n"; return L("top con"); } KBHeader(L("text")) { L("file") = DisplayFileName(); L("file") << "#######################\n";
  L("file") << "# " << L("text") << "\n"; L("file") << "#######################\n\n";
}

DisplayFileName() {
  if (num(G("$passnum")) < 10) {
    L("file") = "ana00" + str(G("$passnum"));
  }else if (num(G("$passnum")) < 100) {
    L("file") = "ana0" + str(G("$passnum"));
  } else {
    L("file") = "ana" + str(G("$passnum"));
  }
  L("file") = L("file") + ".kbb";
  return L("file");
}

DisplayKBRecurse(L("file"),L("parent"),L("level"),L("display type")) {
  if (L("level") == 0) {
    L("file") << conceptname(L("parent")) << "\n";
  }
  L("con") = down(L("parent"));
  while (L("con")) {
    L("file") << SpacesStr(L("level")+1) << conceptname(L("con"));
    DisplayAttributes(L("file"),L("con"),L("display type"),L("level"));
    L("file") << "\n";
    if (down(L("con"))) {
      L("lev") = 1;
      DisplayKBRecurse(L("file"),L("con"),L("level")+L("lev"),L("display type"));
    }
    L("con") = next(L("con"));
  }
}

DisplayAttributes(L("file"),L("con"),L("display type"),L("level")) {
  L("attrs") = findattrs(L("con"));
  if (L("attrs")) L("file") << ": ";
  if (L("display type") == 1 && L("attrs")) L("file") << "\n";
  L("first attr") = 1;
  
  while (L("attrs")) {
    L("vals") = attrvals(L("attrs"));
    L("count") = ValCount(L("vals"));
    if (L("display type") != 1 && !L("first attr")) {
      L("file") << ", ";
    }
    if (L("display type") == 1) {
      if (!L("first attr")) L("file") << "\n";
      L("file") << SpacesStr(L("level")+2);
    }
    L("name") = attrname(L("attrs"));
    L("file") << QuoteIfNeeded(L("name")) << "=";
    L("first") = 1;
    L("type") = attrtype(L("con"),L("name"));

    while (L("vals")) {
      if (!L("first"))
        L("file") << ",";
      else if (L("type") != 2 && L("count") > 1)
        L("file") << "[";

      if (L("type") == 1) {
        L("num") = getnumval(L("vals"));
        L("file") << str(L("num"));

      } else if (L("type") == 2) {
        if (L("first"))
          L("file") << "[";
        L("c") = getconval(L("vals"));
        L("file") << conceptpath(L("c"));

      } else if (L("type") == 3) {
        L("flt") = getfltval(L("vals"));
        L("file") << str(L("flt"));

      } else {
        L("val") = getstrval(L("vals"));
        if (L("display type") == 0 && strlength(L("val")) > 20) {
          L("shorty") = strpiece(L("val"),0,20);
          L("val") = L("shorty") + "...";
        }
        L("file") << QuoteIfNeeded(str(L("val")));
      }
      L("first") = 0;
      L("vals") = nextval(L("vals"));
    }
    
    if (L("type") == 2 || L("count") > 1)
      L("file") << "]";
    L("first attr") = 0;
    L("attrs") = nextattr(L("attrs"));
  }
}

QuoteIfNeeded(L("str")) {
  if (!L("str"))
    return 0;
  L("new") = strsubst(L("str"),"\"","\\\"");
  if (strcontains(" ",L("str")) || strhaspunct(L("str")))
    L("new") = "\"" + L("new") + "\"";
  return L("new");
}

# Because NLP++ doesn't allow for empty strings,
# this function can only be called with "num" >= 1
SpacesStr(L("num")) {
  return RepeatStr(L("num")," ");
}

RepeatStr(L("num"),L("str")) {
  L("n") = 1;
  L("spaces") = L("str");
  while (L("n") < L("num")) {
    L("spaces") = L("spaces") + L("str");
    L("n")++;
  }
  return L("spaces");
}

PadStr(L("num str"),L("pad str"),L("pad len")) {
  L("len") = strlength(L("num str"));
  L("pad") = 0;
  L("to pad") = L("pad len") - L("len");
  while (L("i")++ < L("to pad")) {
    L("pad") = L("pad") + L("pad str");
  }
  L("padded") = L("pad") + L("num str");
  return L("padded");
}

###############################################
# JSON FUNCTIONS
###############################################

JsonKB(L("file"),L("con")) {
  L("file") << "{\n" << SpacesStr(1) << "\"" << conceptname(L("con")) << "\": {\n";
  JsonKBRecurse(L("file"),L("con"),1);
  L("file") << "\n}\n";
}

JsonKBRecurse(L("file"),L("parent"),L("level")) {
  L("con") = down(L("parent"));
  L("first") = 1;
  L("has concount") = 0;
  while (L("con")) {
    L("name") = conceptname(L("con"));
    L("concount") = SeparateConCount(L("name"));
    L("connum") = G("connum");

    if (L("concount")) {
      "hier.txt" << SpacesStr(L("level")+1) << " ====> " << L("connum") << "\n";
      if (!L("has concount")) {
        L("file") << SpacesStr(L("level")+1) << JsonStr(L("concount")) << ": [\n";
      } else {
        L("file") << "\n";
      }
      L("file") << SpacesStr(L("level")+2) << "{\n";
      L("file") << SpacesStr(L("level")+3) << "\"id\": \"" << L("connum") << "\",\n";
      L("first") = !JsonAttributes(L("file"),L("con"),L("level")+2);
      L("has concount") = 1;
      
      if (down(L("con"))) {
        if (!L("first")) L("file") << ",\n";
        JsonKBRecurse(L("file"),L("con"),L("level")+2);
      } else {
        L("file") << "\n" << SpacesStr(L("level")+2) << "}";
      }

    } else {
      if (L("has concount")) {
        L("file") << "\n" << SpacesStr(L("level")+2) << "}";
        L("file") << "\n" << SpacesStr(L("level")+1) << "]";
        L("has concount") = 0;
      }
      if (!L("first"))
        L("file") << "\n";
      L("file") << SpacesStr(L("level")+1) << JsonStr(L("name")) << ": {\n";
      L("first") = !JsonAttributes(L("file"),L("con"),L("level")+1);

      if (down(L("con"))) {
        if (!L("first")) L("file") << ",\n";
        JsonKBRecurse(L("file"),L("con"),L("level")+1);
      }
      else if (!L("has concount")) {
        L("file") << "\n" << SpacesStr(L("level")+1) << "}";
      }
    }

    L("con") = next(L("con"));
    if (L("con")) {
      L("file") << ",";
    }
    L("first") = 0;
  }
  if (L("has concount")) {
    L("file") << "\n" << SpacesStr(L("level")+1) << "]";
  }
  L("file") << "\n" << SpacesStr(L("level")) << "}";
}

JsonAttributes(L("file"),L("con"),L("level")) {
  L("attrs") = findattrs(L("con"));
  if (!L("attrs")) {
    return 0;
  }

  L("first attr") = 1;
  L("first") = 1;
  L("has attrs") = 0;
  
  while (L("attrs")) {
    L("name") = attrname(L("attrs"));
    if (IsCountCon(L("name"),L("con"))) {
      L("nothing") = 0;
    } else {
      L("has attrs") = 1;
      L("vals") = attrvals(L("attrs"));
      L("count") = ValCount(L("vals"));
      if (!L("first attr")) {
        L("file") << ",\n";
      }

      L("file") << SpacesStr(L("level")+1) << JsonStr(L("name")) << ": ";
      L("type") = attrtype(L("con"),L("name"));

      # NOTE: Only handling one value for now

      # while (L("vals")) {
        # if (L("type") != 2 && L("count") > 1)
        # L("file") << "[";

        if (L("type") == 1) {
          L("num") = getnumval(L("vals"));
          L("file") << JsonStr(str(L("num")));

        } else if (L("type") == 2) {
          L("c") = getconval(L("vals"));
          L("file") << JsonStr(conceptpath(L("c")));

        } else if (L("type") == 3) {
          L("flt") = getfltval(L("vals"));
          L("file") << JsonStr(str(L("flt")));

        } else {
          L("val") = getstrval(L("vals"));
          L("file") << JsonStr(str(L("val")));
        }
        L("first") = 0;
        L("vals") = nextval(L("vals"));
      # }
      L("first attr") = 0;      
    }
      
    L("attrs") = nextattr(L("attrs"));
  }
  return L("has attrs");
}

JsonStr(L("str")) {
  L("str") = strsubst(L("str"), "\\""\\\\");
  L("str") = strsubst(L("str"), "\"", "\\\"");
  return "\"" + L("str") + "\"";
}

SeparateConCount(L("conname")) {
  if (strisdigit(L("conname"))) return 0;

  L("i") = strlength(L("conname")) - 1;
  G("connum") = 0;
  L("stop") = 0;
  while (!L("stop") && L("i") > 0) {
    L("c") = strpiece(L("conname"),L("i"),L("i"));
    if (strisdigit(L("c"))) {
      L("num") = L("c") + L("num");
    } else {
      L("stop");
    }
    L("i")--;
  }
  if (L("num")) {
    G("connum") = L("num");
    L("base") = strpiece(L("conname"),0,strlength(L("conname"))-strlength(L("num"))-1);
    return L("base");
  }
  return 0;
}

IsCountCon(L("str"),L("con")) {
  L("child") = down(L("con"));
  L("first") = L("str") + "1";
  while (L("child")) {
    L("name") = conceptname(L("child"));
    if (L("name") == L("first")) {
      return 1;
    }
    L("child") = next(L("child"));
  }
  return 0;
}

###############################################
# Ambiguity Functions
###############################################

AmbigTrimPOS(L("node"),L("pos")) {
  L("meaning") = pnvar(L("node"),"meaning");
  if (!L("meaning")) {
    return;
  }
  L("con") = down(L("meaning"));
  while (L("con")) {
    L("p") = strval(L("con"),"pos");
    if (L("p") == L("pos")) {
      AmbigCopyAttrs(L("con"),L("node"));
      pnreplaceval(L("node"),"pos num",1);
      pnreplaceval(L("node"),"meaning",L("con"));
    }
    L("con") = next(L("con"));
  }

  L("names") = pnvarnames(L("node"));
  while (L("names")[L("ii")]) {
    L("name") = L("names")[ L("ii") ];
    if (IsPOS(L("name")) && L("name") != L("pos")) {
      pnremoveval(L("node"),L("name"));
    }
    L("ii")++;
  }
}

AmbigCopyAttrs(L("con"),L("node")) {
  L("attrs") = findattrs(L("con"));
  
  while (L("attrs")) {
    L("vals") = attrvals(L("attrs"));
    L("name") = attrname(L("attrs"));
    L("type") = attrtype(L("con"),L("name"));

    if (L("name") != "pos") {
      while (L("vals")) {
        if (L("type") == 1) {
          pnmakevar(L("node"),L("name"),getnumval(L("vals")));
        } else if (L("type") == 2) {
          pnmakevar(L("node"),L("name"),getconval(L("vals")));
        } else if (L("type") == 3) {
          pnmakevar(L("node"),L("name"),getfltval(L("vals")));
        } else {
          pnmakevar(L("node"),L("name"),getstrval(L("vals")));
        }
        L("vals") = nextval(L("vals"));
      }      
    }

    L("attrs") = nextattr(L("attrs"));
  }    
}

IsPOS(L("pos")) {
  if (L("pos") == "noun" || L("pos") == "verb" || L("pos") == "adj" || L("pos") == "adv" || L("pos") == "prep" || L("pos") == "pron" || L("pos") == "conj" || L("pos") == "det" || L("pos") == "num" || L("pos") == "int" || L("pos") == "art" || L("pos") == "pro" || L("pos") == "punct")
    return 1;
  return 0;
}

###############################################
# DICTIONARY FUNCTIONS (These are no longer needed. Relics of the past.)
###############################################

DictionaryStart() {
  G("attrs path") = G("$apppath") + "\\kb\\user\\attrs.kb";
  G("attrs") = openfile(G("attrs path"));
}

DictionaryWord(L("word"),L("attrName"),L("value"),L("attrType")) {
  addword(L("word"));
  addword(L("attrName"));
  G("attrs") << "ind attr\n" << findwordpath(L("word")) << "\n0\n";
  G("attrs") << findwordpath(L("attrName")) << "\n";
  if (L("attrType") == "str")
    G("attrs") << "pst\n" << "\"" << L("value") << "\"";
  else if (L("attrType") == "num")
    G("attrs") << "pnum\n" << str(L("value"));
  else if (L("attrType") == "con")
    G("attrs") << "pcon\n" << conceptpath(L("value"));
  G("attrs") << "\nend ind\n\n";
}

DictionaryEnd() {
  G("attrs") << "\nquit\n\n";
  closefile(G("attrs"));
}

OrderByCount(L("words"),L("order")) {
  L("done") = 0;
  L("sanity") = 0;
  while (!L("done")) {
    L("done") = 1;
    L("conmax") = 0;
    L("max") = 0;
    L("word") = down(L("words"));
    while (L("word")) {
      L("check") = numval(L("word"),"checked");
      if (!L("check")) {
        L("done") = 0;
        L("count") = numval(L("word"),"count");
        if (L("count") > L("max")) {
          "max.txt" << conceptname(L("word")) << " " << L("count") << "\n";
          L("max") = L("count");
          L("conmax") = L("word");
        }
      }
      L("word") = next(L("word"));
    }
    if (!L("done") && L("conmax")) {
      L("word") = conceptname(L("conmax"));
      L("con") = makeconcept(L("order"),L("word"));
      if (!spellword(L("word"))) {
        addnumval(L("con"),"unknown",1);
      }
      addnumval(L("con"),"count",L("max"));
      addnumval(L("conmax"),"checked",1);
    }
    if (L("safety")++ > 300) {
      L("done") = 1;
    }
  }
}

@@DECL