from __future__ import print_function, unicode_literals
import win32api

import wmi
def GetWithPNPDeviceID(PNPDeviceID=None):
	c = wmi.WMI()
	Info = {}
	wql = "SELECT * FROM Win32_PnPEntity WHERE Manufacturer != 'Microsoft' AND NOT PNPDeviceID LIKE 'ROOT\\%' AND {0}".format("PNPDeviceID = '{0}'".format(PNPDeviceID) if PNPDeviceID else "Service = 'monitor'")
	for J in c.query(wql):
		Info[J.PNPDeviceID] = {}
		for Propertie in ('Caption', 'Description', 'DeviceID', 'HardwareID', 'Manufacturer', 'Name'):
			if getattr(J, Propertie) != None:
				Info[J.PNPDeviceID][Propertie] = getattr(J, Propertie)
	return Info

def GetWithWin32_DesktopMonitor(Index):
	c = wmi.WMI()
	Info = {}
	wql = "Select * from Win32_DesktopMonitor WHERE DeviceID LIKE '%{0}'".format(Index)
	for J in c.query(wql):
		#print(J)
		Info[J.DeviceID] = {}
		for Propertie in ('Caption', 'Description', 'DeviceID', 'Name', 'Availability', 'MonitorManufacturer', 'MonitorType', 'PixelsPerXLogicalInch', 'PixelsPerYLogicalInch', 'PNPDeviceID', 'ScreenHeight', 'ScreenWidth', 'Status'):
			if getattr(J, Propertie) != None:
				Info[J.DeviceID][Propertie] = getattr(J, Propertie)
	return Info

def DecodeEDID(edid):
	dtd = 54  # start byte of detailed timing desc.
	EDID = {}
	EDID['version'] = '{0}.{1}'.format(ord(edid[18]), ord(edid[19]))

	def read_short_be(offset, blob):
		return ((ord(blob[offset]) << 8) | ord(blob[offset + 1]))
	def read_short_le(offset, blob):
		return ((ord(blob[offset + 1]) << 8) | ord(blob[offset]))
	MANUFACTURER_ID_OFFSET = 8
	PRODUCT_ID_OFFSET = 10
	MANUFACTURER_ID_BITS = 5
	# Extract manufactuer
	vendor_name = ''
	vendor_code = read_short_be(MANUFACTURER_ID_OFFSET, edid)
	#print(vendor_code)
	# vendor_code: [0 | char1 | char2 | char3]
	for i in range(2, -1, -1):
		vendor_char = (vendor_code >> (i * MANUFACTURER_ID_BITS)) & 0x1F
		vendor_char = chr(vendor_char + ord('@'))
		vendor_name += vendor_char
	#print(vendor_name)
	EDID['vendor_name'] = vendor_name
	product_id = read_short_le(PRODUCT_ID_OFFSET, edid)
	#print(hex(product_id))
	EDID['product_id'] = hex(product_id)

	hres = ((ord(edid[dtd+4]) >> 4) << 8) | ord(edid[dtd+2])
	vres = ((ord(edid[dtd+7]) >> 4) << 8) | ord(edid[dtd+5])

	EDID['resolution'] = (hres, vres)

	#print repr(edid[72:72+89])
	desc = edid[54:126]
	#desc1 = desc[:18]
	#desc.reverse()


	for i in range(0, 72, 18):
		if desc[i:5+i] == b'\x00\x00\x00\xFC\x00':
			EDID['name'] = desc[5+i:13+5+i].strip()
		elif desc[i:5+i] == b'\x00\x00\x00\xFF\x00':
			EDID['serial'] = desc[5+i:13+5+i]


		#if ord(desc[0+i]) == 0:
			#if ord(desc[1+i]) == 0:
				#if ord(desc[2+i]) == 0:
					#if ord(desc[4+i]) == 0:
						#if ord(desc[3+i]) == 0xFC:
							#print repr(desc[0+i])
							#print repr(desc[1+i])
							#print repr(desc[2+i])
							#print repr(desc[3+i])
							#print repr(desc[4+i])
							#print desc[5+i:12+4+i].strip()
							#EDID['name'] = desc[5+i:13+5+i].strip()
						#elif ord(desc[3+i]) == 0xFF:
							#print desc[5+i:12+4+i]
							#EDID['serial'] = desc[5+i:13+5+i]

	#while len(desc):
	#	c = desc.pop()
	#	print repr(c)

	return EDID
import win32com.client
from win32api import EnumDisplayDevices, EnumDisplayMonitors, GetMonitorInfo, EnumDisplaySettings
import _winreg
class Display(object):
	def __init__(self, display):
		"""Initializes an endpoint object."""
		if display != None:
			info = {}
			info['EnumDisplayMonitors'] = display
			info['GetMonitorInfo'] = GetMonitorInfo(display[0])
			PyDISPLAY_DEVICE = win32api.EnumDisplayDevices(info['GetMonitorInfo']['Device'], 0, 1)
			info['EnumDisplayDevices'] = {}
			info['EnumDisplayDevices']['DeviceName'] = PyDISPLAY_DEVICE.DeviceName
			info['EnumDisplayDevices']['DeviceString'] = PyDISPLAY_DEVICE.DeviceString
			info['EnumDisplayDevices']['StateFlags'] = PyDISPLAY_DEVICE.StateFlags
			info['EnumDisplayDevices']['DeviceID'] = PyDISPLAY_DEVICE.DeviceID
			info['EnumDisplayDevices']['DeviceKey'] = PyDISPLAY_DEVICE.DeviceKey
			#self.DeviceString = info['EnumDisplayDevices'].DeviceString
			#self.DeviceKey = info['EnumDisplayDevices'].DeviceKey
			PNPDeviceID = "{0}\\{1}\\{2}".format(PyDISPLAY_DEVICE.DeviceID.split('#')[0].lstrip(r'\?'), PyDISPLAY_DEVICE.DeviceID.split('#')[1], PyDISPLAY_DEVICE.DeviceID.split('#')[2])
			info['Win32_PnPEntity'] = GetWithPNPDeviceID(PNPDeviceID)[PNPDeviceID.upper()]
			info['Win32_DesktopMonitor'] = GetWithWin32_DesktopMonitor(info['GetMonitorInfo']['Device'][-1])['DesktopMonitor'+info['GetMonitorInfo']['Device'][-1]]

			key = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, 'SYSTEM\\CurrentControlSet\\Enum\\' +
					info['Win32_PnPEntity']['DeviceID'] + '\\Device Parameters')
			#print(key)
			skey_name = _winreg.EnumValue(key, 0)
			#print(skey_name)
			#edid = _winreg.QueryValueEx(key, 'EDID')[0]
			#print(edid)
			info['EDID'] = DecodeEDID(_winreg.QueryValueEx(key, 'EDID')[0])
			#print(EDID)

			self.info = info

	def getName(self):
		"""Return an endpoint devices FriendlyName."""
		#print(self.PNPDeviceID)

		#print(self.DeviceKey)

		return self.info['EnumDisplayDevices']['DeviceString']

	def getInfo(self):
		"""Return an endpoint devices FriendlyName."""
		#Info = {'WMI':{}}
		#Info = {'PNP': self.PNPDevice}
		#for Propertie in ('Name', 'Availability', 'ConfigManagerUserConfig', 'Caption', 'Description', 'DeviceID', 'MonitorManufacturer', 'MonitorType', 'PixelsPerXLogicalInch', 'PixelsPerYLogicalInch', 'PNPDeviceID', 'ScreenHeight', 'ScreenWidth', 'Status', ):
		#	if getattr(self.display, Propertie) != None:
		#		Info['WMI'][Propertie] = getattr(self.display, Propertie)

		return self.info

	__str__ = getName

#import ctypes
#import ctypes.wintypes as wintypes
#_PHYSICAL_MONITOR_DESCRIPTION_SIZE = 128
#class _PHYSICAL_MONITOR(ctypes.Structure):
#	_fields_ = [('hPhysicalMonitor', wintypes.HANDLE), ('szPhysicalMonitorDescription', wintypes.WCHAR * _PHYSICAL_MONITOR_DESCRIPTION_SIZE)]

class Displays(object):
	def __init__(self):
		#strComputer = "."
		#objWMIService = win32com.client.Dispatch("WbemScripting.SWbemLocator")
		#self.objSWbemServices = objWMIService.ConnectServer(strComputer,"root\cimv2")
		pass

	def GetPrimery(self):
		pass

	def SetPrimery(self):
		pass

	def __call__(self):
		try:
			return AudioEndpoint(self.pDevEnum.GetDevice(ID), self, self.PKEY_Device)
		except COMError:
			for endpoint in self:
				if endpoint.getName() == ID:
					return endpoint

	def __str__(self):
		return str([str(endpoint) for endpoint in self])

	def ChangeFilter(self):
		if DEVICE_STATE != None: self.DEVICE_STATE = DEVICE_STATE
		if PKEY_Device != None: self.PKEY_Device = PKEY_Device

	def EnumDisplayMonitors(self):
		#monitor_number = wintypes.DWORD()
		for Disp in EnumDisplayMonitors():
			#print(Disp)
			#print(Disp[0])
			#print(GetMonitorInfo(Disp[0]))
			#yield GetMonitorInfo(Disp[0])
			yield Display(Disp)
			#if not ctypes.windll.dxva2.GetNumberOfPhysicalMonitorsFromHMONITOR(int(Disp[0]), ctypes.byref(monitor_number)):
			#	raise ctypes.WinError()
			#physical_monitor_array = (_PHYSICAL_MONITOR * monitor_number.value)()
			#print(monitor_number.value)
			#print(physical_monitor_array)
			#if not ctypes.windll.dxva2.GetPhysicalMonitorsFromHMONITOR(int(Disp[0]), monitor_number, physical_monitor_array):
			#	raise ctypes.WinError()
			#for physical_monitor in physical_monitor_array:
				#displays.append(Display(physical_monitor.hPhysicalMonitor))
			#	print(physical_monitor)
			#	print(physical_monitor.hPhysicalMonitor)
			#	print(physical_monitor.szPhysicalMonitorDescription)
			#if not ctypes.windll.dxva2.DestroyPhysicalMonitors(monitor_number, physical_monitor_array):
			#	raise ctypes.WinError()
		#PyDISPLAY_DEVICE = EnumDisplayDevices(None, 0)
		#pprint.pprint((PyDISPLAY_DEVICE.Size, PyDISPLAY_DEVICE.DeviceName, PyDISPLAY_DEVICE.DeviceString, PyDISPLAY_DEVICE.StateFlags, PyDISPLAY_DEVICE.DeviceID, PyDISPLAY_DEVICE.DeviceKey))
		#PyDISPLAY_DEVICE = EnumDisplayDevices(None, 1)
		#pprint.pprint((PyDISPLAY_DEVICE.Size, PyDISPLAY_DEVICE.DeviceName, PyDISPLAY_DEVICE.DeviceString, PyDISPLAY_DEVICE.StateFlags, PyDISPLAY_DEVICE.DeviceID, PyDISPLAY_DEVICE.DeviceKey))
		#PyDISPLAY_DEVICE = EnumDisplayDevices(None, 2)
		#pprint.pprint((PyDISPLAY_DEVICE.Size, PyDISPLAY_DEVICE.DeviceName, PyDISPLAY_DEVICE.DeviceString, PyDISPLAY_DEVICE.StateFlags, PyDISPLAY_DEVICE.DeviceID, PyDISPLAY_DEVICE.DeviceKey))

	__iter__ = EnumDisplayMonitors
	def __iter__2(self):
		for Item in self.EnumDisplayMonitors():
			yield Item
		#colItems = self.objSWbemServices.ExecQuery("SELECT * FROM Win32_DesktopMonitor")
		#for Item in colItems:
			#yield AudioEndpoint(pEndpoints.Item(i), self, self.PKEY_Device)
			#yield Item
		#	yield Display(Item)

	def __len__(self):
		return len(EnumDisplayMonitors())
		#colItems = self.objSWbemServices.ExecQuery("SELECT * FROM Win32_DesktopMonitor")
		#return len(colItems)

if __name__ == '__main__':
	import pprint

	displays = Displays()
	print(len(displays))
	print(displays)
	for display in displays:
		#print(display.getInfo())
		pprint.pprint(display.getInfo())
	#displays.EnumDisplayMonitors()
