package abstrasy.externals;
/**
* Abstrasy Interpreter
*
* Copyright : Copyright (c) 2006-2012, Luc Bruninx.
*
* Concédée sous licence EUPL, version 1.1 uniquement (la «Licence»).
*
* Vous ne pouvez utiliser la présente oeuvre que conformément à la Licence.
* Vous pouvez obtenir une copie de la Licence à l’adresse suivante:
*
* http://www.osor.eu/eupl
*
* Sauf obligation légale ou contractuelle écrite, le logiciel distribué sous
* la Licence est distribué "en l’état", SANS GARANTIES OU CONDITIONS QUELLES
* QU’ELLES SOIENT, expresses ou implicites.
*
* Consultez la Licence pour les autorisations et les restrictions
* linguistiques spécifiques relevant de la Licence.
*
*
* @author Luc Bruninx
* @version 1.0
*/
import abstrasy.Bivalence;
import abstrasy.Hash;
import abstrasy.Heap;
import abstrasy.Interpreter;
import abstrasy.Node;
import abstrasy.PCoder;
import abstrasy.SELF;
import abstrasy.interpreter.InterpreterException;
import abstrasy.interpreter.ORef;
import abstrasy.interpreter.StdErrors;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
public class External_Date implements AExtClonable,
AExtCachable {
private final static String K_HOUR = "Hour";
private final static String K_MINUTE = "Minute";
private final static String K_SECOND = "Second";
private final static String K_MILLIS = "Millisecond";
private final static String K_DAY = "Day";
private final static String K_MONTH = "Month";
private final static String K_YEAR = "Year";
private final static String DATE_SHORT_FORMAT = "dd/MM/yy";
private final static String DATE_DEFAULT_FORMAT = "dd/MM/yyyy";
private final static String DATE_LONG_FORMAT = "d MMM yyyy";
private final static String TIME_SHORT_FORMAT = "HH:mm";
private final static String TIME_DEFAULT_FORMAT = "HH:mm:ss";
private final static String TIME_LONG_FORMAT = "HH:mm:ss a";
// Formats courants de dates en SQL
private final static String TIME_STAMP_FORMAT = "yyyyMMddHHmmss";
private final static String DATE_STAMP_FORMAT = "yyyy-MM-dd";
private final static String DATETIME_STAMP_FORMAT = "yyyy-MM-dd HH:mm:ss";
private final static String MONTH_STAMP_FORMAT = "yyyy-MM";
private final static String YEAR_STAMP_FORMAT = "yyyy";
// Formats RFC-* courants
private final static String RFC1123_STAMP_FORMAT = "EEE, dd MMM yyyy HH:mm:ss z";
private final static String RFC1036_STAMP_FORMAT = "EEEEEEEEE, dd-MMM-yy HH:mm:ss z";
// Format c-asctime
private final static String ASCTIME_STAMP_FORMAT = "EEE MMM d HH:mm:ss yyyy";
private Date date = new Date();
private String date_default_format = DATE_DEFAULT_FORMAT;
private String time_default_format = TIME_DEFAULT_FORMAT;
public External_Date() {
}
private static Node dateToListOfPairs(Date d) throws Exception {
Calendar c = Calendar.getInstance();
c.setTime(d);
int h = c.get(Calendar.HOUR_OF_DAY);
int m = c.get(Calendar.MINUTE);
int s = c.get(Calendar.SECOND);
int ms = c.get(Calendar.MILLISECOND);
int dd = c.get(Calendar.DAY_OF_MONTH);
int mm = c.get(Calendar.MONTH);
int yy = c.get(Calendar.YEAR);
Node listOfPairs = Node.createHash();
Hash hash=listOfPairs.getHash();
hash.store(new Node(K_DAY), new Node(dd));
hash.store(new Node(K_MONTH), new Node(mm + 1));
hash.store(new Node(K_YEAR), new Node(yy));
hash.store(new Node(K_HOUR), new Node(h));
hash.store(new Node(K_MINUTE), new Node(m));
hash.store(new Node(K_SECOND), new Node(s));
hash.store(new Node(K_MILLIS), new Node(ms));
return listOfPairs;
}
private static Node intToListOfPairs(int h, int m, int s, int ms, int dd, int mm, int yy) throws Exception {
Node listOfPairs = Node.createHash();
Hash hash=listOfPairs.getHash();
if (dd != 0)
hash.store(new Node(K_DAY), new Node(dd));
if (mm != 0)
hash.store(new Node(K_MONTH), new Node(mm));
if (yy != 0)
hash.store(new Node(K_YEAR), new Node(yy));
if (h != 0)
hash.store(new Node(K_HOUR), new Node(h));
if (m != 0)
hash.store(new Node(K_MINUTE), new Node(m + 1));
if (s != 0)
hash.store(new Node(K_SECOND), new Node(s));
if (ms != 0)
hash.store(new Node(K_MILLIS), new Node(ms));
if (listOfPairs.size() == 0)
hash.store(new Node(K_MILLIS), new Node(ms));
return listOfPairs;
}
public static Node external_milliseconds_to_delta(Node startAt) throws Exception {
startAt.isGoodArgsLength(true, 2);
Node anode = startAt.getSubNode(1, Node.TYPE_NUMBER);
long millis = (long) anode.getNumber();
long mps = 1000;
long mpm = mps * 60;
long mph = mpm * 60;
long mpd = mph * 24;
long d = millis / mpd;
millis = millis % mpd;
long h = millis / mph;
millis = millis % mph;
long m = millis / mpm;
millis = millis % mpm;
long s = millis / mps;
millis = millis % mps;
return intToListOfPairs((int) h, (int) m + 1, (int) s, (int) millis, (int) d, 0, 0);
}
public static Node external_delta_to_milliseconds(Node startAt) throws Exception {
startAt.isGoodArgsLength(true, 2);
Node anode = startAt.getSubNode(1, Node.TYPE_HASH);
long mps = 1000;
long mpm = mps * 60;
long mph = mpm * 60;
long mpd = mph * 24;
Hash hash=anode.getHash();
int h = getNumPairValueIfExists(0, hash, new Node(K_HOUR));
int m = getNumPairValueIfExists(0, hash, new Node(K_MINUTE));
int s = getNumPairValueIfExists(0, hash, new Node(K_SECOND));
int ms = getNumPairValueIfExists(0, hash, new Node(K_MILLIS));
int dd = getNumPairValueIfExists(0, hash, new Node(K_DAY));
int mm = getNumPairValueIfExists(0, hash, new Node(K_MONTH));
int yy = getNumPairValueIfExists(0, hash, new Node(K_YEAR));
if ((mm != 0)||(yy != 0)) {
throw new InterpreterException(StdErrors.extend(StdErrors.Invalid_parameter,"unreliable"));
}
return new Node(ms + (s * mps) + (m * mpm) + (h * mph) + (dd * mpd));
}
public Node external_milliseconds(Node startAt) throws Exception {
startAt.isGoodArgsCnt(1);
return new Node(date.getTime());
}
public Node external_get_now(Node startAt) throws Exception {
startAt.isGoodArgsLength(true, 1);
return dateToListOfPairs(new Date());
}
public Node external_mutator_set_now(Node startAt) throws Exception {
startAt.isGoodArgsLength(true, 1);
SELF.require_SELF_mutable();
date = new Date();
return null;
}
private static final Node getNumPairValue(Hash pairlist, Node k) throws Exception {
Node res = null;
if (pairlist.hasKey(k)) {
res=pairlist.ref(k);
if (!res.isNumber()) {
throw new InterpreterException(StdErrors.Argument_type_mismatch);
}
}
return res;
}
private static final int getNumPairValueIfExists(int initialValue, Hash pairlist, Node k) throws Exception {
int res = initialValue;
Node tmp = getNumPairValue(pairlist, k);
if (tmp != null) {
res = (int) tmp.getNumber();
}
return res;
}
private static final Date nodeToDate(Node arg) throws Exception {
Date d = new Date();
long qt=arg.getQType();
if (qt==Node.TYPE_NUMBER) {
d.setTime((long) arg.getNumber());
return d;
}
else if (qt==Node.TYPE_HASH) {
Calendar c = Calendar.getInstance();
int h = c.get(Calendar.HOUR_OF_DAY);
int m = c.get(Calendar.MINUTE);
int s = c.get(Calendar.SECOND);
int ms = c.get(Calendar.MILLISECOND);
int dd = c.get(Calendar.DAY_OF_MONTH);
int mm = c.get(Calendar.MONTH);
int yy = c.get(Calendar.YEAR);
Hash hash=arg.getHash();
h = getNumPairValueIfExists(h, hash, new Node(K_HOUR));
m = getNumPairValueIfExists(m, hash, new Node(K_MINUTE));
s = getNumPairValueIfExists(s, hash, new Node(K_SECOND));
ms = getNumPairValueIfExists(ms,hash, new Node(K_MILLIS));
dd = getNumPairValueIfExists(dd, hash, new Node(K_DAY));
mm = getNumPairValueIfExists(mm, hash, new Node(K_MONTH)) - 1;
yy = getNumPairValueIfExists(yy, hash, new Node(K_YEAR));
c.set(Calendar.MILLISECOND, ms);
c.set(yy, mm, dd, h, m, s);
return c.getTime();
}
else if(arg.isDelegable()){
// délégable...
if(arg.isExternal()){
// optimisation dans le cas d'un external...
Object o=arg.getExternal();
if(o instanceof External_Date)
return ((External_Date)o).date;
}
// pas d'optimisation possible... alors la forme générale...
Node t=Node.VDelegable.evalMethod_or_null(arg, "to-date",null);
if(t!=null)
return nodeToDate(t);
// sinon on essaye avec number...
t=Node.VDelegable.evalMethod_or_null(arg, PCoder.getMethod(PCoder.PC_NUMBER),null);
if(t!=null)
return nodeToDate(t);
}
// sinon, et bien...
throw new InterpreterException(StdErrors.extend(StdErrors.Invalid_parameter, "This object do not implement :to-date method (" + arg.toString() + ")"));
}
public Node external_mutator_set(Node startAt) throws Exception {
startAt.isGoodArgsLength(true, 2);
SELF.require_SELF_mutable();
Node anode = startAt.getSubNode(1, Node.TYPE_HASH|Node.TYPE_NUMBER|Node.VTYPE_DELEGABLE);
if (anode.isNumber()) {
date.setTime((long) anode.getNumber());
}
else if (anode.getQType()==Node.TYPE_HASH) {
Calendar c = Calendar.getInstance();
int h = c.get(Calendar.HOUR_OF_DAY);
int m = c.get(Calendar.MINUTE);
int s = c.get(Calendar.SECOND);
int ms = c.get(Calendar.MILLISECOND);
int dd = c.get(Calendar.DAY_OF_MONTH);
int mm = c.get(Calendar.MONTH);
int yy = c.get(Calendar.YEAR);
Hash hash=anode.getHash();
h = getNumPairValueIfExists(h, hash, new Node(K_HOUR));
m = getNumPairValueIfExists(m, hash, new Node(K_MINUTE));
s = getNumPairValueIfExists(s, hash, new Node(K_SECOND));
ms = getNumPairValueIfExists(ms, hash, new Node(K_MILLIS));
dd = getNumPairValueIfExists(dd, hash, new Node(K_DAY));
mm = getNumPairValueIfExists(mm, hash, new Node(K_MONTH)) - 1;
yy = getNumPairValueIfExists(yy, hash, new Node(K_YEAR));
c.set(Calendar.MILLISECOND, ms);
c.set(yy, mm, dd, h, m, s);
date = c.getTime();
}
else {
// clonage de l'objet externe
Object obj = anode.getExternalInstanceOf(External_Date.class);
External_Date parent = (External_Date) obj;
date.setTime(parent.date.getTime());
date_default_format = parent.date_default_format;
time_default_format = parent.time_default_format;
}
return null;
}
public Node external_is_equ(Node startAt) throws Exception {
startAt.isGoodArgsCnt(2);
Node anode = startAt.getSubNode(1, Node.TYPE_HASH|Node.TYPE_NUMBER|Node.VTYPE_DELEGABLE);
Date d = nodeToDate(anode);
return new Node(date.equals(d) ? Node.TRUE:Node.FALSE);
}
public Node external_compare(Node startAt) throws Exception {
startAt.isGoodArgsCnt(2);
Node anode = startAt.getSubNode(1, Node.TYPE_HASH | Node.TYPE_NUMBER | Node.VTYPE_DELEGABLE);
Date d = nodeToDate(anode);
return new Node(date.compareTo(d));
}
public Node external_is_before(Node startAt) throws Exception {
startAt.isGoodArgsCnt(2);
Node anode = startAt.getSubNode(1, Node.TYPE_HASH|Node.TYPE_NUMBER|Node.VTYPE_DELEGABLE);
Date d = nodeToDate(anode);
Node res;
if (date.before(d)) {
res = new Node(Node.TRUE);
}
else {
res = new Node(Node.FALSE);
}
return res;
}
public Node external_is_after(Node startAt) throws Exception {
startAt.isGoodArgsCnt(2);
Node anode = startAt.getSubNode(1, Node.TYPE_HASH|Node.TYPE_NUMBER|Node.VTYPE_DELEGABLE);
Date d = nodeToDate(anode);
Node res;
if (date == d)
Interpreter.Log("external_is_after : oups !!!");
if (date.after(d))
res = new Node(Node.TRUE);
else
res = new Node(Node.FALSE);
return res;
}
/*
Letter Date or Time Examples
G : Era designator (AD)
y : Year (1996; 96)
M : Month in year (July; Jul; 07)
w : Week in year (27)
W : Week in month (2)
D : Day in year (189)
d : Day in month (10)
F : Day of week in month (2)
E : Day in week (Tuesday; Tue)
a : Am/pm marker (PM)
H : Hour in day (0-23)
k : Hour in day (1-24)
K : Hour in am/pm (0-11)
h : Hour in am/pm (1-12)
m : Minute in hour
s : Second in minute
S : Millisecond
z : Time zone (Pacific Standard Time; PST; GMT-08:00)
Z : Time zone (-0800)
*/
/*
* Si on décommente cette méthode, on supprime la mise en cache
*
public Node externalpc_uncache() throws Exception {
return null;
}
*
*/
private static Node _TK_ = null;
public Node external_get_TK(Node startAt) throws Exception {
startAt.isGoodArgsCnt(1);
if (_TK_ == null) {
Heap tkh = new Heap();
tkh.put("HOUR", new Node(K_HOUR));
tkh.put("MINUTE", new Node(K_MINUTE));
tkh.put("SECOND", new Node(K_SECOND));
tkh.put("MILLIS", new Node(K_MILLIS));
tkh.put("DAY", new Node(K_DAY));
tkh.put("MONTH", new Node(K_MONTH));
tkh.put("YEAR", new Node(K_YEAR));
tkh.put("DATE-SHORT-FORMAT", new Node(DATE_SHORT_FORMAT));
tkh.put("DATE-LONG-FORMAT", new Node(DATE_LONG_FORMAT));
tkh.put("TIME-SHORT-FORMAT", new Node(TIME_SHORT_FORMAT));
tkh.put("TIME-DEFAULT-FORMAT", new Node(TIME_DEFAULT_FORMAT));
tkh.put("TIME-LONG-FORMAT", new Node(TIME_LONG_FORMAT));
tkh.put("TIME-STAMP-FORMAT", new Node(TIME_STAMP_FORMAT));
tkh.put("DATE-STAMP-FORMAT", new Node(DATE_STAMP_FORMAT));
tkh.put("DATETIME-STAMP-FORMAT", new Node(DATETIME_STAMP_FORMAT));
tkh.put("MONTH-STAMP-FORMAT", new Node(MONTH_STAMP_FORMAT));
tkh.put("YEAR-STAMP-FORMAT", new Node(YEAR_STAMP_FORMAT));
tkh.put("RFC1123-STAMP-FORMAT", new Node(RFC1123_STAMP_FORMAT));
tkh.put("RFC1036-STAMP-FORMAT", new Node(RFC1036_STAMP_FORMAT));
tkh.put("ASCTIME-STAMP-FORMAT", new Node(ASCTIME_STAMP_FORMAT));
_TK_ = new Node(tkh);
}
return _TK_;
}
public Node external_date_string(Node startAt) throws Exception {
startAt.isGoodArgsCnt(1);
SimpleDateFormat sdf = new SimpleDateFormat(this.date_default_format);
return new Node(sdf.format(date));
}
public Node external_time_string(Node startAt) throws Exception {
startAt.isGoodArgsCnt(1);
SimpleDateFormat sdf = new SimpleDateFormat(this.time_default_format);
return new Node(sdf.format(date));
}
public Node external_string(Node startAt) throws Exception {
startAt.isGoodArgsCnt(1);
SimpleDateFormat sdf1 = new SimpleDateFormat(this.date_default_format);
SimpleDateFormat sdf2 = new SimpleDateFormat(this.time_default_format);
return new Node(sdf1.format(date) + " " + sdf2.format(date));
}
public Node external_number(Node startAt) throws Exception {
startAt.isGoodArgsCnt(1);
return new Node(date.getTime());
}
public Node external_list(Node startAt) throws Exception {
startAt.isGoodArgsCnt(1);
return dateToListOfPairs(date);
}
public Node external_mutator_set_DateFormat(Node startAt) throws Exception {
startAt.isGoodArgsCnt(2);
SELF.require_SELF_mutable();
Node anode = startAt.getSubNode(1, Node.TYPE_STRING);
date_default_format = anode.getString();
return null;
}
public Node external_mutator_set_TimeFormat(Node startAt) throws Exception {
startAt.isGoodArgsCnt(2);
SELF.require_SELF_mutable();
Node anode = startAt.getSubNode(1, Node.TYPE_STRING);
time_default_format = anode.getString();
return null;
}
public Node external_format_string(Node startAt) throws Exception {
startAt.isGoodArgsCnt(2,3,4);
String format = startAt.getSubNode(1, Node.TYPE_STRING).getString();
Locale locale = null;
if(startAt.size()>=3){
String[] iso=startAt.getSubNode(2, Node.TYPE_STRING).getString().split("\\-");
locale=iso.length==1 ? new Locale(iso[0]) : new Locale(iso[0],iso[1]);
}
SimpleDateFormat sdf = locale==null ? new SimpleDateFormat(format) : new SimpleDateFormat(format,locale);
if(startAt.size()==4){
sdf.setTimeZone(TimeZone.getTimeZone(startAt.getSubNode(3, Node.TYPE_STRING).getString()));
}
return new Node(sdf.format(date));
}
public Node external_mutator_parse(Node startAt) throws Exception {
startAt.isGoodArgsCnt(3,4,5);
SELF.require_SELF_mutable();
String str = startAt.getSubNode(1, Node.TYPE_STRING).getString();
String format = startAt.getSubNode(2, Node.TYPE_STRING).getString();
Locale locale = null;
if(startAt.size()>=4){
String[] iso=startAt.getSubNode(3, Node.TYPE_STRING).getString().split("\\-");
locale=iso.length==1 ? new Locale(iso[0]) : new Locale(iso[0],iso[1]);
}
SimpleDateFormat sdf = locale==null ? new SimpleDateFormat(format) : new SimpleDateFormat(format,locale);
if(startAt.size()==5){
sdf.setTimeZone(TimeZone.getTimeZone(startAt.getSubNode(4, Node.TYPE_STRING).getString()));
}
date = sdf.parse(str);
return null;
}
public Node external_mutator_parse_date(Node startAt) throws Exception {
startAt.isGoodArgsLength(true, 2);
SELF.require_SELF_mutable();
Node anode = startAt.getSubNode(1, Node.TYPE_STRING);
SimpleDateFormat sdf = new SimpleDateFormat(this.date_default_format);
date = sdf.parse(anode.getString());
return null;
}
public Node external_mutator_parse_time(Node startAt) throws Exception {
startAt.isGoodArgsLength(true, 2);
SELF.require_SELF_mutable();
Node anode = startAt.getSubNode(1, Node.TYPE_STRING);
SimpleDateFormat sdf = new SimpleDateFormat(this.time_default_format);
date = sdf.parse(anode.getString());
return null;
}
public Node external_mutator_add_delta(Node startAt) throws Exception {
startAt.isGoodArgsLength(true, 2);
SELF.require_SELF_mutable();
Node anode = startAt.getSubNode(1, Node.TYPE_HASH | Node.TYPE_NUMBER);
if (anode.getQType()==Node.TYPE_NUMBER) {
date.setTime(date.getTime() + (long) anode.getNumber());
}
else {
// hash
Hash hash = anode.getHash();
Calendar c = Calendar.getInstance();
c.setTime(date);
Node tmp;
tmp = getNumPairValue(hash, new Node(K_HOUR));
if (tmp != null) {
c.add(Calendar.HOUR, (int) tmp.getNumber());
}
tmp = getNumPairValue(hash, new Node(K_MINUTE));
if (tmp != null) {
c.add(Calendar.MINUTE, (int) tmp.getNumber());
}
tmp = getNumPairValue(hash, new Node(K_SECOND));
if (tmp != null) {
c.add(Calendar.SECOND, (int) tmp.getNumber());
}
tmp = getNumPairValue(hash, new Node(K_MILLIS));
if (tmp != null) {
c.add(Calendar.MILLISECOND, (int) tmp.getNumber());
}
tmp = getNumPairValue(hash, new Node(K_YEAR));
if (tmp != null) {
c.add(Calendar.YEAR, (int) tmp.getNumber());
}
tmp = getNumPairValue(hash, new Node(K_MONTH));
if (tmp != null) {
c.add(Calendar.MONTH, (int) tmp.getNumber());
}
tmp = getNumPairValue(hash, new Node(K_DAY));
if (tmp != null) {
c.add(Calendar.DATE, (int) tmp.getNumber());
}
date = c.getTime();
}
return null;
}
/**
* Implémentation de la méthode init:
* - ((new Date) ':init! millis)
* - ((new Date) ':init! millis dateFormat)
* - ((new Date) ':init! millis dateFormat timeFormat)
*
* @param startAt
* @return
* @throws Exception
*/
public Node external_mutator_init(Node startAt) throws Exception{
switch(startAt.size()){
case 4:
time_default_format = startAt.getSubNode(3, Node.TYPE_STRING).getString();
case 3:
date_default_format = startAt.getSubNode(2, Node.TYPE_STRING).getString();
case 2:
date.setTime((long) startAt.getSubNode(1, Node.TYPE_NUMBER).getNumber());
default:
startAt.isGoodArgsCnt(4);
}
return SELF.get(); // retourner une référence de l'objet courrant...
}
public Node external_quote(Node startAt) throws Exception {
startAt.isGoodArgsCnt(1,2);
return abstrasy.externals.AExtTools.SerializationTK.createInitExpr(Node.createPattern(External_Date.class.getName()), new Node(date.getTime()),
new Node(this.date_default_format), new Node(this.time_default_format));
}
public Object clone_my_self(Bivalence bival) {
External_Date t= new External_Date();
t.date=new Date(this.date.getTime());
t.date_default_format=this.date_default_format;
t.time_default_format=this.time_default_format;
return t;
}
/*
* ----------------------------------------------------------------------------
*
* Optimisation par cache d'instanciantion (mars 2012) rev 1.0-6321.0
*
* ----------------------------------------------------------------------------
*/
private static ORef _optim_symbols_cache_ = new ORef();
@Override
public Object getSymbolsCache() {
return _optim_symbols_cache_.getRef();
}
@Override
public void setSymbolsCache(Object cache) {
_optim_symbols_cache_.setRef(cache);
}
}