#!/usr/bin/python
# -*- coding: utf-8 -*-

""" 
Set ICC profiles and load calibration curves for all configured display devices

"""

import sys

if sys.platform == "win32":
	# Setup sys.path for running frozen
	# i.e. add C:\Program Files\dispcalGUI\lib\library.zip
	libpath = "\\".join(sys.executable.replace("/", "\\").split("\\")[:-1]) + "\\library.zip"
	sys.path.insert(0, libpath)

import os

if sys.platform == "win32":
	if os.path.isfile(libpath):
		sys.frozen = True

parent_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

if not getattr(sys, "frozen", False):
	# Setup sys.path if running from source
	if os.path.exists(os.path.join(parent_dir, "dispcalGUI", "__init__.py")):
		sys.path.insert(0, parent_dir)

from dispcalGUI import config, localization as lang

if getattr(sys, "frozen", False):
	# Add script parent directory to data directories if running frozen
	config.data_dirs.insert(0, parent_dir)
	
config.initcfg()
if not config.getcfg("profile.load_on_login"):
	# Early exit incase profile loading has been disabled
	sys.exit()

from dispcalGUI.config import geticon
from dispcalGUI.log import safe_print
from dispcalGUI.util_os import which
from dispcalGUI.worker import Worker, get_argyll_util
from dispcalGUI.wxwindows import InfoDialog, wx


worker = Worker()


def apply_profiles():
	errors = []
	
	safe_print("=" * 80)
	safe_print(lang.getstr("calibration.loading_from_display_profile"))

	# dispwin sets the _ICC_PROFILE(_n) root window atom, per-output xrandr 
	# _ICC_PROFILE property (if xrandr is working) and loads the vcgt for the 
	# requested screen (ucmm backend using color.jcnf), and has to be called 
	# multiple times to setup multiple screens.
	#
	# If there is no profile configured in ucmm for the requested screen (or 
	# ucmm support has been removed, like in the Argyll CMS versions shipped by 
	# recent Fedora releases), it falls back to a possibly existing per-output 
	# xrandr _ICC_PROFILE property (if xrandr is working) or _ICC_PROFILE(_n) 
	# root window atom.
	dispwin = get_argyll_util("dispwin")
	if dispwin:
		worker.enumerate_displays_and_ports(silent=True, check_lut_access=False)
	else:
		errors.append(lang.getstr("argyll.util.not_found", "dispwin"))

	if sys.platform != "win32":
		# gcm-apply sets the _ICC_PROFILE root window atom for the first screen, 
		# per-output xrandr _ICC_PROFILE properties (if xrandr is working) and 
		# loads the vcgt for all configured screens (device-profiles.conf)
		gcm_apply = which("gcm-apply")
		if gcm_apply:
			worker.exec_cmd(gcm_apply, capture_output=True, skip_scripts=True,
							silent=False)

		# oyranos-monitor sets _ICC_PROFILE(_n) root window atoms (oyranos 
		# db backend) and loads the vcgt for all configured screens when 
		# xcalib is installed
		oyranos_monitor = which("oyranos-monitor")

	for i, display in enumerate([display.replace("[PRIMARY]", 
												 lang.getstr("display.primary")) 
								 for display in worker.displays]):
		# Load profile and set vcgt
		if (sys.platform != "win32" and oyranos_monitor and 
			worker.check_display_conf_oy_compat(i + 1)):
			worker.exec_cmd(oyranos_monitor, 
							["-x", str(worker.display_rects[i][0]), 
							 "-y", str(worker.display_rects[i][1])], 
							capture_output=True, skip_scripts=True, 
							silent=False)
		if dispwin:
			profile_arg = worker.get_dispwin_display_profile_argument(i)
			worker.exec_cmd(dispwin, ["-v", "-d%i" % (i + 1), "-c", 
									  profile_arg], 
							capture_output=True, skip_scripts=True, 
							silent=False)
			errortxt = "\n".join(worker.errors).strip()
			if errortxt and (not "using linear" in errortxt or 
							 len(errortxt.split("\n")) > 1):
				if "Failed to get the displays current ICC profile" in errortxt:
					# Maybe just not configured
					continue
				elif sys.platform == "win32" or \
				   "Failed to set VideoLUT" in errortxt or \
				   "We don't have access to the VideoLUT" in errortxt:
					errstr = lang.getstr("calibration.load_error")
				else:
					errstr = lang.getstr("profile.load_error")
				errors.append(": ".join([display, errstr]))
				continue
			# Verify the calibration was actually loaded
			worker.exec_cmd(dispwin, ["-v", "-d%i" % (i + 1), "-V",
									  profile_arg], 
							capture_output=True, skip_scripts=True, 
							silent=False)
			# The 'NOT loaded' message goes to stdout!
			# Other errors go to stderr
			errortxt = "\n".join(worker.errors + worker.output).strip()
			if "NOT loaded" in errortxt or \
			   "We don't have access to the VideoLUT" in errortxt:
				errors.append(": ".join([display, 
										lang.getstr("calibration.load_error")]))

	return errors


def apply_profiles_and_warn_on_error():
	errors = apply_profiles()
	if errors:
		InfoDialog(None, msg="\n".join(errors), 
				   ok=lang.getstr("ok"), 
				   bitmap=geticon(32, "dialog-error"))


def main():
	lang.init()
	app = wx.App(0)
	apply_profiles_and_warn_on_error()


if __name__ == "__main__":
	main()
