// Map.java
// $Id: Map.java,v 1.7 1996/08/18 19:18:26 anto Exp $
// (c) COPYRIGHT MIT and INRIA, 1996.
// Please first read the full copyright statement in file COPYRIGHT.html


package w3c.jigsaw.map;

import java.util.*;
import java.io.*;

/** Internal representation of a map */
class Map {
    private static final int HAS_DEFAULT = 1 << 0  ;
    private static final int HAS_NOSEARCH = 1 << 1  ;

    
    private DefaultMapEntry defaultEntry;
    private NoSearchMapEntry noSearchEntry;
    private Vector nearestPointEntries;
    private Vector entries;

    /** Parses itself from the map file stream
     *  @param in the DataInputStream to read from */
    public Map(DataInputStream in,boolean useNCSA)
	throws MapException, IOException
    {
	String line;
	MapEntry me;

	try {
	    defaultEntry = null;
	    noSearchEntry = null;
	    entries = new Vector(5);
	    nearestPointEntries = null;

	    while(true) {
		line = in.readLine();
		if(line == null) break;

		// Skip comments and empty lines.
		line = line.trim();
		if(line.equals("") || line.charAt(0)=='#')
		    continue;

		me = MapEntry.parse(line,useNCSA);

		if(me instanceof NoSearchMapEntry) {
		    noSearchEntry = (NoSearchMapEntry) me;
		} else if(me instanceof DefaultMapEntry) {
		    defaultEntry = (DefaultMapEntry) me;
		} else if(me instanceof PointMapEntry) {
		    if(nearestPointEntries == null)
			nearestPointEntries = new Vector(5);
		    nearestPointEntries.addElement(me);
		} else {
		      entries.addElement(me);
		}
	    }

	} catch ( EOFException ex) {
	    // do nothing
	}

	if(defaultEntry==null && nearestPointEntries==null)
	    throw new MapException("no default mechanism defined");

	// Ignore default entry if nearest point entries exist
	if(nearestPointEntries != null)
	    defaultEntry = null;
    }
    
    public Map()
    {
	defaultEntry = null;
	nearestPointEntries = null;
	entries = null;
    }

    public void pickle(DataOutputStream out)
	throws IOException
    {
	int flags = 0 ;
	if(defaultEntry != null) flags |= HAS_DEFAULT ;
	if(noSearchEntry != null) flags |= HAS_NOSEARCH ;

	out.writeInt(flags) ;

	if((flags & HAS_DEFAULT) != 0) defaultEntry.pickle(out) ;
	if((flags & HAS_NOSEARCH) != 0) noSearchEntry.pickle(out) ;

	out.writeInt(entries.size()) ;
	for(int i = 0;i < entries.size();i++)
	    ((MapEntry)entries.elementAt(i)).pickle(out) ;

	if(nearestPointEntries != null) {
	    out.writeInt(nearestPointEntries.size()) ;
	    for(int i = 0;i < nearestPointEntries.size();i++)
		((MapEntry)nearestPointEntries.elementAt(i)).pickle(out) ;
	} else out.writeInt(0) ;
    }

    public void unpickle(DataInputStream in)
	throws IOException
    {
	int flags = in.readInt() ;
	if((flags & HAS_DEFAULT) != 0)
	    defaultEntry = (DefaultMapEntry) MapEntry.unpickle(in) ;
	else
	    defaultEntry = null ;

	if((flags & HAS_NOSEARCH) != 0)
	    noSearchEntry = (NoSearchMapEntry) MapEntry.unpickle(in) ;
	else
	    noSearchEntry = null ;

	int n = in.readInt() ;
	entries = new Vector(n) ;
	for(int i = 0;i < n;i++)
	    entries.addElement(MapEntry.unpickle(in)) ;

	n = in.readInt() ;
	if(n!=0) {
	    nearestPointEntries = new Vector(n) ;
	    for(int i = 0;i < n;i++)
		nearestPointEntries.addElement(MapEntry.unpickle(in)) ;
	} else nearestPointEntries = null ;
    }

    public String getDefaultURL()
    {
	if(defaultEntry==null) return null;
	else return defaultEntry.getURL();
    }

    public String getMatchingURL(Point p)
    {
	if(p==null) return noSearchEntry != null
			? noSearchEntry.getURL()
			: null ;
	for(int i=0;i<entries.size();i++) {
	    if( ((MapEntry)entries.elementAt(i)).matches(p))
		return ((MapEntry)entries.elementAt(i)).getURL();
	}

	// Nearest points override defaults:
	if(nearestPointEntries != null) {
	    int minDistanceSq = Integer.MAX_VALUE;
	    MapEntry minEntry = null;
	    for(int i=0;i<nearestPointEntries.size();i++) {
		PointMapEntry thisEntry =
		    (PointMapEntry)nearestPointEntries.elementAt(i);
		int thisDistanceSq=thisEntry.distanceSquared(p);

		if(thisDistanceSq<minDistanceSq) {
		    minDistanceSq = thisDistanceSq;
		    minEntry = thisEntry;
		}
	    }
	    return minEntry != null
		   ? minEntry.getURL()
		   : null;
	} else return getDefaultURL();
    }
		    
    /* For testing purposes: */
    public static void main(String args[])
	throws IOException
    {
	try {
	    if(args.length!=3) {
		System.out.println("You're a dork");
		return;
	    }
	    
	    int x = Integer.parseInt(args[1]);
	    int y = Integer.parseInt(args[2]);
	    
	    Point p = new Point(x,y);

	    DataInputStream dis =
		new DataInputStream(new FileInputStream(args[0]));
	    Map map = new Map(dis,true);
	    System.out.println(map.getMatchingURL(p));

	} catch (Exception e) {
	    e.printStackTrace();
	}
    }

    public String toString()
    {
	StringBuffer sb = new StringBuffer(160) ;
	sb.append("<d:"+defaultEntry+
	    ", ns:"+noSearchEntry+
	    ", np:[") ;
	if(nearestPointEntries==null) sb.append("none") ;
	else for(int i=0;i<nearestPointEntries.size();i++) 
	    sb.append(nearestPointEntries.elementAt(i)) ;
	sb.append("], e:[") ;
	if(entries==null) sb.append("none") ;
	else for(int i=0;i<entries.size();i++) 
	    sb.append(entries.elementAt(i)) ;
	sb.append("]>") ;
	return sb.toString() ;
    }
	
		
}








