/*
	$Id: clip.c,v 1.3 2000/12/30 01:23:55 rogue Exp $

	Copyright (c) 1999, 2000 Xforge project
*/

#include <Xm/Xm.h>
#include <stdlib.h>
#include <string.h>
#include "xforge.h"
#include "bufutil.h"
#include "glob.h"

struct buffer *clip;

void buf_copy(struct buffer *buf) {
	float *p, *q;
	int i, mask, channels = 0;
	int copylen, copysize;

	/* count the selected channels */
	mask = 0x1;
	for (i = 0; i < buf->channels; i++) {
		if (mask & buf->selmask)
			channels++;
		mask = mask << 1;
	}

	if (!channels)
		return;

	copylen = buf->selend - buf->selstart + 1;
	copysize = copylen * channels;

	if (!(p = malloc(copysize * sizeof(float)))) {
		syserr(EMEM_MSG);
		return;
	}

	if (clip->data)
		free(clip->data);
	clip->data = p;
	clip->len = copylen;
	clip->channels = channels;
	clip->rate = buf->rate;

	mask = 0x1;
	for (i = 0; i < buf->channels; i++) {
		if (mask & buf->selmask) {
			q = buf->data + buf->selstart + buf->len * i;
			memcpy(p, q, copylen * sizeof(float));
			p += copylen;
		}
		mask = mask << 1;
	}
}

void buf_cut(struct buffer *buf) {
	float *p, *q, *r;
	int i, mask, channels = 0;
	int buflen, copylen, bufsize, copysize;

	/* count the selected channels */
	mask = 0x1;
	for (i = 0; i < buf->channels; i++) {
		if (mask & buf->selmask)
			channels++;
		mask = mask << 1;
	}

	if (!channels)
		return;

	buflen = buf->len;
	copylen = buf->selend - buf->selstart + 1;
	bufsize = buflen * buf->channels;
	copysize = copylen * channels;

	if (!(p = malloc(copysize * sizeof(float)))) {
		syserr(EMEM_MSG);
		return;
	}
	if (!(r = malloc((buflen - copylen) * buf->channels *
		sizeof(float)))) {
		syserr(EMEM_MSG);
		free(p);
		return;
	}

	if (undo_create(buf)) {
		free(p);
		free(r);
		return;
	}

	if (clip->data)
		free(clip->data);
	clip->data = p;
	clip->len = copylen;
	clip->channels = channels;
	clip->rate = buf->rate;

	mask = 0x1;
	for (i = 0; i < buf->channels; i++) {
		if (mask & buf->selmask) {
			q = buf->data + buf->selstart + buf->len * i;
			memcpy(p, q, copylen * sizeof(float));
			p += copylen;
		}
		mask = mask << 1;
	}

	q = r;
	for (i = 0; i < buf->channels; i++) {
		/* copy the beginning */
		p = buf->data + buf->len * i;
		memcpy(q, p, buf->selstart * sizeof(float));
		q += buf->selstart;
		/* copy the rest */
		p = buf->data + buf->len * i + buf->selend + 1;
		memcpy(q, p, (buf->len - buf->selend - 1) * sizeof(float));
		q += buf->len - buf->selend - 1;
	}

	free(buf->data);
	buf->len -= copylen;
	buf->data = r;
	buf->mod = 1;
}

void buf_paste(struct buffer *buf) {
	float *p, *q, *r;
	int i;
	int buflen, copylen, bufsize, copysize;

	if (!(clip->data))
		return;

	buflen = buf->len;
	copylen = clip->len;
	bufsize = buflen * buf->channels;
	copysize = copylen * clip->channels;

	/* if buffer is empty, copy clip to buffer */
	if (!(buf->data)) {
		if (!(r = buf->data = malloc(copysize * sizeof(float)))) {
			syserr(EMEM_MSG);
			return;
		}
		if (undo_create(buf)) {
			free(r);
			return;
		}
		p = clip->data;
		memcpy(r, p, copysize * sizeof(float));
		buf->len = clip->len;
		buf->channels = clip->channels;
		buf->mod = 1;
		buf->filef = FILEF_RAW;
		buf->rate = clip->rate;
		return;
	}

	/* don't allow stereo clip to mono buffer or vice versa (yet) */
	if (clip->channels != buf->channels) {
		xferr("Clipboard channel count mismatch, paste aborted");
		return;
	}

	if (!(r = malloc((bufsize + copysize) * sizeof(float)))) {
		syserr(EMEM_MSG);
		return;
	}

	if (undo_create(buf)) {
		free(r);
		return;
	}

	q = r;
	for (i = 0; i < buf->channels; i++) {
		/* copy the beginning */
		p = buf->data + buf->len * i;
		memcpy(q, p, buf->selstart * sizeof(float));
		q += buf->selstart;
		/* copy clipboard */
		p = clip->data + clip->len * i;
		memcpy(q, p, clip->len * sizeof(float));
		q += clip->len;
		/* copy rest of data */
		p = buf->data + buf->len * i + buf->selstart;
		memcpy(q, p, (buf->len - buf->selstart) * sizeof(float));
		q += buf->len - buf->selstart;
	}

	free(buf->data);
	buf->data = r;
	buf->len += copylen;
	buf->mod = 1;
}

void buf_delete(struct buffer *buf) {
	float *p, *q, *r;
	int i;
	int newlen, newsize;

	if (!(buf->selmask))
		return;

	newlen = buf->len - buf->selend + buf->selstart - 1;
	newsize = newlen * buf->channels;

	if (!(p = r = malloc(newsize * sizeof(float)))) {
		xferr(EMEM_MSG);
		return;
	}

	if (undo_create(buf)) {
		free(p);
		return;
	}

	for (i = 0; i < buf->channels; i++) {
		/* copy the beginning */
		q = buf->data + buf->len * i;
		memcpy(p, q, buf->selstart * sizeof(float));
		p += buf->selstart;
		/* copy rest of data */
		q = buf->data + buf->len * i + buf->selend + 1;
		memcpy(p, q, (buf->len - buf->selend - 1) * sizeof(float));
		p += buf->len - buf->selend - 1;
	}
	buf->len = newlen;
	free(buf->data);
	buf->data = r;
	buf->mod = 1;
}

void buf_swaptoclip(struct buffer *buf) {
	float *data;
	int len, channels, rate;

	if (undo_create(buf))
		return;

	data = buf->data;
	len = buf->len;
	channels = buf->channels;
	rate = buf->rate;

	buf->data = clip->data;
	buf->len = clip->len;
	buf->channels = clip->channels;
	buf->rate = clip->rate;

	clip->data = data;
	clip->len = len;
	clip->channels = channels;
	clip->rate = rate;

	buf->mod = 1;
}
