<?php

/**
 * Correct wordpress bug. Replaces date_i18n() function which has some bugs.
 */
add_filter('date_i18n', 'fix_date_i18n', 10, 4);
function fix_date_i18n($dateformated, $dateformatstring, $unixtimestamp = false, $gmt = false)
{
	/* @var $wp_locale WP_Locale */
	global $wp_locale;
	$timestamp = $unixtimestamp;

	// get current timestamp if $unixtimestamp is false
	if (false === $timestamp)
	{
		if ($gmt)
			$timestamp = time();
		else
			$timestamp = current_time('timestamp');
	}


	// get components of the date (timestamp) as array
	$datecomponents = getdate($timestamp);

	// numeric representation of a month, with leading zeros
	$datemonth = $wp_locale->get_month($datecomponents['mon']);
	$datemonth_abbrev = $wp_locale->get_month_abbrev($datemonth);
	// numeric representation of the day of the week
	$dateweekday = $wp_locale->get_weekday($datecomponents['wday']);
	$dateweekday_abbrev = $wp_locale->get_weekday_abbrev($dateweekday);
	// get if hour is Ante meridiem or Post meridiem
	$meridiem = $datecomponents['hours'] >= 12 ? 'pm' : 'am';
	// lowercase Ante meridiem and Post meridiem hours
	$datemeridiem = $wp_locale->get_meridiem($meridiem);
	// uppercase Ante meridiem and Post meridiem
	$datemeridiem_capital = $wp_locale->get_meridiem(strtoupper($meridiem));

	// escape literals
	$dateweekday_abbrev = backslashit($dateweekday_abbrev);
	$datemonth = backslashit($datemonth);
	$dateweekday = backslashit($dateweekday);
	$datemonth_abbrev = backslashit($datemonth_abbrev);
	$datemeridiem = backslashit($datemeridiem);
	$datemeridiem_capital = backslashit($datemeridiem_capital);

	// the translated format string
	$translateddateformatstring = '';
	// the 2 arrays map a format literal to its translation (e. g. 'F' to the escaped month translation)
	$tranlateformates = array('D', 'F', 'l', 'M', 'a', 'A', 'c', 'r');
	$translations = array(
		$dateweekday_abbrev, // D
		$datemonth, // F
		$dateweekday, // l
		$datemonth_abbrev, // M
		$datemeridiem, // a
		$datemeridiem_capital, // A
		'Y-m-d\TH:i:sP', // c
		sprintf('%s, d %s Y H:i:s O', $dateweekday_abbrev, $datemonth_abbrev), // r
	);

	// find each format literal that needs translation and replace it by its translation
	// respects the escaping
	// iterate $dateformatstring from ending to beginning
	for ($i = strlen($dateformatstring) - 1; $i > -1; $i--)
	{
		// test if current char is format literal that needs translation
		$tranlateformateindex = array_search($dateformatstring[$i], $tranlateformates);

		if ($tranlateformateindex !== false)
		{
			// counts the slashes (the escape char) in front of the current char
			$slashescounter = 0;

			// count all slashes left-hand side of the current char
			for ($j = $i - 1; $j > -1; $j--)
			{
				if ($dateformatstring[$j] == '\\')
					$slashescounter++;
				else
					break;
			}

			// number of slashes is even
			if ($slashescounter % 2 == 0)
				// current char is not escaped, therefore it is a format literal
				$translateddateformatstring = $translations[$tranlateformateindex] . $translateddateformatstring;
			else
				// current char is escaped, therefore it is not a format literal, just add it unchanged
				$translateddateformatstring = $dateformatstring[$i] . $translateddateformatstring;
		}
		else
			// current char is no a format literal, just add it unchanged
			$translateddateformatstring = $dateformatstring[$i] . $translateddateformatstring;
	}

	$dateformatstring = $translateddateformatstring;

	if ($gmt)
		// get GMT date string
		$dateformated = gmdate($dateformatstring, $timestamp);
	else
	{
		// get Wordpress time zone
		$timezone_string = get_option('timezone_string');

		// TODO: If get_option('timezone_string') is empty we should work with the gmt offset. Not easy to implement.
		/*// get Wordpress gmt offset (in hours)
		$gmtoffset = get_option('gmt_offset');

		// try to get time zone from gmt offset if timezone_string is not given
		if($timezone_string == '' && $gmtoffset !== false)
		{
			$timezone_string = timezone_name_from_abbr('', intval($gmtoffset) * HOUR_IN_SECONDS, 0);
		}*/

		if ($timezone_string)
		{
			// create time zone object
			$timezone_object = timezone_open($timezone_string);
			// create date object from time zone object
			$localdateobject = date_create(null, $timezone_object);
			// set time and date of $localdateobject to $timestamp
			$datecomponents = isset($datecomponents) ? $datecomponents : getdate($timestamp);
			date_date_set($localdateobject, $datecomponents['year'], $datecomponents['mon'], $datecomponents['mday']);
			date_time_set($localdateobject, $datecomponents['hours'], $datecomponents['minutes'], $datecomponents['seconds']);
			// format date according to the Wordpress time zone
			$dateformated = date_format($localdateobject, $dateformatstring);
		}
		else
		{
			// fall back if no Wordpress time zone set
			$dateformated = date($dateformatstring, $i);
		}
	}

	return $dateformated;
}
