#!/usr/bin/env python
#
#   ANY-LICENSE V1.0
#   ----------------
#
#   You can use these files under any license approved by the
#   Open Source Initiative, preferrably one of the popular licenses,
#   as long as the license you choose is compatible to the
#   dependencies of these files.
#
#   See http://www.opensource.org/licenses/ for a list of
#   approved licenses.
#
#   Author:   Martin Furter <mf@borg.ch>
#   Modified: 2015
#
#--------------------------------------------------------------------------
#
# licensify.py
#
# A tool to add an ANY-LICENSE header to source code files.


LICENSE_PATH = "/home/mf/electronics/projects/projects"
LICENSE_NAME = "ANY-LICENSE"
AUTHOR = "Martin Furter <mf@borg.ch>"
PROJECT = ""

import datetime
import os
import os.path
import stat
import sys

comment_styles = {
	"C": (
		( "/*", "    ", "*/" ),
		( "c", "h", "C", "cpp", "hpp", "cs", "java" ),
	),
	"assembler": (
		( ";", ";   ", ";" ),
		( "S", ),
	),
	"python": (
		( "#", "#   ", "#" ),
		( "py", "sh" ),
	),
}

comment_file_extensions = {}

def init_file_extensions():
	for filetype in comment_styles.keys():
		style, exts = comment_styles[filetype]
		for ext in exts:
			comment_file_extensions[ext] = style

def guess_file_comment_style( filename ):
	if '.' in filename:
		filename = filename[filename.rindex('.')+1]
	if filename in comment_file_extensions:
		return comment_file_extensions[filename]
	#if recursive:
	#	# don't touch unknown files in recursive mode
	#	return ( None, None, None )
	#else:
	#	# explicitely specified files are treated like python or shell
	#	return ( "#", "#   ", "#" )
	return ( None, None, None )

class FileInfo:

	def __init__( self, filename ):
		try:
			st = os.lstat( filename )
			self.exists = True
			self.isreg = stat.S_ISREG( st.st_mode )
			self.isdir = stat.S_ISDIR( st.st_mode )
			self.isowner = st.st_uid == os.getuid()
			self.isgroup = st.st_gid == os.getgid()
			if self.isowner:
				self.readable = (st.st_mode & stat.S_IRUSR) != 0
				self.writable = (st.st_mode & stat.S_IWUSR) != 0
			elif self.isowner:
				self.readable = (st.st_mode & stat.S_IRGRP) != 0
				self.writable = (st.st_mode & stat.S_IWGRP) != 0
			else:
				self.readable = (st.st_mode & stat.S_IROTH) != 0
				self.writable = (st.st_mode & stat.S_IWOTH) != 0
		except:
			self.exists = False
			self.isreg = False
			self.isdir = False
			self.isowner = False
			self.isgroup = False


def read_lic( licensefile ):
	ifd = open( licensefile, "r" )
	lines = None
	for line in ifd:
		line = line.strip()
		if lines != None:
			lines.append( line )
		elif line.startswith( LICENSE_NAME ):
			lines = [ line ]
	ifd.close()
	while len(lines[-1]) == 0:
		del lines[-1]
	return lines

def check_license( filename ):
	ifd = open( filename, "r" )
	eol = None
	found = False
	n = 0
	for line in ifd:
		if eol == None:
			i = len(line)-1
			while i >= 0 and line[i] in ( '\r', '\n' ):
				i -= 1
			eol = line[i+1:]
		if line.strip().startswith( LICENSE_NAME ):
			found = True
			break
		n += 1
		if n > 20:
			break
	ifd.close()
	if eol == None:
		eol = "\n"
	return eol, found

def licensify_file( lic_lines, filename, recursive ):
	newfile = False
	info = FileInfo( filename )
	if info.exists:
		if info.isdir:
			if recursive:
				licensify_dir( lic_lines, filename, recursive )
				return
			else:
				print filename, "is a directory, use -r for recursive."
				return
		elif not info.isreg:
			print filename, "is not a regular file."
			return
		if not info.writable:
			print filename, "is not writable."
			return
		if not info.readable:
			print filename, "is not readable."
			return
		eol, found = check_license( filename )
		if found:
			print filename, "already contains %s." % LICENSE_NAME
			return
	else:
		ifd = open( "/dev/null" )
		eol = "\n"
		newfile = True
	pre, mid, suf = guess_file_comment_style( filename )
	if mid == None:
		return
	if newfile:
		print filename, "creating %s." % LICENSE_NAME
	else:
		print filename, "adding %s." % LICENSE_NAME
		origname = filename + ".orig"
		os.rename( filename, origname )
		ifd = open( origname, "r" )
	ofd = open( filename, "wb" )
	ofd.write( pre + eol )
	for line in lic_lines:
		line = mid + line
		ofd.write( line.rstrip() + eol )
	ofd.write( mid.rstrip() + eol )
	ofd.write( "%sAuthor:   %s%s" % ( mid, AUTHOR, eol ) )
	ofd.write( "%sProject:  %s%s" % ( mid, PROJECT, eol ) )
	ofd.write( "%sModified: %s%s" % ( mid, YEAR, eol ) )
	ofd.write( suf + eol + eol )
	for line in ifd:
		ofd.write( line )
	ifd.close()
	ofd.close()

def licensify_dir( lic_lines, filename, recursive ):
	for dirname, subdirs, filenames in os.walk( filename ):
		for filename in filenames:
			filename = os.path.join( dirname, filename )
			licensify_file( lic_lines, filename, recursive )

def licensify( licensefile, filenames ):
	global YEAR, PROJECT, AUTHOR
	YEAR = "%d" % datetime.date.today().year
	init_file_extensions()
	lic_lines = read_lic( licensefile )
	i = 0
	l = len(filenames)
	recursive = False
	while i < l:
		filename = filenames[i]
		if filename.startswith( "-" ):
			i += 1
			if i >= l:
				print "missing argument for option '%s'." % filename
			if filename == "-p":
				PROJECT = filenames[i]
			elif filename == "-a":
				AUTHOR = filenames[i]
			elif filename == "-r":
				recursive = True
				i -= 1
			else:
				print "unknown option '%s'." % filename
		else:
			licensify_file( lic_lines, filename, recursive )
		i += 1

if __name__ == "__main__":
	if len(sys.argv) <= 1:
		print "usage: licensify.py [-a author] [-p project] [-r dirs...] files..."
	else:
		licensify( os.path.join( LICENSE_PATH, "LICENSE.txt" ), sys.argv[1:] )

