/********************************************************************
 * Copyright © 2005-2006 VHA. All rights reserved
 ********************************************************************/
package gov.va.med.fw.ui.taglib;

// Java Classes
import java.util.Iterator;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.TagSupport;

// Library Classes
import org.apache.struts.Globals;
import org.apache.struts.action.ActionMessages;
import org.apache.struts.taglib.TagUtils;
import org.apache.strutsel.taglib.utils.EvalHelper;

// Framework Classes
import gov.va.med.fw.util.StringUtils;

/**
 * The body enclosed by this tag will be highlighted in the event of validation error. Also, the required attribute can
 * optionally display the required symbol next to the field.
 *
 * @author Muddaiah Ranga
 * @author Andrew Pach
 * @version 3.0
 */

public class LabelTag extends TagSupport
{
    /**
     * An instance of serialVersionUID
     */
    private static final long serialVersionUID = 7654954868896911653L;
    private String forId;
    private String property;
    private String styleClass;
    private boolean required = false;

    public String getProperty()
    {
        return property;
    }

    public void setProperty(String prop)
    {
        this.property = prop;
        if (StringUtils.isNotEmpty(prop))
        {
            try
            {
                String string = EvalHelper.evalString("property", prop, this, pageContext);
                if (StringUtils.isNotEmpty(string))
                {
                    this.property = string;
                }
            }
            catch (Exception ex)
            {
                ex.printStackTrace();
            }
        }
    }

    public String getRequired()
    {
        return String.valueOf(required);
    }

    public void setRequired(String required)
    {
        // Lookup the EL value
        if (StringUtils.isNotEmpty(required))
        {
            required = required.trim();
            try
            {
                String requiredEl = EvalHelper.evalString("required", required, this, pageContext);
                if (StringUtils.isNotEmpty(requiredEl))
                {
                    required = requiredEl;
                }
            }
            catch (Exception ex)
            {
                ex.printStackTrace();
            }
        }

        // If a value isn't set, default it to "false"
        if (StringUtils.isEmpty(required))
        {
            required = "false";
        }

        // Store the value
        this.required = required.equalsIgnoreCase("true") || required.equalsIgnoreCase("yes");
    }

    public String getStyleClass()
    {
        return styleClass;
    }

    public void setStyleClass(String style)
    {
        this.styleClass = style;
        if (StringUtils.isNotEmpty(style))
        {
            try
            {
                String string = EvalHelper.evalString("styleClass", style, this, pageContext);
                if (StringUtils.isNotEmpty(string))
                {
                    this.styleClass = string;
                }
            }
            catch (Exception ex)
            {
                ex.printStackTrace();
            }
        }
    }

    /**
     * Creates a span start tag around the label if there the field has a validation error.
     * Also, the required symbol will be written if specified.
     */
    public int doStartTag() throws JspException
    {
        TagUtils util = TagUtils.getInstance();
        boolean tagInError = isTagInError(pageContext, getProperty());
        StringBuffer buffer = new StringBuffer();
        if (required || tagInError)
        {
            // Process the error
            if (tagInError)
            {
                String errorStyle = getStyleClass();
                if (StringUtils.isEmpty(errorStyle))
                {
                    errorStyle = util.message(pageContext, null, Globals.LOCALE_KEY, "errors.label.errorStyle", null);
                }
                buffer.append("<span class=\"");
                buffer.append(errorStyle);
                buffer.append("\">");
                String errorLabelStart = util.message(pageContext, null, Globals.LOCALE_KEY, "errors.label.prefix", null);
                buffer.append(errorLabelStart);
                buffer.append(" ");
            }

        }

        buffer.append("<label for=\"" + (StringUtils.isNotEmpty(forId) ? forId : property) + "\">");

        // Process the required field
        if (required)
        {
            String requiredLabelStart = util.message(pageContext, null, Globals.LOCALE_KEY, "label.required.prefix", null);
            buffer.append(requiredLabelStart);
            buffer.append(" ");
        }
        // Write the output
        util.write(pageContext, buffer.toString());

        return (EVAL_BODY_INCLUDE);
    }

    /**
     * Creates a span end tag around the label if there the field has a validation error.
     */
    public int doEndTag() throws JspException
    {
        TagUtils util = TagUtils.getInstance();
        util.write(pageContext, "</label>");

        if (isTagInError(pageContext, getProperty()))
        {
            util.write(pageContext, "</span>");
        }
        return (EVAL_PAGE);
    }

    public void release()
    {
        super.release();
    }

    /**
     * Determines if the property contains an error.
     * @param pageContext The page context.
     * @param property The property to check.
     * @return true if the property contains an error or false if not.
     */
    private static boolean isTagInError(PageContext pageContext, String property)
    {
        // Get the list of global error messages
        Object value = pageContext.findAttribute(Globals.ERROR_KEY);
        if (value != null)
        {
            // Get the list of lables that may be separated by commas
            String[] properties = property.split(",");
            if (properties != null)
            {
                // Go through each label and see if there are any errors for each one
                for (int i = 0; i < properties.length; i++)
                {
                    String oneProperty = (String)properties[i];

                    // Get any messages related to our label
                    Iterator iter = ((ActionMessages)value).get(oneProperty);

                    // If any messages exist, return true
                    if (iter.hasNext())
                    {
                        return true;
                    }
                }
            }
        }

        // No errors were found for our list of labels so return false.
        return false;
    }

	public String getForId() {
		return forId;
	}

	public void setForId(String forId) {
		this.forId = forId;
	}
}
