/* 

VASP modular - vector assembling signal processor / objects for Max/MSP and PD

Copyright (c) 2002 Thomas Grill (xovo@gmx.net)
For information on usage and redistribution, and for a DISCLAIMER OF ALL
WARRANTIES, see the file, "license.txt," in this distribution.  

*/

#include "main.h"
#include "env.h"
#include "classes.h"
#include "util.h"

Env::Env(I argc,const t_atom *argv)
{
	I ix = 0;
	t_symbol *v = ix < argc?flext::GetASymbol(argv[ix]):NULL;
	if(v && v == vasp_base::sym_env) ix++; // if it is "env" ignore it

	cnt = (argc-ix)/2;
	pos = new R[cnt];
	val = new R[cnt];

	R prev = -BIG;
	BL ok = true;
	for(I i = 0; i < cnt; ++i) {
		val[i] = flext::GetAFloat(argv[ix++]);
		pos[i] = flext::GetAFloat(argv[ix++]);
		if(pos[i] < prev) ok = false;
		prev = pos[i];
	}

	if(ix < argc) {
		post("vasp - env pos/value pairs incomplete, omitted dangling value");
	}

	if(!ok) Clear();
}

/*
Env::Env(const Env &s):
	cnt(s.cnt),pos(new R[s.cnt]),val(new R[s.cnt])
{
	for(I i = 0; i < cnt; ++i) pos[i] = s.pos[i],val[i] = s.val[i];
}
*/

Env::~Env() { Clear(); }


BL Env::ChkArgs(I argc,const t_atom *argv)
{
	I ix = 0;

	// vasp keyword
	t_symbol *v = ix < argc?flext::GetASymbol(argv[ix]):NULL;
	if(v && v == vasp_base::sym_env) ix++; // if it is "env" ignore it

	while(argc > ix) {
		// check for value 
		if(flext::CanbeFloat(argv[ix])) ix++;
		else 
			return false;

		// check for position
		if(argc > ix)
			if(flext::CanbeFloat(argv[ix])) ix++;
			else 
				return false;
	}

	return true;
}

V Env::MakeList(flext::AtomList &ret) const
{
	ret(cnt*2+1);
	flext::SetSymbol(ret[0],vasp_base::sym_env);
	for(I i = 0; i < cnt; ++i) {
		flext::SetFloat(ret[i*2+1],val[i]);
		flext::SetFloat(ret[i*2+2],pos[i]);
	}
}

V Env::Clear()
{
	cnt = 0;
	if(pos) delete[] pos; pos = NULL;
	if(val) delete[] val; val = NULL;
}


Env::Iter::Iter(const Env &bpl): bp(bpl),ppt(-BIG),npt(BIG),pvl(0),k(0) {}

V Env::Iter::Init(R p) 
{
	I cnt = bp.Count();
	FLEXT_ASSERT(cnt > 0);

	if(p < bp.Pos(0)) {
		// position is before the head
		ix = -1;
		ppt = -BIG; pvl = bp.Val(0);
	}
	else if(p > bp.Pos(cnt-1)) { 
		// position is after the tail
		ix = cnt-1;
		ppt = bp.Pos(ix); pvl = bp.Val(ix);
	}
	else { 
		// somewhere in the list
		for(ix = 0; ix < cnt; ++ix)
			if(p >= bp.Pos(ix)) break;
		ppt = bp.Pos(ix); pvl = bp.Val(ix);

		FLEXT_ASSERT(ix < cnt);
	}

	if(ix >= cnt) {
		npt = BIG; nvl = pvl;
		k = 0;
	}
	else {
		npt = bp.Pos(ix+1); nvl = bp.Val(ix+1);
		k = (nvl-pvl)/(npt-ppt); 
	}
}

// \todo iteration first, then calculation of k
V Env::Iter::UpdateFwd(R p) 
{
	do {
		ppt = npt,pvl = nvl;
		if(++ix >= bp.Count()-1) npt = BIG,k = 0;
		else {
			k = ((nvl = bp.Val(ix+1))-pvl)/((npt = bp.Pos(ix+1))-ppt); 
		}
	} while(p > npt);
}

// \todo iteration first, then calculation of k
V Env::Iter::UpdateBwd(R p) 
{
	do {
		npt = ppt,nvl = pvl;
		if(--ix < 0) ppt = -BIG,k = 0;
		else {
			k = (nvl-(pvl = bp.Val(ix)))/(npt-(ppt = bp.Pos(ix))); 
		}
	} while(p < ppt);
}