winston = require "winston"
util = require "util"
AWS = require "aws-sdk"
uuid = require("node-uuid")
_ = require "lodash"
hostname = require("os").hostname()

# Return timestamp with YYYY-MM-DD HH:mm:ss
datify = (timestamp) ->
	date = new Date timestamp
	date = 
		year: date.getFullYear()
		month: date.getMonth() + 1
		day: date.getDate()

		hour: date.getHours()
		minute: date.getMinutes()
		second: date.getSeconds()
		millisecond: date.getMilliseconds()

	keys = _.without Object.keys date, "year", "month", "day"
	date[key] = "0" + date[key] for key in keys when date[key] < 10
	"#{date.year}-#{date.month}-#{date.day} #{date.hour}:#{date.minute}:#{date.second}.#{date.millisecond}"

DynamoDB = exports.DynamoDB = (options = {}) ->
	regions = [
		"us-east-1"
		"us-west-1"
		"us-west-2"
		"eu-west-1"
		"eu-central-1"
		"ap-northeast-1"
		"ap-northeast-2"
		"ap-southeast-1"
		"ap-southeast-2"
		"sa-east-1"
	]
	
	if options.useEnvironment
		options.accessKeyId = process.env.AWS_ACCESS_KEY_ID
		options.secretAccessKey = process.env.AWS_SECRET_ACCESS_KEY
		options.region = process.env.AWS_REGION

	unless options.accessKeyId?
		throw new Error "need accessKeyId"

	unless options.secretAccessKey?
		throw new Error "need secretAccessKey"

	unless options.region?
		throw new Error "need region"

	unless options.region in regions
		throw new Error "unavailable region given"

	unless options.tableName?
		throw new Error "need tableName"

	unless options.useEnvironment
		AWS.config.update
			accessKeyId: options.accessKeyId
			secretAccessKey: options.secretAccessKey
			region: options.region

	# Winston Options
	@.name = "dynamodb"
	@.level = options.level or "info"

	# DynamoDB Options=
	@.db = new AWS.DynamoDB()
	@.AWS = AWS
	@.region = options.region
	
	# a-z, A-Z, 0-9, _ (underscore), - (hyphen) and . (period)
	@.tableName = options.tableName
	@.dynamoDoc = options.dynamoDoc

util.inherits DynamoDB, winston.Transport

DynamoDB::log = (level, msg, meta, callback) ->
	putCallback = (err, data) =>
		if err
			@.emit "error", err
			callback err, null if callback
		else
			@.emit "logged"
			callback null, "logged" if callback

	if @.dynamoDoc == true
		params =
			TableName: @.tableName
			Item:
				id: uuid.v4()
				level: level
				timestamp: datify Date.now()
				msg: msg
				hostname: hostname

		unless _.isEmpty meta
			params.Item.meta = meta

		dynamoDocClient = new @.AWS.DynamoDB.DocumentClient({
			service: @.db
		})
		dynamoDocClient.put params, putCallback
	else
		params =
			TableName: @.tableName
			Item:
				id:
					"S": uuid.v4()
				level:
					"S": level
				timestamp:
					"S": datify Date.now()
				msg:
					"S": msg
				hostname:
					"S": hostname

		unless _.isEmpty meta
			params.Item.meta = "S": JSON.stringify meta

		@.db.putItem params, putCallback

# Add DynamoDB to the transports by winston
winston.transports.DynamoDB = DynamoDB
