#include <iostream>
#include <math.h>
/*
 Prayers calculator start
*/

//convert Degree to Radian
double degToRad(double degree)
{
    return ((3.1415926 / 180) * degree);
}

//convert Radian to Degree
double radToDeg(double radian)
{
    return (radian * (180/3.1415926));
}

//make sure a value is between 0 and 360
double moreLess360(double value)
{
    while(value > 360 || value < 0)
    {
        if(value > 360)
            value -= 360;
        else if (value <0)
            value += 360;
    }

    return value;
}

//make sure a value is between 0 and 24
double moreLess24(double value)
{
    while(value > 24 || value < 0)
    {
        if(value > 24)
            value -= 24;
        else if (value <0)
            value += 24;
    }

    return value;
}

//convert the double number to Hours and Minutes
void doubleToHrMin(double number, int &hours, int &minutes)
{
    hours = floor(moreLess24(number));
    minutes = floor(moreLess24(number - hours) * 60);
}

void calcPrayerTimes(int year, int month, int day,
                     double longitude, double latitude, int timeZone,
                     double fajrTwilight, double ishaTwilight,
                     double &fajrTime, double &sunRiseTime, double &zuhrTime,
                     double &asrTime, double &maghribTime, double &ishaTime)
{
    double W1 = (367 * year);
    std::cout << "Julian Day (W1): " << W1 << std::endl;
    double W2 = ((year + (int)((month + 9) / 12)) * 7 / 4);
    std::cout << "Julian Day (W2): " << W2 << std::endl;
    double W3 = (367 * year) - ((year + (int)((month + 9) / 12)) * 7 / 4) + (((int)(275 * month / 9)) + day - 730531.5);
    std::cout << "Julian Day (W3): " << W3 << std::endl;





double D = (367 * year);

    double L = 280.461 + 0.9856474 * D;
    L = moreLess360(L);
    
    // Debugging L (Longitude)
    std::cout << "L: " << L << std::endl;

    double M = 357.528 + (0.9856003) * D;
    M = moreLess360(M);
    
    // Debugging M (Mean anomaly)
    std::cout << "M: " << M << std::endl;

    double Lambda = L + 1.915 * sin(degToRad(M)) + 0.02 * sin(degToRad(2 * M));
    Lambda = moreLess360(Lambda);
    
    // Debugging Lambda (Ecliptic longitude)
    std::cout << "Lambda: " << Lambda << std::endl;

    double Obliquity = 23.439 - 0.0000004 * D;
    double Alpha = radToDeg(atan((cos(degToRad(Obliquity)) * tan(degToRad(Lambda)))));
    Alpha = moreLess360(Alpha);
    
    // Debugging Alpha (Right Ascension)
    std::cout << "Alpha: " << Alpha << std::endl;

    Alpha = Alpha - (360 * (int)(Alpha / 360));
    Alpha = Alpha + 90 * (floor(Lambda / 90) - floor(Alpha / 90));

    double ST = 100.46 + 0.985647352 * D;
    double Dec = radToDeg(asin(sin(degToRad(Obliquity)) * sin(degToRad(Lambda))));
    
    // Debugging Declination
    std::cout << "Declination (Dec): " << Dec << std::endl;

    double Durinal_Arc = radToDeg(acos((sin(degToRad(-0.8333)) - sin(degToRad(Dec)) * sin(degToRad(latitude))) / (cos(degToRad(Dec)) * cos(degToRad(latitude)))));
    
    // Debugging Durinal Arc
    std::cout << "Durinal Arc: " << Durinal_Arc << std::endl;

    double Noon = Alpha - ST;
    Noon = moreLess360(Noon);
    
    // Debugging Noon (Solar Noon)
    std::cout << "Noon: " << Noon << std::endl;

    double UT_Noon = Noon - longitude;
    
    // Debugging UT Noon
    std::cout << "UT Noon: " << UT_Noon << std::endl;

    ////////////////////////////////////////////
    // Calculating Prayer Times Arcs & Times //
    //////////////////////////////////////////

    // 2) Zuhr Time [Local noon]
    zuhrTime = UT_Noon / 15 + timeZone;
    
    // Debugging Zuhr Time
    std::cout << "Zuhr Time: " << zuhrTime << std::endl;

    // Asr Hanafi
    double Asr_Alt = radToDeg(atan(1 + tan(degToRad(abs(latitude - Dec)))));
    double Asr_Arc = radToDeg(acos((sin(degToRad(90 - Asr_Alt)) - sin(degToRad(Dec)) * sin(degToRad(latitude))) / (cos(degToRad(Dec)) * cos(degToRad(latitude)))));
    Asr_Arc = Asr_Arc / 15;
    
    // Debugging Asr Time
    std::cout << "Asr Arc: " << Asr_Arc << std::endl;

    // 3) Asr Time
    asrTime = zuhrTime + Asr_Arc;
    
    // Debugging Asr Time
    std::cout << "Asr Time: " << asrTime << std::endl;

    // 1) Shorouq Time
    sunRiseTime = zuhrTime - (Durinal_Arc / 15);
    
    // Debugging Sunrise Time
    std::cout << "Sunrise Time: " << sunRiseTime << std::endl;

    // 4) Maghrib Time
    maghribTime = zuhrTime + (Durinal_Arc / 15);
    
    // Debugging Maghrib Time
    std::cout << "Maghrib Time: " << maghribTime << std::endl;

    double Esha_Arc = radToDeg(acos((sin(degToRad(ishaTwilight)) - sin(degToRad(Dec)) * sin(degToRad(latitude))) / (cos(degToRad(Dec)) * cos(degToRad(latitude)))));
    // 5) Isha Time
    ishaTime = zuhrTime + (Esha_Arc / 15);
    
    // Debugging Isha Time
    std::cout << "Isha Time: " << ishaTime << std::endl;

    // 0) Fajr Time
    double Fajr_Arc = radToDeg(acos((sin(degToRad(fajrTwilight)) - sin(degToRad(Dec)) * sin(degToRad(latitude))) / (cos(degToRad(Dec)) * cos(degToRad(latitude)))));
    fajrTime = zuhrTime - (Fajr_Arc / 15);
    
    // Debugging Fajr_Arc and Fajr Time
    std::cout << "Fajr Arc: " << Fajr_Arc << std::endl;
    std::cout << "Fajr Time: " << fajrTime << std::endl;

    return;
}

/*
 Personal code. Calculating for Cairo.

Date: 18-1-2012
Longitude: 30.2
Latitude: 30
Time Zone: +2 
Fajr Twilight: -19.5
Esha Twilight: -17.5
*/

int main() { 
    double fajr, sunRise, zuhr, asr, maghrib, isha;
    calcPrayerTimes(2025,3,9, 3.34, 36.6, 1, -18, -17,
                    fajr, sunRise, zuhr, asr, maghrib, isha);

    int hours, minutes;

    doubleToHrMin(fajr, hours, minutes);
    std::cout << "Fajr: " << hours << ":" << minutes << std::endl;

    doubleToHrMin(sunRise, hours, minutes);
    std::cout << "Sunrise: " << hours << ":" << minutes << std::endl;

    doubleToHrMin(zuhr, hours, minutes);
    std::cout << "Zuhr: " << hours << ":" << minutes << std::endl;

    doubleToHrMin(asr, hours, minutes);
    std::cout << "Asr: " << hours << ":" << minutes << std::endl;

    doubleToHrMin(maghrib, hours, minutes);
    std::cout << "Maghrib: " << hours << ":" << minutes << std::endl;

    doubleToHrMin(isha, hours, minutes);
    std::cout << "Isha: " << hours << ":" << minutes << std::endl;    
}
