import numpy as np

def isListy(x):
    if isinstance(x,(list,tuple)): return True
    if (isinstance(x,np.ndarray)): return True
    return False
def toArray(x):
    if ((int==type(x)) | (float==type(x))): x=np.array([x])
    if (list==type(x)): x=np.array(x)
    return x
def isLeap(year):
    return (0==year%4) & ( (0!=year%100) | (0==year%400) )

def gregToJDN(year,month,day):
    a=(14 - month)//12
    y = year + 4800 - a
    m = month + (12*a) - 3
    jdn = day + (2+153*m)//5 + 365*y + y//4 - y//100 + y//400 - 32045
    return jdn

def jdnToGreg(jd):
    a = jd + 32044
    b = (4*a + 3)//146097
    c = a - (146097*b)//4
    d = (4*c + 3)//1461
    e = c - (1461*d)//4
    m = (5*e + 2)//153

    day = e + 1 - (153*m + 2)//5
    month = m + 3 - 12*(m//10)
    year = 100*b + d - 4800 + m/10
    return (year,month,day)

class datex:
    def __init__(self,jd):
        if (str==type(jd)): jd=[jd]
        if (isListy(jd)):
            if (str==type(jd[0])):
                jd = gregToJDN(*np.array([ (int(x[:4]),int(x[5:7]),int(x[8:10])) for x in jd ]).transpose())

        self._jd = toArray(jd)
    @classmethod
    def fromJulian(cls,jd):
        return cls(jd)
    @classmethod
    def fromYMD(cls,year,month,day):
        year=toArray(year)
        month=toArray(month)
        day = toArray(day)
        jdn = gregToJDN(year,month,day)
        return cls(jdn)
    def asJulian(self):
        return self._jd
    def asYMD(self):
        return jdnToGreg(self._jd)
    def asYMDs(self):
        return np.array(self.asYMD()).transpose()
    def addYears(self,n):
        (y,m,d) = self.asYMD()
        self._jd = gregToJDN(y+toArray(n),m,d)
    def addMonths(self,n):
        n=toArray(n)
        (y,m,d) = self.asYMD()
        y=y+n//12
        m=m+(n%12)
        self._jd = gregToJDN(y,m,d)
    def addDays(self,n):
        self._jd += toArray(n)
    def isoformat(self):
        fmt = "%04d-%02d-%02d"
        return [ fmt%tuple(x) for x in self.asYMDs() ]
    def __repr__(self):
        return "datex(" + str(self.isoformat()) + ")"

