<?php

// Copyright (C) 2009  Vahid sohrabloo (iranphp.org) 
// 
// This program is free software; you can redistribute it and/or 
// modify it under the terms of the GNU General Public License 
// as published by the Free Software Foundation; either version 2 
// of the License, or (at your option) any later version. 
// 
// This program is distributed in the hope that it will be useful, 
// but WITHOUT ANY WARRANTY; without even the implied warranty of 
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
// GNU General Public License for more details. 
// 
// A copy of the GNU General Public License is available from: 
// 
//    <a href="http://www.gnu.org/copyleft/gpl.html" target="_blank">http://www.gnu.org/copyleft/gpl.html</a> 
// 
if (class_exists('PdateCore'))
	return;

class PdateCore
{
	// Version 1.2

	static $pdateWeekName = array(
		"شنبه",
		"یکشنبه",
		"دوشنبه",
		"سه شنبه",
		"چهارشنبه",
		"پنج شنبه",
		"جمعه");
	static $pdateMonthName = array(
		"",
		"فروردین",
		"اردیبهشت",
		"خرداد",
		"تیر",
		"مرداد",
		"شهریور",
		"مهر",
		"آبان",
		"آذر",
		"دی",
		"بهمن",
		"اسفند");
	static $MonthDays = array(0, 31, 31, 31, 31, 31, 31, 30, 30, 30, 30, 30, 29);

	public static function pdate($format, $timestamp = "")
	{
		//global $pdateMonthName,$pdateWeekName,$MonthDays;
		if ($timestamp === "") {
			$timestamp = time();
		}

		// Create need date parametrs
		$date = date("Y-m-d-w", $timestamp);
		list($gYear, $gMonth, $gDay, $gWeek) = explode('-', $date);
		list($pYear, $pMonth, $pDay) = Pdate::gregorian_to_jalali($gYear, $gMonth, $gDay);
		$pWeek = $gWeek + 1;
		if ($pWeek == 7) $pWeek = 0;

		$lenghFormat = strlen($format);
		$i = 0;
		$result = "";
		while ($i < $lenghFormat) {
			$par = $format{$i};
			if ($par == '\\') {
				$result .= $format{++$i};
				$i++;
				continue;
			}
			switch ($par) {
				//Day
				case 'd':
					$result .= ($pDay < 10) ? "0" . $pDay : $pDay;
					break;

				case 'D':
					$result .= substr(Pdate::$pdateWeekName[$pWeek], 0, 2);
					break;

				case 'j':
					$result .= $pDay;
					break;

				case 'l':
					$result .= Pdate::$pdateWeekName[$pWeek];
					break;

				case 'N':
					$result .= $pWeek + 1;
					break;

				case 'w':
					$result .= $pWeek;
					break;

				case 'z':
					$result .= Pdate::DayOfYear($pYear, $pMonth, $pDay);
					break;

				case 'S':
					$result .= "م";
					break;

				//Week
				case 'W':
					$result .= ceil(Pdate::DayOfYear($pYear, $pMonth, $pDay) / 7);
					break;

				//Month
				case 'F':
					$result .= Pdate::$pdateMonthName[$pMonth];
					break;

				case 'm':
					$result .= ($pMonth < 10) ? "0" . $pMonth : $pMonth;
					break;

				case 'M':
					$result .= substr(Pdate::$pdateMonthName[$pMonth], 0, 6);
					break;

				case 'n':
					$result .= $pMonth;
					break;

				case 't':
					$result .= (isKabise($pYear) and $pMonth == 12) ? 30 : Pdate::$MonthDays[$pMonth];
					break;

				//Years
				case 'L':
					$result .= (int)isKabise($pYear);
					break;

				case 'Y':
				case 'o':
					$result .= $pYear;
					break;

				case 'y':
					$result .= substr($pYear, 2);
					break;

				//Time
				case 'a':
				case 'A':
					if (date('a', $timestamp) == 'am') {
						$result .= ($par == 'a') ? 'ق.ظ' : 'قبل از ظهر';
					} else {
						$result .= ($par == 'a') ? 'ب.ظ' : 'بعد از ظهر';
					}
					break;

				case 'B':
				case 'g':
				case 'G':
				case 'h':
				case 'H':
				case 's':
				case 'u':
				case 'i':

					//Timezone
				case 'e':
				case 'I':
				case 'O':
				case 'P':
				case 'T':
				case 'Z':
					$result .= date($par, $timestamp);
					break;

				//Full Date/Time

				case 'c':
					$result .= $pYear . "-" . $pMonth . "-" . $pDay . "T" . date("H::i:sP", $timestamp);
					break;

				case 'r':
					$result .= substr(Pdate::$pdateWeekName[$pWeek], 0, 2) . "، " . $pDay . " " . substr(Pdate::$pdateMonthName[$pMonth], 0, 6) . " " . $pYear . " " . date("H::i:s P", $timestamp);
					break;
				case 'U':
					$result .= $timestamp;
					break;
				default:
					$result .= $par;


			}
			$i++;
		}
		return $result;


	}


	public static function pstrftime($format, $timestamp = "")
	{
		//global $pdateMonthName,$pdateWeekName,$MonthDays;
		if ($timestamp === "") {
			$timestamp = time();
		}
		// Create need date parametrs
		$date = date("Y-m-d-w", $timestamp);
		list($gYear, $gMonth, $gDay, $gWeek) = explode('-', $date);
		list($pYear, $pMonth, $pDay) = Pdate::gregorian_to_jalali($gYear, $gMonth, $gDay);
		$pWeek = $gWeek + 1;
		if ($pWeek == 7) $pWeek = 0;

		$lenghFormat = strlen($format);
		$i = 0;
		$result = "";
		while ($i < $lenghFormat) {
			$par = $format{$i};
			if ($par == "%") {
				$type = $format{++$i};
				switch ($type) {
					//Day
					case 'a':
						$result .= substr(Pdate::$pdateWeekName[$pWeek], 0, 2);
						break;

					case 'A':
						$result .= Pdate::$pdateWeekName[$pWeek];
						break;

					case 'd':
						$result .= ($pDay < 10) ? "0" . $pDay : $pDay;
						break;

					case 'e':
						$result .= $pDay;
						break;

					case 'j':
						$dayinM = Pdate::DayOfYear($pYear, $pMonth, $pDay);
						$result .= ($dayinM < 10) ? "00" . $dayinM : (($dayinM < 100) ? "0" . $dayinM : $dayinM);
						break;

					case 'u':
						$result .= $pWeek + 1;
						break;

					case 'w':
						$result .= $pWeek;
						break;

					//Week
					case 'U':
						$result .= floor(Pdate::DayOfYear($pYear, $pMonth, $pDay) / 7);
						break;

					case 'V':
					case 'W':
						$result .= ceil(Pdate::DayOfYear($pYear, $pMonth, $pDay) / 7);
						break;

					//Month
					case 'b':
					case 'h':
						$result .= substr(Pdate::$pdateMonthName[$pMonth], 0, 6);
						break;

					case 'B':
						$result .= Pdate::$pdateMonthName[$pMonth];
						break;

					case 'm':
						$result .= ($pMonth < 10) ? "0" . $pMonth : $pMonth;
						break;

					//Year
					case 'C':
						$result .= ceil($pYear / 100);
						break;

					case 'g':
					case 'y':
						$result .= substr($pYear, 2);
						break;

					case 'G':
					case 'Y':
						$result .= $pYear;
						break;

					//Time
					case 'H':
					case 'I':
					case 'l':
					case 'M':
					case 'R':
					case 'S':
					case 'T':
					case 'X':
					case 'z':
					case 'Z':
						$result .= strftime("%" . $type, $timestamp);
						break;
					case 'p':
					case 'P':
					case 'r':
						if (date('a', $timestamp) == 'am') {
							$result .= ($type == 'p') ? 'ق.ظ' : (($type == 'P') ? 'قبل از ظهر' : strftime("%I:%M:%S قبل از ظهر", $timestamp));
						} else {
							$result .= ($type == 'p') ? 'ب.ظ' : (($type == 'P') ? 'بعد از ظهر' : strftime("%I:%M:%S بعد از ظهر", $timestamp));
						}
						break;

					//Time and Date Stamps
					case 'c':
						$result .= substr(Pdate::$pdateWeekName[$pWeek], 0, 2) . " " . substr(Pdate::$pdateMonthName[$pMonth], 0, 6) . " " . $pDay . " " . strftime("%T", $timestamp) . " " . $pYear;
						break;

					case 'D':
					case 'x':
						$result .= (($pMonth < 10) ? "0" . $pMonth : $pMonth) . "/" . (($pDay < 10) ? "0" . $pDay : $pDay) . "/" . substr($pYear, 2);
						break;

					case 'F':
						$result .= $pYear . "-" . (($pMonth < 10) ? "0" . $pMonth : $pMonth) . "-" . (($pDay < 10) ? "0" . $pDay : $pDay);
						break;

					case 's':
						$result .= $timestamp;
						break;

					//Miscellaneous
					case 'n':
						$result .= "\n";
						break;

					case 't':
						$result .= "\t";
						break;

					case '%':
						$result .= "%";
						break;

					default:
						$result .= "%" . $type;


				}
			} else {
				$result .= $par;
			}
			$i++;
		}
		return $result;
	}

	public static function DayOfYear($pYear, $pMonth, $pDay)
	{
		$days = 0;
		for ($i = 1; $i < $pMonth; $i++) {
			$days += Pdate::$MonthDays[$i];
		}
		return $days + $pDay;
	}

	public static function isKabise($year)
	{
		$mod = $year % 33;
		if ($mod == 1 or $mod == 5 or $mod == 9 or $mod == 13 or $mod == 17 or $mod == 22 or $mod == 26 or $mod == 30) return true;
		return false;
	}

	public static function pmktime($hour = 0, $minute = 0, $second = 0, $month = 0, $day = 0, $year = 0, $is_dst = -1)
	{

		if ($hour == 0 && $minute == 0 && $second == 0 && $month == 0 && $day == 0 && $year == 0) return time();

		list($year, $month, $day) = Pdate::jalali_to_gregorian($year, $month, $day);

		return mktime($hour, $minute, $second, $month, $day, $year, $is_dst);
	}

	public static function pcheckdate($month, $day, $year)
	{
		if ($month < 1 || $month > 12 || $year < 1 || $year > 32767 || $day < 1) {
			return false;
		}
		if ($day > Pdate::$MonthDays[$month]) {
			if ($month != 12 || $day != 30 || !isKabise($year)) {
				return false;
			}
		}
		return true;
	}


	public static function pgetdate($timestamp = "")
	{
		if ($timestamp === "")
			$timestamp = mktime();
		list($seconds, $minutes, $hours, $mday, $wday, $mon, $year, $yday, $weekday, $month) = explode("-", Pdate::pdate("s-i-G-j-w-n-Y-z-l-F", $timestamp));
		return array(
			0 => $timestamp,
			"seconds" => $seconds,
			"minutes" => $minutes,
			"hours" => $hours,
			"mday" => $mday,
			"wday" => $wday,
			"mon" => $mon,
			"year" => $year,
			"yday" => $yday,
			"weekday" => $weekday,
			"month" => $month,
		);
	}


	// Copyright (C) 2000  Roozbeh Pournader and Mohammad Toossi 
	// 
	// This program is free software; you can redistribute it and/or 
	// modify it under the terms of the GNU General Public License 
	// as published by the Free Software Foundation; either version 2 
	// of the License, or (at your option) any later version. 
	// 
	// This program is distributed in the hope that it will be useful, 
	// but WITHOUT ANY WARRANTY; without even the implied warranty of 
	// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
	// GNU General Public License for more details. 
	// 
	// A copy of the GNU General Public License is available from: 
	// 
	//    <a href="http://www.gnu.org/copyleft/gpl.html" target="_blank">http://www.gnu.org/copyleft/gpl.html</a> 
	//


	static function div($a, $b)
	{
		return (int)($a / $b);
	}

	public static function gregorian_to_jalali($g_y, $g_m, $g_d)
	{
		$g_days_in_month = array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
		$j_days_in_month = array(31, 31, 31, 31, 31, 31, 30, 30, 30, 30, 30, 29);


		$gy = $g_y - 1600;
		$gm = $g_m - 1;
		$gd = $g_d - 1;

		$g_day_no = 365 * $gy + Pdate::div($gy + 3, 4) - Pdate::div($gy + 99, 100) + Pdate::div($gy + 399, 400);

		for ($i = 0; $i < $gm; ++$i)
			$g_day_no += $g_days_in_month[$i];
		if ($gm > 1 && (($gy % 4 == 0 && $gy % 100 != 0) || ($gy % 400 == 0)))
			/* leap and after Feb */
			$g_day_no++;
		$g_day_no += $gd;

		$j_day_no = $g_day_no - 79;

		$j_np = Pdate::div($j_day_no, 12053); /* 12053 = 365*33 + 32/4 */
		$j_day_no = $j_day_no % 12053;

		$jy = 979 + 33 * $j_np + 4 * Pdate::div($j_day_no, 1461); /* 1461 = 365*4 + 4/4 */

		$j_day_no %= 1461;

		if ($j_day_no >= 366) {
			$jy += Pdate::div($j_day_no - 1, 365);
			$j_day_no = ($j_day_no - 1) % 365;
		}

		for ($i = 0; $i < 11 && $j_day_no >= $j_days_in_month[$i]; ++$i)
			$j_day_no -= $j_days_in_month[$i];
		$jm = $i + 1;
		$jd = $j_day_no + 1;

		return array($jy, $jm, $jd);
	}

	public static function jalali_to_gregorian($j_y, $j_m, $j_d)
	{
		$g_days_in_month = array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
		$j_days_in_month = array(31, 31, 31, 31, 31, 31, 30, 30, 30, 30, 30, 29);


		$jy = $j_y - 979;
		$jm = $j_m - 1;
		$jd = $j_d - 1;

		$j_day_no = 365 * $jy + Pdate::div($jy, 33) * 8 + Pdate::div($jy % 33 + 3, 4);
		for ($i = 0; $i < $jm; ++$i)
			$j_day_no += $j_days_in_month[$i];

		$j_day_no += $jd;

		$g_day_no = $j_day_no + 79;

		$gy = 1600 + 400 * Pdate::div($g_day_no, 146097); /* 146097 = 365*400 + 400/4 - 400/100 + 400/400 */
		$g_day_no = $g_day_no % 146097;

		$leap = true;
		if ($g_day_no >= 36525) /* 36525 = 365*100 + 100/4 */ {
			$g_day_no--;
			$gy += 100 * Pdate::div($g_day_no, 36524); /* 36524 = 365*100 + 100/4 - 100/100 */
			$g_day_no = $g_day_no % 36524;

			if ($g_day_no >= 365)
				$g_day_no++;
			else
				$leap = false;
		}

		$gy += 4 * Pdate::div($g_day_no, 1461); /* 1461 = 365*4 + 4/4 */
		$g_day_no %= 1461;

		if ($g_day_no >= 366) {
			$leap = false;

			$g_day_no--;
			$gy += Pdate::div($g_day_no, 365);
			$g_day_no = $g_day_no % 365;
		}

		for ($i = 0; $g_day_no >= $g_days_in_month[$i] + ($i == 1 && $leap); $i++)
			$g_day_no -= $g_days_in_month[$i] + ($i == 1 && $leap);
		$gm = $i + 1;
		$gd = $g_day_no + 1;

		return array($gy, $gm, $gd);
	}
}