// morphology-hi.el - Hindi morphology for the NLG engine.
//
// Implements Hindi noun declension (direct and oblique cases), postpositional
// particles, verb stem extraction, tense conjugation, and genitive agreement.
//
// Hindi is a fusional/agglutinative hybrid, SOV, pro-drop, with Devanagari script.
//
// Key facts:
//   - 2 genders:  masculine (m), feminine (f)
//   - 2 numbers:  singular (sg), plural (pl)
//   - 2 main cases: direct (nominative/accusative) and oblique (before postpositions)
//   - Verbs agree with subject in gender and number
//   - No articles
//
// Conventions used throughout:
//   gender:  "m" | "f"
//   number:  "sg" | "pl"
//   case:    "direct" | "oblique"
//   tense:   "present" | "past" | "future"
//   person:  "1" | "2" | "3"
//
// Depends on: morphology.el (str_eq, str_len, str_slice, str_ends_with,
//             str_drop_last)

// ── String helpers ────────────────────────────────────────────────────────────

import "morphology.el"
fn hi_str_ends(s: String, suf: String) -> Bool {
    return str_ends_with(s, suf)
}

fn hi_str_drop_last(s: String, n: Int) -> String {
    let len: Int = str_len(s)
    if n >= len {
        return ""
    }
    return str_slice(s, 0, len - n)
}

fn hi_str_last_char(s: String) -> String {
    let n: Int = str_len(s)
    if n == 0 {
        return ""
    }
    return str_slice(s, n - 1, n)
}

// ── Gender inference ──────────────────────────────────────────────────────────
//
// Heuristic from the noun's final Devanagari character.
// Masculine: typically ends in आ (aa), or a consonant cluster
// Feminine:  typically ends in ई (ii), ि (i-matra), or other endings
//
// This is an approximation — gender is inherent to each noun and not always
// predictable.  The caller should supply gender explicitly when known.
//
// Common feminine endings: "ी" (long ii), "ि" (short i matra in some forms),
//   "न" (like बहन), "त" (like रात), "ट" (like बात)
// Common masculine endings: "ा" (aa matra), consonants generally

fn hi_gender(noun: String) -> String {
    // Long ii ending — strongly feminine
    if hi_str_ends(noun, "ी") { return "f" }
    // aa matra ending — strongly masculine
    if hi_str_ends(noun, "ा") { return "m" }
    // Known feminine words by ending
    if hi_str_ends(noun, "न") {
        // बहन (sister), दुकान (shop) — feminine; but also many masc.
        // Default feminine for -न common feminine nouns
        return "f"
    }
    if hi_str_ends(noun, "त") { return "f" }   // रात, बात, बात
    if hi_str_ends(noun, "ट") { return "f" }   // बात (variant spellings)
    if hi_str_ends(noun, "श") { return "m" }   // आकाश etc.
    // Specific common words
    if str_eq(noun, "लड़का")   { return "m" }
    if str_eq(noun, "लड़की")   { return "f" }
    if str_eq(noun, "आदमी")   { return "m" }
    if str_eq(noun, "औरत")    { return "f" }
    if str_eq(noun, "घर")     { return "m" }
    if str_eq(noun, "मेज़")    { return "f" }
    if str_eq(noun, "किताब")  { return "f" }
    if str_eq(noun, "पानी")   { return "m" }
    if str_eq(noun, "दूध")    { return "m" }
    if str_eq(noun, "हाथ")    { return "m" }
    if str_eq(noun, "आँख")    { return "f" }
    if str_eq(noun, "बच्चा")  { return "m" }
    if str_eq(noun, "बच्ची")  { return "f" }
    if str_eq(noun, "काम")    { return "m" }
    if str_eq(noun, "बात")    { return "f" }
    if str_eq(noun, "दिन")    { return "m" }
    if str_eq(noun, "रात")    { return "f" }
    if str_eq(noun, "देश")    { return "m" }
    if str_eq(noun, "भाषा")   { return "f" }
    if str_eq(noun, "जगह")    { return "f" }
    if str_eq(noun, "समय")    { return "m" }
    if str_eq(noun, "साल")    { return "m" }
    // Default to masculine
    return "m"
}

// ── Masculine noun declension ─────────────────────────────────────────────────
//
// Two patterns:
//   (A) Ends in -आ (ा matra): लड़का, बच्चा, घोड़ा — vowel-final type
//       direct sg:  base (लड़का)
//       direct pl:  stem + े  (लड़के)
//       oblique sg: stem + े  (लड़के)
//       oblique pl: stem + ों (लड़कों)
//
//   (B) Consonant-final or other: आदमी, घर, हाथ, दिन — invariant type
//       direct sg:  base
//       direct pl:  base (no change in direct plural for most)
//       oblique sg: base (no change)
//       oblique pl: base + ों (घरों, हाथों, दिनों)
//       Exception: आदमी (masc ending -ī): acts like (B) in direct but
//         oblique pl uses ों drop the ī: आदमियों

fn hi_masc_aa_stem(noun: String) -> String {
    // Strip trailing ा (aa matra, 3 UTF-8 bytes in Devanagari — but El strings
    // are Unicode so we drop the last character which is ा)
    return hi_str_drop_last(noun, 1)
}

fn hi_noun_direct_m(noun: String, number: String) -> String {
    if hi_str_ends(noun, "ा") {
        // Pattern A: aa-final masculine
        if str_eq(number, "sg") { return noun }
        // pl: replace ा with े
        return hi_masc_aa_stem(noun) + "े"
    }
    // Pattern B: invariant direct forms
    return noun
}

fn hi_noun_oblique_m(noun: String, number: String) -> String {
    if hi_str_ends(noun, "ा") {
        // Pattern A
        let stem: String = hi_masc_aa_stem(noun)
        if str_eq(number, "sg") { return stem + "े" }
        return stem + "ों"
    }
    // Pattern B: consonant-final or ī-final
    // आदमी and similar ī-final masculines: oblique pl inserts य
    if hi_str_ends(noun, "ी") {
        if str_eq(number, "sg") { return noun }
        // oblique pl: drop ी, add ियों
        let stem: String = hi_str_drop_last(noun, 1)
        return stem + "ियों"
    }
    // Default consonant-final masculines
    if str_eq(number, "sg") { return noun }
    return noun + "ों"
}

// ── Feminine noun declension ──────────────────────────────────────────────────
//
// Two patterns:
//   (A) Ends in -ई/-ी (long ii): लड़की, बच्ची
//       direct sg:  base (लड़की)
//       direct pl:  stem + ियाँ  (लड़कियाँ)
//       oblique sg: base (लड़की)
//       oblique pl: stem + ियों  (लड़कियों)
//
//   (B) Consonant-final or other: मेज़, रात, किताब, बात, औरत, भाषा
//       direct sg:  base (मेज़)
//       direct pl:  base + ें    (मेज़ें, किताबें)
//       oblique sg: base
//       oblique pl: base + ों    (मेज़ों, किताबों)

fn hi_noun_direct_f(noun: String, number: String) -> String {
    if hi_str_ends(noun, "ी") {
        // Pattern A: ii-final feminine
        if str_eq(number, "sg") { return noun }
        let stem: String = hi_str_drop_last(noun, 1)
        return stem + "ियाँ"
    }
    // Pattern B: other feminine
    if str_eq(number, "sg") { return noun }
    // Direct plural: add ें
    return noun + "ें"
}

fn hi_noun_oblique_f(noun: String, number: String) -> String {
    if hi_str_ends(noun, "ी") {
        // Pattern A
        if str_eq(number, "sg") { return noun }
        let stem: String = hi_str_drop_last(noun, 1)
        return stem + "ियों"
    }
    // Pattern B
    if str_eq(number, "sg") { return noun }
    return noun + "ों"
}

// ── Unified noun declension entry points ──────────────────────────────────────

// hi_noun_direct: direct case form (nominative/bare accusative).
fn hi_noun_direct(noun: String, gender: String, number: String) -> String {
    if str_eq(gender, "m") { return hi_noun_direct_m(noun, number) }
    if str_eq(gender, "f") { return hi_noun_direct_f(noun, number) }
    return noun
}

// hi_noun_oblique: oblique case form (before postpositions).
fn hi_noun_oblique(noun: String, gender: String, number: String) -> String {
    if str_eq(gender, "m") { return hi_noun_oblique_m(noun, number) }
    if str_eq(gender, "f") { return hi_noun_oblique_f(noun, number) }
    return noun
}

// ── Postpositional particles ──────────────────────────────────────────────────
//
// Hindi marks grammatical relations with postpositions that follow the oblique
// noun.  The genitive postposition agrees with the possessed noun's gender and
// number — use hi_agree_genitive for that case.
//
// case values:
//   "nominative"        — no postposition (direct case subject)
//   "accusative_animate"— को (ko) — animate direct objects
//   "dative"            — को (ko)
//   "genitive"          — का/की/के — use hi_agree_genitive instead
//   "locative_in"       — में (meṃ — in)
//   "locative_on"       — पर (par — on)
//   "instrumental"      — से (se — with/by)
//   "ablative"          — से (se — from)
//   "comitative"        — के साथ (ke saath — with/together with)
//   "benefactive"       — के लिए (ke liye — for)

fn hi_postposition(gram_case: String) -> String {
    if str_eq(gram_case, "nominative")         { return "" }
    if str_eq(gram_case, "accusative_animate") { return "को" }
    if str_eq(gram_case, "dative")             { return "को" }
    if str_eq(gram_case, "genitive")           { return "का" }   // base; use hi_agree_genitive
    if str_eq(gram_case, "locative_in")        { return "में" }
    if str_eq(gram_case, "locative_on")        { return "पर" }
    if str_eq(gram_case, "instrumental")       { return "से" }
    if str_eq(gram_case, "ablative")           { return "से" }
    if str_eq(gram_case, "comitative")         { return "के साथ" }
    if str_eq(gram_case, "benefactive")        { return "के लिए" }
    return ""
}

// hi_agree_genitive: return the genitive postposition (का/की/के) that agrees
// with the gender and number of the POSSESSED noun (not the possessor).
//
// possessed_gender: "m" | "f"
// possessed_number: "sg" | "pl"
//
//   m sg  → का (kaa)
//   f sg  → की (kii)
//   m pl  → के (ke)
//   f pl  → की (kii)

fn hi_agree_genitive(possessed_gender: String, possessed_number: String) -> String {
    if str_eq(possessed_gender, "f") { return "की" }
    if str_eq(possessed_number, "pl") { return "के" }
    return "का"
}

// ── Verb stem extraction ──────────────────────────────────────────────────────
//
// Most Hindi infinitives end in -ना (naa).  Stripping it gives the verb stem.
// Examples: खाना → खा, जाना → जा, करना → कर, देखना → देख
//
// Irregulars that do not follow this pattern return a hardcoded stem.

fn hi_verb_stem(infinitive: String) -> String {
    // Irregular stems
    if str_eq(infinitive, "होना")   { return "हो" }
    if str_eq(infinitive, "करना")   { return "कर" }
    if str_eq(infinitive, "जाना")   { return "जा" }
    if str_eq(infinitive, "आना")    { return "आ" }
    if str_eq(infinitive, "देना")   { return "दे" }
    if str_eq(infinitive, "लेना")   { return "ले" }
    if str_eq(infinitive, "देखना")  { return "देख" }
    if str_eq(infinitive, "कहना")   { return "कह" }
    if str_eq(infinitive, "जानना")  { return "जान" }
    if str_eq(infinitive, "चाहना")  { return "चाह" }
    if str_eq(infinitive, "खाना")   { return "खा" }
    if str_eq(infinitive, "पीना")   { return "पी" }
    if str_eq(infinitive, "सोना")   { return "सो" }
    if str_eq(infinitive, "लिखना")  { return "लिख" }
    if str_eq(infinitive, "पढ़ना")  { return "पढ़" }
    if str_eq(infinitive, "बोलना")  { return "बोल" }
    if str_eq(infinitive, "चलना")   { return "चल" }
    if str_eq(infinitive, "बैठना")  { return "बैठ" }
    if str_eq(infinitive, "उठना")   { return "उठ" }
    if str_eq(infinitive, "मिलना")  { return "मिल" }
    if str_eq(infinitive, "रहना")   { return "रह" }
    if str_eq(infinitive, "सुनना")  { return "सुन" }
    if str_eq(infinitive, "समझना") { return "समझ" }
    if str_eq(infinitive, "मानना")  { return "मान" }
    if str_eq(infinitive, "बनाना")  { return "बना" }
    if str_eq(infinitive, "लाना")   { return "ला" }
    if str_eq(infinitive, "भेजना")  { return "भेज" }
    if str_eq(infinitive, "खोलना")  { return "खोल" }
    if str_eq(infinitive, "बंद करना") { return "बंद कर" }
    // Generic: strip trailing ना (last character)
    if hi_str_ends(infinitive, "ना") {
        return hi_str_drop_last(infinitive, 1)
        // Note: ना is two Unicode chars (न + ा) but as a suffix pattern
        // we want to strip the last char 'ा' and keep 'न' — however the
        // actual Devanagari suffix ना is a single syllable grapheme cluster.
        // str_drop_last drops the last Unicode codepoint.
        // ना = न (na) + ा (aa-matra): str_drop_last(s,1) drops ा, leaving न at end.
        // We need to drop 2 codepoints (न and ा = ना) to get the true stem.
    }
    return infinitive
}

// hi_verb_stem_clean: correctly strips -ना (2 Unicode codepoints: न + ा matra)
fn hi_verb_stem_clean(infinitive: String) -> String {
    // Irregulars first
    if str_eq(infinitive, "होना")   { return "हो" }
    if str_eq(infinitive, "करना")   { return "कर" }
    if str_eq(infinitive, "जाना")   { return "जा" }
    if str_eq(infinitive, "आना")    { return "आ" }
    if str_eq(infinitive, "देना")   { return "दे" }
    if str_eq(infinitive, "लेना")   { return "ले" }
    if str_eq(infinitive, "देखना")  { return "देख" }
    if str_eq(infinitive, "कहना")   { return "कह" }
    if str_eq(infinitive, "जानना")  { return "जान" }
    if str_eq(infinitive, "चाहना")  { return "चाह" }
    if str_eq(infinitive, "खाना")   { return "खा" }
    if str_eq(infinitive, "पीना")   { return "पी" }
    if str_eq(infinitive, "सोना")   { return "सो" }
    if str_eq(infinitive, "लिखना")  { return "लिख" }
    if str_eq(infinitive, "पढ़ना")  { return "पढ़" }
    if str_eq(infinitive, "बोलना")  { return "बोल" }
    if str_eq(infinitive, "चलना")   { return "चल" }
    if str_eq(infinitive, "बैठना")  { return "बैठ" }
    if str_eq(infinitive, "उठना")   { return "उठ" }
    if str_eq(infinitive, "मिलना")  { return "मिल" }
    if str_eq(infinitive, "रहना")   { return "रह" }
    if str_eq(infinitive, "सुनना")  { return "सुन" }
    if str_eq(infinitive, "समझना") { return "समझ" }
    if str_eq(infinitive, "मानना")  { return "मान" }
    if str_eq(infinitive, "बनाना")  { return "बना" }
    if str_eq(infinitive, "लाना")   { return "ला" }
    if str_eq(infinitive, "भेजना")  { return "भेज" }
    if str_eq(infinitive, "खोलना")  { return "खोल" }
    // Strip ना = 2 codepoints
    if hi_str_ends(infinitive, "ना") {
        return hi_str_drop_last(infinitive, 2)
    }
    return infinitive
}

// ── Present tense habitual conjugation ───────────────────────────────────────
//
// Structure: stem + aspect-suffix + auxiliary
//
// Aspect suffixes (agree with SUBJECT gender/number):
//   m sg: ता (taa)
//   f sg: ती (tii)
//   m pl: ते (te)
//   f pl: ती (tii)
//
// Auxiliary हो/है/हैं (am/is/are) agreed with person and number:
//   1sg:  हूँ (huuṃ)
//   2sg:  हो (ho)   [informal], हैं (haiṃ) [formal]
//   3sg:  है (hai)
//   1pl:  हैं (haiṃ)
//   2pl:  हो (ho)   [informal], हैं (haiṃ) [formal]
//   3pl:  हैं (haiṃ)

fn hi_present_aspect(gender: String, number: String) -> String {
    if str_eq(gender, "f") { return "ती" }
    if str_eq(number, "pl") { return "ते" }
    return "ता"
}

fn hi_aux_present(person: String, number: String) -> String {
    if str_eq(person, "1") {
        if str_eq(number, "sg") { return "हूँ" }
        return "हैं"
    }
    if str_eq(person, "2") {
        if str_eq(number, "sg") { return "हो" }
        return "हो"
    }
    // third person
    if str_eq(number, "sg") { return "है" }
    return "हैं"
}

// ── Past tense conjugation ────────────────────────────────────────────────────
//
// Simple past suffix agrees with subject (when object has no को).
// stem + past-suffix:
//   m sg: आ (aa)   e.g. खाया (khaayaa)
//   f sg: ई (ii)   e.g. खाई (khaaii)
//   m pl: ए (e)    e.g. खाए (khaae)
//   f pl: ईं (iiṃ) e.g. खाईं (khaaiṃ)
//
// Many verb stems ending in a vowel undergo contraction — the irregulars table
// handles known cases; otherwise stem + suffix is concatenated.

fn hi_past_suffix(gender: String, number: String) -> String {
    if str_eq(gender, "m") {
        if str_eq(number, "sg") { return "आ" }
        return "ए"
    }
    // feminine
    if str_eq(number, "sg") { return "ई" }
    return "ईं"
}

// Past tense irregulars — full past form returned for known verb+gender+number.
fn hi_past_irregular(stem: String, gender: String, number: String) -> String {
    // होना (ho): था/थी/थे/थीं
    if str_eq(stem, "हो") {
        if str_eq(gender, "m") {
            if str_eq(number, "sg") { return "था" }
            return "थे"
        }
        if str_eq(number, "sg") { return "थी" }
        return "थीं"
    }
    // जाना (jaa): गया/गई/गए/गईं
    if str_eq(stem, "जा") {
        if str_eq(gender, "m") {
            if str_eq(number, "sg") { return "गया" }
            return "गए"
        }
        if str_eq(number, "sg") { return "गई" }
        return "गईं"
    }
    // करना (kar): किया/की/किए/कीं
    if str_eq(stem, "कर") {
        if str_eq(gender, "m") {
            if str_eq(number, "sg") { return "किया" }
            return "किए"
        }
        if str_eq(number, "sg") { return "की" }
        return "कीं"
    }
    // देना (de): दिया/दी/दिए/दीं
    if str_eq(stem, "दे") {
        if str_eq(gender, "m") {
            if str_eq(number, "sg") { return "दिया" }
            return "दिए"
        }
        if str_eq(number, "sg") { return "दी" }
        return "दीं"
    }
    // लेना (le): लिया/ली/लिए/लीं
    if str_eq(stem, "ले") {
        if str_eq(gender, "m") {
            if str_eq(number, "sg") { return "लिया" }
            return "लिए"
        }
        if str_eq(number, "sg") { return "ली" }
        return "लीं"
    }
    // आना (aa): आया/आई/आए/आईं
    if str_eq(stem, "आ") {
        if str_eq(gender, "m") {
            if str_eq(number, "sg") { return "आया" }
            return "आए"
        }
        if str_eq(number, "sg") { return "आई" }
        return "आईं"
    }
    // खाना (khaa): खाया/खाई/खाए/खाईं
    if str_eq(stem, "खा") {
        if str_eq(gender, "m") {
            if str_eq(number, "sg") { return "खाया" }
            return "खाए"
        }
        if str_eq(number, "sg") { return "खाई" }
        return "खाईं"
    }
    // पीना (pii): पिया/पी/पिए/पीं
    if str_eq(stem, "पी") {
        if str_eq(gender, "m") {
            if str_eq(number, "sg") { return "पिया" }
            return "पिए"
        }
        if str_eq(number, "sg") { return "पी" }
        return "पीं"
    }
    // No irregular match
    return ""
}

// ── Future tense conjugation ──────────────────────────────────────────────────
//
// Future: stem + future-suffix (fused person+gender+number)
//
//   1sg m: ऊँगा (uuṃgaa)    1sg f: ऊँगी (uuṃgii)
//   2sg m: ओगे (oge)         2sg f: ओगी (ogii)
//   3sg m: एगा (egaa)         3sg f: एगी (egii)
//   1pl m: एंगे (eṃge)        1pl f: एंगी (eṃgii)
//   2pl m: ओगे (oge)          2pl f: ओगी (ogii)
//   3pl m: एंगे (eṃge)        3pl f: एंगी (eṃgii)

fn hi_future_suffix(person: String, number: String, gender: String) -> String {
    if str_eq(person, "1") {
        if str_eq(number, "sg") {
            if str_eq(gender, "f") { return "ऊँगी" }
            return "ऊँगा"
        }
        if str_eq(gender, "f") { return "एंगी" }
        return "एंगे"
    }
    if str_eq(person, "2") {
        if str_eq(gender, "f") { return "ओगी" }
        return "ओगे"
    }
    // third person
    if str_eq(number, "sg") {
        if str_eq(gender, "f") { return "एगी" }
        return "एगा"
    }
    if str_eq(gender, "f") { return "एंगी" }
    return "एंगे"
}

// ── Tense suffix (aspect suffix only, without auxiliary) ─────────────────────
//
// For callers that need just the aspect suffix to construct compound tenses.

fn hi_tense_suffix(tense: String, gender: String, number: String) -> String {
    if str_eq(tense, "present") { return hi_present_aspect(gender, number) }
    if str_eq(tense, "past")    { return hi_past_suffix(gender, number) }
    // future uses hi_future_suffix (includes person)
    return ""
}

// ── होना (honaa — to be) special handling ────────────────────────────────────
//
// होना is deeply irregular.  Its forms are used as auxiliaries throughout.
//
// present: हूँ/हो/है/हैं (via hi_aux_present)
// past:    था/थी/थे/थीं  (via hi_past_irregular)
// future:  होऊँगा/होओगे/होएगा etc. (stem हो + future suffix)

fn hi_hona_present(person: String, number: String) -> String {
    return hi_aux_present(person, number)
}

fn hi_hona_past(gender: String, number: String) -> String {
    if str_eq(gender, "m") {
        if str_eq(number, "sg") { return "था" }
        return "थे"
    }
    if str_eq(number, "sg") { return "थी" }
    return "थीं"
}

// ── Full verb conjugation ─────────────────────────────────────────────────────
//
// hi_conjugate: conjugate a Hindi verb.
//
// verb:   Hindi infinitive in Devanagari (e.g. "खाना", "जाना", "करना")
// tense:  "present" | "past" | "future"
// person: "1" | "2" | "3"
// gender: "m" | "f"   (subject gender)
// number: "sg" | "pl"
//
// Returns the complete inflected verb string (including auxiliary where needed).

fn hi_conjugate(verb: String, tense: String, person: String, gender: String, number: String) -> String {
    let stem: String = hi_verb_stem_clean(verb)

    // होना — fully irregular
    if str_eq(verb, "होना") {
        if str_eq(tense, "present") { return hi_hona_present(person, number) }
        if str_eq(tense, "past")    { return hi_hona_past(gender, number) }
        // future: होऊँगा etc.
        return "हो" + hi_future_suffix(person, number, gender)
    }

    if str_eq(tense, "present") {
        let aspect: String = hi_present_aspect(gender, number)
        let aux: String = hi_aux_present(person, number)
        return stem + aspect + " " + aux
    }

    if str_eq(tense, "past") {
        let irreg: String = hi_past_irregular(stem, gender, number)
        if !str_eq(irreg, "") {
            return irreg
        }
        return stem + hi_past_suffix(gender, number)
    }

    if str_eq(tense, "future") {
        return stem + hi_future_suffix(person, number, gender)
    }

    // Unknown tense: return infinitive
    return verb
}

// ── Noun phrase construction helpers ─────────────────────────────────────────

// hi_noun_with_post: return the oblique noun form followed by its postposition.
// Use for all cases that require an oblique form (dative, locative, etc.).
//
// noun:   Devanagari noun string
// gender: "m" | "f"
// number: "sg" | "pl"
// case:   postposition case key (see hi_postposition)

fn hi_noun_with_post(noun: String, gender: String, number: String, gram_case: String) -> String {
    let post: String = hi_postposition(gram_case)
    if str_eq(post, "") {
        // Nominative: use direct form
        return hi_noun_direct(noun, gender, number)
    }
    let oblique: String = hi_noun_oblique(noun, gender, number)
    return oblique + " " + post
}

// hi_genitive_phrase: "X का/की/के Y" — possessive phrase.
// possessor and possessed are bare noun strings; the function computes all
// inflections and agreement automatically.
//
// possessor_gender/number: gender and number of the possessor noun
// possessed_gender/number: gender and number of the possessed noun (drives agreement)

fn hi_genitive_phrase(possessor: String, possessor_gender: String, possessor_number: String,
                      possessed: String, possessed_gender: String, possessed_number: String) -> String {
    let obl: String = hi_noun_oblique(possessor, possessor_gender, possessor_number)
    let gen: String = hi_agree_genitive(possessed_gender, possessed_number)
    let poss: String = hi_noun_direct(possessed, possessed_gender, possessed_number)
    return obl + " " + gen + " " + poss
}
