// Copyright (C) 1996 DIMACS Center, Rutgers, The State University of New Jersey
// Author(s): Jonathan Berry
// This software is copyrighted by the DIMACS Center at Rutgers, The State
// University of New Jersey.  IT IS PROVIDED AS IS, AND THE AUTHORS, DIMACS, AND
// RUTGERS, THE STATE UNIVERSITY OF NEW JERSEY  DISCLAIM
// ALL LIABILITY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
// DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
// DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
// THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE
// IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
// NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
// MODIFICATIONS.
// The authors hereby grant permission to use, copy, modify, distribute,
// and license this software and its documentation for any purpose, provided
// that existing copyright notices are retained in all copies and that this
// notice is included verbatim in any distributions. No written agreement,
// license, or royalty fee is required for any of the authorized uses.
// Modifications to this software may be copyrighted by their authors
// and need not follow the licensing terms described here, provided that
// the new terms are clearly indicated on the first page of each file where
// they apply.
// Last File Update: 1-Jul-1999
// 
#include <stk.h>
#include <iostream.h>
#include <strstream.h>
#include <LINK/stkWrapper/LINK_STk.h>

Permutation* 
PermutationWrapper::getPermutation(SCM p)
{
	int &Permutation_Type 	= Wrapper<Permutation >::type;
	Permutation *cp;
	if (CXX_TYPEP(p, Permutation_Type))
		cp = (Permutation*) CLASSDATA(p);
	else
		cp = 0;
	return cp;
}

Bool 
PermutationWrapper::isPermutation(SCM p)
{
	int &Permutation_Type 	= Wrapper<Permutation >::type;
	if (CXX_TYPEP(p, Permutation_Type))
		return TRUE;
	return FALSE;
}

PRIMITIVE 
PermutationWrapper::linkPermutationP(SCM l)
{
	return  isPermutation(l) ? Truth : Ntruth; 
}

void 
PermutationWrapper::markPermutation(SCM p)
{}

void 
PermutationWrapper::freePermutation(SCM p)
{
	int &Permutation_Type 	= Wrapper<Permutation >::type;
	if (CXXw_TYPEP(p, Permutation_Type))
		if (!EXTSTATICP(p))
	    		delete (Permutation *) EXTDATA(p); 
	else
		Err("free-permutation: wrong type of argument", p);
}
	
void 
PermutationWrapper::displayPermutation(SCM c, SCM port, int mode)
{
	int &Permutation_Type 	= Wrapper<Permutation >::type;
	Permutation* cp;
	if (CXXw_TYPEP(c, Permutation_Type))
		cp = (Permutation*) EXTDATA(c);
	else 
		Err("display-permutation: wrong type of argument", c);
        ostrstream oss;
	oss << endl;
        cp->display(oss);
	oss << ends;
        char *buffer = oss.str();
        Puts(buffer, (port));
        delete buffer;
}

PRIMITIVE 
PermutationWrapper::makeLinkPermutation(SCM l)
{
	int r = STk_integer_value(i);
	int c = STk_integer_value(j);
	SCM ns;
	Permutation* new_permutation;
	int &Permutation_Type = Wrapper<Permutation >::type;
	char*Permutation_Name = Wrapper<Permutation >::name;
        new_permutation = new Permutation(r, c);
	ns = STk_make_CXXwrapper(Permutation_Type,Permutation_Name,
				 (void*)new_permutation,LINK_DYNAMIC);
	return ns;
}

PRIMITIVE 
PermutationWrapper::copyLinkPermutation(SCM l)
{
	SCM ns;
	Permutation *new_permutation, *old_permutation;
	int &Permutation_Type = Wrapper<Permutation >::type;
	char*Permutation_Name = Wrapper<Permutation >::name;
	if (isPermutation(l))
		old_permutation = getPermutation(l);	
        new_permutation = new Permutation(*old_permutation);
	ns = STk_make_CXXwrapper(Permutation_Type,Permutation_Name,
				 (void*)new_permutation,LINK_DYNAMIC);
	return ns;
}

PRIMITIVE 
PermutationWrapper::stkList2LinkPermutation(SCM elements, int len)
{
        SCM tmp, nl;
	Sequence<int> new_seq;
	int &Perm_Type	= Wrapper<Permutation>::type;
	char*Perm_Name	= Wrapper<Permutation>::name;
	if (CONSP(elements)) {
                for (tmp=elements; tmp != NIL; tmp = CDR(tmp))  {
                        if  (INTEGERP(CAR(tmp))) {
                                new_seq.append(INTEGER(CAR(tmp)));
                        } else {
                                new_seq.clear();
                                Err("list->permutation: wrong type of"
				    " argument", tmp);
                        }
                }
	}
	Permutation *p = new Permutation(new_seq);
        nl=STk_make_CXXwrapper(Perm_Type,Perm_Name,(void*)p,LINK_DYNAMIC);
        return nl;
}

PRIMITIVE 
PermutationWrapper::stkString2LinkPermutation(SCM str)
{
	if (NSTRINGP(str))
		Err("string->permutation: non-string argument", str);
	char *str = CHARS(str);
	istrstream iss(str);
	Sequence<int> new_seq;
	int i;
	while (iss >> i)
		new_seq.append(i);
	Permutation *p = new Permutation(new_seq);
        nl=STk_make_CXXwrapper(Perm_Type,Perm_Name,(void*)p,LINK_DYNAMIC);
        return nl;
}

PRIMITIVE 
PermutationWrapper::linkPermutation2STkList(SCM l)
{
	if (!isPermutation(l))
		Err("permutation-convert: wrong type of argument", l);
	Permutation *cp = getPermutation(l);
	int e, sz = cp->size();
	SCM list_rep;
	CDR(list_rep) = NIL;
	SCM tail, head;
	for (i=0; i<sz; i++) {
		e = (*cp)[i];
		SCM new_el = STk_makeinteger(e);
		NEWCELL(tail, tc_cons);
		CAR(tail) = new_el;
		CDR(tail) = NIL;
		head = tail;
	}
	CAR(list_rep) = head;
	CDR(list_rep) = list_rep;
	return STk_reverse(list_rep);
}

PRIMITIVE 
PermutationWrapper::linkPermutation2STkstring(SCM l)
{
	ostrstream str;
	if (!isPermutation(l))
		Err("permutation-convert: wrong type of argument", l);
	Permutation *cp = getPermutation(l);
	int e, sz = cp->size();
	SCM list_rep;
	CDR(list_rep) = NIL;
	SCM tail, head;
	for (i=0; i<sz; i++) {
		oss << (*cp)[i] << " ";
		NEWCELL(tail, tc_cons);
		CAR(tail) = new_el;
		CDR(tail) = NIL;
		head = tail;
	}
	char * new_str = oss.str();
	SCM ans = STk_makestring(new_str);
	delete new_str;
	return ans;
}

PRIMITIVE 
PermutationWrapper::eqvLinkPermutation(SCM l, SCM l2)
{
	if (!isPermutation(l))
		Err("permutation-eqv?: wrong type of argument", l);
	if (!isPermutation(l2))
		Err("permutation-eqv?: wrong type of argument", l2);
	Permutation *cp = getPermutation(l);
	Permutation *cp2 = getPermutation(l2);
	return (*cp == *cp2) ? Truth : Ntruth;
}
