/**
 * Redistribution and use of this software and associated documentation
 * ("Software"), with or without modification, are permitted provided
 * that the following conditions are met:
 *
 * 1. Redistributions of source code must retain copyright
 *    statements and notices.  Redistributions must also contain a
 *    copy of this document.
 *
 * 2. Redistributions in binary form must reproduce the
 *    above copyright notice, this list of conditions and the
 *    following disclaimer in the documentation and/or other
 *    materials provided with the distribution.
 *
 * 3. The name "Exolab" must not be used to endorse or promote
 *    products derived from this Software without prior written
 *    permission of Intalio, Inc.  For written permission,
 *    please contact info@exolab.org.
 *
 * 4. Products derived from this Software may not be called "Exolab"
 *    nor may "Exolab" appear in their names without prior written
 *    permission of Intalio, Inc. Exolab is a registered
 *    trademark of Intalio, Inc.
 *
 * 5. Due credit should be given to the Exolab Project
 *    (http://www.exolab.org/).
 *
 * THIS SOFTWARE IS PROVIDED BY INTALIO, INC. AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
 * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
 * INTALIO, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Copyright 1999-2004 (C) Intalio, Inc. All Rights Reserved.
 *
 * $Id: UnmarshalState.java 8805 2011-02-23 08:49:08Z wguttmn $
 */

package org.exolab.castor.xml;

import java.util.HashSet;
import java.util.Set;

import org.apache.commons.lang.StringUtils;

/**
 * The state information class for the UnmarshalHandler.
 * 
 * @author <a href="mailto:kvisco-at-intalio.com">Keith Visco</a>
 * @version $Revision: 8805 $ $Date: 2004-12-11 02:25:45 -0700 (Sat, 11 Dec 2004) $
 */
public class UnmarshalState {
    
    /** Holds on to Constructor arguments. */
    private UnmarshalHandler.Arguments _args = null;
    
    /** Holds the current location path. */
    private String _location = "";
    
    /** Indicates if the xsi:nil='true' attribute was present on the element. */
    private boolean _nil = false;
    
    /** The xml element name of the current object. */
    private String _elementName = null;

    /** Characters read in during unmarshalling. */
    private StringBuffer _buffer = null;

    /** The key for the object. This may be null if no key
     *  or identity has been specified. */
    private Object _key = null;
    
    /** The current that we are unmarshalling to. */
    private Object _object = null;
    
    /** The class of the object, mainly used for primitives. */
    private Class<?> _type = null;

    /** The field descriptor for the Object. */
    private XMLFieldDescriptor _fieldDescriptor = null;

    /** The class descriptor for the Object, in case
     *  FieldDescriptor#getClassDescriptor returns null. */
    private XMLClassDescriptor _classDescriptor = null;

    /** Is the field a primitive or immutable type? */
    private boolean _primitiveOrImmutable = false;

    /** The list of *used* field descriptors. */
    private Set<XMLFieldDescriptor> _markedList = new HashSet<XMLFieldDescriptor>();

    /** Is this a derived field? */
    private boolean _derived = false;
    
    /** Is this a wrapper state? */
    private boolean _wrapper = false;
    
    /** The whitespace preserve flag. */
    private boolean _whitespacePreserving = false;
    
    private boolean _trailingWhitespaceRemoved = false;
    
    /** Index of next expected sequence element; used during validation. */
    private int _expectedIndex = 0;
    
    /** Indicates (during validation) whether the current field descriptor 
     *  points to a multi-valued element. */
    private boolean _withinMultivaluedElement = false;
    
    /** The {@link UnmarshalState} which contains information about the parent object for the object
     *  contained within this state. Used when handling element containers/wrappers. */
    private UnmarshalState _targetState = null;
    
    /** A reference to the parent state. */
    private UnmarshalState _parent = null;

    /**
     * Reinitializes all variables
     */
    void clear() {
        
        setConstructorArguments(null);
        setLocation("");
        setElementName(null);
        setBuffer(null);
        setKey(null);
        setNil(false);
        setObject(null);
        setType(null);
        setFieldDescriptor(null);
        setClassDescriptor(null);
        setPrimitiveOrImmutable(false);
        if (_markedList != null) {
            _markedList.clear();
        }
        setDerived(false);
        setWrapper(false);
        setTargetState(null);
        setWhitespacePreserving(false);
        setParent(null);
        setTrailingWhitespaceRemoved(false);
    } //-- clear

    /**
     * Marks the given XMLFieldDescriptor as having been used.
     * 
     * @param descriptor the XMLFieldDescriptor to mark.
     */
    void markAsUsed(XMLFieldDescriptor descriptor) {
        _markedList.add(descriptor);
    }

    void markAsNotUsed(XMLFieldDescriptor descriptor) {
        if (_markedList == null) { 
            return; 
         }
        _markedList.remove(descriptor);
    }

    boolean isUsed(XMLFieldDescriptor descriptor) {
        if (_markedList.isEmpty()) { 
            return false; 
        }
        return _markedList.contains(descriptor);
    }

    void setFieldDescriptor(XMLFieldDescriptor fieldDesc) {
        _fieldDescriptor = fieldDesc;
    }

    XMLFieldDescriptor getFieldDescriptor() {
        return _fieldDescriptor;
    }

    void setObject(Object object) {
        _object = object;
    }

    Object getObject() {
        return _object;
    }

    void setKey(Object key) {
        _key = key;
    }

    Object getKey() {
        return _key;
    }

    void setType(Class<?> type) {
        _type = type;
    }

    Class<?> getType() {
        return _type;
    }

    void setClassDescriptor(XMLClassDescriptor classDesc) {
        _classDescriptor = classDesc;
    }

    XMLClassDescriptor getClassDescriptor() {
        return _classDescriptor;
    }

    void setLocation(String location) {
        _location = location;
    }

    String getLocation() {
        return _location;
    }

    void setElementName(String elementName) {
        _elementName = elementName;
    }

    String getElementName() {
        return _elementName;
    }

    void setBuffer(StringBuffer buffer) {
        _buffer = buffer;
    }

    StringBuffer getBuffer() {
        return _buffer;
    }

    void setDerived(boolean derived) {
        _derived = derived;
    }

    boolean isDerived() {
        return _derived;
    }

    void setWrapper(boolean wrapper) {
        _wrapper = wrapper;
    }

    boolean isWrapper() {
        return _wrapper;
    }

    void setWhitespacePreserving(boolean wsPreserve) {
        _whitespacePreserving = wsPreserve;
    }

    boolean isWhitespacePreserving() {
        return _whitespacePreserving;
    }

    void setPrimitiveOrImmutable(boolean primitiveOrImmutable) {
        _primitiveOrImmutable = primitiveOrImmutable;
    }

    boolean isPrimitiveOrImmutable() {
        return _primitiveOrImmutable;
    }

    void setTrailingWhitespaceRemoved(boolean trailingWhitespaceRemoved) {
        _trailingWhitespaceRemoved = trailingWhitespaceRemoved;
    }

    boolean isTrailingWhitespaceRemoved() {
        return _trailingWhitespaceRemoved;
    }

    void setTargetState(UnmarshalState targetState) {
        _targetState = targetState;
    }

    UnmarshalState getTargetState() {
        return _targetState;
    }

    void setParent(UnmarshalState parent) {
        _parent = parent;
    }

    UnmarshalState getParent() {
        return _parent;
    }

    void setNil(boolean nil) {
        _nil = nil;
    }

    boolean isNil() {
        return _nil;
    }

    public void setExpectedIndex(int expectedIndex) {
        _expectedIndex = expectedIndex;
    }

    public int getExpectedIndex() {
        return _expectedIndex;
    }

    public void setWithinMultivaluedElement(boolean withinMultivaluedElement) {
        _withinMultivaluedElement = withinMultivaluedElement;
    }

    public boolean isWithinMultivaluedElement() {
        return _withinMultivaluedElement;
    }

    void setConstructorArguments(UnmarshalHandler.Arguments args) {
        _args = args;
    }

    UnmarshalHandler.Arguments getConstructorArguments() {
        return _args;
    }

    @Override
    public String toString() {
        StringBuffer buffer = new StringBuffer();
        buffer.append("UnmarshalState [" + _elementName + "("+ _type + ") ");
        if (!StringUtils.isEmpty(_location)) {
            buffer.append("rooted at location=" + _location + ", ]");
        }
        return buffer.toString();
        
    }
    
    
}
