#include <config.h>
#include <stdio.h>
#include "IMState.hh"
#include "ICState.hh"
#include "IMProtocol.hh"
#include "IMLog.hh"
#include "IIIMP_hotkey_profile.hh"

const CARD16BIT void_im_id = 0xFFFF;
const CARD16BIT void_ic_id = 0xFFFF;
const int ic_id_max = 0xFFFE;

IMState::IMState(
	CARD16BIT x_im_id,
	IMProtocol *x_pimp,
	IMHandler *x_pimh,
	int x_protocol_version
	)
{
  pshared = new IMShared();
  pshared->im_id = x_im_id;
  pshared->pimp = x_pimp;
  pshared->pimh = x_pimh;
  pshared->hotkey_profile = new IIIMP_hotkey_profile();
  pshared->register_hotkey_flag = false;
  protocol_version = x_protocol_version;
  pproc_state = NULL;
  pbase_state = this;
}

IMState::~IMState()
{
  if (!substatep()) {
    cleanup_ic();
    delete pshared->hotkey_profile;
    pshared->pimh->destroy();
    delete pshared;
    if (pproc_state) delete pproc_state;
  }
}

IMAccept* 
IMState::get_imaccept()
{
    return get_improtocol()->pimaccept;
}

void
IMState::add_icstate(
    ICState *pics
)
{
    CARD16BIT ic_id = pics->get_ic_id();
    ICStateMap& icmap = pshared->icmap;
    ASSERT(icmap.find(ic_id) == icmap.end());
    icmap[ic_id] = pics;
}

void
IMState::remove_icstate(
    ICState *pics
)
{
    pshared->icmap.erase(pics->get_ic_id());
}


void
IMState::cleanup_ic()
{
    ICStateMap::iterator it, it2;
    ICStateMap& icmap = pshared->icmap;
    for (it = icmap.begin(); it != icmap.end();) {
	it2 = it;
	it++;
	// this operation may invalidate it2.
	it2->second->destroy();
    }
}

void
IMState::destroy()
{
    if (!substatep()) pshared->pimp->remove_imstate(this);
    delete this;
}

bool
IMState::dispatch(
    CARD16BIT im_id,
    CARD16BIT ic_id,
    void *message
)
{
    if ((im_id != void_im_id) && (im_id != get_im_id())) {
	LOG_ERROR("Invalid im_id(%d).  This must be %d.",
		  (int) im_id, (int) get_im_id());
	return false;
    }
    if (ic_id != void_ic_id) {
	ICStateMap::iterator it;

	it = pshared->icmap.find(ic_id);
	if (it != pshared->icmap.end()) {
	    it->second->deliver(message);
	    return true;
	} else {
	    LOG_ERROR("Invalid ic_id(%d).  This ic_id is never issued.",
		      (int) ic_id);
	}
    } else {
	deliver(message);
	return true;
    }
    LOG_ERROR("Invalid im_id and ic_id (%d, %d)",
	      (int) im_id, (int) ic_id);
    return false;
}

bool
IMState::new_ic_id(CARD16BIT &newid) const
{
    int tid, size;
    ICStateMap *pmap = &pshared->icmap;

    size = pmap->size();
    for (tid = size + 1; ; ) {
	if (pmap->find(tid) == pmap->end()) {
	    newid = tid;
	    return true;
	}
	tid++;
	if (tid > ic_id_max) {
	    tid = 1;
	}
	if (tid == size) {
	    LOG_ERROR("Could not allocate new input context.");
	    return false;
	}
    }
// not reached
    return false;
}

/* Local Variables: */
/* c-file-style: "iiim-project" */
/* End: */
