/* maximum.c -- output the maximum of a group of numbers ------- */
// Japanese comments by Masayuki Akamatsu

// ヘッダの読み込み
#include "ext.h"	// 【必須】

// 定数宣言
#define MAXSIZE 256

// オブジェクト構造体（インスタンス変数）の宣言
typedef struct _maximum
{
	struct object m_ob;		// インスタンスの基本部分【必須】
	t_atom m_args[MAXSIZE];	// 以下は任意
	long m_count;
	short m_incount;
	short m_outtype;
	void *m_out;		// アウトレットへのポインタ
} t_maximum;

// グローバル変数（クラス変数）の宣言
void *maximum_class;	// オブジェクトクラスへのポインタ【必須】

// 関数プロトタイプ宣言
void maximum_compare(t_atom *max, t_atom *newone);
void maximum_bang(t_maximum *x);
void maximum_int(t_maximum *x, long n);
void maximum_in1(t_maximum *x, long n);
void maximum_float(t_maximum *x, double f);
void maximum_ft1(t_maximum *x, double f);
void maximum_list(t_maximum *x, t_symbol *s, short ac, t_atom *av);
void maximum_assist(t_maximum *x, void *b, long m, long a, char *s);
void *maximum_new(t_symbol *s, short ac, t_atom *av);

// メイン関数【必須】
// Max起動時などオブジェクトファイル読み込み時に呼び出される
// クラスとして必要な初期化などの設定を行う
void main()
{
	// クラスの設定【必須】
	setup((t_messlist **)&maximum_class, (method)maximum_new,0L, (short)sizeof(t_maximum), 0L, A_GIMME, 0);
	// &maximum_class　クラスへのポインタへのポインタ、Maxがクラスを生成する
	// maximum_new　newメッセージ処理関数（オブジェクト生成関数）を指定
	// 0L　freeメッセージ処理関数（オブジェクト消滅関数）を指定〜ここでは必要ないので指定していない
	// sizeof(t_maximum)　オブジェクト構造体のサイズを指定
	// 0L　メニュー処理関数を指定〜ここでは使用しないので指定していない
	// A_GIMME　アーギュメントのデータタイプを指定、A_GIMMEは任意のアーギュメントを受け入れる指定
	// 0　アーギュメントのデータタイプの指定の終わり
	
	// メッセージ処理関数の登録〜対応するメッセージに応じて登録【ほぼ必須】
	addbang((method)maximum_bang);
	addint((method)maximum_int);
	addinx((method)maximum_in1,1);
	addfloat((method)maximum_float);
	addftx((method)maximum_ft1,1);
	addmess((method)maximum_list,"list",A_GIMME,0);
	addmess((method)maximum_assist,"assist",A_CANT,0);
	
	// オブジェクトリストへの登録
	finder_addclass("Arith/Logic/Bitwise","maximum");
	
	// 使用するリソースのコピー
	rescopy('STR#',3007);
}

// 特定処理（サブルーチン）関数...という名前があるわけではないが...
// 引数のmaxとnewoneを比べてより大きな数値をmaxに代入する
void maximum_compare(t_atom *max, t_atom *newone)
{
	if (max->a_type==A_NOTHING) {
		*max = *newone;
		return;
	}
	if (max->a_type==A_FLOAT) {
		if (newone->a_type==A_FLOAT) {
			if (newone->a_w.w_float > max->a_w.w_float)
				max->a_w.w_float = newone->a_w.w_float;
		} else {
			if ((float)newone->a_w.w_long > max->a_w.w_float)
				max->a_w.w_float = (float)newone->a_w.w_long;
		}
	} else {
		if (newone->a_type==A_LONG) {
			if (newone->a_w.w_long > max->a_w.w_long)
				max->a_w.w_long = newone->a_w.w_long;
		} else {
			if ((long)newone->a_w.w_float > max->a_w.w_long)
				max->a_w.w_long = (long)newone->a_w.w_float;
		}
	}
}

// 以下は、メッセージ処理関数【ほぼ必須】
// main()で登録したメッセージ処理関数はすべて必要
// オブジェクトにメッセージが送られた時に対応する関数が呼び出される

// bangメッセージ処理関数
// インスタンス変数のt_atom配列m_args、有効要素数m_countから最大値を探して出力する
void maximum_bang(t_maximum *x)
{
	short i;
	t_atom theMax;
	long res;
	double fres;
	
	theMax.a_type = A_NOTHING;
	for (i=0; i < x->m_count; i++)
		maximum_compare(&theMax,x->m_args+i);
	if (x->m_outtype==A_LONG) {
		if (theMax.a_type==A_LONG)
			res = theMax.a_w.w_long;
		else
			res = (long)theMax.a_w.w_float;
		outlet_int(x->m_out,res);		// 整数を出力
	} else {
		if (theMax.a_type==A_FLOAT)
			fres = theMax.a_w.w_float;
		else
			fres = (float)theMax.a_w.w_long;
		outlet_float(x->m_out,fres);	// 実数を出力
	}
}

// 整数メッセージ処理関数
void maximum_int(t_maximum *x, long n)
{
	SETLONG(x->m_args,n);
	maximum_bang(x);
}

// 第2インレットへの整数メッセージ処理関数
void maximum_in1(t_maximum *x, long n)
{
	SETLONG(x->m_args+1,n);
	x->m_count = 2;
}

// 実数メッセージ処理関数
void maximum_float(t_maximum *x, double f)
{
	SETFLOAT(x->m_args,f);
	maximum_bang(x);
}

// 第2インレットへの実数メッセージ処理関数
void maximum_ft1(t_maximum *x, double f)
{
	SETFLOAT(x->m_args+1,f);
	x->m_count = 2;
}

// リストメッセージ処理関数
void maximum_list(t_maximum *x, t_symbol *s, short ac, t_atom *av)
{
	short i;
	
	if (ac > MAXSIZE)
		ac = MAXSIZE;
	for (i=0; i < ac; i++,av++) {
		if (av->a_type==A_LONG)
			SETLONG(x->m_args+i,av->a_w.w_long);
		else if (av->a_type==A_FLOAT)
			SETFLOAT(x->m_args+i,av->a_w.w_float);
	}
	x->m_count = ac;
	maximum_bang(x);
}

// assistメッセージ処理関数
void maximum_assist(t_maximum *x, void *b, long m, long a, char *s)
{
	// STR#リソースを使ってアシスタンスを表示
	assist_string(3007,m,a,1,3,s);
}

// newメッセージ処理関数【必須】
// オブジェクト生成時に呼び出される
// インスタンスとして必要な初期化などの設定を行う
void *maximum_new(t_symbol *s, short ac, t_atom *av)
{
	t_maximum *x;	// オブジェクト（インスタンス）へのポインタ〜必須
	
	// オブジェクトを生成【必須】
	x = (t_maximum *)newobject(maximum_class);
	
	x->m_count = 2;
	
	if (ac) {	// アーギュメントが指定されていれば...
		x->m_args[1] = *av;
		if (av->a_type==A_LONG) {	// アーギュメントが整数なら...
			x->m_args[0].a_type = x->m_outtype = A_LONG;
			x->m_out = intout(x);	// 整数のアウトレットを作成
			x->m_args[0].a_w.w_long = 0;
			intin(x,1);				// 整数の第2インレットを作成
		} else if (av->a_type==A_FLOAT) {	// アーギュメントが実数なら...
			x->m_args[0].a_type = x->m_outtype = A_FLOAT;
			x->m_out = floatout(x);	// 実数のアウトレットを生成
			x->m_args[0].a_w.w_float = 0;
			floatin(x,1);			// 実数の第2インレットを作成
		}
	} else {	// アーギュメントが指定されていなければ...
		x->m_outtype = A_LONG;
		intin(x,1);					// 整数の第2インレットを作成
		x->m_out = intout(x);		// 整数のアウトレットを作成
		SETLONG(x->m_args+1,0L);
		SETLONG(x->m_args,0L);
	}
	
	return x;	// 生成したオブジェクトへのポインタを返す【必須】
}


