import java.util.LinkedList;
import java.util.Iterator;

public class SMBoundedEnv extends SquareEnvironment
{
	
	private LinkedList[]rows;
	private int numberOfCols;
	
	public SMBoundedEnv(int nRows,int nCols)
	{
		super();
		numberOfCols=nCols;
		rows=new LinkedList[nRows];
		for(int index=0;index<rows.length;index++)
		   rows[index]=new LinkedList();
	}
	
	
	public int numRows()
	 {
	 	return rows.length;
	 }
	 
    public int numCols()
    {
    	return numberOfCols;
    }	 
    
    public int numObjects()
    {
    	int objectCount=0;
    	for(int index=0;index<rows.length;index++)
    	  objectCount+=rows[index].size();
    	  
    	return objectCount;  
    }
    
    public Locatable[]allObjects()
    {
    	Locatable[]theObjects=new Locatable[numObjects()];
    	int tempObjectCount=0;
    	//step thru all the rows
    	for(int index=0;index<rows.length;index++)
    	{
    		Iterator itr=rows[index].iterator();
    		while(itr.hasNext())
    		{
    			//put the next object in the array
    			theObjects[tempObjectCount]=(Locatable)itr.next();
    			tempObjectCount++;
    		}
    	}
    	
        return theObjects;	
    }
    
     public boolean isEmpty(Location loc)
    {
        return isValid(loc) && objectAt(loc) == null;
    }
    
     public boolean isValid(Location loc)
    {
        if ( loc == null )
            return false;

        return (0 <= loc.row() && loc.row() < numRows()) &&
               (0 <= loc.col() && loc.col() < numCols());
    }
    
	public Locatable objectAt(Location loc)
	{
		if(!isValid(loc))
		  return null;
		//step thru all the objects in the row for the location
		Iterator itr=rows[loc.row()].iterator();
		while(itr.hasNext())
		{
			Locatable obj=(Locatable)itr.next();
			if(obj.location().equals(loc))
			  {
			  	//found object return it
			  	return obj;
			  }
	  	}  
	  	return null;
	}
	
	
	 public void add(Locatable obj)
    {
        // Check precondition.  Location should be empty.
        Location loc = obj.location();
        if ( ! isEmpty(loc) )
            throw new IllegalArgumentException("Location " + loc +
                                    " is not a valid empty location");

        // Add object to the environment.
        rows[loc.row()].add(obj);
        
    }
    
     public void remove(Locatable obj)
    {
        // Make sure that the object is there to remove.
        Location loc = obj.location();
        if ( objectAt(loc) != obj )
            throw new IllegalArgumentException("Cannot remove " + 
                                               obj + "; not there");

        // Remove the object from the grid.
        rows[loc.row()].remove(obj);
    }
	
	public void recordMove(Locatable obj, Location oldLoc)
	{
		//no movement
		Location newLoc=obj.location();
		if(newLoc.equals(oldLoc))
		  return;
		  
		//verify that there wasn't already an object at new location
		
	   Iterator itr= rows[newLoc.row()].iterator();
	   while(itr.hasNext())
	   {
	   	Locatable current=(Locatable)itr.next();
	   	if(current.location().equals(newLoc) && current!=obj)
	   	 {
	   	 	   	  throw new IllegalArgumentException("Theres already"+
	   	        "an object ("+current+") at location "+newLoc);
	   	 }       
	   }  
	   
	   
	 //if object stayed within same row, no change made
	 //otherwise remove object and add it to the new row
	 
	 if(newLoc.row()!=oldLoc.row())
	 {
	     rows[oldLoc.row()].remove(obj);
	     add(obj);
	   
	}
	}
	
}

