#! /usr/bin/env python
# -*- coding: utf8 -*-

PLUGIN_FILES = []
MAIN_PLUGIN_FOLDER = ""

def main():
	print "creating plugin files and folders..."
	options = parse_command_line()[0]
	validate(options)
	create_files_and_folders(options)
	populate_plugin_files(options)
	print "Done!"
	return

def populate_plugin_files(options):
	populate_plugin_loader(options)
	populate_plugin_modules(options)
	return

def populate_plugin_loader(options):
	source_code = PLUGIN_LOADER_SOURCE_CODE.format(
		name=options.name,
		module="Trigger" if options.shortcut else "Manager",
		instance="__trigger" if options.shortcut else "__manager"
	)
	if options.language: source_code = add_language_to(source_code, options.language)
	loader_module = PLUGIN_FILES[0]
	create_file(loader_module, source_code)
	print "created %s" % loader_module
	return

def populate_plugin_modules(options):
	[process_plugin_modules(_file, options) for _file in PLUGIN_FILES[1:]]
	return

def process_plugin_modules(_file, options):
	module_handler = {
		"Signals.py": populate_signals_module,
		"Trigger.py": populate_trigger_module,
		"Manager.py": populate_manager_module,
		"Exceptions.py": populate_exceptions_module,
		"Utils.py": populate_utils_module,
		"%s.py" % options.name: populate_implementation_module,
	}
	from os.path import basename
	module_handler[basename(_file)](_file, options)
	return

def populate_signals_module(_file, options):
	create_file(_file, SIGNALS_MODULE_SOURCE_CODE)
	print "created %s" % _file
	return

def populate_exceptions_module(_file, options):
	create_file(_file, EXCEPTION_MODULE_SOURCE_CODE % options.name)
	print "created %s" % _file
	return

def populate_utils_module(_file, options):
	create_file(_file, UTILS_MODULE_SOURCE_CODE)
	print "created %s" % _file
	return

def populate_manager_module(_file, options):
	create_file(_file, MANAGER_MODULE_SOURCE_CODE.format(name=options.name))
	print "created %s" % _file
	return

def populate_implementation_module(_file, options):
	create_file(_file, IMPLEMENTATION_MODULE_SOURCE_CODE.format(Name=options.name, name=options.name.lower()))
	print "created %s" % _file
	return

def populate_trigger_module(_file, options):
	create_file(_file, TRIGGER_MODULE_SOURCE_CODE.format(name=options.name, shortcut=options.shortcut))
	print "created %s" % _file
	return

def add_language_to(source_code, language):
	language_line = "languages = ['%s',]" % language
	lines = source_code.splitlines()
	lines.insert(2, language_line)
	return "\n".join(lines)

def create_files_and_folders(options):
	plugins_folder = get_plugins_folder(options)
	create_folder(plugins_folder)
	create_init_module(plugins_folder)
	create_plugin_loader(plugins_folder, options)
	create_main_plugin_folder(plugins_folder, options)
	create_plugin_files(options)
	return

def create_plugin_files(options):
	plugin_files = ["Signals.py", "Manager.py", "Utils.py", "Exceptions.py", "%s.py" % options.name]
	if options.shortcut: plugin_files.append("Trigger.py")
	from os.path import join
	global PLUGIN_FILES
	for _file in plugin_files:
		_file = join(MAIN_PLUGIN_FOLDER, _file)
		create_file(_file)
		PLUGIN_FILES.append(_file)
	return

def create_plugin_loader(plugins_folder, options):
	plugin_loader = "Plugin%s.py" % options.name
	from os.path import join, exists
	_file = join(plugins_folder, plugin_loader)
	if exists(_file): fail("It seems the plugin already exists!")
	create_file(_file)
	global PLUGIN_FILES
	PLUGIN_FILES.append(_file)
	return

def create_main_plugin_folder(plugins_folder, options):
	from os.path import join, exists
	folder = join(plugins_folder, options.name)
	if exists(folder): fail("It seems the plugin already exists!")
	create_folder(folder)
	create_init_module(folder)
	global MAIN_PLUGIN_FOLDER
	MAIN_PLUGIN_FOLDER = folder
	return

def create_folder(folder):
	from os import error, makedirs
	from os.path import exists
	try:
		if exists(folder): return
		makedirs(folder)
	except error:
		fail("Failed to create %s!" % folder)
	return

def create_init_module(folder):
	from os.path import exists, join
	_file = join(folder, "__init__.py")
	if exists(_file): return
	create_file(_file)
	return

def create_file(_file, content=""):
	try:
		with open(_file, "w") as f:
			f.write(content)
	except IOError:
		fail("Failed to create %s" % _file)
	return

def get_plugins_folder(options):
	from os import environ
	from os.path import join
	config_folder = join(environ["HOME"], ".config", "scribes")
	plugin_type = "LanguagePlugins" if options.language else "GenericPlugins"
	return join(config_folder, plugin_type)

def validate(options):
	if not options.name: fail("--name is a required option")
	if not options.name.isalnum(): fail("Invalid option for --name")
	if options.language and not options.language.isalpha(): fail("Invalid option for --language")
	return

def fail(message):
	print message
	raise SystemExit

def parse_command_line():
	# options.name, options.author, options.shortcut, options.language
	from optparse import OptionParser
	usage = "usage: %prog [options]"
	parser = OptionParser(usage=usage)
	parser.add_option("-n", "--name",
		dest="name",
		help="Name of the plugin",
	)
	parser.add_option("-s", "--shortcut",
		dest="shortcut",
		help="Keyboard shortcut to activate the plugin [OPTIONAL]",
	)
	parser.add_option("-l", "--language",
		dest="language",
		help="Language the plugin affects [OPTIONAL]",
	)
	return parser.parse_args()

TRIGGER_MODULE_SOURCE_CODE = """from SCRIBES.SignalConnectionManager import SignalManager
from SCRIBES.TriggerManager import TriggerManager
from gettext import gettext as _

class Trigger(SignalManager, TriggerManager):

	def __init__(self, editor):
		SignalManager.__init__(self)
		TriggerManager.__init__(self, editor)
		self.__init_attributes(editor)
		self.connect(self.__trigger, "activate", self.__activate_cb)

	def __init_attributes(self, editor):
		self.__editor = editor
		self.__manager = None
		name, shortcut, description, category = (
			"activate-{name}", 
			"{shortcut}", 
			_("Activate {name}"), 
			_("Miscellaneous Operations") ##### <--- Update this!
		)
		self.__trigger = self.create_trigger(name, shortcut, description, category)
		return

	def destroy(self):
		self.disconnect()
		self.remove_triggers()
		if self.__manager: self.__manager.destroy()
		del self
		return False

	def __get_manager(self):
		if self.__manager: return self.__manager
		from Manager import Manager
		self.__manager = Manager(self.__editor)
		return self.__manager

	def __activate(self):
		self.__get_manager().activate()
		return False

	def __activate_cb(self, *args):
		from gobject import idle_add
		idle_add(self.__activate)
		return False

"""

IMPLEMENTATION_MODULE_SOURCE_CODE = """from SCRIBES.SignalConnectionManager import SignalManager

class {Name}(SignalManager):

	def __init__(self, manager, editor):
		SignalManager.__init__(self)
		self.__init_attributes(manager, editor)
		self.connect(manager, "activate", self.__activate_cb)
		self.connect(manager, "destroy", self.__destroy_cb)

	def __init_attributes(self, manager, editor):
		self.__manager = manager
		self.__editor = editor
		return

	def __{name}(self):
		message = "Witness the awesome power of {Name}!"
		title = "{Name} Power"
		# Update the message bar.
		self.__editor.update_message(message, "yes", 10)
		# Show a window containing message.
		self.__editor.show_info(title, message, self.__editor.window)
		return False

	def __activate_cb(self, *args):
		self.__{name}()
		return False

	def __destroy_cb(self, *args):
		self.disconnect()
		del self
		return False

"""

MANAGER_MODULE_SOURCE_CODE = """from Signals import Signal

class Manager(Signal):

	def __init__(self, editor):
		Signal.__init__(self)
		from {name} import {name}
		{name}(self, editor)

	def destroy(self):
		self.emit("destroy")
		del self
		return False

	def activate(self):
		self.emit("activate")
		return False

"""

EXCEPTION_MODULE_SOURCE_CODE = """# Custom exceptions belong in this module.

class %sError(Exception):
	pass

"""

UTILS_MODULE_SOURCE_CODE = """# Utility functions shared among modules belong here.

def answer_to_life():
	return 42

"""

SIGNALS_MODULE_SOURCE_CODE="""from SCRIBES.SIGNALS import GObject, TYPE_NONE, TYPE_PYOBJECT, SSIGNAL

class Signal(GObject):

	__gsignals__ = {
		"activate": (SSIGNAL, TYPE_NONE, ()),
		"destroy": (SSIGNAL, TYPE_NONE, ()),
		"dummy-signal": (SSIGNAL, TYPE_NONE, (TYPE_PYOBJECT,)),
	}

	def __init__(self):
		GObject.__init__(self)

"""

PLUGIN_LOADER_SOURCE_CODE = """name = "{name} Plugin"
authors = ["Your Name <youremailaddress@gmail.com>"]
version = 0.1
autoload = True
class_name = "{name}Plugin"
short_description = "A short description"
long_description = "A long description"

class {name}Plugin(object):

	def __init__(self, editor):
		self.__editor = editor
		self.{instance} = None

	def load(self):
		from {name}.{module} import {module}
		self.{instance} = {module}(self.__editor)
		return

	def unload(self):
		self.{instance}.destroy()
		return

"""

if __name__ == "__main__":
	main()

# scribesplugin --name=Foo --shortcut=<alt>BackSpace --language=python
