#!/usr/bin/env python

#http://invisible-island.net/xterm/ctlseqs/ctlseqs.html

import termios
import fcntl
import struct
import signal
import errno
import os
import StringIO
bSizeChanged = False
terminals = {} # FD -> File
def handleWindowSizeChange(signalNumber, frame):
	global bSizeChanged
	bSizeChanged = True
def isSizeChanged():
	return(bSizeChanged)
def clearSizeChanged():
	global bSizeChanged
	bSizeChanged = False
def consumeSizeChanged():
	result = isSizeChanged()
	if(result):
		clearSizeChanged()
	return(result)
signal.signal(signal.SIGWINCH, handleWindowSizeChange)
def getTerminalSize(FD):
	data = fcntl.ioctl(FD, termios.TIOCGWINSZ, '1234') 
	height, width = struct.unpack('HH',data[:4])
	return(width, height)
bInSendReportSizeOfTextAreaRequests = False
def sendReportSizeOfTextAreaRequests():
	global bInSendReportSizeOfTextAreaRequests
	if bInSendReportSizeOfTextAreaRequests: # avoid endless recursion
		return
	try:
		# FIXME what happens if we send something while we are in the middle of receiving an escape sequence ourselves?
		for i, o in terminals.values():
			o.write("\033[18t") # "report the size of the text area in characters"
			o.flush()
	finally:
		bInSendReportSizeOfTextAreaRequests = False
def repeatedRead(FD, count):
	while True:
		try:
			text = os.read(FD, count)
			return(text)
		except OSError as e:
			if e.errno == errno.EINTR:
				if not consumeSizeChanged(): # WTF
					raise
				sendReportSizeOfTextAreaRequests()
			else:
				raise
def repeatedWrite(FD, text):
	while True:
		try:
			os.write(FD, text)
			return
		except OSError as e:
			if e.errno == errno.EINTR:
				if not consumeSizeChanged(): # WTF
					raise
				sendReportSizeOfTextAreaRequests()
			else:
				raise
class File(object):
	def __init__(self, FD):
		self.fFD = FD
		self.fRefCount = 0
		self.fBuffer = StringIO.StringIO()
	def flush(self):
		pass
	def read(self, count=None):
		text = "X"
		while len(text) > 0:
			chunkSize = max(min(count - self.fBuffer.pos, 10000), 0) if count is not None else 10000
			text = repeatedRead(self.fFD, chunkSize)
			self.fBuffer.write(text)
		result = self.fBuffer.getvalue()
		self.fBuffer.seek(0)
		self.fBuffer.truncate()
		return(result)
	def write(self, text):
		repeatedWrite(self.fFD, text)
		#import traceback
		#traceback.print_stack()
	def __enter__(self):
		self.fRefCount += 1
		return(self)
	def __exit__(self, exc_type, exc_value, traceback):
		self.fRefCount -= 1
		if self.fRefCount == 0:
			os.close(self.fFD)
def open(name, mode):
	return(File(os.open(name, os.O_WRONLY if "w" in mode else os.O_RDONLY if "r" in mode else os.O_RDONLY)))
def createTerminalIO(FDi, FDo):
	terminals[FDo] = (File(FDi), File(FDo))
	return(terminals[FDo])
def createTempFile(prefix, mode):
	assert(mode == "w")
	FD = None
	name = prefix
	for num in range(100):
		try:
			name = "%s.new.%05d" % (prefix, num)
			FD = os.open(name, os.O_WRONLY|os.O_CREAT)
			break
		except IOError as e:
			if e.errno != errno.EEXIST:
				raise
	if FD is None:
		raise OSError()
	f = File(FD)
	f.name = name
	return(f)
if __name__ == "__main__":
	width, height = getSize(0)
	assert(width >= 0)
	assert(height >= 0)
	print(width, height)
	