package ola.jsame;

import java.util.*;

public class SameGameModel
{
    public static int INVALID = -1;
    private static int DEFAULT_RANGE = 6;
    private static int OFFSET = 2000;
    
    private int myRows;
    private int myCols;
    private int[][] myGrid;
    private ISameGameView myView;
    private int myRange;
    private ArrayList myList;
    private int       myLastMove;
    
    public SameGameModel(int rows, int cols)
    {
        this(rows,cols,DEFAULT_RANGE);
    }
    
    public SameGameModel(int rows, int cols, int range)
    {
        myRows = rows;
        myCols = cols;
        myRange = range;
        myGrid = new int[rows][cols];
        myList = new ArrayList();
        init();
    }

    private void init()
    {
        java.util.Random rando = new java.util.Random();
        for(int j=0; j < myRows; j++) {
            for(int k=0; k < myCols; k++) {
                int val = rando.nextInt(myRange);
                myGrid[j][k] = val;
            }
        }
    }

    private void flood(int row, int col, int match, ArrayList list)
    {
        if (0 <= row && row < getRows() && 0 <= col && col < getCols()){
            if (myGrid[row][col] == match){
                list.add(new GridPoint(row,col));
                myGrid[row][col] = myGrid[row][col] - OFFSET;                
                flood(row,col+1,match,list);
                flood(row,col-1,match,list);
                flood(row+1,col,match,list);
                flood(row-1,col,match,list);
            }
        }
    }

    
    public int getRows()
    {
        return myRows;
    }

    public int getCols()
    {
        return myCols;
    }

    private void shift(int col)
    {
        if (myGrid[myRows-1][col] == INVALID){
//	    Debug.println("col removal "+col);
            for(int r=0; r < myRows; r++){
                for(int c=col; c < myCols-1; c++){
                    myGrid[r][c] = myGrid[r][c+1];   
                }
                myGrid[r][myCols-1] = INVALID;
            }
        }
    }
    private void clearAll()
    {
        GridPoint[] array = (GridPoint[]) myList.toArray(new GridPoint[0]);
        myView.highlight(array);

        Collections.sort(myList);
        for(int k=0; k < myList.size(); k++){
            GridPoint p = (GridPoint) myList.get(k);

            for(int r = p.row; r > 0; r--){
                myGrid[r][p.col] = myGrid[r-1][p.col];
            }
            myGrid[0][p.col] = INVALID;
        }
        for(int col=myCols-2; col >= 0; col--){
            shift(col);
        }
        myView.showGrid(myGrid);        
        myList.clear();
    }

    private void clear(GridPoint[] array)
    {	
	for(int k=0; k < array.length; k++){
	    myGrid[array[k].row][array[k].col] += OFFSET;
	}	
    }
    private void clearOne()
    {
        GridPoint p = (GridPoint) myList.get(0);
	myGrid[p.row][p.col] += OFFSET;
	myList.clear();
    }
    
    public void reset()
    {
        GridPoint[] array = (GridPoint[]) myList.toArray(new GridPoint[0]); 
        myView.highlight(array);
	clear(array);
        myLastMove = -1;
    }

    private boolean inBlock(SameMove move)
    {
	int val = move.getValue();
	int row = val/myCols;
	int col = val%myCols;
	GridPoint gp = new GridPoint(row,col);
	return myList.contains(gp);
    }
    
    public void makeMove(SameMove move)
    {
	int val = move.getValue();
	int row = val/myCols;
	int col = val%myCols;
	if (myGrid[row][col] == INVALID){
	    return;
	}
	
        if (inBlock(move)){
            clearAll();
        }
        else {
            reset();
            myList.clear();
            val = move.getValue();
            myLastMove = val;
            row = val/myCols;
            col = val%myCols;
//            Debug.println("move at "+row+" "+col);
            flood(row,col,myGrid[row][col],myList);
            if (myList.size() > 1){
                GridPoint[] array = (GridPoint[]) myList.toArray(new GridPoint[0]);
                myView.highlight(array);                
            }
            else {
		clearOne();
            }
        }
    }

    public void addView(ISameGameView view)
    {
        myView = view;
        myView.showGrid(myGrid);
    }
}
