/*
 *    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 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.
 *
 *    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., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

/*
 * Stack.java
 * Copyright (C) 2006 Alina Beygelzimer and Sham Kakade and John Langford
 */

package weka.core.neighboursearch.covertrees;

import weka.core.RevisionHandler;
import weka.core.RevisionUtils;

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

/**
 * Class implementing a stack.
 * 
 * @param <T> The type of elements to be stored in 
 * the stack.
 * @author Alina Beygelzimer (original C++ code)
 * @author Sham Kakade (original C++ code)
 * @author John Langford (original C++ code)
 * @author Ashraf M. Kibriya (amk14[at-the-rate]cs[dot]waikato[dot]ac[dot]nz) (Java port)
 * @version $Revision: 1.3 $
 */
public class Stack<T>
  implements Serializable, RevisionHandler {

  /** for serialization. */
  private static final long serialVersionUID = 5604056321825539264L;
  
  /** The number of elements in the stack. */
  public int length;

  /** The elements inside the stack. */
  public ArrayList<T> elements;
  
  /** Constructor. */
  public Stack() { 
    length=0; 
    elements = new ArrayList<T>();
  }

  /**
   * Constructor. 
   * @param capacity The initial capacity of the stack.
   */
  public Stack(int capacity) { 
    length=0; 
    elements = new ArrayList<T>(capacity);
  }
  
  /**
   * Returns the last element in the stack.
   * @return The last element.
   */
  public T last() { 
    return elements.get(length-1);
  }
  
  /**
   * Returns the ith element in the stack.
   * @param i The index of the element to return.
   * @return The ith element. 
   */
  public T element(int i) { 
    return elements.get(i);
  }
  
  /**
   * Sets the ith element in the stack. 
   * @param i The index at which the element is
   * to be inserted. 
   * @param e The element to insert. 
   */
  public void set(int i, T e) {
    elements.set(i, e);
  }
  
  /**
   * Returns a sublist of the elements in the 
   * stack. 
   * @param beginIdx The start index of the 
   * sublist. 
   * @param uptoLength The length of the 
   * sublist.
   * @return The sublist starting from 
   * beginIdx and of length uptoLength.
   */
  public List subList(int beginIdx, int uptoLength) {
    return elements.subList(beginIdx, uptoLength);
  }
  
  /** Removes all the elements from the stack. */
  public void clear() {
    elements.clear();
    length=0;
  }
  
  /** 
   * Adds all the given elements in the stack.
   * @param c The collection of elements to add
   * in the stack.
   */ 
  public void addAll(Collection c) {
    elements.addAll(c);
    length = c.size();
  }
  
  /**
   * Replace all elements in the stack with 
   * the elements of another given stack.
   * It first removes all the elements 
   * currently in the stack, and then adds all
   * the elements of the provided stack. 
   * @param s The stack whose elements should 
   * be put in this stack.
   */
  public void replaceAllBy(Stack<T> s) {
    elements.clear();
    elements.addAll(s.elements);
    length = elements.size();
  }
  
  /** 
   * Pops (removes) the first (last added) 
   * element in the stack.
   * @return The poped element. 
   */
  public T pop() {
    length--;
    return elements.remove(length);    
  }
  
  /**
   * Pushes the given element to the stack.
   * @param new_ele The element to be pushed
   * to the stack. 
   */
  public void push(T new_ele) {
    length++;
    elements.add(new_ele);
  }
  
  /**
   * Pushes the given element onto the given 
   * stack. 
   * @param v The stack onto push the element.
   * @param new_ele The element to push.
   */
  public void push(Stack<T> v, T new_ele) {
    length++; 
    v.elements.add(new_ele);
  }
  
  /**
   * Returns the revision string.
   * 
   * @return		the revision
   */
  public String getRevision() {
    return RevisionUtils.extract("$Revision: 1.3 $");
  }
}
