#include <config.h>
#include <stdio.h>
#include <signal.h>
#include "IMDesktop.hh"
#include "IMUser.hh"
#include "IMInputContext.hh"
#include "IMConnection.hh"
#include "LE.hh"
#include "IMLog.hh"
#include <SunIM.h>

const char unknown_display_name[] = "Unknown:0";

void
IMDesktop::initialize()
{
    IMDesktopAttr::iterator it;

    iiim_xbe = false;

    it = attrs.find(CLIENT_NAME);
    if (it == attrs.end()) {
	client_type = UNKNOWN_CLIENT;
    } else {
	u16string& client_name = it->second;
	if (client_name.find("Htt XIM") != u16string::npos) {
	    iiim_xbe = true;
	    client_type = IIIMXCF;
	} else if (client_name.find("XBE XIM") != u16string::npos) {
	    iiim_xbe = true;
	    client_type = IIIMXCF;
	} else if (client_name.find("XIM IIIMP") != u16string::npos) {
	    client_type = IIIMXCF;
	} else if (client_name.find("JDK") != u16string::npos) {
	    client_type = IIIMJCF;
	} else if (client_name.find("GTK IIIMCF Module") != u16string::npos) {
	    client_type = IIIMGCF;
	} else if (client_name.find("IIIMECF") != u16string::npos) {
	    client_type = IIIMECF;
	}
    }

    // set alternative display_name.
    const u16string* pstr = get_attr(X_DISPLAY_NAME);
    if (pstr && pstr->get_charstr()) {
	desktop_display_name = pstr->get_charstr();
    } else {
	pstr = get_attr(CLIENT_HOST);
	if (!pstr) {
	    LOG_ERROR("IMDesktop is requested, but the client host is unknown.");
	}
	if (pstr->get_charstr()) {
	    desktop_display_name = pstr->get_charstr();
	} else {
	    desktop_display_name = "unknown";
	}
	desktop_display_name.append(":0");
    }
}

iml_desktop_t*
IMDesktop::create_iml_desktop(
    LEContext &lec
)
{
    iml_desktop_t *pidt;
    const char *username, *hostname, *displayname;
    IMDesktopAttr::iterator it;
    IMConnection *pimc = lec.get_inputcontext()->get_imconnection();

    username = puser->get_username().get_charstr();
    if (!username) username = "";
    hostname = pimc->get_hostname().c_str();

    it = attrs.find(X_DISPLAY_NAME);
    if (it != attrs.end()) {
	displayname = it->second.get_charstr();
	if (!displayname)
	    displayname = unknown_display_name;
    } else {
	displayname = unknown_display_name;
    }
    pidt = new_user(lec.get_lebase()->get_iml_if(),
		    username, hostname, displayname);

    return pidt;
}

iml_desktop_t*
IMDesktop::request_iml_desktop(
    LEContext &lec
)
{
    iml_desktop_t *pidt;
    LEBase *plebase = lec.get_lebase();
    IMLDesktopMap::iterator it = iml_desktop_map.find(plebase);
    if (it == iml_desktop_map.end()) {
	pidt = create_iml_desktop(lec);
	if (!pidt) return NULL;
	if (!plebase->open_iml_desktop(this, pidt)) {
	    del_user(pidt);
	    return NULL;
	}
	iml_desktop_map[plebase] = pidt;
    } else {
	pidt = it->second;
    }

    return pidt;
}

void
IMDesktop::release_iml_desktop(
    LEContext &lec,
    iml_desktop_t *iml_desktop
)
{
    // TODO: need to pass command line option -desktop.
    // Use environment varialbe tentatively for now.
    static int iiimd_option_desktop;
    if (0 == iiimd_option_desktop) {
	if (NULL != getenv("IIIMD_OPTION_DESKTOP")) {
	    iiimd_option_desktop = 1;
	} else {
	    iiimd_option_desktop = -1;
	}
    }

    // TODO: Life-cycles of iml_desktop should be controlled by LEBase.
    // But it would involve redesign of LEbase.  Currently, the life-cycle
    // is reference of session.
    if (!iml_desktop->session_list) {
	LEBase *plebase = lec.get_lebase();
	IMLDesktopMap::iterator it = iml_desktop_map.find(plebase);
	ASSERT(it != iml_desktop_map.end());
	ASSERT(it->second == iml_desktop);
	plebase->close_iml_desktop(iml_desktop);
	del_user(iml_desktop);
	iml_desktop_map.erase(it);
	if ((1 == iiimd_option_desktop) && (0 == iml_desktop_map.size())) {
	    kill(getpid(), SIGTERM);
	}
    }
}

bool
IMDesktop::match(
    IMDesktop::IMDesktopAttr &req_attrs
)
{
    IMDesktopAttr::iterator itr;
    IMDesktopAttr::iterator it;

    for (itr = req_attrs.begin(); itr != req_attrs.end(); itr++) {
	// need to compare client host and display names only
	if (itr->first == IMDesktop::CLIENT_HOST ||
	    itr->first == IMDesktop::X_DISPLAY_NAME) {
	  it = attrs.find(itr->first);
	  if (it == attrs.end()) return false;
	  if (it->second.compare(itr->second) != 0) return false;
	}
    }
    return true;
}

const u16string*
IMDesktop::get_attr(
    enum IMDESKTOP_ATTRS attr
)
{
    IMDesktopAttr::iterator it = attrs.find(attr);
    if (it == attrs.end()) return NULL;
    return &it->second;
}

void
IMDesktop::get_iml_desktop_args(
    vector<IMArg> &args
)
{
    IMArg a;

    args.reserve(MAX_UI_ATTRIBUTE);

    const u16string *pstr;

    a.id = UI_USER_NAME;
    a.value = (char*) puser->get_username().get_charstr();
    if (!a.value) a.value = "Nobody";
    args.push_back(a);

    a.id = UI_HOST_NAME;
    pstr = get_attr(IMDesktop::CLIENT_HOST);
    if (pstr && pstr->get_charstr()) {
	a.value = (char*) pstr->get_charstr();
    } else {
	LOG_DEBUG("client host name is unknown.  It must be a problem.");
	a.value = "unknown";
    }
    args.push_back(a);

    a.id = UI_DISPLAY_ID;
    a.value = (char*) get_desktop_display_name().c_str();
    args.push_back(a);

    a.id = UI_PROTOCOL_TYPE;
    if (iiim_xbe_p())
	a.value = UI_PROTOCOL_TYPE_XIMP;
    else
	a.value = UI_PROTOCOL_TYPE_IIIMP;
    args.push_back(a);

    a.id = UI_CLIENT_TYPE;
    switch (get_client_type()) {
      case IMDesktop::IIIMXCF:
      case IMDesktop::IIIMGCF:
       a.value = UI_CLIENT_TYPE_X;
       break;
      case IMDesktop::IIIMJCF:
       a.value = UI_CLIENT_TYPE_JAVA;
       break;
      case IMDesktop::IIIMECF:
      case IMDesktop::UNKNOWN_CLIENT:
      default:
       a.value = UI_CLIENT_TYPE_UNKNOWN;
       break;
    }
    args.push_back(a);

    a.id = UI_XSERVER_VENDOR;
    pstr = get_attr(IMDesktop::X_SERVER_VENDOR);
    if (pstr && pstr->get_charstr()) {
	a.value = (char*) pstr->get_charstr();
    } else {
	a.value = "unknown";
    }
    args.push_back(a);

    a.id = UI_OS_NAME;
    pstr = get_attr(IMDesktop::OS_NAME);
    if (pstr && pstr->get_charstr()) {
	a.value = (char*) pstr->get_charstr();
    } else {
	a.value = "unknown";
    }
    args.push_back(a);

    a.id = UI_OS_ARCH;
    pstr = get_attr(IMDesktop::OS_ARCH);
    if (pstr && pstr->get_charstr()) {
	a.value = (char*) pstr->get_charstr();
    } else {
	a.value = "unknown";
    }
    args.push_back(a);

    a.id = UI_OS_VERSION;
    pstr = get_attr(IMDesktop::OS_VERSION);
    if (pstr && pstr->get_charstr()) {
	a.value = (char*) pstr->get_charstr();
    } else {
	a.value = "unknown";
    }
    args.push_back(a);

    a.id = UI_AUTH_PASSWD;
    // For security reason, currently
    // we don't pass a clear password to LE.
    a.value = NULL;
    args.push_back(a);

    return;
}

void
IMDesktop::get_lecontext_args(
    vector<IMArg> &args
)
{
    IMArg a;

    //TODO!!!
    IMSetArg(a, SC_LOOKUP_LABELTYPE, "numeric");
    args.push_back(a);
    IMSetArg(a, SC_LOOKUP_NCOLS, 4);
    args.push_back(a);
    IMSetArg(a, SC_LOOKUP_NROWS, 4);
    args.push_back(a);

    return;
}

IMDesktop::IMDesktop(
    IMUser *pu
)
{
    puser = pu;
    initialize();
}

IMDesktop::IMDesktop(
    IMUser *pu,
    IMDesktopAttr &x_attrs
)
{
    puser = pu;
    attrs = x_attrs;
    initialize();
}

IMDesktop::~IMDesktop()
{
    LEBase *plebase;
    iml_desktop_t *pidt;
    IMLDesktopMap::iterator it;
    for (it = iml_desktop_map.begin(); it != iml_desktop_map.end(); it++) {
	plebase = it->first;
	pidt = it->second;
	plebase->close_iml_desktop(pidt);
	del_user(pidt);
    }
}

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