/*-------------------------------------------------------*/
/* ProjectOmega                 									*/
/* Written by T.Miles												*/
/* ID: 289175															*/
/* Module:	Track, InputType & Condition Classes	      */
/* Provides the actual storage space for module data.    */
/* Provides mechanisms to check data conforms with       */
/* user defined conditions                               */
/*-------------------------------------------------------*/



#include <string.h>
#include <iostream.h>
#include <stdlib.h>
#include "base/tracks.h"
 
/************************************************/
/* InputType Class Methods                      */
/************************************************/

InputType::InputType(){
	name=NULL;
	ID=0;
	min=0;
	max=0;
}

InputType::InputType(char *n,UBYTE a, UBYTE b,UBYTE c){
	name=new char[strlen(n)+1];
	if (name)
		strcpy(name,n);
	ID=a;
	min=b;
	max=c;
}

InputType::~InputType(){
	if (name)
		delete[] name;
}

void InputType::SetName(char *n){
	UINT len=strlen(n);
	if (name){
		delete []name;
		name=NULL;
	}
	printf("Input: %s  Length: %d\n",n,len);	
	name=new char[len+1];
	if (name){
		memcpy(name,n,len);
		name[len]=NULL;
	}
	else
		printf("Name fuckup\n");
	printf("Output: %s\n",name);
}


/************************************************/
/* Condition Class Methods                      */
/************************************************/
OmegaCondition::OmegaCondition(){
	c_Type=0;
	c_Min=0;
	c_Max=0;
	c_Scale=0.0;
	OrNext=FALSE;
}

void OmegaCondition::SetCondition(UBYTE t, UBYTE min, UBYTE max, BOOL or){
	c_Type=t;
	
	if (min<max){
		c_Min=min;
		c_Max=max;
	}
	else{
		c_Min=max;
		c_Max=min;
	}
	
	if (c_Max-c_Min!=0){
		c_Scale=(float)255/(float)(c_Max-c_Min);
	}
	else
		c_Scale=1.0;
}

void OmegaCondition::SetCondition(OmegaCondition *con){
	c_Type=con->c_Type;
	c_Min=con->c_Min;
	c_Max=con->c_Max;
	c_Scale=con->c_Scale;
}

UBYTE OmegaCondition::ScaleValue(UINT val){
	return (UBYTE)((val-c_Min)*c_Scale);
}

BOOL OmegaCondition::InRange(UBYTE val){
	if (c_Max==0 && c_Min==0)
		return FALSE;
		
	if (val<=c_Max && val>=c_Min)
		return TRUE;
	else
		return FALSE;
}

void OmegaCondition::Save(FILE *file){
	fprintf(file,"%d %d %d %d\n",c_Type,c_Min,c_Max, OrNext);
}

void OmegaCondition::Load(FILE *file){
/*
	*file >> c_Type >> c_Min >> c_Max >> c_Scale >> OrNext;
	printf("%x %d %d %f %d\n",c_Type,c_Min,c_Max,c_Scale, OrNext);
*/
}

/************************************************/
/* Track Class Methods                          */
/************************************************/

OmegaTrack::OmegaTrack(char *name, UBYTE use, UBYTE scale){
	UINT n;
	for (n=0;n<BUFFERSIZE;n++){
		ot_buffer[n]=0;
		if (n<MAXCONDITIONS)
			ot_condSet[n]=FALSE;
	}
	ot_bufIndex=0;
	ot_used=FALSE;
	ot_scaleValue=1;
	ot_Name=new char[strlen(name)+1];
	strcpy(ot_Name,name);
	// Should possibly check for valid 'use' values here?
	ot_useValue=use;
	ot_min=0;
	ot_curExt=0;
	if (scale>=0 && scale<=4)
		ot_scaleType=scale;
}


OmegaTrack::~OmegaTrack(){
	UINT size=ot_Outputs.GetSize();
	for (UINT n=0;n<size;n++){
		delete ot_Outputs.GetItem(0);
		ot_Outputs.DeleteItem(0);
	} 
	if (ot_Name)
		delete[] ot_Name;
}


void OmegaTrack::SetName(char *name){
	if (ot_Name)
		delete [] ot_Name;
		
	ot_Name=new char[strlen(name)+1];
	strcpy(ot_Name,name);
}


//
// SatConditions - See if all the conditions we have in this track are
// satisfied by the data presented
// Returns true if condition(s) are met.  False if not!
//
// This could get messy - if it works it'll be a miracle!
// 
// See entry on 24/1/00 for how to improve this method!
// More important things to work on right now!
// 
// 15/2/00 - Changed the approach somewhat.  This will probably slow it
// down no end :(

BOOL OmegaTrack::ot_SatConditions(UINT numValues, UBYTE *values){
	UBYTE passed=0;
	UBYTE shouldPass=0;
	OmegaCondition *pCond;
	UINT index=0;
	UBYTE scaledVal=0;
		
	// We need to read the input in (type,value) pairs
	// There are only 3 conditions atm - might make this dynamic sometime,
	// but don't count on it!
	// Compare condition 1 to value pair 1, condition 2 to value 2 etc

	for (UINT n=0;n<MAXCONDITIONS;n++){		// Check through each condition
		pCond=&ot_Conditions[n];
		if (ot_condSet[n]){					// If it needs checking
			shouldPass++;						// We need to pass this
			for (index=0;index<numValues;index+=2){	// Check each of our value pairs
				if (pCond->InRange(values[index+1]) && pCond->IsType(values[index])){
					passed++;
				}
			}
		}
	}
	
	if (passed==shouldPass){
		scaledVal=(UBYTE)((FLOAT)(values[(2*ot_useValue)+1]-ot_min)*ot_scaleValue);		// We need to scale this, but to what?
		AddToBuffer(scaledVal);
		return TRUE;
	}
	return FALSE;
}

void OmegaTrack::AddToBuffer(UBYTE value){
	ot_bufIndex++;
	if (ot_bufIndex==BUFFERSIZE)
		ot_bufIndex=0;
	ot_buffer[ot_bufIndex]=value;
}

void OmegaTrack::SetScaleValue(Array<InputType *> *typeArray, UINT *typeMap){
	UINT min, max;
	UINT cond=0;
	UINT type=0;
		
	switch(ot_scaleType){
	case 0:
		ot_scaleValue=1;
		ot_min=0;
		break;
	case 1:
		if (typeMap)
			type=typeMap[ot_useValue];

		if (typeArray && type>0 && type<typeArray->GetSize()){
			min=(typeArray->GetItem(type))->min;
			max=(typeArray->GetItem(type))->max;
		}

		else{
			cout << "Incorrect Value held in typemap " << endl;
			cout << "UseValue: " << ot_useValue << endl;
			min=max=0;
		}	
		ot_min=min;
		if (max-min!=0)
			ot_scaleValue=(float)255/(float)(max-min);
		else
			ot_scaleValue=1;
		break;
	default:							// Condition scaling
		type=ot_Conditions[ot_useValue].GetType();
		min=(typeArray->GetItem(type))->min;
		max=(typeArray->GetItem(type))->max;
		cond=ot_scaleType-2;
		ot_min=ot_Conditions[cond].GetMin();
		if (cond>=0 && cond<3 && ot_condSet[cond])
			ot_scaleValue=ot_Conditions[cond].GetScale();
		else{
			cout << "Incorrect condition scaletype " << cond << endl; 
			ot_scaleValue=1.0;
		}
		break;
	}

}

void OmegaTrack::SetCondition(UINT no, UBYTE type, UBYTE min, UBYTE max, BOOL or){
	if (no>=0 && no<=MAXCONDITIONS){
		ot_Conditions[no].SetCondition(type,min,max,or);
		if (type==0 && min==0 && max==0)
			ot_condSet[no]=FALSE;
		else
			ot_condSet[no]=TRUE;
	}
}

void OmegaTrack::SetCondition(UINT no, OmegaCondition *con){
	ot_Conditions[no].SetCondition(con);
	if (ot_Conditions[no].GetType()==0 && 
		ot_Conditions[no].GetMin()==0 && 
		ot_Conditions[no].GetMax()==0)
		
		ot_condSet[no]=FALSE;
	else
		ot_condSet[no]=TRUE;
}
	
OmegaCondition * OmegaTrack::GetCondition(UINT c){ 
	if (c<MAXCONDITIONS && c>=0) 
		return &ot_Conditions[c];
}

UBYTE OmegaTrack::GetConditionMin(UINT c){
	if (c<MAXCONDITIONS && c>=0) 
		return ot_Conditions[c].GetMin();
}

UBYTE OmegaTrack::GetConditionType(UINT c){
	if (c<MAXCONDITIONS && c>=0) 
		return ot_Conditions[c].GetType();
}

UBYTE OmegaTrack::GetConditionMax(UINT c){
		if (c<5 && c>=0) 
		return ot_Conditions[c].GetMax();
}

void OmegaTrack::Save(FILE *file){
	fprintf(file,"%s %d %d\n",ot_Name,ot_useValue, ot_scaleType);
	for (UINT n=0;n<MAXCONDITIONS;n++)
		ot_Conditions[n].Save(file);
}

void OmegaTrack::SetScaleType(UBYTE val){
	ot_scaleType=val;
}

void OmegaTrack::SetOutput(MsgPort *port,UINT effect){
	InputExtension *newExt=new InputExtension;
	
	newExt->ie_MsgPort=port;
	newExt->ie_EffectNo=effect;
	ot_Outputs.AddItem(newExt);
	ot_used=TRUE;
}

InputExtension *OmegaTrack::GetNextOutput(){
	if (ot_curExt==ot_Outputs.GetSize()){
		ot_curExt=0;
		return NULL;
	}
	return ot_Outputs.GetItem(ot_curExt++);
}


void OmegaTrack::Cancel(MsgPort *port,UINT effect){
	UINT size=ot_Outputs.GetSize();
	InputExtension *ext;
	
	for (UINT n=0;n<size;n++){
		ext=ot_Outputs.GetItem(n);
		if(ext->ie_MsgPort==port && ext->ie_EffectNo==effect){
			ot_Outputs.DeleteItem(n);
			break;
		}
	}
	if (ot_Outputs.GetSize()==0)
		ot_used=FALSE;
}	
	