#include <k/type.h>
#include <k/io.h>
#include <k/str.h>

kcond
ksbufput(ksbuf* b, ksraw src) {
	ksmut dest = { b->run - (b->cur - b->buf), b->cur };
	/* there are a number of scenarios we need to account for:
	 *
	 * - the ksraw has an unknown size. in this case, we
	 *   determine the size with kssz and proceed according to
	 *   the following rules. we could also count the string
	 *   as we copy, taking advantage of kscp's behavior on
	 *   strings of unknown length, but this would drastically
	 *   complicate the code for an almost certainly negligible
	 *   gain in performance.
	 *
	 * - the ksraw has a known size that is shorter than the
	 *   remaining space in the buffer. in this case, we copy
	 *   it into the buffer and return the result of the copy.
	 *
	 * - the ksraw has a known size that is the same as the
	 *   remaining space in the buffer. in this case, we copy
	 *   it into the buffer and flush the buffer immediately.
	 *
	 * - the ksraw has a known size that is longer than the
	 *   remaining space in the buffer. in this case, we flush
	 *   the buffer immediately and then copy in the new string.
	 *
	 * - the ksraw has a known size that is greater than or
	 *   equal to the buffer's run. in this case, we flush the
	 *   buffer and print the ksraw directly, bypassing the
	 *   buffer as it would only be a performance impediment.
	 */

	if (src.size == 0) src.size = kssz(src.ptr, -1);

	if (src.size < dest.size) {
		kcond c = kscp(src, dest, null);
		if (!kokay(c)) return c;
		b -> cur += src.size;
		return kscond_ok;
	} else if (src.size == dest.size) {
		kcond c = kscp(src, dest, null);
		if (!kokay(c)) return c;
		b -> cur += src.size;
		return ksbufflush(b);
	} else if (src.size > b -> run) {
		kcond c = ksbufflush(b);
		if (!kokay(c)) return c;
		return kiosend(b -> channel, src, null);
	} else if (src.size > dest.size) {
		kcond c = ksbufflush(b);
		if (!kokay(c)) return c;
		dest.size = b -> run;
		dest.ptr = b -> cur;
		c = kscp(src, dest, null);
		if (!kokay(c)) return c;
		b -> cur += src.size;
		return kscond_ok;
	} else return kscond_fail; /* what in the sam heck */
}
