// 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 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 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 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 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 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());
    }
  }
  
}
