package jp.kirikiri.tjs2;

import java.text.DateFormat;
import java.text.ParseException;
import java.util.Calendar;
import java.util.TimeZone;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class DateClass extends NativeClass {

	static private final int
		S_OK = 0,
		E_BADPARAMCOUNT	= -1004,
		E_NATIVECLASSCRASH = -1008;
	static private final int NIS_GETINSTANCE = 0x00000002; // get native pointer

	public static int mClassID;

	protected NativeInstance createNativeInstance() {
		return new DateNI();
	}
	public static DateNI getNativeInstance( Dispatch2 objthis ) {
		Holder<NativeInstance> holder = new Holder<NativeInstance>(null);
		int hr = objthis.nativeInstanceSupport( NIS_GETINSTANCE, mClassID, holder );
		if( hr < 0 ) return null;
		return (DateNI) holder.mValue;
	}
	public DateClass() throws VariantException, TJSException {
		super("Date");
		final String __classname = "Date";
		final int NCM_CLASSID = TJS.registerNativeClass(__classname);
		setClassID( NCM_CLASSID );
		mClassID = NCM_CLASSID;

		Class<? extends DateClass> c = getClass();
		registerMethods( c, __classname );
	}
	public static int constructor( Variant result, Variant[] param, Dispatch2 objthis ) throws TJSException, VariantException {
		DateNI _this;
		Holder<NativeInstance> holder = new Holder<NativeInstance>(null);
		int hr = objthis.nativeInstanceSupport( NIS_GETINSTANCE, mClassID, holder );
		_this = (DateNI) holder.mValue;
		if( hr < 0 ) return E_NATIVECLASSCRASH;
		if( _this == null ) return E_NATIVECLASSCRASH;
		hr = _this.construct( param, objthis );
		if( hr < 0 ) return hr;

		if( param.length == 0 ) {
			_this.mDateTime = Calendar.getInstance();
		} else if( param.length >= 1 ) {
			if( param[0].isString() ) {
				// formatted string -> date/time
				_this.mDateTime = parseDateString( param[0].getString() );
			} else {
				int y, mon=0, day=1, h=0, m=0, s=0;
				y = param[0].asInteger();
				if( param.length > 1 && param[1].isVoid() != true ) mon = param[1].asInteger();
				if( param.length > 2 && param[2].isVoid() != true ) day = param[2].asInteger();
				if( param.length > 3 && param[3].isVoid() != true ) h = param[3].asInteger();
				if( param.length > 4 && param[4].isVoid() != true ) m = param[4].asInteger();
				if( param.length > 5 && param[5].isVoid() != true ) s = param[5].asInteger();

				Calendar cal = Calendar.getInstance();
				cal.set( y, mon, day, h, m, s );
				_this.mDateTime = cal;
				// if( _this.mDateTime == -1) throw new TJSException(Error.InvalidValueForTimestamp);
			}
		}
		return S_OK;
	}
	public static int finalize( Variant result, Variant[] param, Dispatch2 objthis ) {
		return S_OK;
	}
	public static int setYear( Variant result, Variant[] param, Dispatch2 objthis ) throws VariantException, TJSException {
		DateNI _this = getNativeInstance(objthis);	// インスタンス所得
		if( _this == null ) return E_NATIVECLASSCRASH;
		if( param.length < 1) return E_BADPARAMCOUNT;
		_this.mDateTime.set(Calendar.YEAR, param[0].asInteger() );
		return S_OK;
	}
	public static int setMonth( Variant result, Variant[] param, Dispatch2 objthis ) throws VariantException, TJSException {
		DateNI _this = getNativeInstance(objthis);	// インスタンス所得
		if( _this == null ) return E_NATIVECLASSCRASH;
		if( param.length < 1) return E_BADPARAMCOUNT;
		_this.mDateTime.set(Calendar.MONTH, param[0].asInteger() );
		return S_OK;
	}
	public static int setDate( Variant result, Variant[] param, Dispatch2 objthis ) throws VariantException, TJSException {
		DateNI _this = getNativeInstance(objthis);	// インスタンス所得
		if( _this == null ) return E_NATIVECLASSCRASH;
		if( param.length < 1) return E_BADPARAMCOUNT;
		_this.mDateTime.set(Calendar.DAY_OF_MONTH, param[0].asInteger() );
		return S_OK;
	}
	public static int setHours( Variant result, Variant[] param, Dispatch2 objthis ) throws VariantException, TJSException {
		DateNI _this = getNativeInstance(objthis);	// インスタンス所得
		if( _this == null ) return E_NATIVECLASSCRASH;
		if( param.length < 1) return E_BADPARAMCOUNT;
		_this.mDateTime.set(Calendar.HOUR_OF_DAY, param[0].asInteger() );
		return S_OK;
	}
	public static int setMinutes( Variant result, Variant[] param, Dispatch2 objthis ) throws VariantException, TJSException {
		DateNI _this = getNativeInstance(objthis);	// インスタンス所得
		if( _this == null ) return E_NATIVECLASSCRASH;
		if( param.length < 1) return E_BADPARAMCOUNT;
		_this.mDateTime.set(Calendar.MINUTE, param[0].asInteger() );
		return S_OK;
	}
	public static int setSeconds( Variant result, Variant[] param, Dispatch2 objthis ) throws VariantException, TJSException {
		DateNI _this = getNativeInstance(objthis);	// インスタンス所得
		if( _this == null ) return E_NATIVECLASSCRASH;
		if( param.length < 1) return E_BADPARAMCOUNT;
		_this.mDateTime.set(Calendar.SECOND, param[0].asInteger() );
		return S_OK;
	}
	public static int setTime( Variant result, Variant[] param, Dispatch2 objthis ) throws VariantException, TJSException {
		DateNI _this = getNativeInstance(objthis);	// インスタンス所得
		if( _this == null ) return E_NATIVECLASSCRASH;
		if( param.length < 1) return E_BADPARAMCOUNT;
		int num = param[0].asInteger();
		long y = num < 0 ? (long)num + 0x100000000L : num;
		_this.mDateTime.setTimeInMillis( y );
		return S_OK;
	}
	public static int getDate( Variant result, Variant[] param, Dispatch2 objthis ) throws VariantException, TJSException {
		DateNI _this = getNativeInstance(objthis);	// インスタンス所得
		if( _this == null ) return E_NATIVECLASSCRASH;
		if( result != null ) {
			result.set( _this.mDateTime.get(Calendar.DAY_OF_MONTH) );
		}
		return S_OK;
	}
	public static int getDay( Variant result, Variant[] param, Dispatch2 objthis ) throws VariantException, TJSException {
		DateNI _this = getNativeInstance(objthis);	// インスタンス所得
		if( _this == null ) return E_NATIVECLASSCRASH;
		if( result != null ) {
			result.set( _this.mDateTime.get(Calendar.DAY_OF_WEEK) );
		}
		return S_OK;
	}
	public static int getHours( Variant result, Variant[] param, Dispatch2 objthis ) throws VariantException, TJSException {
		DateNI _this = getNativeInstance(objthis);	// インスタンス所得
		if( _this == null ) return E_NATIVECLASSCRASH;
		if( result != null ) {
			result.set( _this.mDateTime.get(Calendar.HOUR_OF_DAY) );
		}
		return S_OK;
	}
	public static int getMinutes( Variant result, Variant[] param, Dispatch2 objthis ) throws VariantException, TJSException {
		DateNI _this = getNativeInstance(objthis);	// インスタンス所得
		if( _this == null ) return E_NATIVECLASSCRASH;
		if( result != null ) {
			result.set( _this.mDateTime.get(Calendar.MINUTE) );
		}
		return S_OK;
	}
	public static int getMonth( Variant result, Variant[] param, Dispatch2 objthis ) throws VariantException, TJSException {
		DateNI _this = getNativeInstance(objthis);	// インスタンス所得
		if( _this == null ) return E_NATIVECLASSCRASH;
		if( result != null ) {
			result.set( _this.mDateTime.get(Calendar.MONTH) );
		}
		return S_OK;
	}
	public static int getSeconds( Variant result, Variant[] param, Dispatch2 objthis ) throws VariantException, TJSException {
		DateNI _this = getNativeInstance(objthis);	// インスタンス所得
		if( _this == null ) return E_NATIVECLASSCRASH;
		if( result != null ) {
			result.set( _this.mDateTime.get(Calendar.SECOND) );
		}
		return S_OK;
	}
	public static int getTime( Variant result, Variant[] param, Dispatch2 objthis ) throws VariantException, TJSException {
		DateNI _this = getNativeInstance(objthis);	// インスタンス所得
		if( _this == null ) return E_NATIVECLASSCRASH;
		if( result != null ) {
			long num = _this.mDateTime.getTimeInMillis();
			int y = (int) (num > Integer.MAX_VALUE ? num - 0x100000000L : num);
			result.set( y );
		}
		return S_OK;
	}
	public static int getTimezoneOffset( Variant result, Variant[] param, Dispatch2 objthis ) {
		if( result != null ) {
			result.set( TimeZone.getDefault().getRawOffset()/(60*1000) );
		}
		return S_OK;
	}
	public static int getYear( Variant result, Variant[] param, Dispatch2 objthis ) throws VariantException, TJSException {
		DateNI _this = getNativeInstance(objthis);	// インスタンス所得
		if( _this == null ) return E_NATIVECLASSCRASH;
		if( result != null ) {
			result.set( (int)_this.mDateTime.get(Calendar.YEAR) );
		}
		return S_OK;
	}
	public static int parse( Variant result, Variant[] param, Dispatch2 objthis ) throws VariantException, TJSException {
		DateNI _this = getNativeInstance(objthis);	// インスタンス所得
		if( _this == null ) return E_NATIVECLASSCRASH;
		_this.mDateTime = parseDateString( param[0].getString() );
		return S_OK;
	}


	public static Calendar parseDateString( final String str ) throws TJSException {
		DateFormat format = DateFormat.getInstance();
		try {
			Calendar cal = Calendar.getInstance();
			cal.setTime(format.parse(str));
			return cal;
		} catch (ParseException e) {
			// TODO "年/月/日 時:分:秒" には対応していないかも、以下でいいか確認する
			Pattern regex = Pattern.compile("([0-9]+)\\/([0-9]+)\\/([0-9]+)[ \t]+([0-9]+):([0-9]+):([0-9]+)");
			Matcher m = regex.matcher(str);
			if( m.groupCount() > 6 ) {
				int y = Integer.valueOf(m.group(1));
				int mon = Integer.valueOf(m.group(2));
				int day = Integer.valueOf(m.group(3));
				int h = Integer.valueOf(m.group(4));
				int min = Integer.valueOf(m.group(5));
				int s = Integer.valueOf(m.group(6));
				Calendar cal = Calendar.getInstance();
				cal.set( y, mon, day, h, min, s );
				return cal;
			} else {
				throw new TJSException(Error.CannotParseDate);
			}
		}
	}
}
