/* 
   elmo - ELectronic Mail Operator

   Copyright (C) 2003, 2004 rzyjontko

   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; version 2.

   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 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.  

   ----------------------------------------------------------------------

*/
/****************************************************************************
 *    IMPLEMENTATION HEADERS
 ****************************************************************************/

#include "keymap.h"
#include "xmalloc.h"
#include "error.h"
#include "exec.h"

/****************************************************************************
 *    IMPLEMENTATION PRIVATE DEFINITIONS / ENUMERATIONS / SIMPLE TYPEDEFS
 ****************************************************************************/

#define FIRST_ALLOC 10

/****************************************************************************
 *    IMPLEMENTATION PRIVATE CLASS PROTOTYPES / EXTERNAL CLASS REFERENCES
 ****************************************************************************/
/****************************************************************************
 *    IMPLEMENTATION PRIVATE STRUCTURES / UTILITY CLASSES
 ****************************************************************************/
/****************************************************************************
 *    IMPLEMENTATION REQUIRED EXTERNAL REFERENCES (AVOID)
 ****************************************************************************/
/****************************************************************************
 *    IMPLEMENTATION PRIVATE DATA
 ****************************************************************************/

static int no_default = 0;

/****************************************************************************
 *    INTERFACE DATA
 ****************************************************************************/

keymap_t keymap_default;

/****************************************************************************
 *    IMPLEMENTATION PRIVATE FUNCTION PROTOTYPES
 ****************************************************************************/
/****************************************************************************
 *    IMPLEMENTATION PRIVATE FUNCTIONS
 ****************************************************************************/

static void
reallocate (keymap_t *km)
{
        if (km->k_size == km->k_count){
                km->k_size = (km->k_size + 1) * 2;
                km->keys   = xrealloc (km->keys,
                                       km->k_size * sizeof (struct key));
        }

        if (km->m_size == km->m_count){
                km->m_size = (km->m_size + 1) * 2;
                km->meta   = xrealloc (km->meta,
                                       km->m_size * sizeof (struct key));
        }
}


static void
execute (struct key *k)
{
        exec_run (k->exec);
}


/****************************************************************************
 *    INTERFACE FUNCTIONS
 ****************************************************************************/

void
keymap_init (keymap_t *km)
{
        km->k_size  = FIRST_ALLOC;
        km->k_count = 0;
        km->keys    = xmalloc (km->k_size * sizeof (struct key));

        km->m_size  = FIRST_ALLOC;
        km->m_count = 0;
        km->meta    = xmalloc (km->m_size * sizeof (struct key));
}


void
keymap_destroy (keymap_t *km)
{
        if (km->keys)
                xfree (km->keys);
        if (km->meta)
                xfree (km->meta);
}



struct key *
keymap_lookup (keymap_t *km, int key, int no_default)
{
        int i;

        for (i = 0; i < km->k_count; i++){
                if (km->keys[i].key == key)
                        return km->keys + i;
        }

	if (no_default)
		return NULL;
	
	for (i = 0; i < keymap_default.k_count; i++){
		if (keymap_default.keys[i].key == key)
			return keymap_default.keys + i;
	}
        return NULL;
}



struct key *
keymap_meta_lookup (keymap_t *km, int key, int no_default)
{
        int i;

        for (i = 0; i < km->m_count; i++){
                if (km->meta[i].key == key)
                        return km->meta + i;
        }

	if (no_default)
		return NULL;
	
	for (i = 0; i < keymap_default.m_count; i++){
		if (keymap_default.meta[i].key == key)
			return keymap_default.meta + i;
	}
        return NULL;
}



struct key *
keymap_lookup_fun (keymap_t *km, void (*fun)(void))
{
        int     i;
        exec_t *exec = exec_lookup_fun (fun);

        if (exec == NULL)
                return NULL;

        for (i = 0; i < km->k_count; i++){
                if (km->keys[i].exec == exec)
                        return km->keys + i;
        }

        if (no_default)
                return NULL;
        
        for (i = 0; i < keymap_default.k_count; i++){
                if (keymap_default.keys[i].exec == exec){
                        if (keymap_lookup (km, keymap_default.keys[i].key, 1))
                                return NULL;
                        return keymap_default.keys + i;
                }
        }
        return NULL;
}



void
keymap_add (keymap_t *km, int key, int meta, void (*fun)(void))
{
        struct key *k;
        exec_t     *exec = exec_lookup_fun (fun);


        if (meta)
                k = keymap_meta_lookup (km, key, 1);
        else
                k = keymap_lookup (km, key, 1);

        if (k){
                k->exec = exec;
                return;
        }

        reallocate (km);
        if (! meta){
                km->keys[km->k_count].key  = key;
                km->keys[km->k_count].exec = exec;
                km->k_count++;
        }
        else {
                km->meta[km->m_count].key  = key;
                km->meta[km->m_count].exec = exec;
                km->m_count++;
        }
}



int
keymap_action (keymap_t *km, int key, int meta)
{
        struct key *k;

        if (meta)
                k = keymap_meta_lookup (km, key, no_default);
        else
                k = keymap_lookup (km, key, no_default);

        if (k){
                execute (k);
                return 0;
        }

        return 1;
}



void
keymap_disable_default (void)
{
        no_default = 1;
}



void
keymap_enable_default (void)
{
        no_default = 0;
}

/****************************************************************************
 *    INTERFACE CLASS BODIES
 ****************************************************************************/
/****************************************************************************
 *
 *    END MODULE keymap.c
 *
 ****************************************************************************/


syntax highlighted by Code2HTML, v. 0.9.1