// List.java by David Binger <binger@centre.edu>

// Copyright (C) 1997 David Binger

// 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., 59 Temple Place - Suite 330, 

// Boston, MA  02111-1307, USA.



// Version 2.1







import java.io.*;



// A List is like a java.utils.Vector, except

// that the array of elements is available as

// a public variable.

// A list also has methods that support

// reading parenthesized lists of numbers and words 

// from an input stream.



public class List

implements Serializable {



  public Object[] elements = new Object[3];

  

  public int length = 0;

  

  public List() {

    super();

  }

  

  public final boolean contains(Object s) {

    for (int j=0;j<length;j++) {

      if (s.equals(elements[j])) return true;

    }

    return false;

  }

  

  public final int count(Object s) {

    int n = 0;

    for (int j=0;j<length;j++) {

      if (s.equals(elements[j])) n++;

    }

    return n;

  }

  

  public static Object nextToken(StreamTokenizer st) {

    try { st.nextToken(); }

    catch (Exception e) { System.err.println(e); return null; }

    switch(st.ttype) {

      case StreamTokenizer.TT_NUMBER:

	if (((long)st.nval-st.nval)==0) 

	  return new Long((long)st.nval);

	else return new Double(st.nval);

      case StreamTokenizer.TT_WORD:

	return st.sval;

      default: return new Integer(st.ttype);

    }

  }

  

  public static List delimitedList(StreamTokenizer s) {

    // Assume first '(' has been seen.

    List result = new List();

    while (true) {

      Object obj = nextToken(s);

      if ((obj instanceof Long) || 

	  (obj instanceof Double) ||    

	  (obj instanceof String))    

	result.push(obj);

      else { // obj is an Integer.

	int c = ((Integer)obj).intValue();

	if (c=='(') {

	  result.push(delimitedList(s));

	} else break;

      }

    }

    return result;

  }

  

  public final Object get(Object key) {

    for (int j=0;j<(length-1);j+=2) {

      if (key.equals(elements[j])) 

	return elements[j+1];

    }

    return null;

  }

  public final Object get(int index)
  {
    if (index < length)
      return elements[index];
    return null;
  }

  public final void put(Object key,Object val) {

    for (int j=0;j<(length-1);j+=2) {

      if (key.equals(elements[j])) 

	elements[j+1] = val;

      return;

    }

    push(key);

    push(val);

  }

  

  public List(InputStream s) {

    StreamTokenizer st = new StreamTokenizer(new InputStreamReader(s));

    st.parseNumbers();

    st.commentChar('#');

    st.commentChar(';');

    st.ordinaryChar('(');

    st.ordinaryChar(')');

    st.quoteChar('"');

    List x = delimitedList(st);

    length = x.length;

    elements = x.elements;

  }

  

  public final void expandFor(int n) {

    if ((elements.length-length)<n) {

      Object[] old = elements;

      elements = new Object[1+old.length*3/2];

      System.arraycopy(old,0,elements,0,old.length);

    }

  }

  

  public final void push(Object x) {

    expandFor(1);

    elements[length++]=x;

  }

  

  public final void push(double x) {

    push(new Double(x));

  }

  

  public final void push(long x) {

    push(new Long(x));

  }

  

  public final void push(char x) {

    push(new Character(x));

  }

  

  public final Object pop() {

    return elements[length--];

  }

  

  public final int indexOf(Object s) {

    for (int j=0;j<length;j++) {

      if (s.equals(elements[j])) return j;

    }

    return -1;

  }

  

  public final void delete(Object s) {
    int k = indexOf(s);
    if (k!=-1) {
      for (int j=k+1;j<length;j++)
	      elements[j-1] = elements[j];
      length--;
    }
  }

  public final Object delete(int index) {
    Object obj = elements[index];
    if (index!=-1) {
      for (int j=index+1;j<length;j++)
	      elements[j-1] = elements[j];
      length--;
    }
    return obj;
  }

  public final void append(Object obj)
  {
    expandFor(1);
    elements[length++] = obj;
  }

  public final void insert(Object s,int pos) {

    expandFor(1);

    for (int j=length;j>pos;j--) {

      elements[j]=elements[j-1];

    }

    length++;

    elements[pos]=s;

  }

  

  public final void append(List b) {

    expandFor(b.length);

    System.arraycopy(b.elements,0,elements,length,b.length);

  }

  

  public final void reverse() {

    Object tmp;

    for (int j=0;j<length/2;j++) {

      tmp = elements[j];

      elements[j]=elements[length-j-1];

      elements[length-j-1]=tmp;

    }

  }

  

  public final Object at(int n) {

    return elements[n];

  }

  

  public String toString() {

    String s = "";

    for (int j=0;j<length;j++) {

	//   s += "\n"+j+": ";

	s+="\n";

      s += String.valueOf(elements[j]);

    }

    s = "(List" + s + "\n)";

    return s;

  }

  

  public List (List x) {

    for (int j=0;j<x.length;j++) 

      push(x.elements[j]);

  }

  

  public List(double a,double b,double c) {

    push(a);

    push(b);

    push(c);

  }

  

  public List(double a,double b) {

    push(a);

    push(b);

  }

  

  public List(Object a,Object b) {

    push(a);

    push(b);

  }  

  

  public List(long a,long b,long c) {

    push(a);

    push(b);

    push(c);

  }

  

  public List(long a,long b) {

    push(a);

    push(b);

  }

  

  public final List sum(List p) {

    List result = new List();

    for (int j=0;j<length;j++) {

      Number a = (Number)elements[j];

      Number b = (Number)(p.elements[j]);

      if ((a instanceof Long) && (b instanceof Long)) {

	result.push(a.longValue()+b.longValue());

      } else {

	result.push(a.doubleValue()+b.doubleValue());

      }

    }

    return result;

  }

  

  public final List scalarProduct(double s) {

    List result = new List();

    for (int j=0;j<length;j++) {

      Number a = (Number)elements[j];

      result.push(a.doubleValue()*s);

    }

    return result;

  }

  

  public final int intX() {

    return ((Number)elements[0]).intValue();

  }

  

  public final int intY() {

    return ((Number)elements[1]).intValue();

  }

  

  public final double doubleX() {

    return ((Number)elements[0]).doubleValue();

  }

  

  public final double doubleY() {

    return ((Number)elements[1]).doubleValue();

  }

  

  public final List average(List p) {

    List result = new List();

    for (int j=0;j<length;j++) {

      Number a = (Number)elements[j];

      Number b = (Number)(p.elements[j]);

      result.push((a.doubleValue()*b.doubleValue())/2);

    }

    return result;

  }

  

  public final List scalarProduct(long s) {

    List result = new List();

    for (int j=0;j<length;j++) {

      Number a = (Number)elements[j];

      if (a instanceof Long) result.push(a.longValue()*s);

      else result.push(a.doubleValue()*s);

    }

    return result;

  }

  

  public final List product(List p) {

    List result = new List();

    for (int j=0;j<length;j++) {

      Number a = (Number)elements[j];

      Number b = (Number)(p.elements[j]);

      if ((a instanceof Long) && (b instanceof Long)) {

	result.push(a.longValue()*b.longValue());

      } else {

	result.push(a.doubleValue()*b.doubleValue());

      }

    }

    return result;

  }

  

  public final double distance(List b) {

    double sumSqrs = 0;

    for (int j=0;j<length;j++) {

      double av = ((Number)elements[j]).doubleValue();

      double bv = ((Number)(b.elements[j])).doubleValue();

      double d = av-bv;

      sumSqrs += d*d;

    }

    return Math.sqrt(sumSqrs);

  }

  

  public final double length() {

    double sumSqrs = 0;

    for (int j=0;j<length;j++) {

      double d = ((Number)elements[j]).doubleValue();

      sumSqrs += d*d;

    }

    return Math.sqrt(sumSqrs);

  }

  

  // Serializable

  private void writeObject(ObjectOutputStream out)

       throws IOException {

	 out.write(length);

	 out.writeObject(elements);

  }

  

  // Serializable

  private void readObject(ObjectInputStream in)

       throws IOException, ClassNotFoundException {

	 length = in.read();

	 elements = (Object[])in.readObject();

  }

  

  public static void main(String args[]) {

    List z = new List(System.in);

    System.out.println(z);

    for(int i=0;i<z.length;i++){

	System.out.println(z.elements[i].getClass().getName());

    }

  }

  

}


