/*
    libundo, an easy to use undo/redo management library
    Copyright 1999 Matt Kimball

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#include <string.h>

#include "undoP.h"

UNDO *undo_new(void) {
	UNDO *undo = NULL;

	undo = NEW(UNDO);
	if(undo == NULL)
		return NULL;

	undo->memory = undo_memory_new();
	if(undo->memory == NULL) {
		undo_destroy(undo);
		return NULL;
	}

	undo->history = undo_history_new();
	if(undo->history == NULL) {
		undo_destroy(undo);
		return NULL;
	}

	return undo;
}

int undo_destroy(UNDO *undo) {
	if(undo == NULL)
		UNDO_ERROR(undo, UNDO_NOSESSION);

	if(undo->memory)
		undo_memory_destroy(undo->memory);
	
	if(undo->history)
		undo_history_destroy(undo->history);

	free(undo);

	UNDO_SUCCESS;
}

int undo_set_memory_limit(UNDO *undo, size_t max_memory) {
	if(undo == NULL)
		UNDO_ERROR(undo, UNDO_NOSESSION);

	undo_history_set_memory_limit(undo->history, max_memory);

	UNDO_SUCCESS;
}

int undo_set_history_logical(UNDO *undo, int onoff) {
	if(undo == NULL)
		UNDO_ERROR(undo, UNDO_NOSESSION);

	undo_history_set_logical(undo->history, onoff);

	UNDO_SUCCESS;
}

unsigned undo_get_undo_count(const UNDO *undo) {
	if(undo == NULL)
		return 0;

	return undo_history_undo_count(undo->history);
}

unsigned undo_get_redo_count(const UNDO *undo) {
	if(undo == NULL)
		return 0;

	return undo_history_redo_count(undo->history);
}

int undo_undo(UNDO *undo) {
	UNDO_MEMORY_STREAM *stream;
	int ret;

	if(undo == NULL)
		UNDO_ERROR(undo, UNDO_NOSESSION);

	if(undo_history_undo_count(undo->history) == 0)
		UNDO_ERROR(undo, UNDO_NODO);

	stream = undo_history_undo(undo->history);
	if(stream == NULL)
		UNDO_ERROR(undo, UNDO_NOMEM);
	ret = undo_memory_set(undo->memory, stream);
	if (ret)
		UNDO_ERROR(undo, ret);
	stream->destroy(stream);

	return ret;
}

int undo_redo(UNDO *undo) {
	UNDO_MEMORY_STREAM *stream;
	int ret;

	if(undo == NULL)
		UNDO_ERROR(undo, UNDO_NOSESSION);
	
	if(undo_history_redo_count(undo->history) == 0)
		UNDO_ERROR(undo, UNDO_NODO);

	stream = undo_history_redo(undo->history);
	if(stream == NULL)
		UNDO_ERROR(undo, UNDO_NOMEM);
	ret = undo_memory_set(undo->memory, stream);
	stream->destroy(stream);

	return ret;
}

int undo_snapshot(UNDO *undo) {
	UNDO_MEMORY_STREAM *stream;
	int ret;

	if(undo == NULL)
		UNDO_ERROR(undo, UNDO_NOSESSION);

	stream = undo_memory_stream(undo->memory);
	if(stream == NULL)
		UNDO_ERROR(undo, UNDO_NOMEM);
	ret = undo_history_record(undo->history, stream);
	if(ret) {
		UNDO_ERROR(undo, ret);
        }
        stream->destroy(stream);

	return ret;
}

void *undo_malloc(UNDO *undo, size_t size) {
	void  *p;
        if(undo == NULL)
		UNDO_ERROR_NULL(undo, UNDO_NOSESSION);

	p = undo_memory_alloc(undo->memory, size);
	if (size > 0 && p == NULL)
		UNDO_ERROR_NULL(undo, UNDO_NOMEM);
	return p;
}

void *undo_realloc(UNDO *undo, void *mem, size_t size) {
	size_t min_size;
	void *new_mem;

	if(undo == NULL)
		UNDO_ERROR_NULL(undo, UNDO_NOSESSION);

	if(mem == NULL)
		return undo_memory_alloc(undo->memory, size);

	min_size = undo_memory_size(undo->memory, mem);
	if(size < min_size)
		min_size = size;

	if(size == min_size)
		return mem;

	new_mem = undo_memory_alloc(undo->memory, size);
	if(new_mem == NULL)
		UNDO_ERROR_NULL(undo, UNDO_NOMEM);

	memcpy(new_mem, mem, min_size);
	undo_memory_free(undo->memory, mem); /* FIXME - check for return code */
	
	return new_mem; 
}

void undo_free(UNDO *undo, void *mem) {
	if(undo == NULL)
		return;

	undo_memory_free(undo->memory, mem);
}


syntax highlighted by Code2HTML, v. 0.9.1