package jp.kirikiri.tjs2;

import java.util.ArrayList;

class ArrayObject extends CustomObject {

	// copy for optimize
	private static final int
		MEMBERMUSTEXIST = 0x00000400, // member *must* exist ( for Dictionary/Array )
		NIS_GETINSTANCE = 0x00000002; // get native pointer

	private static final int
		E_MEMBERNOTFOUND = (-1001),
		E_NOTIMPL = (-1002),
		E_INVALIDOBJECT = (-1006),
		E_NATIVECLASSCRASH = (-1008),
		S_OK = 0;

	public ArrayObject() {
		super();
		mCallFinalize = false;
	}
	protected void finalizeObject() throws TJSException {
		Holder<NativeInstance> holder = new Holder<NativeInstance>(null);
		if( nativeInstanceSupport( NIS_GETINSTANCE, ArrayNI.ClassID_Array, holder ) < 0 ) {
			throw new TJSException( Error.NativeClassCrash );
		}
		ArrayNI ni = (ArrayNI)holder.mValue;
		clear(ni);
		super.finalizeObject();
	}
	public void clear(ArrayNI ni) {
		// clear members
		final int count = ni.mItems.size();
		for( int i = 0; i < count; i++) {
			Variant v = ni.mItems.get(i);
			v.clear();
		}
		ni.mItems.clear();
	}
	public void erase(ArrayNI ni, int num) throws TJSException {
		if(num < 0) num += ni.mItems.size();
		if(num < 0) throw new TJSException(Error.RangeError);
		if( num >= ni.mItems.size() ) throw new TJSException(Error.RangeError);

		ni.mItems.remove(num);
	}
	public int remove(ArrayNI ni, Variant ref, boolean removeall) {
		int count = 0;
		ArrayList<Integer> todelete = new ArrayList<Integer>();
		final int arrayCount = ni.mItems.size();
		for( int i = 0; i < arrayCount; i++ ) {
			Variant v = ni.mItems.get(i);
			if(ref.discernCompareInternal(v)) {
				count++;
				todelete.add(i);
				if(!removeall) break;
			}
		}

		// list objects up
		final int delCount = todelete.size();
		for( int i = 0; i < delCount; i++  ) {
			int pos = todelete.get(i);
			Variant v = ni.mItems.get(pos);
			v.clear();
		}
		// remove items found
		for( int i = delCount - 1; i >= 0; i-- ) {
			ni.mItems.remove( todelete.get(i).intValue() );
		}
		return count;
	}
	public void insert(ArrayNI ni, Variant val, int num) throws TJSException {
		if(num < 0) num += ni.mItems.size();
		if(num < 0) throw new TJSException(Error.RangeError);
		int count = ni.mItems.size();
		if(num > count) throw new TJSException(Error.RangeError);

		ni.mItems.add( num, val );
	}
	public void add(ArrayNI ni, Variant val) {
		ni.mItems.add(val);
	}
	public void insert(ArrayNI ni, Variant[] val, int num ) throws TJSException {
		if(num < 0) num += ni.mItems.size();
		if(num < 0) throw new TJSException(Error.RangeError);
		int count = ni.mItems.size();
		if(num > count) throw new TJSException(Error.RangeError);

		int end = val.length;
		ni.mItems.ensureCapacity( count+end );
		for( int i = 0; i < end; i++ ) {
			ni.mItems.add( num+i, val[i] );
		}
	}

	// function invocation
	public int funcCall( int flag, final String memberName, IntWrapper hint, Variant result, Variant[] param, Dispatch2 objThis ) throws VariantException, TJSException {
		try {
			if( memberName != null ) {
				int idx = Integer.parseInt(memberName);
				return funcCallByNum(flag, idx, result, param, objThis);
			}
		} catch( NumberFormatException e) { /* 無視する */ }
		return super.funcCall(flag, memberName, hint, result, param, objThis );
	}

	// function invocation by index number
	public int funcCallByNum( int flag, int num, Variant result, Variant[] param, Dispatch2 objthis ) throws VariantException, TJSException {
		if(!getValidity())
			return E_INVALIDOBJECT;

		Holder<NativeInstance> holder = new Holder<NativeInstance>(null);
		if( objthis.nativeInstanceSupport( NIS_GETINSTANCE, ArrayNI.ClassID_Array, holder) < 0 )
			return E_NATIVECLASSCRASH;

		ArrayNI ni = (ArrayNI) holder.mValue;
		int membercount = ni.mItems.size();
		if(num < 0) num = membercount + num;
		if( (flag & MEMBERMUSTEXIST) != 0 && (num < 0 || membercount <= num) )
			return E_MEMBERNOTFOUND;
		Variant val = new Variant( (membercount<=num || num < 0) ? null : ni.mItems.get(num) );
		return defaultFuncCall( flag, val, result, param, objthis );
	}

	// property get
	public int propGet( int flag, final String memberName, IntWrapper hint, Variant result, Dispatch2 objThis ) throws VariantException, TJSException {
		try {
			if( memberName != null ) {
				int idx = Integer.parseInt(memberName);
				return propGetByNum( flag, idx, result, objThis );
			}
		} catch( NumberFormatException e) { /* 無視する */ }
		return super.propGet(flag, memberName, hint, result, objThis );
	}

	// property get by index number
	public int propGetByNum( int flag, int num, Variant result, Dispatch2 objthis ) throws VariantException, TJSException {
		if(!getValidity())
			return E_INVALIDOBJECT;

		Holder<NativeInstance> holder = new Holder<NativeInstance>(null);
		if( objthis.nativeInstanceSupport( NIS_GETINSTANCE, ArrayNI.ClassID_Array, holder) < 0 )
			return E_NATIVECLASSCRASH;

		ArrayNI ni = (ArrayNI) holder.mValue;
		int membercount = ni.mItems.size();
		if(num < 0) num = membercount + num;
		if( (flag & MEMBERMUSTEXIST) != 0 && (num < 0 || membercount <= num) )
			return E_MEMBERNOTFOUND;
		Variant val = new Variant( (membercount<=num || num < 0) ? null : ni.mItems.get(num) );
		return defaultPropGet( flag, val, result, objthis);
	}

	// property set
	public int propSet( int flag, String memberName, IntWrapper hint, final Variant param, Dispatch2 objThis ) throws VariantException, TJSException {
		try {
			if( memberName != null ) {
				int idx = Integer.parseInt(memberName);
				return propSetByNum( flag, idx, param, objThis );
			}
		} catch( NumberFormatException e) { /* 無視する */ }
		return super.propSet(flag, memberName, hint, param, objThis );
	}

	// property set by index number
	public int propSetByNum( int flag, int num, final Variant param, Dispatch2 objthis ) throws VariantException, TJSException {
		if(!getValidity())
			return E_INVALIDOBJECT;

		Holder<NativeInstance> holder = new Holder<NativeInstance>(null);
		if( objthis.nativeInstanceSupport( NIS_GETINSTANCE, ArrayNI.ClassID_Array, holder) < 0 )
			return E_NATIVECLASSCRASH;

		ArrayNI ni = (ArrayNI) holder.mValue;
		if(num < 0) num += ni.mItems.size();
		if( num >= ni.mItems.size() ) {
			if( (flag & MEMBERMUSTEXIST) != 0 ) return E_MEMBERNOTFOUND;
			//ni.mItems.resize(num+1);
			for( int i = ni.mItems.size(); i <= num; i++ ) {
				ni.mItems.add( new Variant() );
			}
		}
		if(num < 0) return E_MEMBERNOTFOUND;
		Variant val = ni.mItems.get(num);
		return defaultPropSet(flag, val, param, objthis);
	}

	// property for internal use
	public int propSetByVS( int flag, String memberName, final Variant param, Dispatch2 objThis ) throws VariantException, TJSException {
		try {
			if( memberName != null ) {
				int idx = Integer.parseInt(memberName);
				return propSetByNum( flag, idx, param, objThis );
			}
		} catch( NumberFormatException e) { /* 無視する */ }
		return super.propSetByVS(flag, memberName, param, objThis );
	}

	// enumerate members
	public int enumMembers( int flag, VariantClosure callback, Dispatch2 objThis ) throws VariantException, TJSException {
		return E_NOTIMPL; // currently not implemented
	}

	// delete member
	public int deleteMember( int flag, String memberName, IntWrapper hint, Dispatch2 objThis ) throws VariantException, TJSException {
		try {
			if( memberName != null ) {
				int idx = Integer.parseInt(memberName);
				return deleteMemberByNum( flag, idx, objThis );
			}
		} catch( NumberFormatException e) { /* 無視する */ }
		return super.deleteMember(flag, memberName, hint, objThis );
	}

	// delete member by index number
	public int deleteMemberByNum( int flag, int num, Dispatch2 objthis ) throws VariantException, TJSException {
		if(!getValidity())
			return E_INVALIDOBJECT;

		Holder<NativeInstance> holder = new Holder<NativeInstance>(null);
		if( objthis.nativeInstanceSupport( NIS_GETINSTANCE, ArrayNI.ClassID_Array, holder) < 0 )
			return E_NATIVECLASSCRASH;

		ArrayNI ni = (ArrayNI) holder.mValue;
		if(num < 0) num += ni.mItems.size();
		if(num < 0 || num>=ni.mItems.size()) return E_MEMBERNOTFOUND;
		ni.mItems.remove( num );
		return S_OK;
	}

	// invalidation
	public int invalidate( int flag, String memberName, IntWrapper hint, Dispatch2 objThis ) throws VariantException, TJSException {
		try {
			if( memberName != null ) {
				int idx = Integer.parseInt(memberName);
				return invalidateByNum( flag, idx, objThis );
			}
		} catch( NumberFormatException e) { /* 無視する */ }
		return super.invalidate(flag, memberName, hint, objThis );
	}

	// invalidation by index number
	public int invalidateByNum( int flag, int num, Dispatch2 objthis ) throws VariantException, TJSException {
		if(!getValidity())
			return E_INVALIDOBJECT;

		Holder<NativeInstance> holder = new Holder<NativeInstance>(null);
		if( objthis.nativeInstanceSupport( NIS_GETINSTANCE, ArrayNI.ClassID_Array, holder) < 0 )
			return E_NATIVECLASSCRASH;

		ArrayNI ni = (ArrayNI) holder.mValue;
		int membercount = ni.mItems.size();
		if(num < 0) num = membercount + num;
		if( (flag & MEMBERMUSTEXIST) != 0 && (num < 0 || membercount <= num) )
			return E_MEMBERNOTFOUND;
		Variant val = new Variant( (membercount<=num || num < 0) ? null : ni.mItems.get(num) );
		return defaultInvalidate(flag, val, objthis);
	}

	// get validation, returns true or false
	public int isValid( int flag, String memberName, IntWrapper hint, Dispatch2 objThis ) throws VariantException, TJSException {
		try {
			if( memberName != null ) {
				int idx = Integer.parseInt(memberName);
				return isValidByNum( flag, idx, objThis );
			}
		} catch( NumberFormatException e) { /* 無視する */ }
		return super.isValid(flag, memberName, hint, objThis );
	}

	// get validation by index number, returns true or false
	public int isValidByNum( int flag, int num, Dispatch2 objthis ) throws VariantException, TJSException {
		if(!getValidity())
			return E_INVALIDOBJECT;

		Holder<NativeInstance> holder = new Holder<NativeInstance>(null);
		if( objthis.nativeInstanceSupport( NIS_GETINSTANCE, ArrayNI.ClassID_Array, holder) < 0 )
			return E_NATIVECLASSCRASH;

		ArrayNI ni = (ArrayNI) holder.mValue;
		int membercount = ni.mItems.size();
		if(num < 0) num = membercount + num;
		if( (flag & MEMBERMUSTEXIST) != 0 && (num < 0 || membercount <= num) )
			return E_MEMBERNOTFOUND;
		Variant val = new Variant( (membercount<=num || num < 0) ? null : ni.mItems.get(num) );
		return defaultIsValid(flag, val, objthis);
	}

	// create new object
	public int createNew( int flag, String memberName, IntWrapper hint, Holder<Dispatch2> result, Variant[] param, Dispatch2 objThis ) throws VariantException, TJSException {
		try {
			if( memberName != null ) {
				int idx = Integer.parseInt(memberName);
				return createNewByNum( flag, idx, result, param, objThis );
			}
		} catch( NumberFormatException e) { /* 無視する */ }
		return super.createNew(flag, memberName, hint, result, param, objThis );
	}

	// create new object by index number
	public int createNewByNum( int flag, int num, Holder<Dispatch2> result, Variant[] param, Dispatch2 objthis ) throws VariantException, TJSException {
		if(!getValidity())
			return E_INVALIDOBJECT;

		Holder<NativeInstance> holder = new Holder<NativeInstance>(null);
		if( objthis.nativeInstanceSupport( NIS_GETINSTANCE, ArrayNI.ClassID_Array, holder) < 0 )
			return E_NATIVECLASSCRASH;

		ArrayNI ni = (ArrayNI) holder.mValue;
		int membercount = ni.mItems.size();
		if(num < 0) num = membercount + num;
		if( (flag & MEMBERMUSTEXIST) != 0 && (num < 0 || membercount <= num) )
			return E_MEMBERNOTFOUND;
		Variant val = new Variant( (membercount<=num || num < 0) ? null : ni.mItems.get(num) );
		return defaultCreateNew(flag, val, result, param, objthis);
	}

	// reserved1 not use

	// class instance matching returns false or true
	public int isInstanceOf( int flag, String memberName, IntWrapper hint, String className, Dispatch2 objThis ) throws VariantException, TJSException {
		try {
			if( memberName != null ) {
				int idx = Integer.parseInt(memberName);
				return isInstanceOfByNum( flag, idx, className, objThis );
			}
		} catch( NumberFormatException e) { /* 無視する */ }
		return super.isInstanceOf(flag, memberName, hint, className, objThis );
	}

	// class instance matching by index number
	public int isInstanceOfByNum( int flag, int num, String className, Dispatch2 objthis ) throws VariantException, TJSException {
		if(!getValidity())
			return E_INVALIDOBJECT;

		Holder<NativeInstance> holder = new Holder<NativeInstance>(null);
		if( objthis.nativeInstanceSupport( NIS_GETINSTANCE, ArrayNI.ClassID_Array, holder) < 0 )
			return E_NATIVECLASSCRASH;

		ArrayNI ni = (ArrayNI) holder.mValue;
		int membercount = ni.mItems.size();
		if(num < 0) num = membercount + num;
		if( (flag & MEMBERMUSTEXIST) != 0 && (num < 0 || membercount <= num) )
			return E_MEMBERNOTFOUND;
		Variant val = new Variant( (membercount<=num || num < 0) ? null : ni.mItems.get(num) );
		return defaultIsInstanceOf(flag, val, className, objthis);
	}

	// operation with member
	public int operation( int flag, String memberName, IntWrapper hint, Variant result, final Variant param, Dispatch2 objThis ) throws VariantException, TJSException {
		try {
			if( memberName != null ) {
				int idx = Integer.parseInt(memberName);
				return operationByNum( flag, idx, result, param, objThis );
			}
		} catch( NumberFormatException e) { /* 無視する */ }
		return super.operation(flag, memberName, hint, result, param, objThis );
	}

	// operation with member by index number
	public int operationByNum( int flag, int num, Variant result, final Variant param, Dispatch2 objthis ) throws VariantException, TJSException {
		if(!getValidity())
			return E_INVALIDOBJECT;

		Holder<NativeInstance> holder = new Holder<NativeInstance>(null);
		if( objthis.nativeInstanceSupport( NIS_GETINSTANCE, ArrayNI.ClassID_Array, holder) < 0 )
			return E_NATIVECLASSCRASH;

		ArrayNI ni = (ArrayNI) holder.mValue;
		if(num < 0) num += ni.mItems.size();
		if( num >= ni.mItems.size() ) {
			if( (flag & MEMBERMUSTEXIST) != 0 ) return E_MEMBERNOTFOUND;
			//ni.mItems.resize(num+1);
			for( int i = ni.mItems.size(); i <= num; i++ ) {
				ni.mItems.add( new Variant() );
			}
		}
		if(num < 0) return E_MEMBERNOTFOUND;
		Variant val = ni.mItems.get(num);
		return defaultOperation( flag, val, result, param, objthis );
	}

}

