#!/usr/bin/python

import sys,os,time,random

import curses

A_BG		= 0
A_BORDER	= 1
A_TEXT		= 2
A_RED		= 3
A_GREEN		= 4
A_BLUE		= 5
A_CYAN		= 6
A_MAGENTA	= 7
A_YELLOW	= 8
A_WHITE		= 9

colors = [
	(curses.COLOR_BLACK,	curses.COLOR_BLACK),	#A_BG
	(curses.COLOR_BLACK,	curses.COLOR_WHITE),	#A_BORDER
	(curses.COLOR_BLACK,	curses.COLOR_WHITE),	#A_TEXT
	(curses.COLOR_BLACK,	curses.COLOR_RED),		#A_RED
	(curses.COLOR_BLACK,	curses.COLOR_GREEN),	#A_GREEN
	(curses.COLOR_BLACK,	curses.COLOR_BLUE),		#A_BLUE
	(curses.COLOR_BLACK,	curses.COLOR_CYAN),		#A_CYAN
	(curses.COLOR_BLACK,	curses.COLOR_MAGENTA),	#A_MAGENTA
	(curses.COLOR_BLACK,	curses.COLOR_YELLOW),	#A_YELLOW
	(curses.COLOR_BLACK,	curses.COLOR_WHITE),	#A_WHITE
]

attribs = [
	curses.A_DIM,		#A_BG
	curses.A_DIM,		#A_BORDER
	curses.A_NORMAL,	#A_TEXT
	curses.A_NORMAL,	#A_RED
	curses.A_NORMAL,	#A_GREEN
	curses.A_NORMAL,	#A_BLUE
	curses.A_NORMAL,	#A_CYAN
	curses.A_NORMAL,	#A_MAGENTA
	curses.A_NORMAL,	#A_YELLOW
	curses.A_NORMAL,	#A_WHITE
]

pieces = [
	(
	 ["  # ",
	  "  # ",
	  "  # ",
	  "  # ",],
	 [ (0,0),(0,1),(1,0),(0,0) ],
	 A_RED
	),
	(
	 ["    ",
	  " #  ",
	  "### ",
	  "    ",],
	 [ (0,0),(-1,0),(-1,1),(0,1) ],
	 A_GREEN
	),
	(
	 ["    ",
	  " ## ",
	  " ## ",
	  "    ",],
	 [ (0,0),(0,0),(0,0),(0,0) ],
	 A_BLUE
	),
	(
	 ["    ",
	  "  # ",
	  " ## ",
	  " #  ",],
	 [ (0,0),(0,0),(0,1),(1,0) ],
	 A_CYAN
	),
	(
	 ["    ",
	  " #  ",
	  " ## ",
	  "  # ",],
	 [ (0,0),(-1,0),(0,1),(0,0) ],
	 A_MAGENTA
	),
	(
	 ["    ",
	  " ## ",
	  "  # ",
	  "  # ",],
	 [ (0,0),(-1,0),(-1,1),(0,1) ],
	 A_YELLOW
	),
	(
	 ["    ",
	  " ## ",
	  " #  ",
	  " #  ",],
	 [ (0,0),(0,1),(1,1),(1,0) ],
	 A_WHITE
	),
]

class piece:
	def __init__(self,data=None):
		if data==None:
			return
		self.pos=data[1]
		self.attributes=data[2]
		self.blocks=[]
		for i in data[0]:
			tmp=[]
			for j in i:
				tmp.append(j!=' ')
			self.blocks.append(tmp)
	
	def getdata(self,angle):
		nd=self.blocks
		for i in nd:
			for j in range(len(i)):
				if i[j]:
					i[j]=self.attributes
				else:
					i[j]=0
		for a in range(angle):
			nb=[]
			for i in range(4):
				tmp=[]
				for j in range(4):
					tmp.append(nd[j][3-i])
				nb.append(tmp)
			nd=nb
		
		px,py=self.pos[angle]
		
		if py>0:
			nd=([[0,0,0,0]]*py)+nd[:-py]
		elif py<0:
			nd=nd[-py:]+([[0,0,0,0]]*(-py))
		
		for i in range(len(nd)):
			if px>0:
				nd[i]=([0]*px)+nd[i][:-px]
			elif px<0:
				nd[i]=nd[i][-px:]+([0]*(-px))
			
		
		return nd

class plane:
	def __init__(self,w,h):
		self.w=w
		self.h=h
		self.clear()
	
	def collides(self,otherplane):
		if otherplane.w != self.w or otherplane.h != self.h:
			raise ValueError
		for i in range(self.h):
			for j in range(self.w):
				if self.isset(j,i) and otherplane.isset(j,i):
					return 1
		return 0
			
	def isset(self,x,y):
		return self.blocks[y][x]!=0
	
	def __add__(self,otherplane):
		if otherplane.w != self.w or otherplane.h != self.h:
			raise ValueError
		newplane=plane(self.w,self.h)
		for i in range(self.h):
			for j in range(self.w):
				newplane.blocks[i][j]=self.blocks[i][j]
				if otherplane.isset(j,i):
					newplane.blocks[i][j]=otherplane.blocks[i][j]
		return newplane
	def copy(self):
		newplane=plane(self.w,self.h)
		for i in range(self.h):
			for j in range(self.w):
				newplane.blocks[i][j]=self.blocks[i][j]
		return newplane
	def draw(self,scr,x,y):
		for i in range(self.h):
			for j in range(self.w):
				d=self.blocks[i][j]
				if d==0:
					d=A_BG
				scr.addstr(y+i+1,x+(j*2)+2, "  ", attribs[d] )
		for i in range(self.h+2):
			scr.addstr(y+i,x, "  ", attribs[A_BORDER] )
			scr.addstr(y+i,x+self.w*2+2, "  ", attribs[A_BORDER] )
		for i in range(self.w+2):
			scr.addstr(y,x+i*2, "  ", attribs[A_BORDER] )
			scr.addstr(y+self.h+1,x+i*2, "  ", attribs[A_BORDER] )
			
	def clear(self):
		self.blocks=[]
		for i in range(h):
			tmp=[]
			for j in range(w):
				tmp.append(0)
			self.blocks.append(tmp)
	def insertpiece(self,data,x,y):
		for i in range(len(data)):
			for j in range(len(data[i])):
				if ( (self.h)>(y+i)>=0 ) and ( (self.w)>(x+j)>=0 ):
					self.blocks[y+i][x+j]=data[i][j]
				elif data[i][j]!=0:
					return 0
		return 1
	def delrow(self,r):
		self.blocks.pop(r)
		self.blocks=[[]]+self.blocks
		for i in range(self.w):
			self.blocks[0].append(0)
		return 1
	def countrow(self,r):
		n=0
		for i in self.blocks[r]:
			if i>0:
				n=n+1
		return n
		
w=12
h=20
x=4
y=2

tmr=25

def progmain(mainscr):
	curses.start_color()
	curses.curs_set(0)
	mainscr.nodelay(1)
	ipieces=[]
	
	for i in range(len(colors)):
		curses.init_pair(i+1, colors[i][0], colors[i][1])
		attribs[i]=attribs[i]|curses.color_pair(i+1)
	
	for i in pieces:
		ipieces.append(piece(i))
	
	
	mainscr.bkgd(" ",attribs[A_BG]|curses.color_pair(A_BG))
	top_plane=plane(w,h)
	bot_plane=plane(w,h)
	
	px=4
	py=0
	pa=0
	pt=random.randint(0,6)
	
	while 1:
		np=plane(w,h)
		if np.insertpiece(ipieces[pt].getdata(pa),px,py) and not np.collides(bot_plane):
			top_plane=np
		else:
			bot_plane=(bot_plane+top_plane)
			for i in range(h):
				if bot_plane.countrow(i)==w:
					bot_plane.delrow(i)
			px=4
			py=0
			pa=0
			pt=random.randint(0,6)
			top_plane.clear()
			top_plane.insertpiece(ipieces[pt].getdata(pa),px,py)
			if top_plane.collides(bot_plane):
				return
		(bot_plane+top_plane).draw(mainscr,x,y) #cool, huh? operator overloading rules :)
		mainscr.refresh()
		
		for i in range(tmr):
			time.sleep(0.01)
			c=mainscr.getch()
			if(c>-1):
				if c=='q' or c=='Q':
					return
				if c==curses.KEY_LEFT or c==curses.KEY_RIGHT or c==curses.KEY_UP or c==curses.KEY_DOWN:
					(xd,yd,ad) = {
									curses.KEY_LEFT:	(-1,0,0),
									curses.KEY_RIGHT:	( 1,0,0),
									curses.KEY_UP:		( 0,0,1),
									curses.KEY_DOWN:	( 0,1,0)
								}[c]
					
					np=plane(w,h)
					if np.insertpiece(ipieces[pt].getdata((pa+ad)%4),px+xd,py+yd) and not np.collides(bot_plane):
						top_plane=np
						px=px+xd
						py=py+yd
						pa=(pa+ad)%4
						(bot_plane+top_plane).draw(mainscr,x,y) #cool, huh? operator overloading rules :)
						mainscr.refresh()
		
		py=py+1
		
			

def main():
	curses.wrapper(progmain)
	#progmain(curses.initscr())

if __name__ == "__main__":
	main()
