

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Timer;

import javax.swing.JOptionPane;
import javax.swing.JPanel;

import sun.audio.AudioPlayer;
import sun.audio.AudioStream;



public class MinePanel extends JPanel {
	public final int GRID_WIDTH = 20;
	public final int GRID_HEIGHT = 20;
	private MineFrame mf;
	private int cols;
	private int rows;
	private int mines;
	private int remainedMines;
	private int openedBlocks;
	private Block[][] blocks;
	
	UpdateTimeTask utt;

	public MinePanel(MineFrame mf, int rows, int cols, int mines) {
		this.mf = mf;
		initMinePanel(rows, cols, mines);
		this.addMouseListener(new MouseMonitor());
		this.setBackground(new Color(210,210,210));
	}
//
	/**
	 * ʼз飬
	 * @param rows   
	 * @param cols   
	 * @param mines  
	 */
	public void initMinePanel(int rows, int cols, int mines){
		this.cols = cols;
		this.rows = rows;
		this.mines = mines;
		remainedMines = mines;
		openedBlocks = 0;
		createBlocks();
		layMines();
		repaint();
	}
	/**
	 * blocksеĶͳʼΪ0״̬Ϊʼ״̬0
	 */
	private void createBlocks(){	
		blocks = new Block[rows][cols];
		for(int i=0; i<rows; i++){
			for(int j=0; j<cols; j++){
				blocks[i][j]= new Block(this,i,j,BlockType.ZERO,BlockState.ORIGINAL);
			}
		}		
	}
	/**
	 * ףʼףÿΧ
	 */
	private void layMines(){
		int r;
		int c;
		//ʼ
		for(int i=0; i<rows; i++){
			for(int j=0; j<cols; j++){
				blocks[i][j].setType(BlockType.ZERO);
				blocks[i][j].setState(BlockState.ORIGINAL);
			}
		}
		//
		int m = 0;
		while(m<mines){
			r = (int) (Math.random()*rows);
			c = (int) (Math.random()*cols);
			if(blocks[r][c].getType()!=BlockType.MINE){
				blocks[r][c].setType(BlockType.MINE);
				m++;
			}
		}
		//ÿblockΧ
		for(int i=0; i<rows; i++){
			for(int j=0; j<cols; j++){
				if(blocks[i][j].getType()!=BlockType.MINE){
					countMines(i,j);
				}
			}
		}
	}
	/**
	 * СΧ
	 * @param row    Ск
	 * @param col    Ск
	 */
	private void countMines(int row, int col){
		int mineNumber=0;  //blocks[i][j]Χ
		for(int i=row-1; i<=row+1;i++){ //blockΧ(У
			if( (i>=0)&&(i<rows) ){ //жûԽ磨±Խ磩
				for(int j=col-1; j<=col+1; j++){ //blockΧ(У
					if( (j>=0)&&(j<cols) ){  //жûԽ磨±Խ磩
						if(blocks[i][j].getType()==BlockType.MINE){ //
							mineNumber++;
						}
					}
				}
			}					
		}
		blocks[row][col].setType(mineNumber);
	}
	/** 
	 * дpaintʾз
	 */
	public void paint(Graphics g) {
		super.paint(g);
		for(int i=0; i<rows; i++){
			for(int j=0; j<cols; j++){
				blocks[i][j].draw(g);
			}
		}
	}
	/** 
	 * дgetPreferredSize
	 */
	public Dimension getPreferredSize() {
		return new Dimension(cols * GRID_WIDTH, rows*GRID_HEIGHT);
	}

	/**
	 * ָС
	 * @param row   Ск
	 * @param col   Ск
	 */
	public void open(int row, int col){
		//ֻԭʼ״̬ŴѾѱ
		if(blocks[row][col].getState()==BlockState.ORIGINAL){
			if(blocks[row][col].open()){
				openedBlocks++;
				if(openedBlocks == rows * cols -  mines){
					wins();
				}
				if(blocks[row][col].getType()==BlockType.ZERO){
					sound("wav/openblocks.wav");
					search(row, col);  //Χ׵ķ
				}						

			}else{
				lose(row,col); //ʧܴ
			}
		}
	}
	/**
	 * ΧΪ0СС鶼ڷĹУ
	 * ΧΪ0С飬ڵС鷭
	 * @param row   Ск
	 * @param col   Ск
	 */
	private void search(int row, int col){
		int i,j;
		//Χ
		for(i=row-1; i<=row+1; i++){ 
			if( (i<0) || (i>=rows) ){ //кųΧ
				continue;
			}
			for(j=col-1; j<=col+1; j++){
				if( (j<0)||(j>=cols) ){ //кųΧ
					continue;
				}
				if( blocks[i][j].getState()==BlockState.ORIGINAL ){
					//States.ZEROΧ϶û
					blocks[i][j].open();
					openedBlocks++;
					if(openedBlocks == rows * cols -  mines){
						wins();
					}
					if(blocks[i][j].getType()==BlockType.ZERO){
						search(i,j);  //ݹ
					}
				}
			}
		}
	}
	

	/**
	 * ȵ׺Ĵ
	 * @param row
	 * @param col
	 */
	public void lose(int row, int col) {
		sound("wav/explode.wav");
		int i,j;
		utt.cancel();
		//ûбΪ׵׷
		for(i=0; i<rows; i++){
			for(j=0; j<cols; j++){
				if( (blocks[i][j].getType()==BlockType.MINE) && (blocks[i][j].getState()!=BlockState.MINE_FLAG)){
					blocks[i][j].setState(BlockState.OPEN);
					blocks[i][j].draw(MinePanel.this.getGraphics());
				}
			}
		}
		blocks[row][col].setState(BlockState.EXPLODED);
		blocks[row][col].draw(MinePanel.this.getGraphics());

		mf.setGamming(false);
		mf.setStoped(true);
		JOptionPane.showMessageDialog(this, "ɨʧܣŬ");
	}
	/**
	 * ɨ׽ Ĵ
	 */
	public void wins() {
		sound("wav/success.wav");
		int second = utt.getSecond();
		utt.cancel();
		mf.setGamming(false);
		mf.setStoped(true);
		JOptionPane.showMessageDialog(this, "ϲɨ׳ɹ");
		int grade = mf.getGrade();
		Record record = mf.getRecord();
		boolean newRecord = false;
		switch(grade){
		case Grade.LOWER:
			if(second < record.getLowerScore()){
				newRecord = true;
			}
			break;
		case Grade.MEDIAL:
			if(second < record.getMedialScore()){
				newRecord = true;
			}
			break;
		case Grade.HIGHER:
			if(second < record.getHigherScore()){
				newRecord = true;
			}
			break;
		}
		if(newRecord){
			String name = null;
			DialogRecordName dlg = new DialogRecordName(mf,second, grade);
			int option = dlg.openDialog();
			if(option==1){
				name = dlg.name.getText();
				switch(grade){
				case Grade.LOWER:
					record.setLowerName(name);
					record.setLowerScore(second);
					break;
				case Grade.MEDIAL:
					record.setMedialName(name);
					record.setMedialScore(second);
					break;
				case Grade.HIGHER:
					record.setHigherName(name);
					record.setHigherScore(second);
					break;
				}
				RecordDao rd = new RecordDao();
				rd.writeRecord(record);
			}			
		}
	}
	@SuppressWarnings("restriction")
	public void sound(String fileName){
		try {
			//System.out.println(fileName);
			InputStream in = new FileInputStream(fileName);
			AudioStream as = new AudioStream(in);			
			AudioPlayer.player.start(as);// ʼ
		}catch(FileNotFoundException e){
		}
		catch(IOException e){
		}
	}
	/**
	 * Ϣ
	 */
	class MouseMonitor extends MouseAdapter{
		public void mouseClicked(MouseEvent event) {
			System.out.println("11111111111111111111111111111111111111111111111111");
			int col = event.getX()/GRID_WIDTH;
			int row = event.getY()/GRID_HEIGHT;
			if(mf.isStoped()) //Ϸֹͣ
				return;
			//ԭϷ״̬ʼϷϷ
			if(!mf.isGamming()){ 
				mf.setGamming(true);
				utt = new UpdateTimeTask(mf);
				Timer timer = new Timer();
				timer.schedule(utt, 1000, 1000);
				
			}
			//С
			if(event.getButton() == MouseEvent.BUTTON1){
				open(row,col);
			}
			else if(event.getButton() == MouseEvent.BUTTON3){ 
				if(blocks[row][col].getState()==BlockState.ORIGINAL){
					blocks[row][col].setState(BlockState.MINE_FLAG);
					remainedMines--; 
					mf.setMinesRemained(remainedMines);
					blocks[row][col].draw(MinePanel.this.getGraphics());
				}
				else if(blocks[row][col].getState()==BlockState.MINE_FLAG){
					blocks[row][col].setState(BlockState.QUESTION_FLAG);
					remainedMines++;
					mf.setMinesRemained(remainedMines);
					blocks[row][col].draw(MinePanel.this.getGraphics());
				}
				else if(blocks[row][col].getState()==BlockState.QUESTION_FLAG){
					blocks[row][col].setState(BlockState.ORIGINAL);
					blocks[row][col].draw(MinePanel.this.getGraphics());
				}
				else if(blocks[row][col].getState()==BlockState.OPEN){
					//ѾģΧ׶ѱǳûбǵķ
					int flagNumber = 0;
					for(int i=row-1; i<=row+1; i++){
						for(int j=col-1; j<=col+1; j++){
							if((i>=0)&&(i<rows)&&(j>=0)&&(j<cols)){
								if(blocks[i][j].getState() == BlockState.MINE_FLAG){
									flagNumber++;
								}
							}
						}
					}
					if(flagNumber == blocks[row][col].getType()){//Ѿǳ
						for(int i=row-1; i<=row+1; i++){
							for(int j=col-1; j<=col+1; j++){
								if((i>=0)&&(i<rows)&&(j>=0)&&(j<cols)){
									open(i,j);
								}
							}
						}
					}
				}
			}			
		}
	}	
}

