/*
 * Copyright 2004-2005 The Trix Development Team.
 *
 * 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 org.trix.cuery.style;

import java.util.LinkedList;

import org.trix.cuery.value.Value;

/**
 * DOCUMENT.
 * 
 * @author <a href="mailto:Teletha.T@gmail.com">Teletha Testarossa</a>
 * @version $ Id: CascadableStyle.java,v 1.0 2005/08/10 22:12:41 Teletha Exp $
 */
public class CascadableStyle extends AbstractStyle {

    /** This is the UA's default stylesheet. */
    public static final int ORIGIN_AGENT = 1;

    /** This is the user's stylesheet. */
    public static final int ORIGIN_USER = 2;

    /** This is the author's stylesheet. */
    public static final int ORIGIN_AUTHOR = 3;

    /** The list of styles. */
    private LinkedList<Object[]> styles = new LinkedList<Object[]>();

    /** The position of a seperator between author and user. */
    private int author = 0;

    /** The position of a seperator between user and agent. */
    private int user = 0;

    /**
     * @see org.trix.cuery.style.Style#getPropertyValue(java.lang.String)
     */
    public Value getPropertyValue(String name) {
        for (int i = author; i < user; i++) {
            Style style = (Style) styles.get(i)[0];

            if (style.isImportant(name)) {
                return style.getPropertyValue(name);
            }
        }

        for (int i = 0; i < author; i++) {
            Style style = (Style) styles.get(i)[0];

            if (style.isImportant(name)) {
                return style.getPropertyValue(name);
            }
        }

        for (int i = 0; i < author; i++) {
            Style style = (Style) styles.get(i)[0];
            Value value = style.getPropertyValue(name);

            if (value != null) {
                return value;
            }
        }

        for (int i = author; i < user; i++) {
            Style style = (Style) styles.get(i)[0];
            Value value = style.getPropertyValue(name);

            if (value != null) {
                return value;
            }
        }

        for (int i = user; i < styles.size(); i++) {
            Style style = (Style) styles.get(i)[0];
            Value value = style.getPropertyValue(name);

            if (value != null) {
                return value;
            }
        }
        return null;
    }

    /**
     * @see org.trix.cuery.style.Style#isImportant(java.lang.String)
     */
    public boolean isImportant(String name) {
        return false;
    }

    /**
     * Add style.
     * 
     * @param style A target style.
     * @param origin A origin type.
     * @param specificity A specificity of this style.
     * @param position A position of this style.
     */
    public void addStyle(Style style, int origin, int specificity, int position) {
        switch (origin) {
        case ORIGIN_AUTHOR:
            addStyle(style, specificity, position, 0, author);
            author++;
            user++;
            break;

        case ORIGIN_USER:
            addStyle(style, specificity, position, author, user);
            user++;
            break;

        case ORIGIN_AGENT:
            addStyle(style, specificity, position, user, styles.size());
            break;

        default:
            break;
        }
    }

    /**
     * Add style to a suitable position in list of styles.
     * 
     * @param style A target style.
     * @param specificity A specificity of this style.
     * @param position A position of this style.
     * @param start A start position for this style origin.
     * @param end A end position for this style origin.
     */
    private void addStyle(Style style, int specificity, int position, int start, int end) {
        Object[] styleObject = new Object[] {style, specificity, position};

        for (int i = start; i < end; i++) {
            Object[] objects = styles.get(i);

            // check specificity
            if (specificity > (Integer) objects[1]) {
                styles.add(i, styleObject);
                return;
            }

            // check position
            if (specificity == (Integer) objects[1] && position > (Integer) objects[2]) {
                styles.add(i, styleObject);
                return;
            }
        }
        // lowest weight
        styles.add(end, styleObject);
    }
}
