 {EOL} = require 'os'
 Readline = require 'readline'
 {readFileSync, createReadStream, createWriteStream} = require 'fs'
+{Writable} = require 'stream'
 Path = require 'path'
 
 module.exports = class CodeCat

		js: '//'
		coffee: '#'

	getSourceCommenter = (source) ->
		ext = Path.extname(source).slice(1)
		commenter = CodeCat.Commenters[ext]
		if commenter? then regexpEscape(commenter) else ''

	regexpEscape = (str) ->
		str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&')

			appendRegexp:
				value: getDirectiveRegExp('append')

	findConcats: (options, callback) ->
		[{relative = false}, callback] = discernOptions(options, callback)
		{prepend, append} = concats = {prepend: [], append: []}
		lineReader = Readline.createInterface
			input: createReadStream(@source, encoding: @encoding)

		lineReader.on 'line', (line) =>
			if match = line.match(@prependRegexp)?[2]
				prepend.push(match)
			else if match = line.match(@appendRegexp)?[2]
				append.push(match)

		lineReader.on 'close', =>
			concats = mapConcats(concats, @getRelativePath, this) if relative
			callback?(concats)

	concat: (options, callback) ->
		[options, callback] = discernOptions(options, callback)
		concatted = ''
		write = (chunk, encoding, cb) ->
			concatted += chunk
			cb?(null)
		stream = new Writable(write: write)
		@concatTo stream, options, (error) -> callback?(concatted)

	concatTo: (dest, options, callback) ->
		[{separator = EOL}, callback] = discernOptions(options, callback)
		@findConcats relative: true, (concats) =>
			error = null
			paths = [concats.prepend..., @source, concats.append...]
			ensureStream dest, defaultEncoding: @encoding, (stream) ->
				joinFiles(paths, @encoding, separator, stream)
				stream.end -> callback?(error)

	getRelativePath: (file) ->
		sourceDir = Path.dirname(@source)
