# -*- coding: utf-8 -*-

# Copyright (C) 2006 by Igor E. Novikov
#
# This library is covered by GNU Library General Public License.
# For more info see COPYRIGHTS file in sK1 root directory.

import os, sys
from xml.sax import handler

from app.events import connector
from const import CHANGED
from app.utils.os_utils import gethome, create_directory
from app.utils import output 
from app import Point, PointType

class Configurator:
	"""Configuration class configs sK1 and loads preferences at start up."""
	def __init__(self, master=None, base_dir='~', cnf={}, **kw):

		self.name = 'UniConvertor'
		self.sk_command = 'uniconvertor'
		
		self.sk_dir = base_dir
		self.sk_share_dir = os.path.join(self.sk_dir,'share')
		self.sk_icc = os.path.join(self.sk_share_dir,'icc')
		self.sk_fonts = os.path.join(self.sk_share_dir,'fonts')
		self.sk_ps = os.path.join(self.sk_share_dir,'ps_templates')
		
		self.user_home_dir = gethome()
		self.user_config_dir = os.path.join(self.user_home_dir,'.uniconvertor')
		self.restore_theme = 0
		self.user_icc = os.path.join(self.user_config_dir,'icc')
		self.user_fonts = os.path.join(self.user_config_dir,'fonts')
		self.user_ps = os.path.join(self.user_config_dir,'ps_templates')
		
		self.plugin_path = []  # Directories where sK1 searches for plugins. The expanded plugin_dir is appended to this
		self.filters_dir = os.path.join(self.sk_dir,'app/plugins/Filters/')  # Subdirectory for i/o filters
		#self.plugins_dir = os.path.join(self.sk_dir,'app/plugins/Objects/')  # Subdirectory for plugins
		#self.plugin_path.append(self.plugins_dir)
		self.plugin_path.append(self.filters_dir)

		self.user_preferences_file = os.path.join(self.user_config_dir, 'preferences.xml')
		
		#print 'Self testing\n=========================================='
		#self.check_sk_dir()
		#self.check_user_config()
		self.preferences = Preferences()
		#self.preferences.load(self.user_preferences_file)
		#print '=========================================='
		if self.restore_theme:
			self.preferences.active_theme = 'Plastik'

		#===============DEPRECATED VARIABLES===============
		self.font_path = [self.user_config_dir]  # Directories where pfa/pfb files are located. The expanded fontmetric_dir is appended to this.
		self.sketch_dir = base_dir  # The directory where sketch and its modules are found. Set automagically from __init__.py of the Sketch package
		self.fontmetric_dir = self.user_fonts  # Subdirectory for the font metrics. On startup it is expanded to an absolute pathname.
		self.postscript_prolog = os.path.join(self.sk_dir, 'share/ps_templates/sk1-proc.ps')  # PostScript Prolog.
		
		self.small_font = '-*-dejavu sans-medium-r-*-*-8-*-*-*-*-*-*'
		self.normal_font = '-*-dejavu sans-medium-r-*-*-10-*-*-*-*-*-*'		
		#============================================
		
	def save_user_preferences(self):
		self.preferences.save(self.user_preferences_file)
		
	def add_options(self, root):
		root.option_readfile(self.tk_defaults, 'startupFile')
		
	#def add_program_default(self,key, value):
		#setattr(configurato.ProgramDefaults, key, value)
	
	def get_preference(self,key, default):
		if hasattr(self.preferences, key):
			return getattr(self.preferences, key)
		return default
		
	def add_mru_file(self, filename):
		if not filename:
			return
		mru_list = self.preferences.mru_files
		if filename in mru_list:
			mru_list.remove(filename)
		mru_list.insert(0, filename)
		self.preferences.mru_files = mru_list[:4]
	
	def remove_mru_file(self, filename):
		if not filename:
			return
		mru_list = self.preferences.mru_files
		if filename in mru_list:
			mru_list.remove(filename)
			if len(mru_list) < 4:
				mru_list = mru_list + ['', '', '', '']
			self.preferences.mru_files = mru_list[:4]
		
	def check_sk_dir(self):		
		#print 'sK1 directories test...         ',
		result = True		
		dirs = (self.sk_share_dir, self.sk_icc, self.sk_ps)
		for dir in dirs:
			if not os.path.isdir(dir): result = False			
		if not result:
			#print '[',output.red('CRASH'),']'
			print output.yellow('sK1 installation is corrupted. Please check sK1 directories or reinstall sK1!')
			sys.exit(1)
		#else:
			#print '[',output.green('OK'),']'
			
	def check_user_config(self):
		#print 'sK1 user config test...         ',
		result = True
		if not os.path.isdir(self.user_config_dir):
			result = False
			try:
				os.mkdir(self.user_config_dir, 0777)
			except (IOError, os.error), value:
				#print '[',output.red('CRASH'),']'
				sys.stderr('cannot write preferences into %s.' % user_config_dir)
				sys.exit(1)		
		if not os.path.isdir(self.user_icc):
			result = False
			os.system("cp -r "+self.sk_icc+" "+self.user_icc)
		if not os.path.isdir(self.user_fonts):
			result = False
			os.system("cp -r "+self.sk_fonts+" "+self.user_fonts)
		if not os.path.isdir(self.user_ps):
			result = False
			os.system("cp -r "+self.sk_ps+" "+self.user_ps)
			
		#if not result:
			#print '[',output.yellow('FIXED'),']'
		#else:
			#print '[',output.green('OK'),']'
		
		
class Preferences(connector.Publisher):

	def __setattr__(self, attr, value):
		if not hasattr(self, attr) or getattr(self, attr) != value:
			self.__dict__[attr] = value
			self.issue(CHANGED, attr, value)
			
	def load(self, filename=None):
		import xml.sax
		from xml.sax.xmlreader import InputSource
		
		content_handler = XMLPrefReader(pref=self)
		error_handler = ErrorHandler()
		entity_resolver = EntityResolver()
		dtd_handler = DTDHandler()
		try:
			input = open(filename, "r")
			input_source = InputSource()
			input_source.setByteStream(input)
			xml_reader = xml.sax.make_parser()
			xml_reader.setContentHandler(content_handler)
			xml_reader.setErrorHandler(error_handler)
			xml_reader.setEntityResolver(entity_resolver)
			xml_reader.setDTDHandler(dtd_handler)
			xml_reader.parse(input_source)
			input.close
		except:
			pass

	def save(self, filename=None):
		if len(self.__dict__) == 0 or filename == None:
			return
		from xml.sax.saxutils import XMLGenerator

		try:
			file = open(filename, 'w')
		except (IOError, os.error), value:
			import sys
			sys.stderr('cannot write preferences into %s: %s'% (`filename`, value[1]))
			return
	
		writer = XMLGenerator(out=file,encoding=self.system_encoding)
		writer.startDocument()	
		defaults = Preferences.__dict__
		items = self.__dict__.items()
		items.sort()
		writer.startElement('preferences',{})
		writer.characters('\n')
		for key, value in items:
			if defaults.has_key(key) and defaults[key] == value:
				continue
			writer.characters('	')
			writer.startElement('%s' % key,{})
			if type(value) == PointType:
				to_write= '(%g, %g)' % tuple(value)
				writer.characters('Point%s' % to_write)
			else:
				writer.characters('%s' % `value`)
			writer.endElement('%s' % key)
			writer.characters('\n')
		writer.endElement('preferences')
		writer.endDocument()
		file.close		
	
	#============== sK1 PREFERENCES ===================

	undo_limit = None	#how many undo steps sketch remembers. None means unlimited.
	system_encoding = 'utf-8'	# default encoding for sK1 (GUI uses utf-8 only)
	
	#The initial grid geometry for a new document. It must be a tuple of the form (ORIG_X, ORIG_Y, WIDTH_X, WIDTH_Y). WIDTH_X and WIDTH_Y are 
	#the horizontal and the vertical distance between points of the grid, (ORIG_X, ORIG_X) is one point of the grid. These coordinates are given in Point
	grid_geometry = (0, 0, 2.83465, 2.83465)
	
	#If the grid should be visible in a new document, set grid_visible to a true value
	grid_visible = 0
	
	#The grid color of a new document as a tuple of RGB values in the range 0..1. E.g. (0, 0, 1) for blue
	grid_color = ('RGB', 0, 0, 1)
	
	#The outline color of a new GuideLayer as a tuple of RGB values in the range 0..1.
	guide_color = ('RGB', 0, 0.3, 1)
	layer_color = ('RGB', 0.196, 0.314, 0.635)
	
	#When objects are duplicated, the new copies are translated by duplicate_offset, given in document coordiates
	duplicate_offset = (10, 10)
	
	#The default unit used in various places. Supported values: 'pt', 'in', 'cm', 'mm'
	default_unit = 'mm'
	
	poslabel_sets_default_unit = 1
	
	#How many steps to draw in a gradient pattern
	gradient_steps_editor = 30
	gradient_steps_print = 50
	
	#If the text on the screen becomes smaller than greek_threshold, don't render a font, but draw little lines instead. XXX see comments in graphics.py
	greek_threshold = 5
	
	#If the metrics file for a font can't be found or if a requested font is not known at all, the (metrics of) fallback_font is used	
	fallback_font = 'Slim'
	
	#When snapping is active, coordinates specified with the mouse are snapped to the nearest `special' point (e.g. a grid point) if that is nearer than 
	#max_snap_distance pixels. (Thus, this length is given in window (pixel-) coordinates).
	max_snap_distance = 30
	
	#If true and snapping is active, the current position displayed in the status bar is the position the mouse position would be snapped to.
	snap_current_pos = 1
	
	#If true, change the cursor when above a selected object or a guide line
	active_cursor = 1
	
	#Icons
	color_icons = 1
	
	#List of most recently used files.
	mru_files = ['', '', '', '', '']
	
	viewport_ring_length = 10
	
	#The standard palette. If this is a relative pathname it is
	#interpreted relative to std_res_dir.
	palette = 'standard.spl'	
	unipalette = 'CMYK standart.skp'
	arrows = 'standard.arrow'
	dashes = 'standard.dashes'
	pattern = 'pattern.ppm'
	
	pattern_dir = ''
	image_dir = ''
	
	set_default_properties = 1		# whether the apply button in the property dialogs sets the default properties for new objects. (   1 - do it, but ask; 0 - don't)
	sample_text = 'Text'	#	Font dialog sample text. Can be changed by simply editing it in the font dialog.
	default_paper_format = 'A4'	#Default paper format for new documents and documents read from a files that don't specify a paper format. This should be one of the formats defined in papersize.py.
	default_page_orientation = 0	#Default page orientation. Portrait = 0, Landscape = 1. Other values are silenty ignored.
	
	#Screen resolution in pixel per point. Used by the canvas to convert document coordinates to screen coordinates for a zoom factor of 100%
	#None means to compute it from information obtained from the X-Server (ScreenWidth and ScreenMMWidth). 1.0 means 72 pixels per inch.
	screen_resolution = 1.0
	
	#If true, switch to selection mode after drawing an object. Stay in creation mode otherwise.
	creation_is_temporary = 0

	autoscroll_interval = 1   # ms, 0 disables auto scrolling
	autoscroll_amount = .5	# no. of scroll units

	#Ask user for confirmation if the memory size of an image is larger than huge_image_size (measured in bytes) (unused at the moment)
	huge_image_size = 1 << 20
	
	#Default resolution in pixels/inch for a new raster image that doesn't specify it itself. (not implemented yet)
	default_image_resolution = 72

	#The resoulution in pixel/inch of the preview image sK1 renders for preview. (using gs). Leave this at 72 for now.
	eps_preview_resolution = 72
	
	#Whether to print internal warning messages. Useful for debugging.
	print_internal_warnings = 1
	
	#print additional messages. these are usually only interesting for development purposes.
	print_debug_messages = 0
	
	#Howto report warnings to the user:   'dialog'	popup a dialog box;   'stderr'	write the message to stderr
	warn_method = 'dialog'
	
	#whether to show the special menu. The special menu contains some commands that provide access to sketch internals and new, experimental features.
	show_special_menu = 0	
	
	show_advanced_snap_commands = 0		#whether to show advanced snapping options.
	activate_tooltips = 1		#Use Tooltips. 
	tooltip_delay = 500	#Delay for tooltips in milliseconds

	window_title_template ='%(appname)s - [%(docname)s]'
	
	panel_use_coordinates = 1		#	If true, use the saved coordinates when opening a panel
	panel_correct_wm = 1	#	If true, try to compensate for the coordinate changes the window manager introduces by reparenting.
	blend_panel_default_steps = 10	
	print_destination = 'printer'	#	Default print destination. 'file' for file, 'printer' for printer	
	print_directory = '~'		#	default directory for printing to file
	menu_tearoff_fix = 1		#	Menus
	
	style = 'Plastik'
	color_theme = 'System'
	#color_theme = 'UbuntuLooks'
	icons='CrystalSVG'
	small_font='Arial 8'
	normal_font='Arial 10'
	large_font='Arial 15'
	
	#---------Color managment---------
	default_rgb_profile='sRGB.icm'
	default_cmyk_profile='GenericCMYK.icm'
	default_monitor_profile='sRGB.icm'
	
	user_rgb_profile=0
	user_cmyk_profile=0
	user_monitor_profile=0
	
	printer_intent=0
	monitor_intent=0
	
	use_cms=0
	simulate_printer=0
	#------------------------------------
	forceCMYK=0
	forceRGB=0
	#------------------------------------

	#RULER data
	ruler_min_tick_step = 4
	ruler_min_text_step = 33
	ruler_max_text_step = 100
	
	ruler_text_color = 'black'
	ruler_tick_color = 'black'
	ruler_color = '#F9F9FC'	#Rulers background color
	
	color_cube = (6, 6, 6, 20)		#	For PseudoColor displays.	
	reduce_color_flashing = 1
	
	#	Screen Gamma. (leave this at 1.0 for now)
	#screen_gamma = 1.0
	
	#
	#	Cairo data
	#
	cairo_enabled=0
	alpha_channel_enabled=0
	
	#
	#	Bezier Objects
	#
	
	#	Whether the first click-drag-release in the PolyLine creator
	#	defines the start and end of the first line segment or just the
	#	start point.
	polyline_create_line_with_first_cklick = 1
	topmost_is_mask = 1	#	Mask Group
	default_font = 'Slim'	#   The name of the font used for new text-objects
	
	#	If true, try to unload some of the import filter modules after
	#	use. Only filters marked as unloadable in their config file are
	#	affected.
	unload_import_filters = 1	
	
	handle_jump= 1  #Handle jump to manipulate objects by keyboard arrows (mm)	
	
	editor_line_width = 1		#   The line width for the outlines during a drag.
	
	#   Load these standard scripts at runtime in interactive mode. This
	#   is really just a list of module names that are passed to
	#   __import__, but don't count on it.
	standard_scripts = ["app.scripts.export_raster", "app.scripts.simple_separation",
						"app.scripts.spread", "app.scripts.reload_image",
						"app.scripts.create_star", "app.scripts.create_star_outline",
						"app.scripts.create_spiral", "app.scripts.read_gimp_path",]
		
class XMLPrefReader(handler.ContentHandler):
	"""Handler for xml file reading"""
	def __init__(self, pref=None):
		self.key = None
		self.value = None
		self.pref = pref

	def startElement(self, name, attrs):
		self.key = name

	def endElement(self, name):
		if name!='preferences':
			code=compile('self.value='+self.value,'<string>','exec')
			exec code
			self.pref.__dict__[self.key] = self.value

	def characters(self, data):
		self.value = data

class ErrorHandler(handler.ErrorHandler): pass
class EntityResolver(handler.EntityResolver): pass
class DTDHandler(handler.DTDHandler): pass	
		
		
		
		
		
		
		
		
