<?php

/**
 * @Project NUKEVIET 4.x
 * @Author VINADES.,JSC (contact@vinades.vn)
 * @Copyright (C) 2014 VINADES.,JSC. All rights reserved
 * @License GNU/GPL version 2 or any later version
 * @Createdate 18/10/2011, 9:45
 */

if (! defined('NV_MAINFILE')) {
    die('Stop!!!');
}

/**
 * jdFromDate()
 *
 * @param mixed $dd
 * @param mixed $mm
 * @param mixed $yy
 * @return
 */
function jdFromDate($dd, $mm, $yy)
{
    $a = floor((14 - $mm) / 12);
    $y = $yy + 4800 - $a;
    $m = $mm + 12 * $a - 3;
    $jd = $dd + floor((153 * $m + 2) / 5) + 365 * $y + floor($y / 4) - floor($y / 100) + floor($y / 400) - 32045;
    if ($jd < 2299161) {
        $jd = $dd + floor((153 * $m + 2) / 5) + 365 * $y + floor($y / 4) - 32083;
    }
    return $jd;
}

/**
 * jdToDate()
 *
 * @param mixed $jd
 * @return
 */
function jdToDate($jd)
{
    if ($jd > 2299160) {
        $a = $jd + 32044;
        $b = floor((4 * $a + 3) / 146097);
        $c = $a - floor(($b * 146097) / 4);
    } else {
        $b = 0;
        $c = $jd + 32082;
    }
    $d = floor((4 * $c + 3) / 1461);
    $e = $c - floor((1461 * $d) / 4);
    $m = floor((5 * $e + 2) / 153);
    $day = $e - floor((153 * $m + 2) / 5) + 1;
    $month = $m + 3 - 12 * floor($m / 10);
    $year = $b * 100 + $d - 4800 + floor($m / 10);

    return array( $day, $month, $year );
}

/**
 * getNewMoonDay()
 *
 * @param mixed $k
 * @param mixed $timeZone
 * @return
 */
function getNewMoonDay($k, $timeZone)
{
    $T = $k / 1236.85;

    $T2 = $T * $T;
    $T3 = $T2 * $T;
    $dr = M_PI / 180;
    $Jd1 = 2415020.75933 + 29.53058868 * $k + 0.0001178 * $T2 - 0.000000155 * $T3;
    $Jd1 = $Jd1 + 0.00033 * sin((166.56 + 132.87 * $T - 0.009173 * $T2) * $dr);

    $M = 359.2242 + 29.10535608 * $k - 0.0000333 * $T2 - 0.00000347 * $T3;

    $Mpr = 306.0253 + 385.81691806 * $k + 0.0107306 * $T2 + 0.00001236 * $T3;

    $F = 21.2964 + 390.67050646 * $k - 0.0016528 * $T2 - 0.00000239 * $T3;

    $C1 = (0.1734 - 0.000393 * $T) * sin($M * $dr) + 0.0021 * sin(2 * $dr * $M);
    $C1 = $C1 - 0.4068 * sin($Mpr * $dr) + 0.0161 * sin($dr * 2 * $Mpr);
    $C1 = $C1 - 0.0004 * sin($dr * 3 * $Mpr);
    $C1 = $C1 + 0.0104 * sin($dr * 2 * $F) - 0.0051 * sin($dr * ($M + $Mpr));
    $C1 = $C1 - 0.0074 * sin($dr * ($M - $Mpr)) + 0.0004 * sin($dr * (2 * $F + $M));
    $C1 = $C1 - 0.0004 * sin($dr * (2 * $F - $M)) - 0.0006 * sin($dr * (2 * $F + $Mpr));
    $C1 = $C1 + 0.0010 * sin($dr * (2 * $F - $Mpr)) + 0.0005 * sin($dr * (2 * $Mpr + $M));
    if ($T < - 11) {
        $deltat = 0.001 + 0.000839 * $T + 0.0002261 * $T2 - 0.00000845 * $T3 - 0.000000081 * $T * $T3;
    } else {
        $deltat = - 0.000278 + 0.000265 * $T + 0.000262 * $T2;
    }
    ;
    $JdNew = $Jd1 + $C1 - $deltat;

    return floor($JdNew + 0.5 + $timeZone / 24);
}

/**
 * getSunLongitude()
 *
 * @param mixed $jdn
 * @param mixed $timeZone
 * @return
 */
function getSunLongitude($jdn, $timeZone)
{
    $T = ($jdn - 2451545.5 - $timeZone / 24) / 36525;

    $T2 = $T * $T;
    $dr = M_PI / 180;

    $M = 357.52910 + 35999.05030 * $T - 0.0001559 * $T2 - 0.00000048 * $T * $T2;

    $L0 = 280.46645 + 36000.76983 * $T + 0.0003032 * $T2;

    $DL = (1.914600 - 0.004817 * $T - 0.000014 * $T2) * sin($dr * $M);
    $DL = $DL + (0.019993 - 0.000101 * $T) * sin($dr * 2 * $M) + 0.000290 * sin($dr * 3 * $M);
    $L = $L0 + $DL;

    $L = $L * $dr;
    $L = $L - M_PI * 2 * (floor($L / (M_PI * 2)));

    return floor($L / M_PI * 6);
}

/**
 * getLunarMonth11()
 *
 * @param mixed $yy
 * @param mixed $timeZone
 * @return
 */
function getLunarMonth11($yy, $timeZone)
{
    $off = jdFromDate(31, 12, $yy) - 2415021;
    $k = floor($off / 29.530588853);
    $nm = getNewMoonDay($k, $timeZone);
    $sunLong = getSunLongitude($nm, $timeZone);

    if ($sunLong >= 9) {
        $nm = getNewMoonDay($k - 1, $timeZone);
    }
    return $nm;
}

/**
 * getLeapMonthOffset()
 *
 * @param mixed $a11
 * @param mixed $timeZone
 * @return
 */
function getLeapMonthOffset($a11, $timeZone)
{
    $k = floor(($a11 - 2415021.076998695) / 29.530588853 + 0.5);
    $last = 0;
    $i = 1;

    $arc = getSunLongitude(getNewMoonDay($k + $i, $timeZone), $timeZone);
    do {
        $last = $arc;
        $i = $i + 1;
        $arc = getSunLongitude(getNewMoonDay($k + $i, $timeZone), $timeZone);
    } while ($arc != $last and $i < 14);
    return $i - 1;
}

/**
 * convertSolar2Lunar()
 *
 * @param mixed $dd
 * @param mixed $mm
 * @param mixed $yy
 * @param mixed $timeZone
 * @return
 */
function convertSolar2Lunar($dd, $mm, $yy, $timeZone)
{
    $dayNumber = jdFromDate($dd, $mm, $yy);
    $k = floor(($dayNumber - 2415021.076998695) / 29.530588853);
    $monthStart = getNewMoonDay($k + 1, $timeZone);
    if ($monthStart > $dayNumber) {
        $monthStart = getNewMoonDay($k, $timeZone);
    }
    $a11 = getLunarMonth11($yy, $timeZone);
    $b11 = $a11;
    if ($a11 >= $monthStart) {
        $lunarYear = $yy;
        $a11 = getLunarMonth11($yy - 1, $timeZone);
    } else {
        $lunarYear = $yy + 1;
        $b11 = getLunarMonth11($yy + 1, $timeZone);
    }
    $lunarDay = $dayNumber - $monthStart + 1;
    $diff = floor(($monthStart - $a11) / 29);
    $lunarLeap = 0;
    $lunarMonth = $diff + 11;
    if ($b11 - $a11 > 365) {
        $leapMonthDiff = getLeapMonthOffset($a11, $timeZone);
        if ($diff >= $leapMonthDiff) {
            $lunarMonth = $diff + 10;
            if ($diff == $leapMonthDiff) {
                $lunarLeap = 1;
            }
        }
    }
    if ($lunarMonth > 12) {
        $lunarMonth = $lunarMonth - 12;
    }
    if ($lunarMonth >= 11 and $diff < 4) {
        $lunarYear -= 1;
    }
    return array( $lunarDay, $lunarMonth, $lunarYear, $lunarLeap );
}

/**
 * convertLunar2Solar()
 *
 * @param mixed $lunarDay
 * @param mixed $lunarMonth
 * @param mixed $lunarYear
 * @param mixed $lunarLeap
 * @param mixed $timeZone
 * @return
 */
function convertLunar2Solar($lunarDay, $lunarMonth, $lunarYear, $lunarLeap, $timeZone)
{
    if ($lunarMonth < 11) {
        $a11 = getLunarMonth11($lunarYear - 1, $timeZone);
        $b11 = getLunarMonth11($lunarYear, $timeZone);
    } else {
        $a11 = getLunarMonth11($lunarYear, $timeZone);
        $b11 = getLunarMonth11($lunarYear + 1, $timeZone);
    }
    $k = floor(0.5 + ($a11 - 2415021.076998695) / 29.530588853);
    $off = $lunarMonth - 11;
    if ($off < 0) {
        $off += 12;
    }
    if ($b11 - $a11 > 365) {
        $leapOff = getLeapMonthOffset($a11, $timeZone);
        $leapMonth = $leapOff - 2;
        if ($leapMonth < 0) {
            $leapMonth += 12;
        }
        if ($lunarLeap != 0 and $lunarMonth != $leapMonth) {
            return array( 0, 0, 0 );
        } elseif ($lunarLeap != 0 or $off >= $leapOff) {
            $off += 1;
        }
    }
    $monthStart = getNewMoonDay($k + $off, $timeZone);
    return jdToDate($monthStart + $lunarDay - 1);
}

/**
 * alhn()
 *
 * @return
 */
function alhn()
{
    $CAN = array( 'Giáp', 'Ất', 'Bính', 'Đinh', 'Mậu', 'Kỷ', 'Canh', 'Tân', 'Nhâm', 'Quý' );
    $CHI = array( 'Tý', 'Sửu', 'Dần', 'Mão', 'Thìn', 'Tỵ', 'Ngọ', 'Mùi', 'Thân', 'Dậu', 'Tuất', 'Hợi' );
    $arr = array_slice(convertSolar2Lunar(date('d'), date('m'), date('Y'), 7), 0, 3);
    $arr[0] = str_pad($arr[0], 2, '0', STR_PAD_LEFT);
    $arr[1] = str_pad($arr[1], 2, '0', STR_PAD_LEFT);
    $arr[2] = $CAN[($arr[2] + 6) % 10] . ' ' . $CHI[($arr[2] + 8) % 12];
    return 'Âm lịch: ngày ' . $arr[0] . ' tháng ' . $arr[1] . ' năm ' . $arr[2];
}
