/**
	15.4.4.4 Array.prototype.concat ( [ item1 [ , item2 [ , 
 ] ] ] )
	When the concat method is called with zero or more arguments item1, item2, etc., it returns an array containing
	the array elements of the object followed by the array elements of each argument in order.
	The following steps are taken:
	1. Let A be a new array created as if by the expression new Array().
	2. Let n be 0.
	3. Let E be this object.
	4. If E is not an Array object, go to step 16.
	5. Let k be 0.
	6. Call the [[Get]] method of E with argument "length".
	7. If k equals Result(6) go to step 19.
	8. Call ToString(k).
	9. If E has a property named by Result(8), go to step 10, 
	but if E has no property named by Result(8), go to step 13.
	10. Call ToString(n).
	11. Call the [[Get]] method of E with argument Result(8).
	12. Call the [[Put]] method of A with arguments Result(10) and Result(11).
	13. Increase n by 1.
	14. Increase k by 1.
	15. Go to step 7.
	16. Call ToString(n).
	17. Call the [[Put]] method of A with arguments Result(16) and E.
	18. Increase n by 1.
	19. Get the next argument in the argument list; if there are no more arguments, go to step 22.
	20. Let E be Result(19).
	21. Go to step 4.
	22. Call the [[Put]] method of A with arguments "length" and n.
	23. Return A.
	The length property of the concat method is 1.
	NOTE The concat function is intentionally generic; it does not require that its this value be an Array object. Therefore it can be
	transferred to other kinds of objects for use as a method. Whether the concat function can be applied successfully to a host
	object is implementation-dependent.
	*/
	/*static*/ ArrayObject* ArrayClass::generic_concat(Toplevel* toplevel, Atom thisAtom, ArrayObject* args)
    {
		AvmCore* core = toplevel->core();
		ScriptObject *d = AvmCore::isObject(thisAtom) ? AvmCore::atomToScriptObject(thisAtom) : 0;
		
		uint32 len = 0;
		if (d)
		{
			len = getLengthHelper(toplevel, d);
		}

        ArrayObject *a = isArray(toplevel, thisAtom);
		uint32 i;

		uint32 argc = args->getLength();

		int  newLength = len;
		for (i = 0; i< argc; i++) 
		{
			Atom atom = args->getUintProperty(i);
			if (AvmCore::istype(atom, ARRAY_TYPE)) 
			{
				ArrayObject *b = (ArrayObject*) AvmCore::atomToScriptObject(atom);
				newLength += b->getLength();
			}
			else
			{
				newLength++;
			}
		}

		ArrayObject *out = toplevel->arrayClass->newArray(newLength);
		int denseLength = 0;
		// Only copy over elements for Arrays, not objects according to spec
		// 4. If E is not an Array object, go to step 16.
		if (a && newLength)
		{
			denseLength = a->getDenseLength();

			// copy over our dense part
			out->m_denseArr.push (&a->m_denseArr);
			out->m_length += denseLength;

			// copy over any non-dense values (or all values if this isn't an array object)
			for (i = denseLength; i < len; i++) {
				out->setUintProperty(i, d->getUintProperty(i));
			}
		}

		for (i = 0; i< (uint32)argc; i++) 
		{
			Atom atom = args->getUintProperty(i);
			if (AvmCore::istype(atom, ARRAY_TYPE)) 
			{
				ArrayObject *b = (ArrayObject*) AvmCore::atomToScriptObject(atom);
				// copy over dense parts
				out->m_denseArr.push (&b->m_denseArr);
				out->m_length += b->getDenseLength();

				// copy over any non-dense values
				uint32 len = b->getLength();
				for (uint32 j=b->getDenseLength(); j<len; j++) {
					out->m_denseArr.push (b->getUintProperty(j));
					out->m_length++;
				}
			}
			else
			{
				out->m_denseArr.push (atom);
				out->m_length++;
			}
		}

		return out;
	}
	ArrayObject* RegExpObject::split(Stringp subject, uint32 limit)
	{
		AvmCore *core = this->core();
		ArrayObject *out = toplevel()->arrayClass->newArray();
		UsesUTF8String utf8Subject(subject);

		int startIndex=0;
		int matchIndex;
		int matchLen;
		ArrayObject* matchArray;
		unsigned n=0;
		bool isEmptyRE = m_source->length() == 0;
		while ((matchArray = _exec(subject,
								  utf8Subject,
								  startIndex,
								  matchIndex,
								  matchLen)) != NULL)
		{
			// [cn 11/22/04] when match is made, but is length 0 we've matched the empty
			//  position between characters.  Although we've "matched", its zero length so just break out.
			if (matchLen == 0 ) {
				matchLen = 0;
				matchIndex = startIndex+numBytesInUtf8Character((uint8*)(utf8Subject->c_str())+startIndex); // +1char  will advance startIndex, extract just one char
				if( !isEmptyRE )
				{
					// don't break if we're processing an empty regex - then we want to split the string into each character
					// so we want the loop to continue
					break;
				}
			}

			//[ed 8/10/04] don't go past end of string. not sure why pcre doesn't return null
			//for a match starting past the end.
			//[cn 12/3/04] because a regular expression which matches an empty position (space between characters)
			//  will match the empty position just past the last character.  This test is correct, though 
			//  it needs to come before we do any setProperties to avoid a bogus xtra result.
			if (matchIndex+matchLen > utf8Subject->length()) {
				startIndex = matchIndex+matchLen;
				break;
			} else {
				out->setUintProperty(n++,
									 (core->newString(utf8Subject->c_str()+startIndex,
													  matchIndex-startIndex))->atom());
				if (n >= limit)
					break;
				for (uint32 j=1; j<matchArray->getLength(); j++) {
					out->setUintProperty(n++, matchArray->getUintProperty(j));
					if (n >= limit)
						break;
				}
				// Advance past this match
				startIndex = matchIndex+matchLen;				
			}
		}

		// If we found no match, or we did find a match and are still under limit, and there is a remainder left, add it 
		if ((unsigned)n < limit && startIndex <= utf8Subject->length()) {
			out->setUintProperty(n++,
								 (core->newString(utf8Subject->c_str()+startIndex,
												  utf8Subject->length()-startIndex))->atom());
		}

		return out;
	}