package navale;

import java.io.Serializable;
import java.util.LinkedList;

//implements Serializable pour Exercice 6
public class Plateau implements Serializable{
	private static final long serialVersionUID = 1L;
	//Attributs toujours privés
	private int m;
	private int n;
	private LinkedList<Bateau> presents;

	public Plateau(int m, int n) {
		this.m = m;
		this.n = n;
		presents = new LinkedList<Bateau>();
	}
	
	/*
	 * On ne stocke pas le plateau par un tableau; pour chaque case, il suffit
	 * de demander à chaque bateau présent s'il occupe la case.
	 */	
	public Bateau quelBateau(int x, int y){
		for(Bateau b : presents)
			if(b.estPresent(x, y))
				return b;
		return null;
	}
	
	/*
	 * Pour ajouter un sous-marin, il faut que la case correspondante soit vide
	 * et dans les limites du plateau
	 */
	public boolean ajouteBateau(SousMarin b){
		int x=b.getX(), y=b.getY();
		if(x>=0 && x<m && y>=0 && y<n && quelBateau(x, y)==null){
			presents.add(b);
			return true;
		}
		return false;
	}

	/*
	 * Pour ajouter un croiseur, il faut que les 3 cases correspondantes soient vides
	 * et dans les limites du plateau
	 */
	public boolean ajouteBateau(Croiseur b){
		int x=b.getX(), y=b.getY();
		int dx=0,dy=0;
		if(b.estHorizontal())
			dx=1;
		else
			dy=1;
		//Le croiseur occupe les cases (x-dx,y-dy), (x,y) et (x+dx,y+dy)
		//Est-on dans les limites ?
		if(x-dx<0 || x+dx>=m || y-dy<0 || y+dy>=n)
			return false;
		//Les cases sont-elles vides ?		
		for(int i=-1; i<=1; i++)
			if(quelBateau(x+i*dx, y+i*dy)!=null)
				return false;
		//Tout est ok
		presents.add(b);
		return true;
	}
	
	public int coup(int x, int y){
		int val=0;
		Bateau b = quelBateau(x, y);
		//pas de bateau ou sous-marin en plonge
		if(b==null || !b.coup(x, y))
			return val;
		//A ce point, 	b.coup(x, y) a reussi, donc le bateau b a été touché
		//Est-il coulé ?
		if(b.estCoule()){
			presents.remove(b);
			if(b instanceof SousMarin)
				val = 3;
			else
				val = 2;
			//S'il ne reste qu'un bateau et que c'est un sous-marin, il fait surface
			if(presents.size()==1){
				b=presents.element();
				if(b instanceof SousMarin)
					((SousMarin)b).surface();
			}
			return val;
		}
		//A ce point, le bateau est touché, mais pas coulé
		return 1;
	}
		
	public boolean deplace(Croiseur b, int d){
		//Le bateau est-il sur le plateau ?
		if(!presents.contains(b))
			return false;
		int dx=0,dy=0;
		if(b.estHorizontal())
			dx=1;
		else
			dy=1;
		//Le croiseur occupe les cases (x-dx,y-dy), (x,y) et (x+dx,y+dy)
		//On se deplace d'un vecteur (d*dx, d*dy); la case d'arrivée est (xa,ya)
		int xa=b.getX()+d*dx;
		int ya=b.getY()+d*dy;
		//Le croiseur occupera les cases (xa-dx,ya-dy), (xa,ya) et (xa+dx,ya+dy)
		//Sont elles dans les limites ?
		if(xa-dx<0 || xa+dx>=m || ya-dy<0 || ya+dy>=n)
			return false;
		//la nouvelle case qui va etre occupee par le croiseur est-elle libre ?
		if(quelBateau(xa+dx*d,ya+dy*d)!=null)
				return false;
		return b.deplace(d);
	}
	
	public boolean deplace(SousMarin b, int dx, int dy){
		if(!presents.contains(b))
			return false;
		int xa=b.getX()+dx;
		int ya=b.getY()+dy;
		//Le sous-marin  occupera la case (xa,ya)
		//Est-elle dans les limites ?
		if(xa<0 || xa>=m || ya<0 || ya>=n)
			return false;
		//Est-elle vide ?
		if(quelBateau(xa,ya)!=null)
			return false;
		return b.deplace(dx, dy);
	}

	public boolean surface(SousMarin b){
		if(!presents.contains(b))
			return false;
		b.surface();
		return true;
	}
	
	public boolean plonge(SousMarin b){
		//Pour pouvoir plonger, il faut être présent sur le plateau et ne pas être seul
		if(!presents.contains(b) || presents.size()==1)
			return false;
		b.plonge();
		return true;		
	}

	public boolean estVide(){
		return presents.isEmpty();
	}
	
	//Non demandé dans le sujet
	//Permet d'afficher l'état du plateau
	public String toString(){
		StringBuffer buffer= new StringBuffer();
		for(int y=0;y<n;y++){
			for(int x=0;x<m;x++){
				Bateau b = quelBateau(x, y);
				if(b==null)
					buffer.append('-');
				else if(b instanceof Croiseur)
					buffer.append('X');
				else if(b instanceof SousMarin)
					if(((SousMarin)b).estVisible())
						buffer.append('O');
					else
						buffer.append('~');
				buffer.append(' ');
			}
			buffer.append('\n');
		}
		return buffer.toString();
	}

}
