/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
package gplx;
import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Locale;
import java.util.TimeZone;
public class DateAdp_ implements GfoInvkAble {
	public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {
		if		(ctx.Match(k, Invk_Now))		return Now();
		else									return GfoInvkAble_.Rv_unhandled;			
	}	public static final String Invk_Now = "Now";
	public static final DateAdp MinValue		= new DateAdp(   1,  1,  1,  0,  0,  0,   0); 
	public static final DateAdp MaxValue		= new DateAdp(9999, 12, 31, 23, 59, 59, 999); 
	public static DateAdp Now() {return Tfds.Now_enabled() ? Tfds.Now() : new DateAdp(new GregorianCalendar());}
	public static DateAdp new_(int year, int month, int day, int hour, int minute, int second, int frac) {return new DateAdp(year, month, day, hour, minute, second, frac);}
	public static DateAdp seg_(int[] ary) {
		int ary_len = ary.length;
		int y = ary_len > 0 ? ary[0] : 1;
		int M = ary_len > 1 ? ary[1] : 1;
		int d = ary_len > 2 ? ary[2] : 1;
		int h = ary_len > 3 ? ary[3] : 0;
		int m = ary_len > 4 ? ary[4] : 0;
		int s = ary_len > 5 ? ary[5] : 0;
		int f = ary_len > 6 ? ary[6] : 0;
		return new DateAdp(y, M, d, h, m, s, f);
	}
	public static DateAdp cast_(Object arg) {try {return (DateAdp)arg;} catch(Exception exc) {throw Err_.type_mismatch_exc_(exc, DateAdp.class, arg);}}
	public static DateAdp parse_iso8561(String raw) {	// NOTE: for now, same as parse_gplx
		int[] ary = date_parser.Parse_iso8651_like(raw);
		if (ary[1] < 1 || ary[1] > 12) return DateAdp_.MinValue;	// guard against invalid month
		if (ary[2] < 1 || ary[2] > 31) return DateAdp_.MinValue;
		return new DateAdp(ary[0], ary[1], ary[2], ary[3], ary[4], ary[5], ary[6]);
	}
	public static DateAdp parse_gplx(String raw)		{
		int[] ary = date_parser.Parse_iso8651_like(raw);
		if (ary[1] < 1 || ary[1] > 12) return DateAdp_.MinValue;	// guard against invalid month
		if (ary[2] < 1 || ary[2] > 31) return DateAdp_.MinValue;
		return new DateAdp(ary[0], ary[1], ary[2], ary[3], ary[4], ary[5], ary[6]);
	}	static DateAdp_parser date_parser = DateAdp_parser.new_();
	public static DateAdp dateTime_(GregorianCalendar v) {return new DateAdp(v);}
	public static DateAdp dateTime_obj_(Object v) {return new DateAdp((GregorianCalendar)v);}
	public static final DateAdp_ Gfs = new DateAdp_();

	public static int DaysInMonth(DateAdp date) {			
		int rv = DaysInMonth_ary[date.Month() - Int_.Base1];
		if (rv == 28 && IsLeapYear(date.Year())) rv = 29;
		return rv;
	}	static int [] DaysInMonth_ary = {31,28,31,30,31,30,31,31,30,31,30,31};
	public static boolean IsLeapYear(int year) {
		if		(year % 4   != 0)	return false;
		else if (year % 400 == 0)	return true;
		else if (year % 100 == 0)	return false;
		else						return true;
	}
	public static DateAdp unixtime_utc_seconds_(long v) {return unixtime_utc_ms_(v * 1000);}
		public static DateAdp db_(Object v) {
		Timestamp ts = (Timestamp)v;		
		Calendar gc = Calendar.getInstance();
		gc.setTimeInMillis(ts.getTime());
		return new DateAdp(gc);
	}
	public static DateAdp parse_(String raw) {
		SimpleDateFormat sdf = new SimpleDateFormat();
		Date d = null;
		try 	{d = sdf.parse(raw);}
		catch 	(ParseException e) {throw Err_.new_key_("parse", "failed to parse to DateAdp").Add("raw", raw);}
		GregorianCalendar cal = (GregorianCalendar)Calendar.getInstance();
		cal.setTime(d);
		return dateTime_(cal);
	}
	public static DateAdp parse_fmt(String raw, String fmt) {
		fmt = fmt.replace('t', 'a');	// AM/PM
		fmt = fmt.replace('f', 'S');	// milliseconds
		SimpleDateFormat sdf = new SimpleDateFormat(fmt, Locale.US);
		Date d = null;
		try 	{d = sdf.parse(raw);}
		catch 	(ParseException e) {throw Err_.new_key_("parse", "failed to parse to DateAdp").Add("raw", raw).Add("fmt", fmt);}
		GregorianCalendar cal = (GregorianCalendar)Calendar.getInstance();
		cal.setTime(d);
		return dateTime_(cal);
	}
	public static DateAdp unixtime_utc_ms_(long v) {return unixtime_lcl_ms_(v).XtoUtc();}
	public static DateAdp unixtime_lcl_ms_(long v) {
		GregorianCalendar c = new GregorianCalendar();
		c.setTimeInMillis(v);
		return new DateAdp(c);
	}
		public static final int SegIdx_year = 0, SegIdx_month = 1, SegIdx_day = 2, SegIdx_hour = 3, SegIdx_minute = 4, SegIdx_second = 5, SegIdx_frac = 6, SegIdx_dayOfWeek = 7, SegIdx_weekOfYear = 8, SegIdx_dayOfYear = 9, SegIdx__max = 10;
	public static final String Fmt_iso8561_date_time = "yyyy-MM-dd HH:mm:ss";
	public static String Xto_str_fmt_or(DateAdp v, String fmt, String or) {
		return v == null ? or : v.XtoStr_fmt(fmt);
	}
}
