/**
 * 
 */
package com.anemoff.android.taquin.model;

import java.io.IOException;
import java.util.Observable;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.provider.MediaStore.Images;
import android.view.Display;
import android.view.WindowManager;

import com.anemoff.android.taquin.R;

/**
 * Une partie de jeu de taquin, avec son plateau, son score, et les méthodes qui
 * permettent de consulter/modifier l'état de la partie.
 * 
 * @author anemoff
 * 
 */
public class Game extends Observable {

	private Context context;

	/** Image du plateau de jeu. */
	private Bitmap fullImage;

	/** Le plateau de jeu du taquin. */
	private Board board;

	/** Nombre de déplacements faits par le joueur. */
	private int moves;
	
	/** Drapeau indiquant si la partie à commencé */
	private boolean started;

	/** Drapeau indiquant si la partie est terminée. */
	private boolean isGameOver;

	// Liste des identifiants des images dans res/drawable-hdpi
	private static int images[] = new int[] { R.drawable.android_01,
			R.drawable.android_02, R.drawable.android_03, R.drawable.android_04 };

	private int minPermut = 10;
	private int maxPermut = 20;

	public Game(Context context) {
		super();
		this.context = context;
		this.started = false;

		// Image aléatoire parmi celles dans res/drawable-hdpi
		int randomImageId = Util.getRandomBoundInt(0, images.length);
		fullImage = BitmapFactory.decodeResource(context.getResources(),
				images[randomImageId]);
	}

	// -------------------------------------------------------------------------
	// Getters/Setters

	public Bitmap getFullImage() {
		return fullImage;
	}

	public void setFullImage(Bitmap fullImage) {
		this.fullImage = fullImage;
	}

	public Board getBoard() {
		return board;
	}

	public void setBoard(Board board) {
		this.board = board;
	}

	public int getMoves() {
		return moves;
	}

	public void setMoves(int moves) {
		this.moves = moves;
	}

	public void incrementMoves() {
		this.moves++;
	}

	public boolean isGameOver() {
		return isGameOver;
	}

	public void setGameOver(boolean isGameOver) {
		this.isGameOver = isGameOver;
	}

	public boolean isStarted() {
		return started;
	}

	public void setStarted(boolean started) {
		this.started = started;
	}
	
	

	// -------------------------------------------------------------------------
	// Autres méthodes

	private final Bitmap loadImage(Uri uri) {
		try {
			Bitmap img = Images.Media.getBitmap(context.getContentResolver(),
					uri);

			Display display = ((WindowManager) context
					.getSystemService(Context.WINDOW_SERVICE))
					.getDefaultDisplay();
			int screenWidth = display.getWidth();
			int screenHeight = display.getHeight();

			int diffW = img.getWidth() - screenWidth;
			int diffH = img.getHeight() - screenHeight;

			if (diffW > diffH) {
				img = Bitmap.createScaledBitmap(img, screenWidth,
						img.getHeight(), true);
			} else {
				img = Bitmap.createScaledBitmap(img, img.getWidth(),
						screenHeight, true);
			}
			return img;

		} catch (IOException e) {
			// TODO
			return null;
		}
	}

	/**
	 * Créé un nouveau plateau de taquin avec la taille donnée (taille = nombre
	 * de colonnes ou de lignes).
	 * 
	 * @param size
	 *            Taille du plateau de taquin.
	 */
	public void createBoard(int size) {
		moves = 0;
		board = new Board(size, size, fullImage);
		System.out.println("# Board init state:\n" + board); // XXX
	}
	
	/**
	 * 
	 */
	public void start() {
		if (!started) {
			setStarted(true);
			// TODO paramétrable via config du jeu : choix de la case et difficulté
			// (nb permutations)
			board.setEmptyCell(false);
			board.shuffleCells2(minPermut, maxPermut);
			System.out.println("# Board shuffled:\n" + board); // XXX
		}
	}

	/**
	 * Déplace une case et actualise l'état de la partie.
	 * 
	 * @param index
	 *            Index de la case à déplacer.
	 * @return true si la case a été déplacé, false sinon.
	 * 
	 */
	public boolean moveCell(int index) {
		if (!isGameOver) {
			if (board.checkAndMoveCell(index)) {
				incrementMoves();
				checkGameOver();
				setChanged();
				notifyObservers();
				return true;
			}
		}
		return false;
	}

	/**
	 * Vérifie si la partie est finie : c'est à dire si toutes les cases se
	 * trouvent à la bonne position.
	 * 
	 */
	public void checkGameOver() {
		isGameOver = true;
		if (board != null) {
			for (int i = 0; i < board.getBoardSize() && isGameOver; i++) {
				if (!board.getCell(i).isAtTarget())
					isGameOver = false;
			}
		}
	}

	/**
	 * Mélange le plateau de jeu et reinitialise le compteur de déplacements.
	 */
	public void shuffleBoard() {
		setGameOver(false);
		setMoves(0);
		board.shuffleCells2(minPermut, maxPermut);
		setChanged();
		notifyObservers();
	}

	/**
	 * Change la taille du plateau.
	 * 
	 * @param newSize
	 *            Nouvelle taille (nb collones ou nb lignes)
	 */
	public void changeSize(int newSize) {
		setStarted(false);
		createBoard(newSize);
		setChanged();
		notifyObservers();
	}

}
