MODULE = Date                PACKAGE = Date
PROTOTYPES: DISABLE
#///////////////////////////// STATIC FUNCTIONS ///////////////////////////////////

DateRel* rdate (SV* from = NULL, SV* till = NULL) {
    RETVAL = new DateRel(sv2daterel(from, till));
}

const DateRel* rdate_const (SV* from = NULL, SV* till = NULL) {
    RETVAL = new DateRel(sv2daterel(from, till));
}

#///////////////////////////// OBJECT METHODS ///////////////////////////////////
MODULE = Date                PACKAGE = Date::Rel
PROTOTYPES: DISABLE

DateRel* new (SV*, SV* from = NULL, SV* till = NULL) {
    RETVAL = new DateRel(sv2daterel(from, till));
}

void DateRel::set (SV* from, SV* till = NULL) {
    *THIS = sv2daterel(from, till);
}

ptime_t DateRel::sec (SV* newval = NULL) : ALIAS(second=1, secs=2, seconds=3) {
    if (newval) {
        THIS->sec(xs::in<ptime_t>(newval));
    }
    RETVAL = THIS->sec();
    PERL_UNUSED_VAR(ix);
}

ptime_t DateRel::min (SV* newval = NULL) : ALIAS(mins=1, minute=2, minutes=3) {
    if (newval) THIS->min(xs::in<ptime_t>(newval));
    RETVAL = THIS->min();
    PERL_UNUSED_VAR(ix);
}

ptime_t DateRel::hour (SV* newval = NULL) : ALIAS(hours=1) {
    if (newval) {
        THIS->hour(xs::in<ptime_t>(newval));
    }
    RETVAL = THIS->hour();
    PERL_UNUSED_VAR(ix);
}

ptime_t DateRel::day (SV* newval = NULL) : ALIAS(days=1) {
    if (newval) {
        THIS->day(xs::in<ptime_t>(newval));
    }
    RETVAL = THIS->day();
    PERL_UNUSED_VAR(ix);
}

ptime_t DateRel::month (SV* newval = NULL) : ALIAS(mon=1, months=2, mons=3) {
    if (newval) {
        THIS->month(xs::in<ptime_t>(newval));
    }
    RETVAL = THIS->month();
    PERL_UNUSED_VAR(ix);
}

ptime_t DateRel::year (SV* newval = NULL) : ALIAS(years=1) {
    if (newval) {
        THIS->year(xs::in<ptime_t>(newval));
    }
    RETVAL = THIS->year();
    PERL_UNUSED_VAR(ix);
}

ptime_t DateRel::to_sec () : ALIAS(to_second=1, to_secs=2, to_seconds=3, duration=4) const {
    RETVAL = THIS->to_sec();
    PERL_UNUSED_VAR(ix);
}

double DateRel::to_min () : ALIAS(to_minute=1, to_mins=2, to_minutes=3) const {
    RETVAL = THIS->to_min();
    PERL_UNUSED_VAR(ix);
}

double DateRel::to_hour () : ALIAS(to_hours=1) const {
    RETVAL = THIS->to_hour();
    PERL_UNUSED_VAR(ix);
}

double DateRel::to_day () : ALIAS(to_days=1) const {
    RETVAL = THIS->to_day();
    PERL_UNUSED_VAR(ix);
}

double DateRel::to_month () : ALIAS(to_mon=1, to_months=2, to_mons=3) const {
    RETVAL = THIS->to_month();
    PERL_UNUSED_VAR(ix);
}

double DateRel::to_year () : ALIAS(to_years=1) const {
    RETVAL = THIS->to_year();
    PERL_UNUSED_VAR(ix);
}

string DateRel::to_string (...) : ALIAS(as_string=1, string=2) const {
    RETVAL = THIS->to_string();
    PERL_UNUSED_VAR(ix);
}

bool DateRel::to_bool (...) : const {
    RETVAL = THIS->to_sec();
}

ptime_t DateRel::to_number (...) : const {
    RETVAL = THIS->to_sec();
}

Sv DateRel::sum (Sv arg, ...) : ALIAS(add_new=1) const {
    if (ix == 1) warn("add_new() is deprecated, use sum() instead");
    if (arg.is_object_ref()) {
        Stash s = Object(arg).stash();
        if (s.name() == "Date::Rel")
            RETVAL = xs::out(new DateRel(*THIS + *xs::in<const DateRel*>(arg)), Object(ST(0)).stash());
        else if (s.name() == "Date")
            RETVAL = xs::out(new Date(*xs::in<Date*>(arg) + *THIS));
        else
            RETVAL = xs::out(new DateInt(*xs::in<DateInt*>(arg) + *THIS));
    }
    else RETVAL = xs::out(new DateRel(*THIS + sv2daterel(arg)), Object(ST(0)).stash());
}

SV* DateRel::add (Sv arg, ...) {
    *THIS += sv2daterel(arg);
    XSRETURN(1);
}

DateRel* DateRel::difference (Sv arg, bool reverse = false) : ALIAS(subtract_new=1) const {
    if (ix == 1) warn("subtract_new() is deprecated, use difference() instead");
    auto op = sv2daterel(arg);
    RETVAL = new DateRel(reverse ? (op - *THIS) : (*THIS - op));
    PROTO = Object(ST(0)).stash();
}

SV* DateRel::subtract (Sv arg, ...) {
    *THIS -= sv2daterel(arg);
    XSRETURN(1);
}

DateRel* DateRel::product (SV* arg, ...) : ALIAS(multiply_new=1) const {
    if (ix == 1) warn("multiply_new() is deprecated, use product() instead");
    RETVAL = new DateRel(*THIS * SvNV(arg));
    PROTO = Object(ST(0)).stash();
}

SV* DateRel::multiply (SV* arg, ...) {
    *THIS *= SvNV(arg);
    XSRETURN(1);
}

DateRel* DateRel::quotient (SV* arg, bool reverse = false) : ALIAS(divide_new=1) const {
    if (ix == 1) warn("divide_new() is deprecated, use quotient() instead");
    if (reverse) throw "Date: illegal divison $num/$reldate";
    RETVAL = new DateRel(*THIS / SvNV(arg));
    PROTO = Object(ST(0)).stash();
}

SV* DateRel::divide (SV* arg, bool reverse = false) {
    if (reverse) throw "Date: illegal divison $num/$reldate";
    *THIS /= SvNV(arg);
    XSRETURN(1);
}

DateRel* DateRel::negated (...) : ALIAS(negative_new=1) const {
    if (ix == 1) warn("negative_new() is deprecated, use negated() instead");
    RETVAL = new DateRel(THIS->negated());
    PROTO = Object(ST(0)).stash();
}

SV* DateRel::negate () : ALIAS(negative=1) {
    if (ix == 1) warn("negative() is deprecated, use negate() instead");
    THIS->negate();
    XSRETURN(1);
}

int DateRel::compare (Sv arg, bool reverse) : const {
    RETVAL = THIS->compare(sv2daterel(arg));
    if (reverse) RETVAL = -RETVAL;
    if      (RETVAL < 0) RETVAL = -1;
    else if (RETVAL > 0) RETVAL = 1;
}

bool DateRel::is_same (Sv arg, ...) : ALIAS(equals=1) const {
    if (ix == 1) warn("equals() is deprecated, use is_same() instead");
    RETVAL = THIS->is_same(sv2daterel(arg));
}

DateRel* DateRel::clone () {
    RETVAL = new DateRel(*THIS);
    PROTO = Object(ST(0)).stash();
}