/*
 * Copyright (c)2004 Cat's Eye Technologies.  All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 
 *   Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 * 
 *   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.
 * 
 *   Neither the name of Cat's Eye Technologies nor the names of its
 *   contributors may be used to endorse or promote products derived
 *   from this software without specific prior written permission. 
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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
 * COPYRIGHT HOLDERS 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. 
 */

/*
 * form.c
 * $Id: form.c,v 1.2 2004/07/10 02:35:22 cpressey Exp $
 */

#include <stdarg.h>
#include <stdlib.h>
#include <string.h>

#include "dfui.h"
#include "mem.h"

/*** IDS ***/

dfui_id_t
dfui_id_new(char *str)
{
	dfui_id_t id;
	
	id = malloc(strlen(str) + 1);
	strcpy(id, str);
	return(id);
}

dfui_id_t
dfui_id_dup(dfui_id_t str)
{
	dfui_id_t id;
	
	id = malloc(strlen(str) + 1);
	strcpy(id, str);
	return(id);
}

void
dfui_id_free(dfui_id_t id)
{
	free(id);
}

int
dfui_id_is(dfui_id_t id, char *name)
{
	return(!strcmp(id, name));
}

/*** INFOS ***/

struct dfui_info *
dfui_info_new(char *name, char *short_desc, char *long_desc)
{
	struct dfui_info *i;

	DFUI_MALLOC(i, dfui_info);
	i->name = dfui_strdup(name);
	i->short_desc = dfui_strdup(short_desc);
	i->long_desc = dfui_strdup(long_desc);
	
	return(i);
}

void
dfui_info_free(struct dfui_info *i)
{
	free(i->name);
	free(i->short_desc);
	free(i->long_desc);
	DFUI_FREE(i, dfui_info);
}

char *
dfui_info_get_name(struct dfui_info *i)
{
	return(i->name);
}

char *
dfui_info_get_short_desc(struct dfui_info *i)
{
	return(i->short_desc);
}

char *
dfui_info_get_long_desc(struct dfui_info *i)
{
	return(i->long_desc);
}

void
dfui_info_set_name(struct dfui_info *i, char *name)
{
	if (i == NULL)
		return;
	if (i->name != NULL)
		free(i->name);
	i->name = dfui_strdup(name);
}

void
dfui_info_set_short_desc(struct dfui_info *i, char *short_desc)
{
	if (i == NULL)
		return;
	if (i->short_desc != NULL)
		free(i->short_desc);
	i->short_desc = dfui_strdup(short_desc);
}

void
dfui_info_set_long_desc(struct dfui_info *i, char *long_desc)
{
	if (i == NULL)
		return;
	if (i->long_desc != NULL)
		free(i->long_desc);
	i->long_desc = dfui_strdup(long_desc);
}

/*** FIELDS ***/

struct dfui_field *
dfui_field_new(dfui_id_t id, struct dfui_info *info)
{
	struct dfui_field *fi;

	DFUI_MALLOC(fi, dfui_field);
	fi->id = id;
	fi->info = info;
	fi->editable = 1;
	fi->obscured = 0;
	fi->option_head = NULL;
	fi->hint_head = NULL;
	fi->next = NULL;

	return(fi);
}

void
dfui_field_free(struct dfui_field *fi)
{
	dfui_id_free(fi->id);
	dfui_info_free(fi->info);
	dfui_options_free(fi->option_head);
	dfui_celldatas_free(fi->hint_head);
	DFUI_FREE(fi, dfui_field);
}

void
dfui_fields_free(struct dfui_field *head)
{
	struct dfui_field *fi;

	fi = head;
	while (fi != NULL) {
		head = fi->next;
		dfui_field_free(fi);
		fi = head;
	}
}

void
dfui_fields_foreach(int (*callback)(struct dfui_field *, void *),
		    struct dfui_field *head, void *userdata)
{
	int result = 1;

	while (head != NULL && result) {
		result = callback(head, userdata);
		head = head->next;
	}
}

struct dfui_field *
dfui_field_get_next(struct dfui_field *fi)
{
	return(fi->next);
}

dfui_id_t
dfui_field_get_id(struct dfui_field *fi)
{
	return(fi->id);
}

struct dfui_info *
dfui_field_get_info(struct dfui_field *fi)
{
	return(fi->info);
}

void
dfui_field_set_editable(struct dfui_field *fi, int editable)
{
	fi->editable = editable;
}

int
dfui_field_is_editable(struct dfui_field *fi)
{
	return(fi->editable);
}

void
dfui_field_set_obscured(struct dfui_field *fi, int obscured)
{
	fi->obscured = obscured;
}

int
dfui_field_is_obscured(struct dfui_field *fi)
{
	return(fi->obscured);
}

struct dfui_option *
dfui_field_option_add(struct dfui_field *fi, char *value)
{
	struct dfui_option *o;
	
	o = dfui_option_new(value);
	o->next = fi->option_head;
	fi->option_head = o;

	return(o);
}

struct dfui_celldata *
dfui_field_hint_add(struct dfui_field *fi, char *name, char *value)
{
	struct dfui_celldata *h;
	
	h = dfui_celldata_new(dfui_id_new(name), value);
	h->next = fi->hint_head;
	fi->hint_head = h;
	
	return(h);
}

char *
dfui_field_hint_find(struct dfui_field *fi, char *name)
{
	struct dfui_celldata *h;
	
	h = dfui_celldata_find(fi->hint_head, name);
	return(h == NULL ? NULL : h->value);
}

int
dfui_field_hint_is(struct dfui_field *fi, char *name, char *value)
{
	struct dfui_celldata *h;
	
	h = dfui_celldata_find(fi->hint_head, name);
	if (h == NULL)
		return(0);
	return(!strcmp(h->value, value));
}

/*** OPTIONS ***/

struct dfui_option *
dfui_option_new(char *value)
{
	struct dfui_option *o;

	DFUI_MALLOC(o, dfui_option);
	o->value = dfui_strdup(value);
	o->next = NULL;
	
	return(o);
}

void
dfui_option_free(struct dfui_option *o)
{
	free(o->value);
	DFUI_FREE(o, dfui_option);
}

void
dfui_options_free(struct dfui_option *head)
{
	struct dfui_option *o;

	o = head;
	while (o != NULL) {
		head = o->next;
		dfui_option_free(o);
		o = head;
	}
}

void
dfui_options_foreach(int (*callback)(struct dfui_option *, void *),
		    struct dfui_option *head, void *userdata)
{
	int result = 1;

	while (head != NULL && result) {
		result = callback(head, userdata);
		head = head->next;
	}
}

/*** ACTIONS ***/

struct dfui_action *
dfui_action_new(dfui_id_t id, struct dfui_info *info)
{
	struct dfui_action *a;

	DFUI_MALLOC(a, dfui_action);
	a->id = id;
	a->info = info;
	a->next = NULL;
	a->hint_head = NULL;
	
	return(a);
}

void
dfui_action_free(struct dfui_action *a)
{
	dfui_id_free(a->id);
	dfui_info_free(a->info);
	DFUI_FREE(a, dfui_action);
}

void
dfui_actions_free(struct dfui_action *head)
{
	struct dfui_action *a;

	a = head;
	while (a != NULL) {
		head = a->next;
		dfui_action_free(a);
		a = head;
	}
}

void
dfui_actions_foreach(int (*callback)(struct dfui_action *, void *),
		    struct dfui_action *head, void *userdata)
{
	int result = 1;

	while (head != NULL && result) {
		result = callback(head, userdata);
		head = head->next;
	}
}

struct dfui_action *
dfui_action_get_next(struct dfui_action *a)
{
	return(a->next);
}

dfui_id_t
dfui_action_get_id(struct dfui_action *a)
{
	return(a->id);
}

struct dfui_info *
dfui_action_get_info(struct dfui_action *a)
{
	return(a->info);
}

struct dfui_celldata *
dfui_action_hint_add(struct dfui_action *a, char *name, char *value)
{
	struct dfui_celldata *h;
	
	h = dfui_celldata_new(dfui_id_new(name), value);
	h->next = a->hint_head;
	a->hint_head = h;
	
	return(h);
}

char *
dfui_action_hint_find(struct dfui_action *a, char *name)
{
	struct dfui_celldata *h;
	
	h = dfui_celldata_find(a->hint_head, name);
	return(h == NULL ? NULL : h->value);
}

int
dfui_action_hint_is(struct dfui_action *a, char *name, char *value)
{
	struct dfui_celldata *h;
	
	h = dfui_celldata_find(a->hint_head, name);
	if (h == NULL)
		return(0);
	return(!strcmp(h->value, value));
}

/*** FORMS ***/

struct dfui_form *
dfui_form_new(dfui_id_t id, struct dfui_info *info)
{
	struct dfui_form *f;

	DFUI_MALLOC(f, dfui_form);
	f->id = id;
	f->info = info;
	f->multiple = 0;
	f->extensible = 0;
	f->field_head = NULL;
	f->action_head = NULL;
	f->dataset_head = NULL;
	f->hint_head = NULL;

	return(f);
};

/*
 * Convenience function for creating a form.
 * This function takes a list of any number of strings.
 * This list MUST be terminated by a NULL pointer.
 * The first four strings are the id, name, short description, and long
 * description of the form.
 * Each subsequent string determines what the strings following it represent:
 *    "f": create a field (id, name, short desc, long desc).
 *    "o": add an option to the last field (value).
 *    "a": create an action (id, name, short desc, long desc).
 *    "h": add a hint to the last object (name, value).
 */
struct dfui_form *
dfui_form_create(char *id_string, char *name, char *short_desc, char *long_desc, ...)
{
#define DFUI_FORM_CREATE_FORM	0
#define DFUI_FORM_CREATE_FIELD	1
#define DFUI_FORM_CREATE_ACTION	2

	struct dfui_form *f;
	struct dfui_info *i;
	dfui_id_t id;
	va_list args;
	int state = DFUI_FORM_CREATE_FORM;
	char *arg;
	void *object = NULL;
	char *a_id, *a_name, *a_short_desc, *a_long_desc;
	
	id = dfui_id_new(id_string);
	i = dfui_info_new(name, short_desc, long_desc);
	f = dfui_form_new(id, i);
	
	va_start(args, long_desc);
	while ((arg = va_arg(args, char *)) != NULL) {
		switch(arg[0]) {
		case 'f':
			a_id = va_arg(args, char *);
			a_name = va_arg(args, char *);
			a_short_desc = va_arg(args, char *);
			a_long_desc = va_arg(args, char *);
			id = dfui_id_new(a_id);
			i = dfui_info_new(a_name, a_short_desc, a_long_desc);
			object = (void *)dfui_form_field_add(f, id, i);
			state = DFUI_FORM_CREATE_FIELD;
			break;
		case 'a':
			a_id = va_arg(args, char *);
			a_name = va_arg(args, char *);
			a_short_desc = va_arg(args, char *);
			a_long_desc = va_arg(args, char *);
			id = dfui_id_new(a_id);
			i = dfui_info_new(a_name, a_short_desc, a_long_desc);
			object = (void *)dfui_form_action_add(f, id, i);
			state = DFUI_FORM_CREATE_ACTION;
			break;
		case 'o':
			a_name = va_arg(args, char *);
			if (state == DFUI_FORM_CREATE_FIELD) {
				dfui_field_option_add(object, a_name);
			} else {
				/* XXX issue some sort of warning? */
			}
			break;
		case 'h':
			a_id = va_arg(args, char *);
			a_short_desc = va_arg(args, char *);
			if (state == DFUI_FORM_CREATE_FIELD) {
				dfui_field_hint_add(object, a_id, a_short_desc);
			} else if (state == DFUI_FORM_CREATE_ACTION) {
				dfui_action_hint_add(object, a_id, a_short_desc);
			} else if (state == DFUI_FORM_CREATE_FORM) {
				dfui_form_hint_add(f, a_id, a_short_desc);
			} else {
				/* XXX issue some sort of warning? */
			}
			break;
		default:
			/* XXX issue some sort of warning? */
			break;
		}
	}

	va_end(args);
	return(f);
}

void
dfui_form_free(struct dfui_form *f)
{
	dfui_id_free(f->id);
	dfui_info_free(f->info);
	dfui_fields_free(f->field_head);
	dfui_actions_free(f->action_head);
	dfui_datasets_free(f->dataset_head);
	dfui_celldatas_free(f->hint_head);
	DFUI_FREE(f, dfui_form);
}

struct dfui_field *
dfui_form_field_add(struct dfui_form *f, dfui_id_t id, struct dfui_info *info)
{
	struct dfui_field *fi;

	fi = dfui_field_new(id, info);
	fi->next = f->field_head;
	f->field_head = fi;
	
	return(fi);
}

struct dfui_action *
dfui_form_action_add(struct dfui_form *f, dfui_id_t id, struct dfui_info *info)
{
	struct dfui_action *a;

	a = dfui_action_new(id, info);
	a->next = f->action_head;
	f->action_head = a;
	
	return(a);
}

void
dfui_form_dataset_add(struct dfui_form *f, struct dfui_dataset *ds)
{
	ds->next = f->dataset_head;
	f->dataset_head = ds;
}

struct dfui_dataset *
dfui_form_dataset_get_first(struct dfui_form *f)
{
	return(f->dataset_head);
}

int
dfui_form_dataset_count(struct dfui_form *f)
{
	int n = 0;
	struct dfui_dataset *ds = f->dataset_head;

	while (ds != NULL) {
		n++;
		ds = ds->next;
	}

	return(n);
}

void
dfui_form_datasets_free(struct dfui_form *f)
{
	dfui_datasets_free(f->dataset_head);
	f->dataset_head = NULL;
}

struct dfui_field *
dfui_form_field_find(struct dfui_form *f, dfui_id_t id)
{
	struct dfui_field *fi = f->field_head;

	while (fi != NULL) {
		if (!strcmp(id, fi->id))
			return(fi);
		fi = fi->next;
	}

	return(NULL);
}

struct dfui_field *
dfui_form_field_get_first(struct dfui_form *f)
{
	return(f->field_head);
}

int
dfui_form_field_count(struct dfui_form *f)
{
	int n = 0;
	struct dfui_field *fi = f->field_head;

	while (fi != NULL) {
		n++;
		fi = fi->next;
	}

	return(n);
}

struct dfui_action *
dfui_form_action_find(struct dfui_form *f, dfui_id_t id)
{
	struct dfui_action *a = f->action_head;

	while (a != NULL) {
		if (!strcmp(id, a->id))
			return(a);
		a = a->next;
	}

	return(NULL);
}

struct dfui_action *
dfui_form_action_get_first(struct dfui_form *f)
{
	return(f->action_head);
}

int
dfui_form_action_count(struct dfui_form *f)
{
	int n = 0;
	struct dfui_action *a = f->action_head;

	while (a != NULL) {
		n++;
		a = a->next;
	}

	return(n);
}

void
dfui_form_fields_foreach(int (*callback)(struct dfui_field *, void *),
		    struct dfui_form *f, void *userdata)
{
	dfui_fields_foreach(callback, f->field_head, userdata);
}

void
dfui_form_actions_foreach(int (*callback)(struct dfui_action *, void *),
		    struct dfui_form *f, void *userdata)
{
	dfui_actions_foreach(callback, f->action_head, userdata);
}

struct dfui_celldata *
dfui_form_hint_add(struct dfui_form *f, char *name, char *value)
{
	struct dfui_celldata *h;
	
	h = dfui_celldata_new(dfui_id_new(name), value);
	h->next = f->hint_head;
	f->hint_head = h;

	return(h);
}

char *
dfui_form_hint_find(struct dfui_form *f, char *name)
{
	struct dfui_celldata *h;
	
	h = dfui_celldata_find(f->hint_head, name);
	return(h == NULL ? NULL : h->value);
}

int
dfui_form_hint_is(struct dfui_form *f, char *name, char *value)
{
	struct dfui_celldata *h;
	
	h = dfui_celldata_find(f->hint_head, name);
	if (h == NULL)
		return(0);
	return(!strcmp(h->value, value));
}

dfui_id_t
dfui_form_get_id(struct dfui_form *f)
{
	return(f->id);
}

struct dfui_info *
dfui_form_get_info(struct dfui_form *f)
{
	return(f->info);
}

void
dfui_form_set_multiple(struct dfui_form *f, int multiple)
{
	f->multiple = multiple;
}

int
dfui_form_is_multiple(struct dfui_form *f)
{
	return(f->multiple);
}

void
dfui_form_set_extensible(struct dfui_form *f, int extensible)
{
	f->extensible = extensible;
}

int
dfui_form_is_extensible(struct dfui_form *f)
{
	return(f->extensible);
}

/*** CELLDATAS ***/

struct dfui_celldata *
dfui_celldata_new(dfui_id_t field_id, char *value)
{
	struct dfui_celldata *c;

	DFUI_MALLOC(c, dfui_celldata);
	c->field_id = field_id;
	c->value = dfui_strdup(value);

	return(c);
}

void
dfui_celldata_free(struct dfui_celldata *c)
{
	if (c == NULL)
		return;
	dfui_id_free(c->field_id);
	free(c->value);
	DFUI_FREE(c, dfui_celldata);
}

void
dfui_celldatas_free(struct dfui_celldata *head)
{
	struct dfui_celldata *c;

	c = head;
	while (c != NULL) {
		head = c->next;
		dfui_celldata_free(c);
		c = head;
	}
}

void
dfui_celldatas_foreach(int (*callback)(struct dfui_celldata *, void *),
			struct dfui_celldata *head, void *userdata)
{
	int result = 1;

	while (head != NULL && result) {
		result = callback(head, userdata);
		head = head->next;
	}
}

struct dfui_celldata *
dfui_celldata_find(struct dfui_celldata *cd, dfui_id_t id)
{
	while (cd != NULL) {
		if (!strcmp(id, cd->field_id))
			return(cd);
		cd = cd->next;
	}

	return(NULL);
}

struct dfui_celldata *
dfui_celldata_get_next(struct dfui_celldata *cd)
{
	if (cd != NULL) {
		return(cd->next);
	} else {
		return(NULL);
	}
}

dfui_id_t
dfui_celldata_get_field_id(struct dfui_celldata *cd)
{
	if (cd != NULL) {
		return(cd->field_id);
	} else {
		return(NULL);
	}
}

char *
dfui_celldata_get_value(struct dfui_celldata *cd)
{
	if (cd != NULL) {
		return(cd->value);
	} else {
		return("");
	}
}

/*** DATASETS ***/

struct dfui_dataset *
dfui_dataset_new(void)
{
	struct dfui_dataset *ds;

	DFUI_MALLOC(ds, dfui_dataset);
	ds->celldata_head = NULL;
	ds->next = NULL;

	return(ds);
}

struct dfui_dataset *
dfui_dataset_dup(struct dfui_dataset *ds)
{
	struct dfui_dataset *nds;
	struct dfui_celldata *cd;

	nds = dfui_dataset_new();

	for (cd = ds->celldata_head; cd != NULL; cd = cd->next) {
		dfui_dataset_celldata_add(nds,
		    dfui_id_dup(cd->field_id), cd->value);
	}

	return(nds);
}

void
dfui_dataset_free(struct dfui_dataset *ds)
{
	dfui_celldatas_free(ds->celldata_head);
	DFUI_FREE(ds, dfui_dataset);
}

void
dfui_datasets_free(struct dfui_dataset *head)
{
	struct dfui_dataset *ds;

	ds = head;
	while (ds != NULL) {
		head = ds->next;
		dfui_dataset_free(ds);
		ds = head;
	}
}

void
dfui_datasets_foreach(int (*callback)(struct dfui_dataset *, void *),
			struct dfui_dataset *head, void *userdata)
{
	int result = 1;

	while (head != NULL && result) {
		result = callback(head, userdata);
		head = head->next;
	}
}

struct dfui_celldata *
dfui_dataset_celldata_add(struct dfui_dataset *ds, dfui_id_t field_id, char *value)
{
	struct dfui_celldata *c;
	
	c = dfui_celldata_new(field_id, value);
	c->next = ds->celldata_head;
	ds->celldata_head = c;
	
	return(c);
}

struct dfui_celldata *
dfui_dataset_celldata_get_first(struct dfui_dataset *ds)
{
	return(ds->celldata_head);
}

struct dfui_celldata *
dfui_dataset_celldata_find(struct dfui_dataset *ds, dfui_id_t field_id)
{
	return(dfui_celldata_find(ds->celldata_head, field_id));
}

void
dfui_dataset_celldatas_foreach(int (*callback)(struct dfui_celldata *, void *),
				struct dfui_dataset *ds, void *userdata)
{
	dfui_celldatas_foreach(callback, ds->celldata_head, userdata);
}

struct dfui_dataset *
dfui_dataset_get_next(struct dfui_dataset *ds)
{
	return(ds->next);
}

/*
 * Returns the value of the celldata with the given id found in the
 * given dataset.  If no such celldata is found, a constant zero-length
 * string is returned.  As such, the return value of this function is
 * guaranteed to not be NULL and must NEVER be freed after use.
 */
char *
dfui_dataset_get_value(struct dfui_dataset *ds, dfui_id_t id)
{
	struct dfui_celldata *cd;

	if ((cd = dfui_dataset_celldata_find(ds, id)) != NULL) {
		return(dfui_celldata_get_value(cd));
	} else {
		return("");
	}
}

/*
 * Allocates a string to hold the value of the celldata with the
 * given id found in the given dataset.  Even if no such celldata
 * is found, an allocated, zero-length string is returned.  As such,
 * the return value of this function is guaranteed to not be NULL,
 * and must ALWAYS be freed after use.
 */
char *
dfui_dataset_dup_value(struct dfui_dataset *ds, dfui_id_t id)
{
	return(dfui_strdup(dfui_dataset_get_value(ds, id)));
}

/*** RESPONSES ***/

struct dfui_response *
dfui_response_new(dfui_id_t form_id, dfui_id_t action_id)
{
	struct dfui_response *r;
		
	DFUI_MALLOC(r, dfui_response);
	r->form_id = form_id;
	r->action_id = action_id;
	r->dataset_head = NULL;
	
	return(r);
}

void
dfui_response_free(struct dfui_response *r)
{
	dfui_id_free(r->form_id);
	dfui_id_free(r->action_id);
	dfui_datasets_free(r->dataset_head);
	DFUI_FREE(r, dfui_response);
}

void
dfui_response_dataset_add(struct dfui_response *r, struct dfui_dataset *ds)
{
	ds->next = r->dataset_head;
	r->dataset_head = ds;
}

struct dfui_dataset *
dfui_response_dataset_get_first(struct dfui_response *r)
{
	return(r->dataset_head);
}

int
dfui_response_dataset_count(struct dfui_response *r)
{
	int n = 0;
	struct dfui_dataset *ds = r->dataset_head;

	while (ds != NULL) {
		n++;
		ds = ds->next;
	}

	return(n);
}

dfui_id_t
dfui_response_get_form_id(struct dfui_response *r)
{
	return(r->form_id);
}

dfui_id_t
dfui_response_get_action_id(struct dfui_response *r)
{
	return(r->action_id);
}

/* PROGRESS BARS */

struct dfui_progress *
dfui_progress_new(struct dfui_info *info, int amount)
{
	struct dfui_progress *pr;
		
	DFUI_MALLOC(pr, dfui_progress);
	pr->info = info;
	pr->amount = amount;
	
	return(pr);
}

void
dfui_progress_free(struct dfui_progress *pr)
{
	dfui_info_free(pr->info);
	DFUI_FREE(pr, dfui_progress);
}

struct dfui_info *
dfui_progress_get_info(struct dfui_progress *pr)
{
	return(pr->info);
}

void
dfui_progress_set_amount(struct dfui_progress *pr, int amount)
{
	pr->amount = amount;
}

int
dfui_progress_get_amount(struct dfui_progress *pr)
{
	return(pr->amount);
}
