###
# ownCloud
#
# @author Bernhard Posselt
# Copyright (c) 2012 - Bernhard Posselt <nukeawhale@gmail.com>
#
# This file is licensed under the Affero General Public License version 3 or later.
# See the COPYING-README file
#
###

# imports
fs = require 'fs'
util = require 'util'
{exec} = require 'child_process'

try
	coffee = require 'coffee-script'
catch err
	util.log 'Please export your node path by entering: export NODE_PATH=/usr/lib/node_modules'
	process.exit(1)


### Configuration ###

# path that contains your coffee files relative to this script
sourceDirectory = __dirname

# path and name of the compiled js file relative to this script
compileToFile = '../js/app.js'

# These files will be compiled in order before any other files
compileFirst = [
	'lib/owncloud.coffee'
	'app.coffee'
]


### Functions ###

# Recursively searches for coffee files
# @param string path: the path to search for coffee files
# @param array coffeeFiles: a hashmap with existing files that will be ignored
getCoffeeFiles = (path, coffeeFiles) ->
	entries = fs.readdirSync(path)

	for entry in entries
		do (entry) ->
			entryPath = path + '/' + entry
			entryStats = fs.statSync(entryPath)

			if entryStats.isFile()
				if entryPath.indexOf('.coffee') > 1 and coffeeFiles[entryPath] == undefined
					coffeeFiles[entryPath] = true

			else if entryStats.isDirectory()
				getCoffeeFiles(entryPath, coffeeFiles)


# returns an array with all coffeefiles in order
getOrderedCoffeeFiles = (directory) ->
	unorderedFiles = {}
	getCoffeeFiles(directory, unorderedFiles)

	# create data structures for quick prioritized files lookup
	orderedFilesHashMap = {}
	for file in compileFirst
		filePath = directory + '/' + file
		orderedFilesHashMap[filePath] = true

	# prepend prioritized files
	orderedFiles = []
	for file in compileFirst
		orderedFiles.push(directory + '/' + file)

	# order files
	for file, exists of unorderedFiles
		if orderedFilesHashMap[file] == undefined
			orderedFiles.push(file)

	util.log "#{orderedFiles.length} coffee files found."
	return orderedFiles


# compiles an array with file content to a js file
compile = (content, toFile) ->
	compiled = []
	compileError = false
	for code in content
		util.log 'Compiling ' + code[0]
		try
			compiled.push(coffee.compile(code[1]))
		catch error
			util.log error
			compileError = true
			break

	if not compileError
		fs.writeFile toFile, compiled.join('\n\n'), 'utf8', (error) ->
			if error
				throw error


# register a callback on an array of files and remove already bound ones
watchFiles = (files, callback) ->
	files = {}
	getCoffeeFiles(sourceDirectory, files)
	for file, exists of files
		fs.unwatchFile(file)
		fs.watchFile(file, callback)


### Tasks ###

task 'watch', 'Watch and rebuild on changes', ->
	invoke 'build'
	util.log "Watching for changes"

	watchFiles getOrderedCoffeeFiles(sourceDirectory), ->
		invoke 'build'

	fs.watchFile sourceDirectory, (current, previous) ->
		watchFiles getOrderedCoffeeFiles(sourceDirectory), ->
			invoke 'build'


task 'build', 'Build and compress CoffeeScript into single JavaScript file', ->
	files = getOrderedCoffeeFiles(sourceDirectory)
	content = new Array(files.length)
	remaining = files.length
	counter = -1

	# read out content of files and compile them afterwards
	for file in files then do (file) ->
		counter += 1
		do (counter) ->
			fs.readFile file, 'utf8', (error, fileContent) ->
				if error
					throw error

				content[counter] = [file, fileContent]

				remaining -= 1
				if remaining <= 0
					compile(content, compileToFile)
