#!/usr/bin/env /usr/bin/python

### hexamine.py ##########################################################
#
# Author:	grayswander@users.sf.net
# License:	GPLv2 (see LICENSE file)
#
# NOTE: hexagonal grig code is taken from HexagonExample by John Eriksson
#       (http://arainyday.se/projects/python/HexagonExample/)
#
##########################################################################

import os, pygame,math,random, sys, ConfigParser
from pygame.locals import *

#############################################################
### Configurable Parameters #################################

config=None

SKIN=None

PROFILE=None

# Maximum mine power
MAX_MINE_POWER = None

# Probability of mine appearance in cell
MINE_PROBABILITY = [0,0,0,0,0]

# Probability for each mine type
# Make sure it sums to 100!
#MINE_1_PROBABILITY = None
#MINE_2_PROBABILITY = None
#MINE_3_PROBABILITY = None
#MINE_4_PROBABILITY = None

# Threat modifier to be added to mines in far neighborhood
FAR_THREAT_MOD = None

### End of Configurable Parameters ##########################
#############################################################

VERSION = "0.2.1"

# This is the rectangular size of the hexagon tiles.
TILE_WIDTH = 38
TILE_HEIGHT = 41

# This is the distance in height between two rows.
ROW_HEIGHT = 31

# This value will be applied to all odd rows x value.
ODD_ROW_X_MOD = 19

# This is the size of the square grid that will help us convert pixel locations to hexagon map locations.
GRID_WIDTH = 38
GRID_HEIGHT = 31

# Defaults
MINEFIELD_X_SIZE = 16
MINEFIELD_Y_SIZE = 15

# Lists of appropriate modifiers to add to current cell to get close and far neighborhood
EVEN_ROW_NEIGHBORHOOD=[(-1,-1),(0,-1),(-1,0),(1,0),(-1,1),(0,1)]
ODD_ROW_NEIGHBORHOOD=[(0,-1),(1,-1),(-1,0),(1,0),(0,1),(1,1)]
EVEN_ROW_FAR_NEIGHBORHOOD=[(-1,-2),(0,-2),(1,-2),(-2,0),(2,0),(-1,2),(0,2),(1,2),(-2,-1),(1,-1),(-2,1),(1,1)]
ODD_ROW_FAR_NEIGHBORHOOD=[(-1,-2),(0,-2),(1,-2),(-2,0),(2,0),(-1,2),(0,2),(1,2),(-1,-1),(2,-1),(-1,1),(2,1)]

X = 0
Y = 1

CLOCK_TICK=30

# This is the modification tables for the square grid.

a1=(-1,-1)
b1=(0,0)
c1=(0,-1)

gridEvenRows = [
[a1,a1,a1,a1,a1,a1,a1,a1,a1,a1,a1,a1,a1,a1,a1,a1,a1,a1,b1,b1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1],
[a1,a1,a1,a1,a1,a1,a1,a1,a1,a1,a1,a1,a1,a1,a1,a1,b1,b1,b1,b1,b1,b1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1],
[a1,a1,a1,a1,a1,a1,a1,a1,a1,a1,a1,a1,a1,a1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1],
[a1,a1,a1,a1,a1,a1,a1,a1,a1,a1,a1,a1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1],
[a1,a1,a1,a1,a1,a1,a1,a1,a1,a1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,c1,c1,c1,c1,c1,c1,c1,c1,c1,c1],
[a1,a1,a1,a1,a1,a1,a1,a1,a1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,c1,c1,c1,c1,c1,c1,c1,c1,c1],
[a1,a1,a1,a1,a1,a1,a1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,c1,c1,c1,c1,c1,c1,c1],
[a1,a1,a1,a1,a1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,c1,c1,c1,c1,c1],
[a1,a1,a1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,c1,c1,c1],
[a1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,c1],
[b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1],
[b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1],
[b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1],
[b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1],
[b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1],
[b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1],
[b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1],
[b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1],
[b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1],
[b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1],
[b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1],
[b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1],
[b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1],
[b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1],
[b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1],
[b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1],
[b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1],
[b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1],
[b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1],
[b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1],
[b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1,b1]
]

a2=(-1,0)
b2=(0,-1)
c2=(0,0)

gridOddRows = [
[a2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,c2],
[a2,a2,a2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,c2,c2,c2],
[a2,a2,a2,a2,a2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,c2,c2,c2,c2,c2],
[a2,a2,a2,a2,a2,a2,a2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,c2,c2,c2,c2,c2,c2,c2],
[a2,a2,a2,a2,a2,a2,a2,a2,a2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,c2,c2,c2,c2,c2,c2,c2,c2,c2],
[a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2],
[a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2],
[a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,b2,b2,b2,b2,b2,b2,b2,b2,b2,b2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2],
[a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,b2,b2,b2,b2,b2,b2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2],
[a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,b2,b2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2],
[a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2],
[a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2],
[a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2],
[a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2],
[a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2],
[a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2],
[a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2],
[a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2],
[a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2],
[a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2],
[a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2],
[a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2],
[a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2],
[a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2],
[a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2],
[a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2],
[a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2],
[a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2],
[a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2],
[a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2],
[a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,a2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2,c2]
]

class Cell:
	"""
	Class representing cell data. 
	"""
	def __init__(self):
		self.state = "closed"	# Cell state. "open" or "close"
		self.mine = 0		# Mine power in cell. 0 - no mine
		self.flag = 0		# User flag on cell. 0 - no cell
		self.threat = 0		# Sum of mine powers in close neighborhood
		self.far_threat = 0	# Threat from far neighborhood. See MineField.calc_far_threat()
	
	def get_state(self): return self.state
	def get_mine(self): return self.mine
	def get_flag(self): return self.flag
	def get_threat(self): return self.threat
	def get_far_threat(self): return self.far_threat
	
	def set_threat(self, new_threat):
		self.threat = new_threat
		return self.threat
	
	def set_far_threat(self, new_far_threat):
		self.far_threat = new_far_threat
		return self.far_threat
	
	def set_flag(self, new_flag): 
		self.flag = new_flag % (MAX_MINE_POWER + 1)
		return self.flag 
	
	def set_mine(self, new_mine): 
		self.mine = new_mine % (MAX_MINE_POWER + 1)
		return self.mine 
	
	def set_state(self, new_state="open"): 
		self.state = new_state
		return self.state 
	

class MineField:
	"""
	Represents hexagonal mine field.
	Attributes:
		field[][]	-- 2-dimensional array of cells
	"""
	
	def __init__(self):
		self.field = []
		self.free_cell_number = 0
		self.open_cell_count = 0
		
		for x in range(MINEFIELD_X_SIZE):
			col = []
			for y in range(MINEFIELD_Y_SIZE):
				new_cell = Cell()
				randval = random.randint(1,100)
				if randval <= MINE_PROBABILITY[0]:
					randval = random.randint(1,100)
					if randval <= MINE_PROBABILITY[1]:
						new_cell.set_mine(1)
					elif randval <= MINE_PROBABILITY[1] + MINE_PROBABILITY[2]:
						new_cell.set_mine(2)
					elif randval <= MINE_PROBABILITY[1] + MINE_PROBABILITY[2] + MINE_PROBABILITY[3]:
						new_cell.set_mine(3)
					else:
						new_cell.set_mine(4)
					#print "M(%d,%d) -> %d" % (x+1,y+1,new_cell.get_mine())
				else:
					self.free_cell_number += 1;	
				col.append(new_cell)
			self.field.append(col)
			
		for x in range(MINEFIELD_X_SIZE):
			for y in range(MINEFIELD_Y_SIZE):
				self.field[x][y].set_threat(self.calc_threat((x,y)))
				self.field[x][y].set_far_threat(self.calc_far_threat((x,y)))
	
	def get_cell(self, position):
		if self.check_position(position): return self.field[position[X]][position[Y]]
		else: return None
	
	def get_neighborhood_list(self, position):
		if not self.check_position(position): return None
		ret = []
		
		if position[Y]&1:
			n_list = ODD_ROW_NEIGHBORHOOD
		else:
			n_list = EVEN_ROW_NEIGHBORHOOD
			
		for (x_off, y_off) in n_list:
			n_cell = (position[X]+x_off, position[Y]+y_off)
			if self.check_position(n_cell):
				ret.append(n_cell)
		
		return ret
	
	def get_neighborhood(self, position):
		if not self.check_position(position): return None
		ret = []
		
		for cur_pos in self.get_neighborhood_list(position):
			ret.append(self.get_cell(cur_pos))
		return ret
	
	def calc_threat(self, position):
		ret = 0
		for cur_cell in self.get_neighborhood(position):
			ret = ret + cur_cell.get_mine();
		#print "T(%d,%d) -> %d\n" % (position[X]+1, position[Y]+1, ret)
		return ret
	
	def get_far_neighborhood_list(self, position):
		if not self.check_position(position): return None
		ret = []
		
		if position[Y]&1:
			n_list = ODD_ROW_FAR_NEIGHBORHOOD
		else:
			n_list = EVEN_ROW_FAR_NEIGHBORHOOD
			
		for (x_off, y_off) in n_list:
			n_cell = (position[X]+x_off, position[Y]+y_off)
			if self.check_position(n_cell):
				ret.append(n_cell)
		
		return ret
	
	def get_far_neighborhood(self, position):
		if not self.check_position(position): return None
		ret = []
		
		for cur_pos in self.get_far_neighborhood_list(position):
			ret.append(self.get_cell(cur_pos))
		return ret
	
	def calc_far_threat(self, position):
		ret = 0
		for cur_cell in self.get_far_neighborhood(position):
			if cur_cell.get_mine() > 0: ret = ret + cur_cell.get_mine() + FAR_THREAT_MOD
		#print "FT(%d,%d) -> %d\n" % (position[X]+1, position[Y]+1, ret)
		return ret
	
	
	def check_position(self, position):
		if position[X] >= 0 and position[X] < MINEFIELD_X_SIZE and position[Y] >= 0 and position[Y] < MINEFIELD_Y_SIZE:
			return True
		else:
			return False
		
	def open_cell(self, position):
		if not self.check_position(position): return None
		if self.get_cell(position).get_state() == "opened" or self.get_cell(position).get_flag() != 0 : return True
		self.get_cell(position).set_state("opened")
		self.open_cell_count += 1
		if self.get_cell(position).get_mine ()!= 0:
			return "RIP"
		if self.get_cell(position).get_threat() == 0:
			for pos in self.get_neighborhood_list(position):
				self.open_cell(pos)
		if self.open_cell_count == self.free_cell_number:
			return "VICTORY"
		return True
	
	def flag_cell(self, position):
		if not self.check_position(position): return None
		self.get_cell(position).set_flag(self.get_cell(position).get_flag() + 1)
		return True

class HexaMine:

    def pixelToHexMap(self,x,y):
        """
        Converts a pixel location to a location on the hexagon map.
        """        

        # Get the square location in our help grid.
        gridX = x/GRID_WIDTH
        gridY = y/GRID_HEIGHT
            
        # Calculate the pixel location within that square
        gridPixelX = x%GRID_WIDTH
        gridPixelY = y%GRID_HEIGHT

        # Update the gridRect to show the correct location in the grid
        self.gridRect.topleft = (gridX*GRID_WIDTH,gridY*GRID_HEIGHT)
       
        # Apply the modifiers to get the correct hexagon map location.
        if gridY&1:
            # Odd rows
            hexMapX=gridX+gridOddRows[gridPixelY][gridPixelX][0]
            hexMapY=gridY+gridOddRows[gridPixelY][gridPixelX][1]
        else:
            # Even rows
            hexMapX=gridX+gridEvenRows[gridPixelY][gridPixelX][0]
            hexMapY=gridY+gridEvenRows[gridPixelY][gridPixelX][1]

        return (hexMapX,hexMapY)

    def hexMapToPixel(self,mapX,mapY):
        """
        Returns the top left pixel location of a hexagon map location.
        """
        if mapY & 1:
            # Odd rows will be moved to the right.
            return (mapX*TILE_WIDTH+ODD_ROW_X_MOD,mapY*ROW_HEIGHT)
        else:
            return (mapX*TILE_WIDTH,mapY*ROW_HEIGHT)
            

    def drawMap(self, special=None):       
        """
        Draw the tiles.
        """
        #fnt = pygame.font.Font(pygame.font.get_default_font(),12)
	fnt = pygame.font.Font("/usr/share/games/hexamine/skins/%s/font.ttf" % (SKIN),14)

        self.mapimg = pygame.Surface((640,480),1)
        self.mapimg= self.mapimg.convert()
        self.mapimg.fill((104,104,104))

        for x in range(16):
            for y in range(15):
                # Get the top left location of the tile.
                pixelX,pixelY = self.hexMapToPixel(x,y)
		
		flag_set = self.minefield.get_cell((x,y)).get_flag()
		
                # Blit the tile to the map image.
		if not special:
			if self.minefield.get_cell((x,y)).get_state() == "closed":
				if flag_set == 0:
					self.mapimg.blit(self.tile,(pixelX,pixelY))
				elif flag_set == 1:
					self.mapimg.blit(self.flag1,(pixelX,pixelY))
				elif flag_set == 2:
					self.mapimg.blit(self.flag2,(pixelX,pixelY))
				elif flag_set == 3:
					self.mapimg.blit(self.flag3,(pixelX,pixelY))
				elif flag_set == 4:
					self.mapimg.blit(self.flag4,(pixelX,pixelY))
			elif self.minefield.get_cell((x,y)).get_state() == "opened":
				self.mapimg.blit(self.tile_open,(pixelX,pixelY))
		else:
			#mine_tile = special == "RIP" and self.tile_rip or self.tile_vic
			if self.minefield.get_cell((x,y)).get_mine() == 0:
				self.mapimg.blit(self.tile_open,(pixelX,pixelY))
			else:
				self.mapimg.blit(special == "RIP" and self.tile_rip or self.tile_vic,(pixelX,pixelY))
			
			if flag_set != 0 and flag_set != self.minefield.get_cell((x,y)).get_mine():
				if flag_set == 1:
					self.mapimg.blit(self.err1,(pixelX,pixelY))
				elif flag_set == 2:
					self.mapimg.blit(self.err2,(pixelX,pixelY))
				elif flag_set == 3:
					self.mapimg.blit(self.err3,(pixelX,pixelY))
				elif flag_set == 4:
					self.mapimg.blit(self.err4,(pixelX,pixelY))
			
		mark = None
                # Show the hexagon map location in the center of the tile.
                #mark = fnt.render("%d,%d" % (x,y), 0, (0xff,0xff,0xff))
		if not special:
			if self.minefield.get_cell((x,y)).get_state() == "opened":
				mark = fnt.render("%d/%d" % (self.minefield.get_cell((x,y)).get_threat(),self.minefield.get_cell((x,y)).get_far_threat()), 0, (0xff,0xff,0xff))
			elif self.minefield.get_cell((x,y)).get_flag() != 0:
				mark = fnt.render("%d" % (self.minefield.get_cell((x,y)).get_flag()), 0, (0xff,0xff,0xff))
		else:
			if self.minefield.get_cell((x,y)).get_mine() == 0:
				mark = fnt.render("%d/%d" % (self.minefield.get_cell((x,y)).get_threat(),self.minefield.get_cell((x,y)).get_far_threat()), 0, (0xff,0xff,0xff))	
			else:
				mark = fnt.render("%d" % (self.minefield.get_cell((x,y)).get_mine()), 0, (0xff,0xff,0xff))
                if mark:
			lrect=mark.get_rect()
                	lrect.center = (pixelX+(TILE_WIDTH/2),pixelY+(TILE_HEIGHT/2))   
                	self.mapimg.blit(mark,lrect.topleft)
                    
    def loadTiles(self):
        """
        Load the tile and the cursor.
        """
	
	if not os.path.isdir("/usr/share/games/hexamine/skins/%s" % (SKIN)):
		print "Skin %s does not exist." % (SKIN)
		sys.exit(1)
	
        self.tile = pygame.image.load("/usr/share/games/hexamine/skins/%s/hextile.png" % (SKIN)).convert()
        self.tile.set_colorkey((0x80, 0x00, 0x80), RLEACCEL)                

        self.cursor = pygame.image.load("/usr/share/games/hexamine/skins/%s/hexcursor.png" % (SKIN)).convert()
        self.cursor.set_colorkey((0x80, 0x00, 0x80), RLEACCEL)                
        self.cursor_fn = pygame.image.load("/usr/share/games/hexamine/skins/%s/hexcursor_fn.png" % (SKIN)).convert()
        self.cursor_fn.set_colorkey((0x80, 0x00, 0x80), RLEACCEL)     
	self.cursorPos = self.cursor.get_rect()
	self.fn_cursorPos=[]
	
	self.flag1 = pygame.image.load("/usr/share/games/hexamine/skins/%s/hextile_flag_1.png" % (SKIN)).convert()
	self.flag1.set_colorkey((0x80, 0x00, 0x80), RLEACCEL)
	
	self.flag2 = pygame.image.load("/usr/share/games/hexamine/skins/%s/hextile_flag_2.png" % (SKIN)).convert()
	self.flag2.set_colorkey((0x80, 0x00, 0x80), RLEACCEL)
	
	self.flag3 = pygame.image.load("/usr/share/games/hexamine/skins/%s/hextile_flag_3.png" % (SKIN)).convert()
	self.flag3.set_colorkey((0x80, 0x00, 0x80), RLEACCEL)
	
	self.flag4 = pygame.image.load("/usr/share/games/hexamine/skins/%s/hextile_flag_4.png" % (SKIN)).convert()
	self.flag4.set_colorkey((0x80, 0x00, 0x80), RLEACCEL)
	
	self.tile_open = pygame.image.load("/usr/share/games/hexamine/skins/%s/hextile_open.png" % (SKIN)).convert()
        self.tile_open.set_colorkey((0x80, 0x00, 0x80), RLEACCEL)
	
	self.tile_rip = pygame.image.load("/usr/share/games/hexamine/skins/%s/hextile_rip.png" % (SKIN)).convert()
	self.tile_rip.set_colorkey((0x80, 0x00, 0x80), RLEACCEL)
	
	self.tile_vic = pygame.image.load("/usr/share/games/hexamine/skins/%s/hextile_vic.png" % (SKIN)).convert()
	self.tile_vic.set_colorkey((0x80, 0x00, 0x80), RLEACCEL)
	
	self.err1 = pygame.image.load("/usr/share/games/hexamine/skins/%s/hexerror_1.png" % (SKIN)).convert()
	self.err1.set_colorkey((0x80, 0x00, 0x80), RLEACCEL)
	self.err2 = pygame.image.load("/usr/share/games/hexamine/skins/%s/hexerror_2.png" % (SKIN)).convert()
	self.err2.set_colorkey((0x80, 0x00, 0x80), RLEACCEL)
	self.err3 = pygame.image.load("/usr/share/games/hexamine/skins/%s/hexerror_3.png" % (SKIN)).convert()
	self.err3.set_colorkey((0x80, 0x00, 0x80), RLEACCEL)
	self.err4 = pygame.image.load("/usr/share/games/hexamine/skins/%s/hexerror_4.png" % (SKIN)).convert()
	self.err4.set_colorkey((0x80, 0x00, 0x80), RLEACCEL)
	
	
    def init(self):
        """
        Setup the screen etc.
        """
	
	# Check configuration
	
	print "Using profile : %s" % (PROFILE)
	
	if not 0 < MINE_PROBABILITY[0] < 100:
		print "Mine probability should be between 1 and 99"
		sys.exit(1)
	
	mp_sum=0
	for i in range(1,5): 
		mp_sum += MINE_PROBABILITY[i]
	
	if mp_sum != 100:
		print "Probabilities for each mine type to appear should sum to 100"
		sys.exit(1)
		
	if not -MAX_MINE_POWER <= FAR_THREAT_MOD <= 0:
		print "Far threat modifier should be between -MAX_MINE_POWER and 0"
		sys.exit(1)
	
        self.screen = pygame.display.set_mode((640, 480),1)
        pygame.display.set_caption("HexaMine %s (%s) | ESC - Quit" % (VERSION, PROFILE))

	self.minefield = MineField()

        self.loadTiles()
        self.drawMap()        

        self.gridRect = pygame.Rect(0,0,GRID_WIDTH,GRID_HEIGHT)
	
	self.cur_cursor_cell = None
	self.redraw = True

    def setCursor(self,x,y):
        """
        Set the hexagon map cursor.
        """
        mapX,mapY = self.pixelToHexMap(x,y)
        
	if self.cur_cursor_cell != (mapX,mapY):
		self.cur_cursor_cell = (mapX,mapY)
		self.redraw = True
		pixelX,pixelY = self.hexMapToPixel(mapX,mapY)
		self.cursorPos.topleft = (pixelX,pixelY)
		
		self.fn_cursorPos=[]
		
		if self.minefield.check_position((mapX,mapY)) and self.minefield.get_cell((mapX,mapY)).get_state() == "opened":
			for fnc in self.minefield.get_far_neighborhood_list((mapX,mapY)):
				trect = pygame.Rect(0,0,GRID_WIDTH,GRID_HEIGHT)
				pixelX,pixelY = self.hexMapToPixel(fnc[X],fnc[Y])
				trect.topleft = (pixelX,pixelY)
				self.fn_cursorPos.append(trect)

    def mainLoop(self):    
        pygame.init()    

        self.init()

        clock = pygame.time.Clock()
                        
        showGridRect = False

        while 1:
		clock.tick(CLOCK_TICK)
		# DRAWING
		if self.redraw: 
			self.drawMap()
			self.screen.blit(self.mapimg, (0, 0))
			self.screen.blit(self.cursor,self.cursorPos)
			for cp in self.fn_cursorPos:
				self.screen.blit(self.cursor_fn,cp)               
			if showGridRect:
				pygame.draw.rect(self.screen, (0xff,0xff,0xff), self.gridRect, 1)
			
			pygame.display.flip()
		self.redraw = False
		for event in pygame.event.get():
                	if event.type == QUIT:
                    		return
		    	#sys.exit()
			elif event.type == KEYUP:
				if event.key == K_ESCAPE:
					return
					#sys.exit()
			elif event.type == MOUSEMOTION:
				self.setCursor(event.pos[0],event.pos[1])
		
			elif event.type == MOUSEBUTTONUP:
				loc = self.pixelToHexMap(event.pos[0],event.pos[1])
				self.redraw = True
				if self.minefield.check_position(loc):
					if event.button == 1:
						if self.minefield.get_cell(loc).get_flag() == 0:
							status = self.minefield.open_cell(loc)
							if status == "RIP" or status == "VICTORY" :
								pygame.display.set_caption("HexaMine %s (%s) | %s | ESC - Quit, SPACE/Mouse click - Continue" % (VERSION, PROFILE, status))
								self.drawMap(status)
								self.screen.blit(self.mapimg, (0, 0))
								pygame.display.flip()
								while 1:
									clock.tick(CLOCK_TICK)
									for event in pygame.event.get():
										if event.type == QUIT:
											return
											#sys.exit()
										elif event.type == KEYUP:
											if event.key == K_ESCAPE:
												return
											elif event.key == K_SPACE:
												return "Continue"
										elif event.type == MOUSEBUTTONUP:
											return "Continue"
								return "Continue"
								
					elif event.button == 2:
						pass
					elif event.button == 3:
						self.minefield.flag_cell(loc)
		
def main():
	global config
	global PROFILE
	global SKIN
	global MAX_MINE_POWER

	global MINE_PROBABILITY
	#global MINE_1_PROBABILITY
	#global MINE_2_PROBABILITY
	#global MINE_3_PROBABILITY
	#global MINE_4_PROBABILITY
	global FAR_THREAT_MOD

	config = ConfigParser.ConfigParser()
	
	config_file = os.path.expanduser("~/.hexamine")
	if not os.path.isfile(config_file):
		if os.path.isfile("/etc/hexamine.conf"):
			config_file = "/etc/hexamine.conf"
		else:
			config_file = "hexamine.conf"
	
	print "Using configuration file %s" % (config_file)
	
	config.read(config_file)
	
	PROFILE = config.get("global", "profile")
	
	SKIN = config.get("global","skin")
	MAX_MINE_POWER = int(config.get(PROFILE,"max_mine_power"))

	MINE_PROBABILITY[0] = int(config.get(PROFILE,"mine_probability"))
	MINE_PROBABILITY[1] = int(config.get(PROFILE,"mine_1_probability"))
	MINE_PROBABILITY[2] = int(config.get(PROFILE,"mine_2_probability"))
	MINE_PROBABILITY[3] = int(config.get(PROFILE,"mine_3_probability"))
	MINE_PROBABILITY[4] = int(config.get(PROFILE,"mine_4_probability"))
	FAR_THREAT_MOD = int(config.get(PROFILE,"far_threat_mod"))
	
	g = HexaMine()
	while g.mainLoop() == "Continue": pass

 
#this calls the 'main' function when this script is executed
if __name__ == '__main__': main()
