/*-
 * Copyright (c) 2001 Jordan DeLong
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the author nor the names of contributors may be
 *    used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */
#include "plugutil.h"

/* default flags and the like for a WM_CLASS */
typedef struct wcdefs {
	char		*res_name;	/* resource name */
	char		*res_class;	/* pointer into res_name, don't free() it */

	/* dgroup to use, or null */
	dgroup_t	*dgroup;

	/* stacking layer to put the client in */
	int		stacklayer;

	/* these correspond to clientflags_t, read client.h */
	int		nofocus;
	int		noresize;
	int		nomove;
	int		noiconify;
	int		nodelete;
	int		sticky;

	SLIST_ENTRY(wcdefs) w_list;
} wcdefs_t;

/* list of wcdefs */
static SLIST_HEAD(, wcdefs) wcdefs_list = SLIST_HEAD_INITIALIZER(wcdefs_list);

/* find a wcdefs based on a res_name and res_class */
static wcdefs_t *wcdefs_find(char *res_name, char *res_class) {
	wcdefs_t *wcdefs;

	/* make sure it has res_name and res_class */
	if (!res_name || !res_class)
		return NULL;

	/* loop through and cmp the strings */
	SLIST_FOREACH(wcdefs, &wcdefs_list, w_list)
		if (strcmp(wcdefs->res_class, res_class) == 0)
			if (strcmp(wcdefs->res_name, res_name) == 0)
				goto found;
	return NULL;

found:
	return wcdefs;
}

/* handle default setting on newly arriving clients */
static int init_hints(int pcall, client_t *client) {
	wcdefs_t *wcdefs;

	/* find an appropriate wcdefs */
	wcdefs = wcdefs_find(client->classhint.res_name, client->classhint.res_class);
	if (!wcdefs)
		return PLUGIN_OK;

	/*
	 * set flags to our wcdefs flags.  don't touch flags that the user didn't
	 * say anything about in their rc.
	 */
	if (wcdefs->nofocus != -1)
		client->flags.nofocus = wcdefs->nofocus;
	if (wcdefs->noresize != -1)
		client->flags.noresize = wcdefs->noresize;
	if (wcdefs->nomove != -1)
		client->flags.nomove = wcdefs->nomove;
	if (wcdefs->noiconify != -1)
		client->flags.noiconify = wcdefs->noiconify;
	if (wcdefs->nodelete != -1)
		client->flags.nodelete = wcdefs->nodelete;
	if (wcdefs->sticky != -1)
		client->flags.sticky = wcdefs->sticky;

	/* set dgroup if we got one specified */
	if (wcdefs->dgroup)
		client->dgroup = wcdefs->dgroup;

	/* set stacking layer if it was specified */
	if (wcdefs->stacklayer != -1)
		client->stacklayer = wcdefs->stacklayer;

	return PLUGIN_OK;
}

/* build our defaults information structures */
int init() {
	wcdefs_t *wcdefs;
	param_t *param;
	char *res_name, *res_class;
	int i;

	/* get all the wcdefs_t's built */
	SUBPARAMS_FOREACH(i, param, &plugin_this->params) {
		if (strcmp(param->name, "def") != 0)
			continue;

		/* get the res_name.res_class pair from the value */
		res_name = strdup(param->value);
		if (!res_name)
			PERR("no memory to strdup res_name.res_class");
		res_class = strrchr(res_name, '.');
		if (*res_class != '\0')
			*res_class++ = '\0';

		/* see if a entry exists, or make one */
		wcdefs = wcdefs_find(res_name, res_class);
		if (!wcdefs) {
			wcdefs = malloc(sizeof(wcdefs_t));
			if (!wcdefs) {
				free(res_name);
				PERR("no memory for wcdefs");
			}

			/* init the structure */
			wcdefs->res_name = res_name;
			wcdefs->res_class = res_class;
			wcdefs->dgroup = NULL;
			wcdefs->stacklayer = -1;
			wcdefs->nofocus = -1;
			wcdefs->noresize = -1;
			wcdefs->nomove = -1;
			wcdefs->noiconify = -1;
			wcdefs->nodelete = -1;
			wcdefs->sticky = -1;
			SLIST_INSERT_HEAD(&wcdefs_list, wcdefs, w_list);
		} else
			free(res_name);
		
		/* now read for anything they set */
		OPTIONAL_PARAM(&param->subparams, "nofocus", bool, wcdefs->nofocus, wcdefs->nofocus);
		OPTIONAL_PARAM(&param->subparams, "noresize", bool, wcdefs->noresize, wcdefs->noresize);
		OPTIONAL_PARAM(&param->subparams, "nomove", bool, wcdefs->nomove, wcdefs->nomove);
		OPTIONAL_PARAM(&param->subparams, "noiconify", bool, wcdefs->noiconify, wcdefs->noiconify);
		OPTIONAL_PARAM(&param->subparams, "nodelete", bool, wcdefs->nodelete, wcdefs->nodelete);
		OPTIONAL_PARAM(&param->subparams, "sticky", bool, wcdefs->sticky, wcdefs->sticky);
		OPTIONAL_PARAM(&param->subparams, "dgroup", dgroup, wcdefs->dgroup, wcdefs->dgroup);
		OPTIONAL_PARAM(&param->subparams, "stacklayer", stacklayer, wcdefs->stacklayer, wcdefs->stacklayer);
	}

	return PLUGIN_OK;
}

/* register our callback */
int start() {
	plugin_callback_add(plugin_this, PCALL_INIT_HINTS, init_hints);
	return PLUGIN_OK;
}

/* free our wcdefs */
void shutdown() {
	wcdefs_t *wcdefs, *next;

	wcdefs = SLIST_FIRST(&wcdefs_list);
	while (wcdefs) {
		/* don't free res_class, it's just a ptr into res_name */
		free(wcdefs->res_name);
		next = SLIST_NEXT(wcdefs, w_list);
		free(wcdefs);
		wcdefs = next;
	}
}
