/*
 * Copyright 2008 Android4ME
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package wind.android.content.res;

import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import wind.v1.XmlPullParserException;

import wind.android.content.res.ChunkUtil;
import wind.android.content.res.IntReader;
import wind.android.content.res.StringBlock;
import wind.android.content.res.XmlResourceParser;
import wind.android.util.TypedValue;

/**
 * @author Dmitry Skiba
 * 
 * Binary xml files parser.
 * 
 * Parser has only two states:
 * (1) Operational state, which parser obtains after first successful call
 * to next() and retains until open(), close(), or failed call to next().
 * (2) Closed state, which parser obtains after open(), close(), or failed
 * call to next(). In this state methods return invalid values or throw exceptions.
 * 
 * TODO:
 * 	* check all methods in closed state
 *
 */
public class AXmlResourceParser implements XmlResourceParser {
	
	public AXmlResourceParser() {
		resetEventInfo();
	}
	
	public void open(InputStream stream) {
		close();
		if (stream!=null) {
			m_reader=new wind.android.content.res.IntReader(stream,false);
		}
	}
	
	public void close() {
		if (!m_operational) {
			return;
		}
		m_operational=false;
		m_reader.close();
		m_reader=null;
		m_strings=null;
		m_resourceIDs=null;
		m_namespaces.reset();
		resetEventInfo();
	}
	
	/////////////////////////////////// iteration
	
	public int next() throws XmlPullParserException,IOException {
		if (m_reader==null) {
			throw new XmlPullParserException("Parser is not opened.",this,null);
		}
		try {
			doNext();
			return m_event;			
		}
		catch (IOException e) {
			close();
			throw e;
		}
	}

	public int nextToken() throws XmlPullParserException,IOException {
		return next();
	}
	
	public int nextTag() throws XmlPullParserException,IOException {
		int eventType=next();
		if (eventType==TEXT && isWhitespace()) {
			eventType=next();
		}
		if (eventType!=START_TAG && eventType!=END_TAG) {
			throw new XmlPullParserException("Expected start or end tag.",this,null);
		}
		return eventType;
	}

	public String nextText() throws XmlPullParserException,IOException {
		if(getEventType()!=START_TAG) {
			throw new XmlPullParserException("Parser must be on START_TAG to read next text.",this,null);
		}
		int eventType=next();
		if (eventType==TEXT) {
			String result=getText();
			eventType=next();
			if (eventType!=END_TAG) {
				throw new XmlPullParserException("Event TEXT must be immediately followed by END_TAG.",this,null);
			}
			return result;
		} else if (eventType==END_TAG) {
			return "";
		} else {
			throw new XmlPullParserException("Parser must be on START_TAG or TEXT to read text.",this,null);
		}
	}

	public void require(int type,String namespace,String name) throws XmlPullParserException,IOException {
		if (type!=getEventType() ||
			(namespace!=null && !namespace.equals(getNamespace())) ||
			(name!=null && !name.equals(getName())))
		{
			throw new XmlPullParserException(TYPES[type]+" is expected.",this,null);
		}
	}
	
	public int getDepth() {
		return m_namespaces.getDepth()-1;
	}

	public int getEventType() throws XmlPullParserException {
		return m_event;
	}
	
	public int getLineNumber() {
		return m_lineNumber;
	}
	
	public String getName() {
		if (m_name==-1 || (m_event!=START_TAG && m_event!=END_TAG)) {
			return null;
		}
		return m_strings.getString(m_name);
	}
	
	public String getText() {
		if (m_name==-1 || m_event!=TEXT) {
			return null;
		}
		return m_strings.getString(m_name);
	}
	
	public char[] getTextCharacters(int[] holderForStartAndLength) {
		String text=getText();
		if (text==null) {
			return null;
		}
		holderForStartAndLength[0]=0;
		holderForStartAndLength[1]=text.length();
		char[] chars=new char[text.length()];
		text.getChars(0,text.length(),chars,0);
		return chars;
	}
	
	public String getNamespace() {
		return m_strings.getString(m_namespaceUri);
	}
	
	public String getPrefix() {
		int prefix=m_namespaces.findPrefix(m_namespaceUri);
		return m_strings.getString(prefix);
	}
	
	public String getPositionDescription() {
		return "XML line #"+getLineNumber();
	}

	public int getNamespaceCount(int depth) throws XmlPullParserException {
		return m_namespaces.getAccumulatedCount(depth);
	}

	public String getNamespacePrefix(int pos) throws XmlPullParserException {
		int prefix=m_namespaces.getPrefix(pos);
		return m_strings.getString(prefix);
	}

	public String getNamespaceUri(int pos) throws XmlPullParserException {
		int uri=m_namespaces.getUri(pos);
		return m_strings.getString(uri);
	}
	
	/////////////////////////////////// attributes

	public String getClassAttribute() {
		if (m_classAttribute==-1) {
			return null;
		}
		int offset=getAttributeOffset(m_classAttribute);
		int value=m_attributes[offset+ATTRIBUTE_IX_VALUE_STRING];
		return m_strings.getString(value);
	}

	public String getIdAttribute() {
		if (m_idAttribute==-1) {
			return null;
		}
		int offset=getAttributeOffset(m_idAttribute);
		int value=m_attributes[offset+ATTRIBUTE_IX_VALUE_STRING];
		return m_strings.getString(value);
	}

	public int getIdAttributeResourceValue(int defaultValue) {
		if (m_idAttribute==-1) {
			return defaultValue;
		}
		int offset=getAttributeOffset(m_idAttribute);
		int valueType=m_attributes[offset+ATTRIBUTE_IX_VALUE_TYPE];
		if (valueType!=TypedValue.TYPE_REFERENCE) {
			return defaultValue;
		}
		return m_attributes[offset+ATTRIBUTE_IX_VALUE_DATA];
	}

	public int getStyleAttribute() {
		if (m_styleAttribute==-1) {
			return 0;
		}
		int offset=getAttributeOffset(m_styleAttribute);
		return m_attributes[offset+ATTRIBUTE_IX_VALUE_DATA];
	}
	
	public int getAttributeCount() {
		if (m_event!=START_TAG) {
			return -1;
		}
		return m_attributes.length/ATTRIBUTE_LENGHT;
	}
	
	public String getAttributeNamespace(int index) {
		int offset=getAttributeOffset(index);
		int namespace=m_attributes[offset+ATTRIBUTE_IX_NAMESPACE_URI];
		if (namespace==-1) {
			return "";
		}
		return m_strings.getString(namespace);
	}

	public String getAttributePrefix(int index) {
		int offset=getAttributeOffset(index);
		int uri=m_attributes[offset+ATTRIBUTE_IX_NAMESPACE_URI];
		int prefix=m_namespaces.findPrefix(uri);
		if (prefix==-1) {
			return "";
		}
		return m_strings.getString(prefix);
	}
	
	public String getAttributeName(int index) {
		int offset=getAttributeOffset(index);
		int name=m_attributes[offset+ATTRIBUTE_IX_NAME];
		if (name==-1) {
			return "";
		}
		return m_strings.getString(name);
	}

	public int getAttributeNameResource(int index) {
		int offset=getAttributeOffset(index);
		int name=m_attributes[offset+ATTRIBUTE_IX_NAME];
		if (m_resourceIDs==null ||
			name<0 || name>=m_resourceIDs.length)
		{
			return 0;
		}
		return m_resourceIDs[name];
	}
	
	public int getAttributeValueType(int index) {
		int offset=getAttributeOffset(index);
		return m_attributes[offset+ATTRIBUTE_IX_VALUE_TYPE];
	}

	public int getAttributeValueData(int index) {
		int offset=getAttributeOffset(index);
		return m_attributes[offset+ATTRIBUTE_IX_VALUE_DATA];
	}
	
	public String getAttributeValue(int index) {
		int offset=getAttributeOffset(index);
		int valueType=m_attributes[offset+ATTRIBUTE_IX_VALUE_TYPE];
		if (valueType==TypedValue.TYPE_STRING) {
			int valueString=m_attributes[offset+ATTRIBUTE_IX_VALUE_STRING];
			return m_strings.getString(valueString);
		}
		int valueData=m_attributes[offset+ATTRIBUTE_IX_VALUE_DATA];
		return "";//TypedValue.coerceToString(valueType,valueData);
	}
	
	public boolean getAttributeBooleanValue(int index,boolean defaultValue) {
		return getAttributeIntValue(index,defaultValue?1:0)!=0;
	}
	
	public float getAttributeFloatValue(int index,float defaultValue) {
		int offset=getAttributeOffset(index);
		int valueType=m_attributes[offset+ATTRIBUTE_IX_VALUE_TYPE];
		if (valueType==TypedValue.TYPE_FLOAT) {
			int valueData=m_attributes[offset+ATTRIBUTE_IX_VALUE_DATA];
			return Float.intBitsToFloat(valueData);
		}
		return defaultValue;
	}

	public int getAttributeIntValue(int index,int defaultValue) {
		int offset=getAttributeOffset(index);
		int valueType=m_attributes[offset+ATTRIBUTE_IX_VALUE_TYPE];
		if (valueType>=TypedValue.TYPE_FIRST_INT &&
			valueType<=TypedValue.TYPE_LAST_INT)
		{
			return m_attributes[offset+ATTRIBUTE_IX_VALUE_DATA];
		}
		return defaultValue;
	}
	
	public int getAttributeUnsignedIntValue(int index,int defaultValue) {
		return getAttributeIntValue(index,defaultValue);
	}

	public int getAttributeResourceValue(int index,int defaultValue) {
		int offset=getAttributeOffset(index);
		int valueType=m_attributes[offset+ATTRIBUTE_IX_VALUE_TYPE];
		if (valueType==TypedValue.TYPE_REFERENCE) {
			return m_attributes[offset+ATTRIBUTE_IX_VALUE_DATA];
		}
		return defaultValue;
	}
	
	public String getAttributeValue(String namespace,String attribute) {
		int index=findAttribute(namespace,attribute);
		if (index==-1) {
			return null;
		}
		return getAttributeValue(index);
	}
	
	public boolean getAttributeBooleanValue(String namespace,String attribute,boolean defaultValue) {
		int index=findAttribute(namespace,attribute);
		if (index==-1) {
			return defaultValue;
		}
		return getAttributeBooleanValue(index,defaultValue);
	}
	
	public float getAttributeFloatValue(String namespace,String attribute,float defaultValue) {
		int index=findAttribute(namespace,attribute);
		if (index==-1) {
			return defaultValue;
		}
		return getAttributeFloatValue(index,defaultValue);
	}
	
	public int getAttributeIntValue(String namespace,String attribute,int defaultValue) {
		int index=findAttribute(namespace,attribute);
		if (index==-1) {
			return defaultValue;
		}
		return getAttributeIntValue(index,defaultValue);
	}
	
	public int getAttributeUnsignedIntValue(String namespace,String attribute,int defaultValue) {
		int index=findAttribute(namespace,attribute);
		if (index==-1) {
			return defaultValue;
		}
		return getAttributeUnsignedIntValue(index,defaultValue);
	}

	public int getAttributeResourceValue(String namespace,String attribute,int defaultValue) {
		int index=findAttribute(namespace,attribute);
		if (index==-1) {
			return defaultValue;
		}
		return getAttributeResourceValue(index,defaultValue);
	}
	
	public int getAttributeListValue(int index,String[] options,int defaultValue) {
		// TODO implement
		return 0;
	}
	
	public int getAttributeListValue(String namespace,String attribute,String[] options,int defaultValue) {
		// TODO implement
		return 0;
	}
	
	public String getAttributeType(int index) {
		return "CDATA";
	}
	
	public boolean isAttributeDefault(int index) {
		return false;
	}
	
	/////////////////////////////////// dummies

	public void setInput(InputStream stream,String inputEncoding) throws XmlPullParserException {
		throw new XmlPullParserException(E_NOT_SUPPORTED);
	}
	public void setInput(Reader reader) throws XmlPullParserException {
		throw new XmlPullParserException(E_NOT_SUPPORTED);
	}

	public String getInputEncoding() {
		return null;
	}
	
	public int getColumnNumber() {
		return -1;
	}

	public boolean isEmptyElementTag() throws XmlPullParserException {
		return false;
	}
	
	public boolean isWhitespace() throws XmlPullParserException {
		return false;
	}
	
	public void defineEntityReplacementText(String entityName,String replacementText) throws XmlPullParserException {
		throw new XmlPullParserException(E_NOT_SUPPORTED);
	}
	
	public String getNamespace(String prefix) {
		throw new RuntimeException(E_NOT_SUPPORTED);
	}

	public Object getProperty(String name) {
		return null;
	}
	public void setProperty(String name,Object value) throws XmlPullParserException {
		throw new XmlPullParserException(E_NOT_SUPPORTED);
	}

	public boolean getFeature(String feature) {
		return false;
	}
	public void setFeature(String name,boolean value) throws XmlPullParserException {
		throw new XmlPullParserException(E_NOT_SUPPORTED);
	}

	///////////////////////////////////////////// implementation
	
	/**
	 * Namespace stack, holds prefix+uri pairs, as well as
	 *  depth information.
	 * All information is stored in one int[] array.
	 * Array consists of depth frames:
	 *  Data=DepthFrame*;
	 *  DepthFrame=Count+[Prefix+Uri]*+Count;
	 *  Count='count of Prefix+Uri pairs';
	 * Yes, count is stored twice, to enable bottom-up traversal.
	 * increaseDepth adds depth frame, decreaseDepth removes it.
	 * push/pop operations operate only in current depth frame.
	 * decreaseDepth removes any remaining (not pop'ed) namespace pairs.
	 * findXXX methods search all depth frames starting 
	 * from the last namespace pair of current depth frame.
	 * All functions that operate with int, use -1 as 'invalid value'.
	 * 
	 * !! functions expect 'prefix'+'uri' pairs, not 'uri'+'prefix' !!
	 * 
	 */
	private static final class NamespaceStack {
		public NamespaceStack() {
			m_data=new int[32];
		}
		
		public final void reset() {
			m_dataLength=0;
			m_count=0;
			m_depth=0;
		}
		
		public final int getTotalCount() {
			return m_count;
		}
		
		public final int getCurrentCount() {
			if (m_dataLength==0) {
				return 0;
			}
			int offset=m_dataLength-1;
			return m_data[offset];
		}
		
		public final int getAccumulatedCount(int depth) {
			if (m_dataLength==0 || depth<0) {
				return 0;
			}
			if (depth>m_depth) {
				depth=m_depth;
			}
			int accumulatedCount=0;
			int offset=0;
			for (;depth!=0;--depth) {
				int count=m_data[offset];
				accumulatedCount+=count;
				offset+=(2+count*2);
			}
			return accumulatedCount;
		}
		
		public final void push(int prefix,int uri) {
			if (m_depth==0) {
				increaseDepth();
			}
			ensureDataCapacity(2);
			int offset=m_dataLength-1;
			int count=m_data[offset];
			m_data[offset-1-count*2]=count+1;
			m_data[offset]=prefix;
			m_data[offset+1]=uri;
			m_data[offset+2]=count+1;
			m_dataLength+=2;
			m_count+=1;
		}
		
		public final boolean pop(int prefix,int uri) {
			if (m_dataLength==0) {
				return false;
			}
			int offset=m_dataLength-1;
			int count=m_data[offset];
			for (int i=0,o=offset-2;i!=count;++i,o-=2) {
				if (m_data[o]!=prefix || m_data[o+1]!=uri) {
					continue;
				}
				count-=1;
				if (i==0) {
					m_data[o]=count;
					o-=(1+count*2);
					m_data[o]=count;
				} else {
					m_data[offset]=count;
					offset-=(1+2+count*2);
					m_data[offset]=count;
					System.arraycopy(
						m_data,o+2,
						m_data,o,
						m_dataLength-o);
				}
				m_dataLength-=2;
				m_count-=1;
				return true;
			}
			return false;
		}
		
		public final boolean pop() {
			if (m_dataLength==0) {
				return false;
			}
			int offset=m_dataLength-1;
			int count=m_data[offset];
			if (count==0) {
				return false;
			}
			count-=1;
			offset-=2;
			m_data[offset]=count;
			offset-=(1+count*2);
			m_data[offset]=count;
			m_dataLength-=2;
			m_count-=1;
			return true;			
		}
		
		public final int getPrefix(int index) {
			return get(index,true);
		}
		
		public final int getUri(int index) {
			return get(index,false);
		}
		
		public final int findPrefix(int uri) {
			return find(uri,false);
		}
		
		public final int findUri(int prefix) {
			return find(prefix,true);
		}
			
		public final int getDepth() {
			return m_depth;
		}
		
		public final void increaseDepth() {
			ensureDataCapacity(2);
			int offset=m_dataLength;
			m_data[offset]=0;
			m_data[offset+1]=0;
			m_dataLength+=2;
			m_depth+=1;
		}
		public final void decreaseDepth() {
			if (m_dataLength==0) {
				return;
			}
			int offset=m_dataLength-1;
			int count=m_data[offset];
			if ((offset-1-count*2)==0) {
				return;
			}
			m_dataLength-=2+count*2;
			m_count-=count;
			m_depth-=1;
		}

		private void ensureDataCapacity(int capacity) {
			int available=(m_data.length-m_dataLength);
			if (available>capacity) {
				return;
			}
			int newLength=(m_data.length+available)*2;
			int[] newData=new int[newLength];
			System.arraycopy(m_data,0,newData,0,m_dataLength);
			m_data=newData;
		}
		
		private final int find(int prefixOrUri,boolean prefix) {
			if (m_dataLength==0) {
				return -1;
			}			
			int offset=m_dataLength-1;
			for (int i=m_depth;i!=0;--i) {
				int count=m_data[offset];
				offset-=2;
				for (;count!=0;--count) {
					if (prefix) {
						if (m_data[offset]==prefixOrUri) {
							return m_data[offset+1];
						}
					} else {
						if (m_data[offset+1]==prefixOrUri) {
							return m_data[offset];
						}
					}
					offset-=2;
				}
			}
			return -1;
		}
		
		private final int get(int index,boolean prefix) {
			if (m_dataLength==0 || index<0) {
				return -1;
			}
			int offset=0;
			for (int i=m_depth;i!=0;--i) {
				int count=m_data[offset];
				if (index>=count) {
					index-=count;
					offset+=(2+count*2);
					continue;
				}
				offset+=(1+index*2);
				if (!prefix) {
					offset+=1;
				}
				return m_data[offset];
			}
			return -1;
		}
		
		private int[] m_data;
		private int m_dataLength;
		private int m_count;
		private int m_depth;
	}
	
	/////////////////////////////////// package-visible
	
//	final void fetchAttributes(int[] styleableIDs,TypedArray result) {
//		result.resetIndices();
//		if (m_attributes==null || m_resourceIDs==null) {
//			return;
//		}
//		boolean needStrings=false;
//		for (int i=0,e=styleableIDs.length;i!=e;++i) {
//			int id=styleableIDs[i];
//			for (int o=0;o!=m_attributes.length;o+=ATTRIBUTE_LENGHT) {
//				int name=m_attributes[o+ATTRIBUTE_IX_NAME];
//				if (name>=m_resourceIDs.length ||
//					m_resourceIDs[name]!=id)
//				{
//					continue;
//				}
//				int valueType=m_attributes[o+ATTRIBUTE_IX_VALUE_TYPE];
//				int valueData;
//				int assetCookie;
//				if (valueType==TypedValue.TYPE_STRING) {
//					valueData=m_attributes[o+ATTRIBUTE_IX_VALUE_STRING];
//					assetCookie=-1;
//					needStrings=true;
//				} else {
//					valueData=m_attributes[o+ATTRIBUTE_IX_VALUE_DATA];
//					assetCookie=0;
//				}
//				result.addValue(i,valueType,valueData,assetCookie,id,0);
//			}
//		}
//		if (needStrings) {
//			result.setStrings(m_strings);
//		}
//	}
	
	final wind.android.content.res.StringBlock getStrings() {
		return m_strings;
	}
	
	///////////////////////////////////
	
	private final int getAttributeOffset(int index) {
		if (m_event!=START_TAG) {
			throw new IndexOutOfBoundsException("Current event is not START_TAG.");
		}
		int offset=index*5;
		if (offset>=m_attributes.length) {
			throw new IndexOutOfBoundsException("Invalid attribute index ("+index+").");
		}
		return offset;
	}
	
	private final int findAttribute(String namespace,String attribute) {
		if (m_strings==null || attribute==null) {
			return -1;
		}
		int name=m_strings.find(attribute);
		if (name==-1) {
			return -1;
		}
		int uri=(namespace!=null)?
			m_strings.find(namespace):
			-1;
		for (int o=0;o!=m_attributes.length;++o) {
			if (name==m_attributes[o+ATTRIBUTE_IX_NAME] &&
				(uri==-1 || uri==m_attributes[o+ATTRIBUTE_IX_NAMESPACE_URI])) 
			{
				return o/ATTRIBUTE_LENGHT;
			}
		}
		return -1;
	}
	
	private final void resetEventInfo() {
		m_event=-1;
		m_lineNumber=-1;
		m_name=-1;
		m_namespaceUri=-1;
		m_attributes=null;
		m_idAttribute=-1;
		m_classAttribute=-1;
		m_styleAttribute=-1;
	}

	private final void doNext() throws IOException {
		// Delayed initialization.
		if (m_strings==null) {
			wind.android.content.res.ChunkUtil.readCheckType(m_reader,CHUNK_AXML_FILE);
			/*chunkSize*/m_reader.skipInt();
			m_strings= wind.android.content.res.StringBlock.read(m_reader);
			m_namespaces.increaseDepth();
			m_operational=true;
		}
		
		if (m_event==END_DOCUMENT) {
			return;
		}

		int event=m_event;
		resetEventInfo();
		
		while (true) {
			if (m_decreaseDepth) {
				m_decreaseDepth=false;
				m_namespaces.decreaseDepth();
			}
			
			// Fake END_DOCUMENT event.
			if (event==END_TAG &&
				m_namespaces.getDepth()==1 &&
				m_namespaces.getCurrentCount()==0)
			{
				m_event=END_DOCUMENT;
				break;
			}
			
			int chunkType;
			if (event==START_DOCUMENT) {
				// Fake event, see CHUNK_XML_START_TAG handler.
				chunkType=CHUNK_XML_START_TAG;
			} else {
				chunkType=m_reader.readInt();
			}
			
			if (chunkType==CHUNK_RESOURCEIDS) {
				int chunkSize=m_reader.readInt();
				if (chunkSize<8 || (chunkSize%4)!=0) {
					throw new IOException("Invalid resource ids size ("+chunkSize+").");
				}
				m_resourceIDs=m_reader.readIntArray(chunkSize/4-2);
				continue;
			}
			
			if (chunkType<CHUNK_XML_FIRST || chunkType>CHUNK_XML_LAST) {
				throw new IOException("Invalid chunk type ("+chunkType+").");
			}

			// Fake START_DOCUMENT event.
			if (chunkType==CHUNK_XML_START_TAG && event==-1) {
				m_event=START_DOCUMENT;
				break;
			}
			
			// Common header.
			/*chunkSize*/m_reader.skipInt();
			int lineNumber=m_reader.readInt();
			/*0xFFFFFFFF*/m_reader.skipInt();

			if (chunkType==CHUNK_XML_START_NAMESPACE ||
				chunkType==CHUNK_XML_END_NAMESPACE)
			{
				if (chunkType==CHUNK_XML_START_NAMESPACE) {
					int prefix=m_reader.readInt();
					int uri=m_reader.readInt();
					m_namespaces.push(prefix,uri);
				} else {
					/*prefix*/m_reader.skipInt();
					/*uri*/m_reader.skipInt();
					m_namespaces.pop();
				}
				continue;
			}
			
			m_lineNumber=lineNumber;
			
			if (chunkType==CHUNK_XML_START_TAG) {
				m_namespaceUri=m_reader.readInt();
				m_name=m_reader.readInt();
				/*flags?*/m_reader.skipInt();
				int attributeCount=m_reader.readInt();
				m_idAttribute=(attributeCount>>>16)-1;
				attributeCount&=0xFFFF;
				m_classAttribute=m_reader.readInt();
				m_styleAttribute=(m_classAttribute>>>16)-1;
				m_classAttribute=(m_classAttribute & 0xFFFF)-1;
				m_attributes=m_reader.readIntArray(attributeCount*ATTRIBUTE_LENGHT);
				for (int i=ATTRIBUTE_IX_VALUE_TYPE;i<m_attributes.length;) {
					m_attributes[i]=(m_attributes[i]>>>24);
					i+=ATTRIBUTE_LENGHT;
				}
				m_namespaces.increaseDepth();
				m_event=START_TAG;
				break;				
			}
			
			if (chunkType==CHUNK_XML_END_TAG) {
				m_namespaceUri=m_reader.readInt();
				m_name=m_reader.readInt();
				m_event=END_TAG;
				m_decreaseDepth=true;
				break;
			}
			
			if (chunkType==CHUNK_XML_TEXT) {
				m_name=m_reader.readInt();
				/*?*/m_reader.skipInt();
				/*?*/m_reader.skipInt();
				m_event=TEXT;
				break;				
			}
		}
	}
	
	/////////////////////////////////// data
	
	/*
	 * All values are essentially indices, e.g. m_name is
	 * an index of name in m_strings.
	 */
	
	private IntReader m_reader;
	private boolean m_operational=false;
	
	private StringBlock m_strings;
	private int[] m_resourceIDs;
	private NamespaceStack m_namespaces=new NamespaceStack();
	
	private boolean m_decreaseDepth;
	
	private int m_event;
	private int m_lineNumber;
	private int m_name;
	private int m_namespaceUri;
	private int[] m_attributes;
	private int m_idAttribute;
	private int m_classAttribute;
	private int m_styleAttribute;

	private static final String
		E_NOT_SUPPORTED			="Method is not supported.";
	
	private static final int
		ATTRIBUTE_IX_NAMESPACE_URI	=0,
		ATTRIBUTE_IX_NAME			=1,
		ATTRIBUTE_IX_VALUE_STRING	=2,
		ATTRIBUTE_IX_VALUE_TYPE		=3,
		ATTRIBUTE_IX_VALUE_DATA		=4,
		ATTRIBUTE_LENGHT			=5;

	private static final int 
		CHUNK_AXML_FILE				=0x00080003,
		CHUNK_RESOURCEIDS			=0x00080180,
		CHUNK_XML_FIRST				=0x00100100,
		CHUNK_XML_START_NAMESPACE	=0x00100100,
		CHUNK_XML_END_NAMESPACE		=0x00100101,
		CHUNK_XML_START_TAG			=0x00100102,
		CHUNK_XML_END_TAG			=0x00100103,
		CHUNK_XML_TEXT				=0x00100104,
		CHUNK_XML_LAST				=0x00100104;
}
