1 /*
  2  * PersianAlgoCal.js - Represent a Persian algorithmic calendar object.
  3  *
  4  * Copyright © 2014-2015,2018, JEDLSoft
  5  *
  6  * Licensed under the Apache License, Version 2.0 (the "License");
  7  * you may not use this file except in compliance with the License.
  8  * You may obtain a copy of the License at
  9  *
 10  *     http://www.apache.org/licenses/LICENSE-2.0
 11  *
 12  * Unless required by applicable law or agreed to in writing, software
 13  * distributed under the License is distributed on an "AS IS" BASIS,
 14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 15  *
 16  * See the License for the specific language governing permissions and
 17  * limitations under the License.
 18  */
 19 
 20 var MathUtils = require("./MathUtils.js");
 21 var Calendar = require("./Calendar.js");
 22 
 23 /**
 24  * @class
 25  * Construct a new Persian algorithmic calendar object. This class encodes information about
 26  * a Persian algorithmic calendar.<p>
 27  *
 28  * @param {Object=} options Options governing the construction of this instance
 29  * @constructor
 30  * @extends Calendar
 31  */
 32 var PersianAlgoCal = function(options) {
 33     this.type = "persian-algo";
 34 
 35     if (options && typeof(options.onLoad) === "function") {
 36         options.onLoad(this);
 37     }
 38 };
 39 
 40 /**
 41  * @private
 42  * @const
 43  * @type Array.<number>
 44  * the lengths of each month
 45  */
 46 PersianAlgoCal.monthLengths = [
 47     31,  // Farvardin
 48     31,  // Ordibehesht
 49     31,  // Khordad
 50     31,  // Tir
 51     31,  // Mordad
 52     31,  // Shahrivar
 53     30,  // Mehr
 54     30,  // Aban
 55     30,  // Azar
 56     30,  // Dey
 57     30,  // Bahman
 58     29   // Esfand
 59 ];
 60 
 61 /**
 62  * Return the number of months in the given year. The number of months in a year varies
 63  * for some luni-solar calendars because in some years, an extra month is needed to extend the
 64  * days in a year to an entire solar year. The month is represented as a 1-based number
 65  * where 1=first month, 2=second month, etc.
 66  *
 67  * @param {number} year a year for which the number of months is sought
 68  * @return {number} The number of months in the given year
 69  */
 70 PersianAlgoCal.prototype.getNumMonths = function(year) {
 71     return 12;
 72 };
 73 
 74 /**
 75  * Return the number of days in a particular month in a particular year. This function
 76  * can return a different number for a month depending on the year because of things
 77  * like leap years.
 78  *
 79  * @param {number} month the month for which the length is sought
 80  * @param {number} year the year within which that month can be found
 81  * @return {number} the number of days within the given month in the given year
 82  */
 83 PersianAlgoCal.prototype.getMonLength = function(month, year) {
 84     if (month !== 12 || !this.isLeapYear(year)) {
 85         return PersianAlgoCal.monthLengths[month-1];
 86     } else {
 87         // Month 12, Esfand, has 30 days instead of 29 in leap years
 88         return 30;
 89     }
 90 };
 91 
 92 /**
 93  * Return the equivalent year in the 2820 year cycle that begins on
 94  * Far 1, 474. This particular cycle obeys the cycle-of-years formula
 95  * whereas the others do not specifically. This cycle can be used as
 96  * a proxy for other years outside of the cycle by shifting them into
 97  * the cycle.
 98  * @param {number} year year to find the equivalent cycle year for
 99  * @returns {number} the equivalent cycle year
100  */
101 PersianAlgoCal.prototype.equivalentCycleYear = function(year) {
102     var y = year - (year >= 0 ? 474 : 473);
103     return MathUtils.mod(y, 2820) + 474;
104 };
105 
106 /**
107  * Return true if the given year is a leap year in the Persian calendar.
108  * The year parameter may be given as a number, or as a PersAlgoDate object.
109  * @param {number} year the year for which the leap year information is being sought
110  * @return {boolean} true if the given year is a leap year
111  */
112 PersianAlgoCal.prototype.isLeapYear = function(year) {
113     return (MathUtils.mod((this.equivalentCycleYear(year) + 38) * 682, 2816) < 682);
114 };
115 
116 /**
117  * Return the type of this calendar.
118  *
119  * @return {string} the name of the type of this calendar
120  */
121 PersianAlgoCal.prototype.getType = function() {
122     return this.type;
123 };
124 
125 
126 /* register this calendar for the factory method */
127 Calendar._constructors["persian-algo"] = PersianAlgoCal;
128 
129 module.exports = PersianAlgoCal;
130