// read configurations

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#ifndef __GNUC__
# ifdef HAVE_ALLOCA_H
#  include <alloca.h>
# endif
#endif

#include "jmode.h"

#define DEFKEYATOM
#include "keyatom.h"

class CAtom {
public:
    char *name;
    std::list<atom_t> bound;
};

struct ConfHook {
    char *name;
    void (*fn)(char *);
};

//遅いのでだれか書きかえて
static std::list<atom_t> atom_list;

static std::list<ConfHook> hook_list;

bool read_a_conf_file(char *fn);

static atom_t
find_atom_by_name(char *s)
{
    std::list<atom_t>::iterator i;
    for (i = atom_list.begin(); i != atom_list.end(); i++) {
        if (!strcmp((*i)->name, s)) {
            return *i;
        }
    }
    return 0;
}

static atom_t
make_atom_by_name(char *name)
{
    atom_t n;
    n = new CAtom();
    n->name = strdup(name);
    atom_list.push_back(n);
    return n;
}


void
add_conf_hook(char *name, void (*fn)(char *))
{
    ConfHook c;
    c.name = strdup(name);
    c.fn = fn;
    hook_list.push_back(c);
}

atom_t
get_atom_by_name(char *name)
{
    atom_t a;
    a = find_atom_by_name(name);
    if (a) {
        return a;
    }
    return make_atom_by_name(name);
}

void
bind_atom(atom_t from, atom_t to)
{
    std::list<atom_t>::iterator i;
    for (i = to->bound.begin(); i != to->bound.end(); i++) {
	if (from == *i) {
	    return ;
	}
    }
    to->bound.push_back(from);
}

void
unbind_atom(atom_t from, atom_t to)
{
    std::list<atom_t>::iterator i;
    for (i = to->bound.begin(); i != to->bound.end(); i++) {
        to->bound.erase(i);
        return ;
    }
}

bool
is_bind_to(atom_t from, atom_t to)
{
    std::list<atom_t>::iterator i;
    for (i = to->bound.begin(); i != to->bound.end(); i++) {
        if (*i == from) {
            return true;
        }
    }
    return false;
}

char *
get_atom_name(atom_t a)
{
    if (!a) {
	return 0;
    }
    return a->name;
}

void
bind_str_to_atom(char *s, atom_t a)
{
    atom_t x = get_atom_by_name(s);
    bind_atom(x, a);
}

void
bind_str_to_str(char *s, char *d)
{
    atom_t x, y;
    x = get_atom_by_name(s);
    y = get_atom_by_name(d);
    bind_atom(x, y);
}

atom_t
get_bound_atoms(atom_t to, atom_t c)
{
    std::list<atom_t>::iterator i;
    if (!to) {
	return 0;
    }
    i = to->bound.begin();
    if (!c) {
	if (i == to->bound.end()) {
	    return 0;
	}
	return (*i);
    }
    for (; i != to->bound.end(); i++) {
	if ((*i) == c) {
	    i ++;
	    if (i == to->bound.end()) {
		return 0;
	    }
	    return *i;
	}
    }
    return 0;
}

int
nr_bound_atoms(atom_t to)
{
    if (!to) {
	return 0;
    }
    return to->bound.size();
}

void
init_default_atoms()
{
    A_env = get_atom_by_name("env");

    A_delete_back = get_atom_by_name("delete_back");
    A_delete_here = get_atom_by_name("delete_here");
    A_go_up = get_atom_by_name("go_up");
    A_go_down = get_atom_by_name("go_down");
    A_go_left = get_atom_by_name("go_left");
    A_go_right = get_atom_by_name("go_right");
    A_cancel = get_atom_by_name("cancel");
    A_return = get_atom_by_name("return");
    A_go_line_head = get_atom_by_name("go_line_head");
    A_go_line_end = get_atom_by_name("go_line_end");
    A_delete_right = get_atom_by_name("delete_right");
    A_next_candidate = get_atom_by_name("next_candidate");
    A_prev_candidate = get_atom_by_name("prev_candidate");
    A_page_up = get_atom_by_name("page_up");
    A_page_down = get_atom_by_name("page_down");
    A_hira_mode = get_atom_by_name("hira_mode");
    A_commit = get_atom_by_name("commit");
    A_latin_mode = get_atom_by_name("latin_mode");
    A_do_conv = get_atom_by_name("do_conv");
}

void
parse_conf(char *buf)
{
    char buf0[256], buf1[256], buf2[256];
    int c;
    c = sscanf(buf,"%s %s %s", buf0, buf1, buf2);
    
    if (c < 1) {
	return ;
    }
    if (!strcmp("bind", buf0)) {
	if (c < 3) {
	    return ;
	}
	bind_str_to_str(buf2, buf1);
	return ;
    }
    if (!strcmp("include", buf0)) {
	bool r;
	if (c < 2) {
	    return ;
	}
	r = read_a_conf_file(buf1);
	if (!r) {
	    printf("Failed to include file %s\n", buf1);
	}
	return ;
    }
    std::list<ConfHook>::iterator it;
    for (it = hook_list.begin(); it != hook_list.end(); it++) {
	if (!strcmp((*it).name, buf0)) {
	    char *b;
	    b = &buf[strlen(buf0)];
	    while(strchr(" \t", *b)) {
		b++;
	    }
	    (*it).fn(b);
	}
    }
}

static FILE *
open_conf_file(char *fn)
{
    if (fn[0] == '/') {
	return fopen(fn, "r");
    }
    char *p;
    p = (char *)alloca(strlen(CONF_DIR) + strlen(fn) + 10);
    sprintf(p, "%s/%s", CONF_DIR, fn);
    return fopen(p, "r");
}

bool
read_a_conf_file(char *fn)
{
    FILE *fp;
    fp = open_conf_file(fn);
    if (!fp) {
        return false;
    }
    char buf[256];
    while (fgets(buf, 256, fp)) {
        if (buf[0] != '#') {
            parse_conf(buf);
        }
    }
    fclose(fp);
    return true;
}

void
read_conf_file()
{
    char *fn;
    fn = (char *)alloca(strlen(homedir)+strlen(PACKAGE)+
			strlen(CONF_DIR)+20);
    fn[0] = 0;
    strcat(fn, homedir);
    strcat(fn, "/."PACKAGE);
    if (read_a_conf_file(fn)) {
	return ;
    }

    if (!read_a_conf_file("jmode-default.conf")) {
	printf("failed to open %s\n", fn);
	return ;
    }
}
/*
 * Local variables:
 *  c-indent-level: 4
 *  c-basic-offset: 4
 * End:
 */
