//***********************************************************
//*
//* File:           PlayerWrapper.java
//* Author:         Srikant Krishna
//* Contact:        srikant@cs.columbia.edu
//* Update:         10.16.2002
//*
//* Description:    Compositional wrapper for IFCPlayer
//*                 objects.
//*
//***********************************************************

package Rectangles;

import java.util.*;
import java.io.*;
import java.awt.Color;

public final class PlayerWrapper implements Serializable, IFCPlayer {

    double        _score;
	IFCPlayer     _player;
	Class         _class;
	Rectangles    _rect;
    ArrayList     _robots;
    ArrayList[]   _corners;
    HashMap[]     _map;

	PlayerWrapper(Class __class) throws Exception {
        int _MAX = _CORIENTATIONS.length;

        _class = __class;
        _robots = new ArrayList();
        _corners = new ArrayList[_MAX];
        _map = new HashMap[_MAX];
        for (int i=0; i < _MAX; i++) {
            _corners[i] = new ArrayList();
            _map[i] = new HashMap();
        }
	}
    
    private Robot[] register_priv(Rectangles __rect) throws Exception {
        try {
            int _MAX;
            int size;
            Robot[] RET;

            _rect = __rect;
            size = _rect.size();
            RET = _player.register(_rect);
            if (RET == null) {
				System.out.println("My Name is " + _player.name());
                throw new Exception("Player Error:  register():  Null Initial Robot Placement List Returned");
            }
            _MAX = RET.length;

            for (int i=0; i < _MAX; i++) {
                if (RET[i] == null) {
				System.out.println("My Name is " + _player.name());
                    throw new Exception("Player Error:  register():  Null Robot Returned In Initial Placement List");
                }
                if (RET[i].xpos() < 0 || RET[i].xpos() >= size || RET[i].ypos() < 0 || RET[i].ypos() >= size) {
				System.out.println("My Name is " + _player.name());
                    throw new Exception("Player Error:  register():  Invalid Initial Placement (Out Of Range) For Robot["+i+"]");
                }
                _robots.add(RET[i]);
            }
            return RET;
        } catch (Exception EXC) {
            System.out.println(EXC.getMessage());
            EXC.printStackTrace();
            return null;
        }
    }


	public Robot[] register(Rectangles __rect) throws Exception {
        _player = (IFCPlayer) _class.newInstance();
        return register_priv(__rect);

    }

    public Robot[] register(Rectangles __rect, IFCPlayer __player) throws Exception {
        _player = __player;
        _class = _player.getClass();
        return register_priv(__rect);
    }

	public String name() throws Exception {
        try {
	        return _player.name();
        } catch (Exception EXC) {
            throw new Exception("Player Error:  name()");
        }
    }

    public Color color() throws Exception {
        try {
            return _player.color();
        } catch (Exception EXC) {
            throw new Exception("Player Error:  color()");
        }
    }

    public Class playerClass() throws Exception {
        return _class;
    }

    public Robot[] robots() throws Exception {
        return (Robot[]) _robots.toArray(new Robot[0]);
    }

    public Robot robot(int __pos) throws Exception {
        return (Robot) _robots.get(__pos);
    }

    public Corner[][] corners() throws Exception {
        int _MAX = _CORIENTATIONS.length;
        Corner[][] RET = new Corner[_MAX][];

        for (int i=0; i < _MAX; i++) {
            RET[i] = (Corner[]) _corners[i].toArray(new Corner[0]);
        }
        return RET;
    }

    public void addCorner(Corner __corner) throws Exception {
        int pos = __corner.orientation();
        Integer iobj = (pos % 2 == 1) ? new Integer(__corner.xpos()) : new Integer(__corner.ypos());
        ArrayList list;

        _corners[pos].add(__corner);
        list = (ArrayList) _map[pos].get(iobj);
        if (list != null) {
            list.add(__corner);
        } else {
            list = new ArrayList();
            list.add(__corner);
            _map[pos].put(iobj, list);
        }
    }

    public void clearCorners() throws Exception {
        int _MAX = _CORIENTATIONS.length;

        for (int i=0; i < _MAX; i++) {
            _corners[i].clear();
            _map[i].clear();
        }
    }
    
    public void removeCorners(int __xpos, int __ypos) throws Exception {
        int _MAX = _CORIENTATIONS.length;
        int pos;
        Corner corner;
        ArrayList list;

        for (int i=0; i < _MAX; i++) {
            pos = 0;
            while (pos < _corners[i].size()) {
                corner = (Corner) _corners[i].get(pos);
                if (corner.xpos() == __xpos && corner.ypos() == __ypos) {
                    _corners[i].remove(pos);
                    continue;
                }
                pos++;
            }
            
            list = (ArrayList) _map[i].get(new Integer(__xpos));
            if (list == null) {
                continue;
            }
            for (int j=0; j < list.size(); j++) {
                if (((Corner) list.get(j)).ypos() == __ypos) {
                    list.remove(j);
                    j--;
                    continue;
                }
            }
        }
    }

    public int cornersSize(int __pos) throws Exception {
        return _corners[__pos].size();
    }

    public boolean containsCorner(Corner __corner) throws Exception {
        int pos = __corner.orientation();
        Integer iobj = (pos % 2 == 1) ? new Integer(__corner.xpos()) : new Integer(__corner.ypos());
        ArrayList list = (ArrayList) _map[pos].get(iobj);

        return (list == null) ? false : list.contains(__corner);
    }
    
    public Corner[] getCorners(int __orientation, int __pos) throws Exception {
        Corner[] RET;
        ArrayList list = (ArrayList) _map[__orientation].get(new Integer(__pos));

        if (list == null) {
            return null;
        } else {
            RET = (Corner[]) list.toArray(new Corner[0]);
        }
        return RET;
    }

    public void gameOver() throws Exception {
        try {
            if (_player instanceof IFCPersistentPlayer) {
                ((IFCPersistentPlayer) _player).gameOver();
            }
        } catch (Exception EXC) {
            throw new Exception("Player Error:  gameOver()");
        }
    }

    public char[] move() throws Exception {
        try {
            int _MAX = _rect.numRobots();
            int _MAXJ;
            char[] RET = _player.move();
            int pos;
            
            if (RET == null) {
				System.out.println("My Name is " + _player.name());
                throw new Exception("Player Error:  Null Move List For Player");
            }

            if (_MAX != RET.length) {
				System.out.println("My Name is " + _player.name());
                throw new Exception("Player Error:  Invalid Move List Length For Player");
            }

            _MAXJ = _CDIRECTIONS.length;
            for (int i=0; i < _MAX; i++) {
                for (pos = 0; pos< _MAXJ; pos++) {
                    if (RET[i] == _CDIRECTIONS[pos]) {
                        break;
                    }
                }
                if (pos == _MAXJ) {
				System.out.println("My Name is " + _player.name());
                    throw new Exception("Player Error:  Invalid Move For Robot["+i+"]: " + RET[pos]);
                }
            }
            return RET;

        } catch (Exception EXC) {
            System.out.println(EXC.getMessage());
            return null;
        }
    }

    public boolean interactive() throws Exception {
        try {
            return _player.interactive();
        } catch (Exception EXC) {
            throw new Exception("Player Error:  interactive()");
        }
    }

	public double score() {
	    return _score;
    }

    public void setScore(double __score) {
        _score = __score;
    }

    public IFCPlayer player() {
        return _player;
    }

    public String toString() {
	    try {
    		StringBuffer SB = new StringBuffer("[");

            SB.append(_player.name());
		    SB.append("]");
    		return new String(SB);
        } catch (Exception EXC) {
            return EXC.getMessage();
        }
	}
}
