/* sunone-component.c
 *
 * Copyright (C) 2002-2004 Sun Microsystems, Inc
 *
 * AUTHORS
 *     Jack Jia <jack.jia@sun.com>
 *     Harry Lu <harry.lu@sun.com>
 *     Alfred Peng <alfred.peng@sun.com>
 *     Jedy Wang <jedy.wang@sun.com>
 *     Rodrigo Moya <rodrigo@ximian.com>
 *
 */

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

#include "sunone-component.h"
#include "shell/e-component-view.h"

#include <unistd.h>
#include <string.h>

#include <libbonobo.h>
#include <libedataserverui/e-passwords.h>

#include "sunone-account.h"
#include "sunone-config-listener.h"
#include "sunone-util.h"
#include "sunone-backend-view.h"

#define d(x) x

#define PARENT_TYPE bonobo_object_get_type ()
static BonoboObjectClass *parent_class = NULL;

struct _SunOneComponentPrivate {
	GdkNativeWindow xid;

	SunOneConfigListener *config_listener;
	SunOneOfflineListener *offline_listener;
	GSList *accounts;
	GSList *views;
};

static void
dispose (GObject *object)
{
	SunOneComponent *component = SUNONE_COMPONENT (object);
	SunOneComponentPrivate *priv = component->priv;
	GSList *p;

	if (priv) {
		if (priv->config_listener) {
			g_object_unref (priv->config_listener);
			priv->config_listener = NULL;
		}

		if (priv->accounts) {
			for (p = priv->accounts; p; p = p->next) {
				if (p->data)
					g_object_unref (p->data);
			}
			g_slist_free (priv->accounts);
			priv->accounts = NULL;
		}

		if (priv->views) {
			for (p = priv->views; p; p = p->next) {
				if (p->data)
					g_object_unref (p->data);
			}
			g_slist_free (priv->views);
			priv->views = NULL;
		}

		g_free (priv);
		component->priv = NULL;
	}

	G_OBJECT_CLASS (parent_class)->dispose (object);
}

static void
finalize (GObject *object)
{
	G_OBJECT_CLASS (parent_class)->finalize (object);
}

static GNOME_Evolution_ComponentView
impl_createView (PortableServer_Servant servant,
			GNOME_Evolution_ShellView parent,
			CORBA_Environment *ev)
{
	SunOneComponent *component = SUNONE_COMPONENT (bonobo_object_from_servant (servant));
	SunOneComponentPrivate *priv = component->priv;
	SunOneBackendView *view;
	EComponentView *component_view;

	d(printf("createControls...\n"));

	view = sunone_backend_view_new (priv->config_listener);
	if (view)
		priv->views = g_slist_append (priv->views, view);

	component_view = e_component_view_new_controls (parent, 
			"JESCS", 
			sunone_backend_view_get_sidebar (view),
			sunone_backend_view_get_view (view),
			sunone_backend_view_get_statusbar (view));

	return BONOBO_OBJREF (component_view);
}

static void
impl_upgradeFromVersion (PortableServer_Servant servant,
			 const CORBA_short major,
			 const CORBA_short minor,
			 const CORBA_short revision,
			 CORBA_Environment *ev)
{
	d(printf("upgradeFromVersion\n"));

	/* FIXME */
}

static CORBA_boolean
impl_requestQuit (PortableServer_Servant servant,
		  CORBA_Environment *ev)
{
	d(printf("requestQuit\n"));

	/* FIXME */
	return TRUE;
}

/* This returns TRUE all the time, so if set as an idle callback it
   effectively causes each and every nested glib mainloop to be quit.  */
static gboolean
idle_quit (gpointer user_data)
{
	bonobo_main_quit ();
	return TRUE;
}

static CORBA_boolean
impl_quit (PortableServer_Servant servant,
	   CORBA_Environment *ev)
{
	d(printf("quit\n"));

	e_passwords_cancel ();
	g_timeout_add (500, idle_quit, NULL);
	return TRUE;
}

static void
impl_interactive (PortableServer_Servant servant,
		  const CORBA_boolean now_interactive,
		  const CORBA_unsigned_long new_view_xid,
		  CORBA_Environment *ev)
{
	SunOneComponent *component = SUNONE_COMPONENT (bonobo_object_from_servant (servant));
	SunOneComponentPrivate *priv = component->priv;

	if (now_interactive) {
		priv->xid = new_view_xid;
	} else
		priv->xid = 0;
}

static void
config_listener_account_created (SunOneConfigListener *config_listener,
				 SunOneAccount *account,
				 gpointer user_data)
{
	SunOneComponent *component = user_data;
	SunOneComponentPrivate *priv = component->priv;

	g_object_ref (account);
	priv->accounts = g_slist_prepend (priv->accounts, account);
}

static void
config_listener_account_removed (SunOneConfigListener *config_listener,
				 SunOneAccount *account,
				 gpointer user_data)
{
	SunOneComponent *component = user_data;
	SunOneComponentPrivate *priv = component->priv;
	SunOneAccount *old_account;
	GSList *acc;

	for (acc = priv->accounts; acc; acc = acc->next) {
		old_account = acc->data;
		if (old_account == account) {
			priv->accounts = g_slist_remove (priv->accounts, account);
			g_object_unref (account);
			return;
		}
	}
}

static void
sunone_component_class_init (SunOneComponentClass *klass)
{
	POA_GNOME_Evolution_Component__epv *epv = &klass->epv;
	GObjectClass *object_class = G_OBJECT_CLASS (klass);

	parent_class = g_type_class_peek_parent (klass);

	object_class->dispose = dispose;
	object_class->finalize = finalize;

	epv->createView 	= impl_createView;
	epv->upgradeFromVersion = impl_upgradeFromVersion;
	epv->requestQuit        = impl_requestQuit;
	epv->quit               = impl_quit;
	epv->interactive        = impl_interactive;

}

static void
sunone_component_init (SunOneComponent *component)
{
	SunOneComponentPrivate *priv;

	priv = component->priv = g_new0 (SunOneComponentPrivate, 1);

   	priv->config_listener = sunone_config_listener_new ();
	g_signal_connect (priv->config_listener, "sunone_account_created",
			  G_CALLBACK (config_listener_account_created),
			  component);
	g_signal_connect (priv->config_listener, "sunone_account_removed",
			  G_CALLBACK (config_listener_account_removed),
			  component);
	sunone_config_listener_construct_account (priv->config_listener);
}

BONOBO_TYPE_FUNC_FULL (SunOneComponent, GNOME_Evolution_Component, PARENT_TYPE, sunone_component)

SunOneComponent *
sunone_component_new (void)
{
	return g_object_new (SUNONE_TYPE_COMPONENT, NULL);
}

SunOneAccount *
sunone_component_get_account_from_uid (SunOneComponent *component, const char *uid)
{
	SunOneComponentPrivate *priv = component->priv;
	SunOneAccount *account;
	const gchar *old_uid;
	GSList *acc;

	for (acc = priv->accounts; acc; acc = acc->next) {
		account = acc->data;

		old_uid = sunone_account_get_uid (account);

		if (old_uid && !strncmp (old_uid, uid, strlen(uid))) {
			g_object_ref (account);
			return account;
		}
	}
	return NULL;
}

SunOneAccount *
sunone_component_get_account_from_uri (SunOneComponent *component, const char *uristr)
{
	SunOneAccount *account = NULL;
	gchar *uid;

	g_return_val_if_fail (uristr != NULL, NULL);

	uid = sunone_util_get_parameter_from_uri (uristr, "uid");
	if (!uid) {
		return NULL;
	}

	account = sunone_component_get_account_from_uid (component, uid);

	g_free (uid);

	return account;
}

GSList *
sunone_component_get_account_list (SunOneComponent *component)
{
	return component->priv->accounts;
}

gboolean
sunone_component_is_interactive (SunOneComponent *component)
{
	return component->priv->xid != 0;
}

void
sunone_component_set_offline_listener (SunOneComponent *component, 
				SunOneOfflineListener *listener)
{
	SunOneComponentPrivate *priv;

	g_return_if_fail (SUNONE_IS_COMPONENT (component));

	priv = component->priv;
	priv->offline_listener = listener;
}

void
sunone_component_is_offline (SunOneComponent *component, int *state)
{
	g_return_if_fail (SUNONE_IS_COMPONENT (component));

	sunone_is_offline (component->priv->offline_listener, state);
}
