// $Id: AbstractDynamicArgumentList.java,v 1.6 2004/02/27 16:30:00 m31 Exp $
//
// This file is part of the program suite "Principia Mathematica II"
// which is a working prototype for the main project:
// "Hilbert II" - http://www.qedeq.org
//
// Copyright 2001-2004  Michael Meyling <mime@qedeq.org>.
//
// "Principia Mathematica II" 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 of the License, 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.

package com.meyling.principia.argument;


import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;


/**
 * Every Operator with dynamic number of arguments must inherit from
 * this class.
 * Its main function is to
 * provide the standard implemention of {@link #equals}, {@link #matches}
 * and {@link #hashCode}.
 *
 * @version $Revision: 1.6 $
 * @author  Michael Meyling
 */
public abstract class AbstractDynamicArgumentList
        extends AbstractArgument implements Argument {

    /** here is are the arguments stored */
    private List arguments = null;


    /**
     * Constructs an argument list.
     *
     * @param  arguments the arguments to make a list of
     * @throws IllegalArgumentException if the argument was a
     *         nullpointer
     */
    public AbstractDynamicArgumentList(final Argument[] arguments) {
        if (arguments == null) {
            throw new IllegalArgumentException(
                ArgumentConstants.NULLPOINTER_PARAMETER);
        }
        this.arguments = new ArrayList(Arrays.asList(arguments));
    }


    /**
     * Adds an argument to end of dynamic list.
     *
     * @param   argument    argument to add
     * @throws  IllegalArgumentException    if the given
     *          argument was a nullpointer
     */
    public void add(final Argument argument) {
        if (argument == null) {
            throw new IllegalArgumentException(
                ArgumentConstants.NULLPOINTER_PARAMETER);
        }
        this.arguments.add(argument);
    }


    /**
     * Inserts an argument to spezified position.
     *
     * @param   position    position of argument to add
     * @param   argument    argument to add
     * @throws  IllegalArgumentException    if the given
     *          argument was a nullpointer or the position
     *          was not valid
     */
    public void insert(int position, final Argument argument) {
        if (argument == null) {
            throw new IllegalArgumentException(
                ArgumentConstants.NULLPOINTER_PARAMETER);
        }
        if (position >= 0 && position <= this.arguments.size()) {
            this.arguments.add(position, argument);
        } else {
            throw new IllegalArgumentException(
                ArgumentConstants.WRONG_ARGUMENT_NUMBER + "{0"
                + (this.arguments.size() > 0 ? ", .. "
                + this.arguments.size() : "")
                + "}");
        }
    }


    /**
     * Replaces an argument at spezified position.
     *
     * @param   position    position of argument to replace
     * @param   argument    replacement argument
     * @throws  IllegalArgumentException    if the given
     *          argument was a nullpointer or the position
     *          was not valid
     */
    public void replace(int position, final Argument argument) {
        if (argument == null) {
            throw new IllegalArgumentException(
                ArgumentConstants.NULLPOINTER_PARAMETER);
        }
        if (position >= 0 && position < this.arguments.size()) {
            this.arguments.set(position, argument);
        } else {
            throw new IllegalArgumentException(
                ArgumentConstants.WRONG_ARGUMENT_NUMBER + "{0"
                + (this.arguments.size() + 1 > 0 ? ", .. "
                + (this.arguments.size() - 1) : "")
                + "}");
        }
    }


    /**
     * Deletes an argument of dynamic list.
     *
     * @param   i    position of argument to delete
     * @throws  IllegalArgumentException    if the given
     *          position was not valid
     */
    public void remove(final int i) {
        if (i >= 0 && i < arguments.size()) {
            arguments.remove(i);
        } else {
            if (arguments.size() == 0)  {
                throw new IllegalArgumentException(
                    ArgumentConstants.NO_ARGUMENT_NUMBER);
            } else {
                throw new IllegalArgumentException(
                    ArgumentConstants.WRONG_ARGUMENT_NUMBER + "{0"
                    + (arguments.size() > 1 ? ", .. "
                    + (arguments.size() - 1) : "")
                    + "}");
            }
        }
    }


    /** @inherited */
    public final int getArgumentSize() {
        return arguments.size();
    };


    /** @inherited */
    public final Argument getArgument(final int i)
            throws IllegalArgumentException {
        if (i >= 0 && i < arguments.size()) {
            return (Argument) arguments.get(i);
        } else {
            if (arguments.size() == 0)  {
                throw new IllegalArgumentException(
                    ArgumentConstants.NO_ARGUMENT_NUMBER);
            } else {
                throw new IllegalArgumentException(
                    ArgumentConstants.WRONG_ARGUMENT_NUMBER + "{0"
                    + (arguments.size() > 1 ? ", .. "
                    + (arguments.size() - 1) : "")
                    + "}");
            }
        }
    }


    /** @inherited */
    public final Argument copy() {
        Argument[] copied = new Argument[arguments.size()];
        for (int i = 0; i < arguments.size(); i++) {
            copied[i] = ((Argument) arguments.get(i)).copy();
        }
        try {
            return ArgumentCreator.createArgument(this.getClass(), copied);
        } catch (ArgumentException e) { // should never occur
            throw new IllegalArgumentException(e.getMessage());
        }
    }


    /** @inherited */
    public abstract Argument create(final Argument[] arguments)
        throws ArgumentException;


    /** @inherited */
    public abstract String toString();



}
