# Copyright (c) 2012 Web Notes Technologies Pvt Ltd (http://erpnext.com)
# 
# MIT License (MIT)
# 
# Permission is hereby granted, free of charge, to any person obtaining a 
# copy of this software and associated documentation files (the "Software"), 
# to deal in the Software without restriction, including without limitation 
# the rights to use, copy, modify, merge, publish, distribute, sublicense, 
# and/or sell copies of the Software, and to permit persons to whom the 
# Software is furnished to do so, subject to the following conditions:
# 
# The above copyright notice and this permission notice shall be included in 
# all copies or substantial portions of the Software.
# 
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 
# INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 
# PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 
# CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE 
# OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# 

from __future__ import unicode_literals
from webnotes.utils.minify import JavascriptMinify

import os, sys, webnotes

class Bundle:
	"""
		Concatenate, compress and mix (if required) js+css files from build.json
	"""
	no_compress = False
	timestamps = {}
	path = '.'
	
	def concat(self, filelist, outfile=None):	
		"""
			Concat css and js files into a bundle
		"""
		from cStringIO import StringIO
		
		out_type = outfile and outfile.split('.')[-1] or 'js'
		
		outtxt = ''
		for f in filelist:
			suffix = None
			if ':' in f:
				f, suffix = f.split(':')
			
			if not os.path.exists(f) or os.path.isdir(f):
				continue
			
			self.timestamps[f] = os.path.getmtime(f)
			
			# get datas
			try:
				with open(f, 'r') as infile:			
					# get file type
					ftype = f.split('.')[-1] 

					data = unicode(infile.read(), 'utf-8', errors='ignore')

				outtxt += ('\n/*\n *\t%s\n */' % f)
					
				# append
				if suffix=='concat' or out_type != 'js' or self.no_compress or ('.min.' in f):
					outtxt += '\n' + data + '\n'
				else:
					jsm = JavascriptMinify()
					tmpin = StringIO(data.encode('utf-8'))
					tmpout = StringIO()
					
					jsm.minify(tmpin, tmpout)
					tmpmin = unicode(tmpout.getvalue() or '', 'utf-8')
					tmpmin.strip('\n')
					outtxt += tmpmin
			except Exception, e:
				print "--Error in:" + f + "--"
				print webnotes.getTraceback()
						
		with open(outfile, 'w') as f:
			f.write(outtxt.encode("utf-8"))
		
		print "Wrote %s - %sk" % (outfile, str(int(os.path.getsize(outfile)/1024)))

	def dirty(self):
		"""check if build files are dirty"""

		self.make_build_data()
		for builddict in self.bdata:
			for f in self.get_infiles(builddict):

				if ':' in f:
					f, suffix = f.split(':')

				if not os.path.exists(f) or os.path.isdir(f):
					continue
				
				
				if os.path.getmtime(f) != self.timestamps.get(f):
					print f + ' dirty'
					return True
		else:
			return False

	def make(self):
		"""Build (stitch + compress) the file defined in build.json"""
						
		print "Building js and css files..."
		self.make_build_data()	
		for builddict in self.bdata:
			outfile = builddict.keys()[0]
			infiles = self.get_infiles(builddict)
			
			self.concat(infiles, os.path.relpath(os.path.join(self.path, outfile), os.curdir))
	
		self.reset_app_html()
		
	def reset_app_html(self):
		import webnotes

		if os.path.exists("public/app.html"):
			os.remove("public/app.html")
					
		with open('lib/public/html/app.html', 'r') as app_html:
			data = app_html.read()
			data = data % {"_version_number": webnotes.generate_hash() }
			with open('public/app.html', 'w') as new_app_html:
				new_app_html.write(data)
	
	def get_infiles(self, builddict):
		"""make list of files to merge"""
		outfile = builddict.keys()[0]
		infiles = builddict[outfile]
		
		# add app js and css to the list
		if outfile in self.appfiles:
			for f in self.appfiles[outfile]:
				if f not in infiles:
					infiles.append(f)
		
		fl = []
		for f in infiles:
			## load files from directory
			if f.endswith('/'):
				# add init js first
				fl += [os.path.relpath(os.path.join(f, 'init.js'), os.curdir)]
				
				# files other than init.js and beginning with "_"
				fl += [os.path.relpath(os.path.join(f, tmp), os.curdir) \
					for tmp in os.listdir(f) if (tmp != 'init.js' and not tmp.startswith('_'))]
			else:
				fl.append(os.path.relpath(os.path.join(self.path, f), os.curdir))
				
		return fl
			
	def make_build_data(self):
		"""merge build.json and lib/build.json"""
		# framework js and css files
		with open('lib/public/build.json', 'r') as bfile:
			bdata = eval(bfile.read())
		
		# app js and css files
		if os.path.exists('app/public/build.json'):
			with open('app/public/build.json', 'r') as bfile:
				appfiles = eval(bfile.read())
		else:
			appfiles = {}
		
		# add additional app files in bdata
		buildfile_list = [builddict.keys()[0] for builddict in bdata]
		for f in appfiles:
			if f not in buildfile_list:
				bdata.append({f: appfiles[f]})
		
		self.appfiles = appfiles
		self.bdata = bdata

def check_public():
	from webnotes.install_lib.setup_public_folder import make
	make()

def bundle(no_compress, cms_make=True):
	"""concat / minify js files"""
	# build js files
	check_public()
	bundle = Bundle()
	bundle.no_compress = no_compress
	bundle.make()

	if cms_make:
		# build index.html and app.html
		from website.helpers.make_web_include_files import make
		make()
			
def watch(no_compress):
	"""watch and rebuild if necessary"""
	import time
	bundle = Bundle()
	bundle.no_compress = no_compress

	while True:
		if bundle.dirty():
			bundle.make()
		
		time.sleep(3)
			
