import metricsMachine
from mm4.mmScripting import MetricsMachineScriptingError
from vanilla import FloatingWindow, List, CheckBox, PopUpButton
from mojo.events import addObserver, removeObserver
from AppKit import *
from mojo.UI import Message

class SyncMM:

	def __init__(self):

		self.altDown = None
		
		self.fontList = []
		self.scaledWindows = []
		self.pointSizes = ["Auto", "50", "75", "100", "125", "150", "200", "250", "300", "350", "400", "450", "500"]

		self.w = FloatingWindow((200, 240), "Sync MM Windows")
		self.w.nameList = List((10,10,-10,-60), [])
		self.updateList(None)

		self.w.t = CheckBox((10,-50,100,20),"Tile Windows", callback=self.tileCallback)
		self.w.c = CheckBox((10,-30,100,20),"Sync Sizes")

		self.w.p = PopUpButton((-80,-30,70,20), self.pointSizes, callback=self.setAllPointSizes)

		addObserver(self, "pairChanged", "MetricsMachine.currentPairChanged")
		addObserver(self, "updateList", "fontDidClose")
		addObserver(self, "updateList", "fontWillOpen")

		self.w.bind("close", self.removeObs)
		self.w.open()

	def updateList(self, info):
		self.fontList = [f"{f.info.familyName} {f.info.styleName}" for f in AllFonts()]
		self.w.nameList.set(self.fontList)

	def removeObs(self, sender):
		removeObserver(self, "MetricsMachine.currentPairChanged")
		removeObserver(self, "fontWillClose")
		removeObserver(self, "fontWillOpen")


	# ================================
	'''
	Window code taken from Tal Leming's Metrics Machine
	'''

	def _getMainWindowControllerForFont(self, font=None):
		if font is None:
			font = CurrentFont()
		for other in AllFonts():
			if other != font:
				continue
			document = other.document()
			for controller in document.windowControllers():
				window = controller.window()
				if hasattr(window, "windowName") and window.windowName() == "MetricsMachineMainWindow":
					delegate = window.delegate()
					mmController = delegate.vanillaWrapper()
					return mmController
		raise MetricsMachineScriptingError("A MetricsMachine window is not open for %r." % font)

	def SetListSelection(self, pair=None, font=None):
		window = self._getMainWindowControllerForFont(font)
		pairList = window.pairList
		pairList.setSelection(pair)

	def getWindowPosSize(self, font=None):
		window = self._getMainWindowControllerForFont(font)
		x,y,w,h = window.w.getPosSize()
		
		return x,y,w,h

	def setWindowPosSize(self, posSize, font=None):
		window = self._getMainWindowControllerForFont(font)
		window.w.setPosSize(posSize)

	def getPointSize(self, font=None):
		window = self._getMainWindowControllerForFont(font)
		return window.editView.pairView.getPointSize()

	def setPointSize(self, pointSize, font=None):
		window = self._getMainWindowControllerForFont(font)
		window.editView.pairView.setPointSize(pointSize)

	def setAllPointSizes(self,sender):
		'''You cant set a window's EditView text to a random PointSize, instead
		we can just use MM's set of predefined values'''

		fonts = metricsMachine.AllFonts()
		fontSelection = [self.fontList[i] for i in self.w.nameList.getSelection()]
		if sender.get() == 0:
			pSize = None
		else:
			pSize = int(self.pointSizes[sender.get()])

		for fs in fonts:
			try:
				if f"{fs.info.familyName} {fs.info.styleName}" in fontSelection:
					self.setPointSize(pSize,fs)
			except MetricsMachineScriptingError:
				pass

	# ================================
		
	'''
	tiling code taken from Frederik Berlean's Arrange Windows
	'''

	def getWindowSize(self,window):
		w,h = (window.frame().size)
		x,y = (window.frame().origin)
		return (x,y,w,h)

	def tileCallback(self, sender):
		if sender.get() == 1:

			self.w.c.set(0)
			self.w.c.enable(False)

			windows = [w for w in NSApp().orderedWindows() if w.isVisible()]

			screen = NSScreen.mainScreen()
			(x, y), (w, h) = screen.visibleFrame()

			self.altDown = NSEvent.modifierFlags() & NSAlternateKeyMask

			NSApp().arrangeInFront_(None)

			windowsToHide = []
			windowsToTile = []
			for window in windows:
				if hasattr(window, "windowName") and window.windowName() == "MetricsMachineMainWindow":
					windowsToTile.append(window)

			tileInfo = {
						1 : [[1]],
						2 : [[1],[1]],
						3 : [[],[1, 1, 1]],
						4 : [[1, 1], [1, 1]],
						5 : [[1, 1], [1, 1, 1]],
						}

			if windowsToTile:
				if len(windowsToTile) > list(tileInfo.keys())[-1]:
					Message("Limit is 10 MM Windows")

				arrangement = tileInfo[len(windowsToTile)]					
				maxHeight = len(arrangement)
				diffx = x
				diffy = y
				c = 0
				for i in arrangement:
					maxWidth = len(i)		
					for j in i:
						window = windowsToTile[c]
						self.scaledWindows.append((window,self.getWindowSize(window)))
						window.setFrame_display_animate_(NSMakeRect(diffx, diffy, w/float(maxWidth), h/float(maxHeight)), True, self.altDown)
						c += 1

						diffx += w/float(maxWidth)
					diffx = x
					diffy += h/float(maxHeight)
		else:
			self.w.c.enable(True)
			for win, posSize in self.scaledWindows:
				xs,ys,ws,hs = posSize
				win.setFrame_display_animate_(NSMakeRect(xs,ys,ws,hs), True, self.altDown)

		
	def pairChanged(self, sender):
		cp = sender["pair"]

		pl = metricsMachine.GetPairList()
		pos = self.getWindowPosSize(CurrentFont())
		pvt = metricsMachine.GetPreviewText(CurrentFont())
		# ptsz = self.getPointSize(CurrentFont())

		fonts = metricsMachine.AllFonts()
		fontSelection = [self.fontList[i] for i in self.w.nameList.getSelection()]

		for fs in fonts:
			try:
				if f"{fs.info.familyName} {fs.info.styleName}" in fontSelection:
					if self.w.c.get() == 1:
						x,y,w,h = self.getWindowPosSize(fs)

						if (pos[2],pos[3]) != (w,h):
							self.setWindowPosSize((x,y,pos[2],pos[3]),fs)
					if metricsMachine.GetPreviewText(fs) != pvt:
						metricsMachine.SetPreviewText(pvt, fs)
					if metricsMachine.GetPairList(fs) != pl:
						metricsMachine.SetPairList(pl, fs)
					while metricsMachine.GetCurrentPair(fs) != cp:
						if fs != metricsMachine.CurrentFont():
							metricsMachine.SetCurrentPair(cp,fs)
							self.SetListSelection(cp,fs)

			except MetricsMachineScriptingError:
				pass


SyncMM()