# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# MIT License. See license.txt 

from __future__ import unicode_literals
"""
	Execute Patch Files

	To run directly
	
	python lib/wnf.py patch patch1, patch2 etc
	python lib/wnf.py patch -f patch1, patch2 etc
	
	where patch1, patch2 is module name
"""
import webnotes

class PatchError(Exception): pass

def run_all(patch_list=None):
	"""run all pending patches"""
	if webnotes.conn.table_exists("__PatchLog"):
		executed = [p[0] for p in webnotes.conn.sql("""select patch from `__PatchLog`""")]	
	else:
		executed = [p[0] for p in webnotes.conn.sql("""select patch from `tabPatch Log`""")]
	import patches.patch_list
	for patch in (patch_list or patches.patch_list.patch_list):
		if patch not in executed:
			if not run_single(patchmodule = patch):
				log(patch + ': failed: STOPPED')
				raise PatchError(patch)

def reload_doc(args):
	import webnotes.modules
	run_single(method = webnotes.modules.reload_doc, methodargs = args)

def run_single(patchmodule=None, method=None, methodargs=None, force=False):
	from webnotes import conf
	
	# don't write txt files
	conf.developer_mode = 0
	
	if force or method or not executed(patchmodule):
		return execute_patch(patchmodule, method, methodargs)
	else:
		return True
		
def execute_patch(patchmodule, method=None, methodargs=None):
	"""execute the patch"""
	success = False
	block_user(True)
	webnotes.conn.begin()
	try:
		log('Executing %s in %s' % (patchmodule or str(methodargs), webnotes.conn.cur_db_name))
		if patchmodule:
			if patchmodule.startswith("execute:"):
				exec patchmodule.split("execute:")[1] in globals()
			else:
				webnotes.get_method(patchmodule + ".execute")()
			update_patch_log(patchmodule)
		elif method:
			method(**methodargs)
			
		webnotes.conn.commit()
		success = True
	except Exception, e:
		webnotes.conn.rollback()
		tb = webnotes.getTraceback()
		log(tb)
		import os
		if webnotes.request:
			add_to_patch_log(tb)

	block_user(False)
	if success:
		log('Success')
	return success

def add_to_patch_log(tb):
	"""add error log to patches/patch.log"""
	import conf, os
	# TODO use get_site_base_path
	with open(os.path.join(os.path.dirname(conf.__file__), 'app', 'patches','patch.log'),'a') as patchlog:
		patchlog.write('\n\n' + tb)
	
def update_patch_log(patchmodule):
	"""update patch_file in patch log"""	
	if webnotes.conn.table_exists("__PatchLog"):
		webnotes.conn.sql("""INSERT INTO `__PatchLog` VALUES (%s, now())""", \
			patchmodule)
	else:
		webnotes.doc({"doctype": "Patch Log", "patch": patchmodule}).insert()

def executed(patchmodule):
	"""return True if is executed"""
	if webnotes.conn.table_exists("__PatchLog"):
		done = webnotes.conn.sql("""select patch from __PatchLog where patch=%s""", patchmodule)
	else:
		done = webnotes.conn.get_value("Patch Log", {"patch": patchmodule})
	if done:
		print "Patch %s executed in %s" % (patchmodule, webnotes.conn.cur_db_name)
	return done
	
def block_user(block):
	"""stop/start execution till patch is run"""
	webnotes.conn.begin()
	msg = "Patches are being executed in the system. Please try again in a few moments."
	webnotes.conn.set_global('__session_status', block and 'stop' or None)
	webnotes.conn.set_global('__session_status_message', block and msg or None)
	webnotes.conn.commit()

def setup():
	webnotes.conn.sql("""CREATE TABLE IF NOT EXISTS `__PatchLog` (
			patch TEXT, applied_on DATETIME) engine=InnoDB""")
		
def log(msg):
	if getattr(webnotes.local, "patch_log_list", None) is None:
		webnotes.local.patch_log_list = []
	
	webnotes.local.patch_log_list.append(msg)
