// Class definition for the lexicon affix name list, stored in the .blf file
//
// Copyright 2001, KUN
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Library General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

// $Id: lexaffixnamelist.h,v 1.12 2006/03/22 15:25:08 marcs Exp $

#ifndef LEXAFFIXNAMELIST_H
#define LEXAFFIXNAMELIST_H

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif // HAVE_CONFIG_H

#include <stdlib.h>
#include <string>
#include <set>
#include <map>
#include <iostream>

#include <lexicon.h>

#include "lexfileio.h"
#include "id.h"
#include "paramtab.h"

typedef struct _LexAffixNameEntry{
    unsigned index;
    unsigned gra2o_idx;
    SET bitset;
    bool is_nonterminal;
    set<string> lhs_list;
} LexAffixNameEntry;

typedef map<string, LexAffixNameEntry> LexAffixNameMap;

class LexAffixNameList
{
    private:
        // map: name -> index, set
        LexAffixNameMap names;

    public:
        void add_affix(string n, unsigned idx, SET s, string lhs);
        unsigned get_index(const ParamID id) const;
        unsigned get_index(string& n) const;
        unsigned get_index_of_set(string& n);
        bool is_defined(string& n) const;
        bool is_defined(const ID aff_id) const;
        void mark_as_nonterminal(string& n);

        size_t calculate_nr_union_sets(Lexicon old_lex);
        bool has_changed(Lexicon old_lex);

        void dump(void) const;
	void write_output(ostream& os) const;

        LexAffixNameMap::const_iterator get_by_index(unsigned idx) const;
        inline unsigned size(void) const { return names.size(); }
};

inline bool
LexAffixNameList::is_defined(const ID aff_id) const
{
    string aff_name(idtable.to_string(aff_id));
    return is_defined(aff_name);
}

inline bool
LexAffixNameList::is_defined(string& n) const
{
    LexAffixNameMap::const_iterator i = names.find(n);

    return i != names.end();
}

inline unsigned
LexAffixNameList::get_index(const ParamID id) const
{
    string param_name = idtable.to_string(id);
    return get_index(param_name);
}

inline unsigned
LexAffixNameList::get_index(string& n) const
{
    LexAffixNameMap::const_iterator i = names.find(n);

    if (i == names.end()) {
        cout << "affix \"" << n << "\" is not defined in any lexicon module" << endl;
        exit(1);
    }

    return i->second.index;
}

inline void LexAffixNameList::mark_as_nonterminal(string& n)
{
    LexAffixNameMap::iterator i = names.find(n);

    if (i == names.end()) {
        cout << "trying to mark unknown affix \"" << n << "\" as affix nonterminal" << endl;
        exit(1);
    }

    i->second.is_nonterminal = true;
}

inline void LexAffixNameList::add_affix(string n, unsigned idx, SET s, string lhs) {
#ifdef DEBUG_LEXGEN
    cout << "LexAffixNameList::add_affix(" << n << ", " << idx << ", ..., " << lhs << ")" << endl;
#endif

    LexAffixNameMap::iterator i = names.find(n);

    if (i != names.end()) {
        if (i->second.bitset != s) {
            cout << "LexAffixNameList::add_affix: \"" << n;
            cout << "\" added twice with different sets" << endl;
            exit(1);
        } else {
            if (lhs != "") {
                if ((i->second.lhs_list.find(lhs)) == (i->second.lhs_list.end())) {
                    // add lhs to lhs list
                    i->second.lhs_list.insert(lhs);
                }
            }
        }
    } else {
        // Add as a new element
        unsigned the_idx = names.size();
#ifdef DEBUG_LEXGEN
        cout << "-> adding \"" << n << "\" with new index " << the_idx << endl;
#endif
        set<string> lhsses;
        if (lhs != "") {
            lhsses.insert(lhs);
        }
        LexAffixNameEntry e;
        e.index = the_idx;
        e.gra2o_idx = idx;
        e.bitset = s;
        e.is_nonterminal = false;
        e.lhs_list = lhsses;
        names[n] = e;
    }
}

#endif // LEXAFFIXNAMELIST_H
