package ws.prova;

/*
 * Copyright (C) 2002-2007 <a href="mailto:a.kozlenkov@city.ac.uk">Alex Kozlenkov</a>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

import org.mandarax.kernel.ComplexTerm;
import org.mandarax.kernel.ConstantTerm;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;

/**
 * Accumulator class used in Prova findall built-in predicate
 * <p>Title: Prova </p>
 * <p>Description: Accumulator class used in Prova findall built-in predicate</p>
 * <p>Copyright: Copyright (C) 2002-2007</p>
 * <p>Company: City University, London, United Kingdom</p>
 *
 * @author Alex Kozlenkov
 * @version 2.0 <25 March 2007>
 */

public class Accumulator extends ArrayList implements Serializable, IAccumulator {

	public Accumulator() {
		super();
	}

    public String toString() {
        return super.toString();
    }

    public Boolean accumulate(final Object[] r, final List bindings) {
        // This method returns no bindings
        Object arg = r[0];
        if (arg instanceof ConstantTerm) {
            ConstantTerm t = (ConstantTerm) arg;
            add(t.getObject());
        } else if (arg instanceof ComplexTerm) {
            ComplexTerm ct = (ComplexTerm) arg;
            Object first = ct.getTerms()[1];
            if (first instanceof ConstantTerm) {
                try {
                    String constructor = ((ConstantTerm) first).getObject().toString();
                    Class cl = Class.forName(constructor);
                    // It is indeed a class (constructor) name
                    List list = new ArrayList();
                    RListUtils.rlist2List((ComplexTerm) ct.getTerms()[0], list, 0);
                    int arity = list.size();
                    Object[] dat = new Object[arity];
                    Class[] par = new Class[arity];
                    int i = 0;
                    for (ListIterator li = list.listIterator(); li.hasNext(); i++) {
                        Object o = li.next();
                        dat[i] = o;
                        par[i] = o.getClass();
                        if (par[i] == Double.class) {
                            par[i] = double.class;
                        } else if (par[i] == Boolean.class) {
                            par[i] = boolean.class;
                        } else if (par[i] == Integer.class) {
                            par[i] = int.class;
                        } else if (o instanceof List) {
                            par[i] = List.class;
                        } else if (o instanceof ComplexTerm) {
                            par[i] = Object.class;
                        }
                    }
                    Object target = null;
                    Object o = cl.getConstructor(par).newInstance(dat);
                    add(o);
                    return Boolean.FALSE;
                } catch (Exception ex) {
                }
            }
            add(arg);
        } else {
            add(arg);
        }
        return Boolean.FALSE;
    }

	public Boolean unwrap(final Object[] r, final List bindings) {
		// Just ignore the input, Resolve in the inference engine takes care of selecting the results properly
		Object[] retobj = null;
		for (ListIterator li = listIterator(); li.hasNext();) {
			// Note that we need a new array for each result in this Accumulator
			retobj = new Object[1];
			retobj[0] = li.next();
			bindings.add(retobj);
		}
		return Boolean.TRUE;
	}

	public List data() {
		return this;
	}

//	/**
//	 * Convert Accumulator to List.
//	 * This method assumes that Accumulator contains lists of something.
//	 *
//	 * @param r
//	 * @param bindings
//	 * @return
//	 */
//	public Boolean toList(final Object[] r, final List bindings) {
//		Object[] retobj = new Object[1];
//		List data = data();
//		List list = new ArrayList();
//		for( ListIterator li = data.listIterator(); li.hasNext(); ) {
//			List sublist = new ArrayList();
//			RListUtils.rlist2List((ComplexTerm) li.next(), sublist, 0);
//			Object[] objs = new Object[sublist.size()];
//			int n = 0;
//			for( ListIterator lisub = sublist.listIterator(); lisub.hasNext(); ) {
//				objs[n++] = lisub.next();
//			}
//			list.add(objs);
//		}
//		retobj[0] = this.toArray();
//		bindings.add(retobj);
//		return Boolean.TRUE;
//	}

//	public Object[] toList() {
//		return this.toArray();
//	}
}
