/*
 * matrix program copyright (C) 2009 H.Niwa
 */

/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.

 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301, USA.
 */

#include "config.h"

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include <errno.h>
#include <setjmp.h>
#include <sys/time.h>
#include <math.h>
#include <libgen.h>
#include <setjmp.h>

#include <string>
#include <complex>

#include "syserr.h"

#include "bin_node.h"
#include "gc.h"
#include "var.h"
#include "pred.h"
#include "context.h"
#include "unify.h"
#include "builtin.h"
#include "matrix.h"

extern void PushStack(Context* cx, Node* goals, Node* md, Node* env);
extern int PopStack(Context* cx, Node* &goals, Node* &md, Node* &env);

int DoMatrix(Context* cx, Node* goalscar, List* module);
int DoSetMatrix(Context* cx, Node* goalscar, List* module);
int DoGetMatrix(Context* cx, Node* goalscar, List* module);

int matrix_rowno(Context* cx, Node* goalscar, List* module);
int matrix_colno(Context* cx, Node* goalscar, List* module);
int matrix_equal(Context* cx, Node* goalscar, List* module);
int matrix_notequal(Context* cx, Node* goalscar, List* module);
int matrix_add(Context* cx, Node* goalscar, List* module);
int matrix_sub(Context* cx, Node* goalscar, List* module);
int matrix_mul(Context* cx, Node* goalscar, List* module);
int matrix_expr(Context* cx, Node* goalscar, List* module);
int matrix_mulscalar(Context* cx, Node* goalscar, List* module);
int matrix_divscalar(Context* cx, Node* goalscar, List* module);
int matrix_tra(Context* cx, Node* goalscar, List* module);
int matrix_inv(Context* cx, Node* goalscar, List* module);
int matrix_solve(Context* cx, Node* goalscar, List* module);
int matrix_det(Context* cx, Node* goalscar, List* module);
int matrix_norm(Context* cx, Node* goalscar, List* module);
int matrix_cofact(Context* cx, Node* goalscar, List* module);
int matrix_adj(Context* cx, Node* goalscar, List* module);
int matrix_issquare(Context* cx, Node* goalscar, List* module);
int matrix_issingular(Context* cx, Node* goalscar, List* module);
int matrix_isdiagonal(Context* cx, Node* goalscar, List* module);
int matrix_issymmetric(Context* cx, Node* goalscar, List* module);
int matrix_isnull(Context* cx, Node* goalscar, List* module);
int matrix_(Context* cx, Node* goalscar, List* module);

/* ---------------------------------------------------------------*/
int matrixmodule(Context* cx, Node* goalscar, Node* goalscdr, 
				Node* goals, List* module, int& r)
{
	Node* retn;
	int	rn;

	std::string	s;

	if (goalscar->Val()->Car()->kind() == ATOM) {
		((Atom*)(goalscar->Val()->Car()))->toString(s);

		if (s == "initmatrix") {
			r = DoMatrix(cx, goalscar, module);
			return 1;
		} else if (s == "setmatrix") {
			r = DoSetMatrix(cx, goalscar, module);
			return 1;
		} else if (s == "getmatrix") {
			r = DoGetMatrix(cx, goalscar, module);
			return 1;
		} else if (s == "rawno") {
			r = matrix_rowno(cx, goalscar, module);
			return 1;
		} else if (s == "colno") {
			r = matrix_colno(cx, goalscar, module);
			return 1;
		}
	}

	r = -1;
	syserr("The predicate that did not exist in the matrix module is used. \n");
	return 1;
}

int DoMatrix(Context* cx, Node* goalscar, List* module)
{
}

int DoSetMatrix(Context* cx, Node* goalscar, List* module)
{
}

int DoGetMatrix(Context* cx, Node* goalscar, List* module)
{
}

int matrix_rowno(Context* cx, Node* goalscar, List* module)
{
	if (ListLength(goalscar->Cdr()) != 1) {
		syserr("usage: <rowno VAR>\n");
		return 0;
	}

	Node* g    = goalscar->Cdr()->Val();
	Node* nvar = g->Car()->Val();

	if (nvar->kind() != UNDEF) {
		syserr("usage: <rowno VAR>\n");
		return 0;
	}

	long long rowno;

	Node* env = Nil->Cons(Nil);

	SetEnv(env, nvar);
	((Undef*)(nvar->Val()))->Set(mka(rowno));

	PushStack(cx, Nil, Nil, env);
	return 1;
}

int matrix_colno(Context* cx, Node* goalscar, List* module)
{
	if (ListLength(goalscar->Cdr()) != 1) {
		syserr("usage: <colno VAR>\n");
		return 0;
	}

	Node* g    = goalscar->Cdr()->Val();
	Node* nvar = g->Car()->Val();

	if (nvar->kind() != UNDEF) {
		syserr("usage: <colno VAR>\n");
		return 0;
	}

	long long colno;

	Node* env = Nil->Cons(Nil);

	SetEnv(env, nvar);
	((Undef*)(nvar->Val()))->Set(mka(colno));

	PushStack(cx, Nil, Nil, env);
	return 1;
}


