//   Copyright 2012 Georg-August-Universität Göttingen, Germany
//
//   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 de.ugoe.cs.autoquest.htmlmonitor;

/**
 * <p>
 * represents an element of an HTML GUI, i.e. a tag within a web page.
 * </p>
 * 
 * @author Patrick Harms
 */
class HtmlPageElement extends HtmlGUIElement {

    /**
     * the document to which the represented tag belongs
     */
    private HtmlDocument document;
    
    /**
     * the parent page element; if null, the document is considered the parent
     */
    private HtmlPageElement parent;
    
    /**
     * the name of the tag represented by this page element.
     */
    private String tagName;
    
    /**
     * the id of the page element inside the DOM.
     */
    private String htmlId;
    
    /**
     * the index of this element regarding all elements with the same tag name in the list of 
     * children of the parent element
     */
    private Integer index;
    
    /**
     * the hash code of this document
     */
    private int hashCode;
    
    /**
     * <p>
     * instantiates a new element representing a tag in an HTML page
     * </p>
     *
     * @param id       the id of the page element
     * @param document the document to which the represented tag belongs
     * @param parent   the parent page element; if null, the document is considered the parent
     * @param tagName  the name of the represented tag
     * @param htmlId   the id of the tag in the DOM
     * @param index    the index of the represented tag regarding all tags with the same
     *                 tag name in the list of children of the parent tag
     */
    HtmlPageElement(String          id,
                    HtmlDocument    document,
                    HtmlPageElement parent,
                    String          tagName,
                    String          htmlId,
                    Integer         index)
    {
        super(id, parent == null ? document : parent);
        
        if (document == null) {
            throw new IllegalArgumentException("document must not be null");
        }

        if (tagName == null) {
            throw new IllegalArgumentException("tagName must not be null");
        }
        
        if ((htmlId == null) && (index == null)) {
            throw new IllegalArgumentException("either one of htmlId and index must not be null");
        }
        
        this.document = document;
        this.parent = parent;
        this.tagName = tagName;
        this.htmlId = htmlId;
        this.index = index;
        
        this.hashCode = this.document.hashCode() + this.tagName.hashCode() +
            (this.parent != null ? this.parent.hashCode() : 0) +
            (this.htmlId != null ? this.htmlId.hashCode() : 0) +
            (this.index != null ? this.index : 0);
    }

    /**
     * <p>
     * returns the document to which the represented tag belongs
     * </p>
     *
     * @return the document
     */
    HtmlDocument getDocument() {
        return document;
    }

    /**
     * <p>
     * returns the name of the tag represented by this page element.
     * </p>
     * 
     * @return the tagName
     */
    String getTagName() {
        return tagName;
    }

    /**
     * <p>
     * returns the id of the page element.
     * </p>
     * 
     * @return the id
     */
    String getHtmlId() {
        return htmlId;
    }

    /**
     * <p>
     * returns the index of this element regarding all elements with the same tag name in the list
     * of children of the parent element
     * </p>
     * 
     * @return the index
     */
    Integer getIndex() {
        return index;
    }

    /**
     * <p>
     * calculates and returns the path to the represented page element through the DOM. Includes
     * the parent path if any. The represented element is included in the path with its tag name
     * and its id if it has one, or its index.
     * </p>
     *
     * @return as described
     */
    String getDOMPath() {
        StringBuffer result = new StringBuffer();
        if (parent != null) {
            result.append(parent.getDOMPath());
        }

        result.append("/");
        result.append(tagName);
        
        if ((htmlId != null) && (!"".equals(htmlId))) {
            result.append("(htmlId=");
            result.append(htmlId);
            result.append(")");
        }
        else {
            result.append("[");
            result.append(index);
            result.append("]");
        }
        
        return result.toString();
    }

    /* (non-Javadoc)
     * @see java.lang.Object#equals(java.lang.Object)
     */
    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        else if (obj instanceof HtmlPageElement) {
            return equals((HtmlPageElement) obj);
        }
        else {
            return false;
        }
    }

    /* (non-Javadoc)
     * @see de.ugoe.cs.autoquest.htmlmonitor.HtmlGUIElement#equals(de.ugoe.cs.autoquest.htmlmonitor.HtmlGUIElement)
     */
    public boolean equals(HtmlPageElement other) {
        if (this == other) {
            return true;
        }

        return (document.equals(other.document) && tagName.equals(other.tagName) &&
                (parent != null ? parent.equals(other.parent) : other.parent == null) &&
                (htmlId != null ? htmlId.equals(other.htmlId) : other.htmlId == null) &&
                (index != null ? index.equals(other.index) : other.index == null));
    }

    /* (non-Javadoc)
     * @see java.lang.Object#hashCode()
     */
    @Override
    public int hashCode() {
        return hashCode;
    }

}
