var SynkiDateFormatter = function(timezone_offset, user_language) {
	this.gmt_offset = timezone_offset || this.findoutUserGMT();
	this.user_language = user_language || this.findoutUserLanguage();
};

SynkiDateFormatter.prototype.findoutUserGMT = function() {
	var current = new Date();
	var gmt = current.getTimezoneOffset() * 60;
	gmt = (gmt<0) ? Math.abs(gmt) : gmt * -1;

	return gmt;
};

SynkiDateFormatter.prototype.findoutUserLanguage = function() {
	// en, ja, ko, default
	var browser_language = (navigator.language) ? navigator.language : navigator.userLanguage

	var mapping_table = {
		"en": "en",
		"ja": "jp",
		"ko": "ko",
		"default": "jp"
	};

	return mapping_table[browser_language] || "jp"
};

// unixtime source
SynkiDateFormatter.prototype.unixtimeToGMTDate = function(_unixtime) {
	var gmt = this.gmt_offset;
	var gmt_unixtime = this.applyGMT(_unixtime, gmt);
	var gmt_date = this.dateFromRequestedUnixtime(gmt_unixtime);

	// drop UTC(GMT) info
	gmt_date = gmt_date.toUTCString().replace(/\s{1}\w{3}$/, "");


	var formed_date = this.formattingDate(gmt_date);
	return formed_date;
};

SynkiDateFormatter.prototype.unixtimeParse = function(unixtime) {

	// var utc_date = this.dateStringFromRequestedUnixtime(unixtime);
	var gmt = this.gmt_offset;
	var gmt_unixtime = this.applyGMT(unixtime, gmt);
	var gmt_date = this.dateFromRequestedUnixtime(gmt_unixtime);
	gmt_date = gmt_date.toUTCString();
	var date_set = this.splitUTCDate(unixtime, gmt_date);

	return date_set;
};

// date source
// need dateToUTC? (return formed date)
SynkiDateFormatter.prototype.dateToSqliteDate = function(_source_date, date_only) {
	var formed_date = this.formattingDate(_source_date, date_only);
	return formed_date;
};

SynkiDateFormatter.prototype.dateToGMTDate = function(_source_date, date_only) {
	if(!this.isValidDate(_source_date)) return false;

	var date_set = this.splitDate(_source_date);
	var unixtime =  this.unixtimeFromRequestedDate(date_set);
	var gmt = this.gmt_offset;
	var gmt_unixtime = this.applyGMT(unixtime, gmt);
	var gmt_date = this.dateFromRequestedUnixtime(gmt_unixtime);

	// drop UTC(GMT) info
	gmt_date = gmt_date.toUTCString().replace(/\s{1}\w{3}$/, "");

	var formed_date = this.formattingDate(gmt_date, date_only);
	return formed_date;
};

SynkiDateFormatter.prototype.dateToUnixtime = function(_source_date) {
	if(!this.isValidDate(_source_date)) return false;

	var date_set = this.splitDate(_source_date);
	var unixtime =  this.unixtimeFromRequestedDate(date_set);

	return unixtime;
};

//
// protected
//
SynkiDateFormatter.prototype.formattingDate = function(gmt_date, date_only) {

	var user_language = this.user_language
	var gmt_pieces = this.splitUTCDate("", gmt_date);

	// ToDo: think more, there's better way exists.
	var format_by_language = {
		"en": gmt_pieces["dayth"] + ', ' + gmt_pieces["day"] + " " + gmt_pieces["alpha_month"] + " " + gmt_pieces["year"] + " " + gmt_pieces["hour"] + ':' + gmt_pieces["minute"] + ":" + gmt_pieces["second"],
		"jp": gmt_pieces["dayth"] + ', ' + gmt_pieces["day"] + " " + gmt_pieces["alpha_month"] + " " + gmt_pieces["year"] + " " + gmt_pieces["hour"] + ':' + gmt_pieces["minute"] + ":" + gmt_pieces["second"],
		"ko": gmt_pieces['year'] + "/" + gmt_pieces['month'] + "/" + gmt_pieces['day'] + " " + gmt_pieces['hour'] + ":" + gmt_pieces['minute'] + ":" + gmt_pieces['second']
	}

	// ToDo: customize style
	var simplicitic_format_by_language = {
		"en": /*gmt_pieces["dayth"] + ', ' + */gmt_pieces["day"] + " " + gmt_pieces["alpha_month"] + " " + gmt_pieces["year"],
		"jp": /*gmt_pieces["dayth"] + ', ' + */gmt_pieces["day"] + " " + gmt_pieces["alpha_month"] + " " + gmt_pieces["year"],
		"ko": gmt_pieces['year'] + "/" + gmt_pieces['month'] + "/" + gmt_pieces['day']
	}

	var wellForm = format_by_language;
	if(date_only) wellForm = simplicitic_format_by_language;

	return wellForm[user_language];
};

SynkiDateFormatter.prototype.applyGMT = function(source_unixtime, user_gmt) {
	return Number(source_unixtime) + (user_gmt * 1000);
};

SynkiDateFormatter.prototype.splitDate = function(_source_date) {
	var _type = this.isValidDate(_source_date);
	if(!_type) return false;

	return this[_type + "DateSplit"](_source_date);
};

// ToDo: refactoring (duplicated)
SynkiDateFormatter.prototype.typeRailsDateSplit = function(_source_date) {
	var date_piece = _source_date.split(/[\s:]/);

	var splitted = new Object;

	splitted["year"] = date_piece[7];
	splitted["month"] = this.alphaToDigit(date_piece[1]) - 1;
	splitted["day"] =  date_piece[2];
	splitted["hour"] =  date_piece[3];
	splitted["minute"] =  date_piece[4];
	splitted["second"] =  date_piece[5];

	return splitted;
};

// ToDo: refactoring (duplicated)
SynkiDateFormatter.prototype.typeGearsDateSplit = function(_source_date) {
	var date_piece = _source_date.split(/[-/\s:]/);

	var splitted = new Object; 

	splitted["year"] = date_piece[0];
	splitted["month"] = date_piece[1] - 1;
	splitted["day"] = date_piece[2];
	splitted["hour"] = date_piece[3];
	splitted["minute"] = date_piece[4];
	splitted["second"] = date_piece[5];

	return splitted;
};

// ToDo: refactoring (duplicated)
SynkiDateFormatter.prototype.splitUTCDate = function(_unixtime, _source_date) {
	var utc_date = _source_date.replace(",", '');
	var date_piece = utc_date.split(/[\s:]/);

	var splitted = new Object;

	splitted["inputed"] = _unixtime;
	splitted["date"] = _source_date;
	splitted["year"] = date_piece[3];
	splitted["alpha_month"] = date_piece[2];
	splitted["month"] = this.alphaToDigit(date_piece[2]);
	splitted["day"] = date_piece[1];
	splitted["dayth"] = date_piece[0];
	splitted["hour"] = date_piece[4] || "";
	splitted["minute"] = date_piece[5] || "";
	splitted["second"] = date_piece[6] || "";

	return splitted;
};

SynkiDateFormatter.prototype.dateFromRequestedUnixtime = function(unixtime) {
	// ToDo: we droped unknown three numbers that's why we * 1000
	var _date = new Date(Number(unixtime));

	return _date;
};

SynkiDateFormatter.prototype.dateStringFromRequestedUnixtime = function(unixtime) {
	// ToDo: we droped unknown three numbers that's why we * 1000
	var _date = new Date(Number(unixtime));

	return _date.toUTCString();
};

SynkiDateFormatter.prototype.unixtimeFromRequestedDate = function(date_set) {
	var unixtime = Date.UTC(
		date_set["year"],
		date_set["month"],
		date_set["day"],
		date_set["hour"],
		date_set["minute"],
		date_set["second"]
	);

	return unixtime;
};

SynkiDateFormatter.prototype.isValidDate = function(_date) {
	var type_rails = /^\w{3}\s\w{3}\s[0-9]{2}\s[0-9]{2}:[0-9]{2}:[0-9]{2}\s\w{3}\s[0-9]{4}/.test(_date)
	var type_gears = /^[0-9]{4}[-/][0-9]{1,2}[-/][0-9]{1,2}\s[0-9]{2}:[0-9]{2}:[0-9]{2}(\s[-+][0-9]{4})?$/.test(_date)

	if(type_rails) {
		return "typeRails";
	}
	else if(type_gears) {
		return "typeGears";
	}

	return false
};

SynkiDateFormatter.prototype.alphaToDigit = function(_alpha) {
	var alpha = _alpha.toLowerCase();
	var digit = null;

	switch(alpha) {
		case "jan": case "january": case "sun": case "sunday":
			digit = "01";
		break;
		case "feb": case "february": case "mon": case "monday":
			digit = "02";
		break;
		case "mar": case "march": case "tue": case "tuesday":
			digit = "03";
		break;
		case "apr": case "april": case "wed": case "wednesday":
			digit = "04";
		break;
		case "may": case "may": case "thu": case "tuesday":
			digit = "05";
		break;
		case "jun": case "june": case "fri": case "friday":
			digit = "06";
		break;
		case "jul": case "july": case "sat": case "saturday":
			digit = "07";
		break;
		case "aug": case "august":
			digit = "08";
		break;
		case "sep": case "september":
			digit = "09";
		break;
		case "oct": case "october":
			digit = "10";
		break;
		case "nov": case "november":
			digit = "11";
		break;
		case "dec": case "december":
			digit = "12";
		break;
	}

	return digit;
}











var OldDateFormatter = function(source_date) {

	if(source_date) this.generateDateSet(source_date);
};

OldDateFormatter.prototype.generateDateSet = function(source_date) {
	this.unixtimeUTC = this.convertToUnix(source_date);
	this.dateUTC = this.convertToDate(source_date);
	this.unixtimeGMT = this.convertToUnixWithGMT(source_date);
	this.dateGMT = this.convertToDateWithGMT(source_date);
};

OldDateFormatter.prototype.splitDate = function(source_date) {
	var d = source_date.split(/[-\s:]/);

	var splitted = {
		"year": d[0],
		"month": d[1] - 1,
		"date": d[2],
		"hour": d[3],
		"minute": d[4],
		"second": d[5]
	};

	return splitted;
};

OldDateFormatter.prototype.genUnix = function(arrayer_source) {
	var unixtime = Date.UTC(
		arrayer_source["year"],
		arrayer_source["month"],
		arrayer_source["date"],
		arrayer_source["hour"],
		arrayer_source["minute"],
		arrayer_source["second"]
	);

	return unixtime;
};

OldDateFormatter.prototype.genDate = function(unixtime) {
	var sourceDate = new Date(unixtime);

	return sourceDate;
};

OldDateFormatter.prototype.genGMT = function() {
	var current = new Date();
	var gmt = current.getTimezoneOffset() * 60;
	gmt = (gmt<0) ? Math.abs(gmt) : gmt * -1;

	return gmt;
};

OldDateFormatter.prototype.applyGMT = function(unixtime, gmt) {
	return unixtime + (gmt * 1000);
};

OldDateFormatter.prototype.convertToDate = function(_source_date) {
	var splitted_date = this.splitDate(_source_date);
	var unixtime =  this.genUnix(splitted_date);
	var source_date = this.genDate(unixtime);
	source_date = source_date.toUTCString().replace(/\s{1}\w{3}$/, "");

	return source_date;
};

OldDateFormatter.prototype.convertToUnix = function(_source_date) {
	var splitted_date = this.splitDate(_source_date);
	var unixtime =  this.genUnix(splitted_date);
	var source_date = this.genDate(unixtime);
	source_date = source_date.getTime();

	return source_date;
};

OldDateFormatter.prototype.convertToDateWithGMT = function(_source_date) {
	var splitted_date = this.splitDate(_source_date);
	var unixtime =  this.genUnix(splitted_date);
	var gmt = this.genGMT();

	unixtime = this.applyGMT(unixtime, gmt);

	var source_date = this.genDate(unixtime);
	source_date = source_date.toUTCString().replace(/\s{1}\w{3}$/, "");

	return source_date;
};

OldDateFormatter.prototype.convertToUnixWithGMT = function(_source_date) {
	var splitted_date = this.splitDate(_source_date);
	var unixtime =  this.genUnix(splitted_date);
	var gmt = this.genGMT();

	unixtime = this.applyGMT(unixtime, gmt);

	return unixtime;
};
