'use strict';

var Type = require( '../type' );

var YAML_TIMESTAMP_REGEXP = new RegExp(
	'^([0-9][0-9][0-9][0-9])' + // [1] year
		'-([0-9][0-9]?)' + // [2] month
		'-([0-9][0-9]?)' + // [3] day
		'(?:(?:[Tt]|[ \\t]+)' + // ...
		'([0-9][0-9]?)' + // [4] hour
		':([0-9][0-9])' + // [5] minute
		':([0-9][0-9])' + // [6] second
		'(?:\\.([0-9]*))?' + // [7] fraction
		'(?:[ \\t]*(Z|([-+])([0-9][0-9]?)' + // [8] tz [9] tz_sign [10] tz_hour
		'(?::([0-9][0-9]))?))?)?$' );         // [11] tz_minute

function resolveYamlTimestamp( data ) {
	if( null === data ) {
		return false;
	}

	var match, year, month, day, hour, minute, second, fraction = 0,
		delta = null, tz_hour, tz_minute, date;

	match = YAML_TIMESTAMP_REGEXP.exec( data );

	if( null === match ) {
		return false;
	}

	return true;
}

function constructYamlTimestamp( data ) {
	var match, year, month, day, hour, minute, second, fraction = 0,
		delta = null, tz_hour, tz_minute, date;

	match = YAML_TIMESTAMP_REGEXP.exec( data );

	if( null === match ) {
		throw new Error( 'Date resolve error' );
	}

	// match: [1] year [2] month [3] day

	year = +(match[1]);
	month = +(match[2]) - 1; // JS month starts with 0
	day = +(match[3]);

	if( !match[4] ) { // no hour
		return new Date( Date.UTC( year, month, day ) );
	}

	// match: [4] hour [5] minute [6] second [7] fraction

	hour = +(match[4]);
	minute = +(match[5]);
	second = +(match[6]);

	if( match[7] ) {
		fraction = match[7].slice( 0, 3 );
		while( fraction.length < 3 ) { // milli-seconds
			fraction += '0';
		}
		fraction = +fraction;
	}

	// match: [8] tz [9] tz_sign [10] tz_hour [11] tz_minute

	if( match[9] ) {
		tz_hour = +(match[10]);
		tz_minute = +(match[11] || 0);
		delta = (tz_hour * 60 + tz_minute) * 60000; // delta in mili-seconds
		if( '-' === match[9] ) {
			delta = -delta;
		}
	}

	date = new Date( Date.UTC( year, month, day, hour, minute, second, fraction ) );

	if( delta ) {
		date.setTime( date.getTime() - delta );
	}

	return date;
}

function representYamlTimestamp( object /*, style*/ ) {
	return object.toISOString();
}

module.exports = new Type( 'tag:yaml.org,2002:timestamp', {
	kind: 'scalar',
	resolve: resolveYamlTimestamp,
	construct: constructYamlTimestamp,
	instanceOf: Date,
	represent: representYamlTimestamp
} );
