/*
 * The Kuali Financial System, a comprehensive financial management system for higher education.
 *
 * Copyright 2005-2016 The Kuali Foundation
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.kuali.kfs.sys.document.web.renderers;

import org.apache.commons.lang.StringUtils;
import org.kuali.kfs.kns.lookup.HtmlData.AnchorHtmlData;
import org.kuali.kfs.kns.web.ui.Field;
import org.kuali.kfs.sys.KFSConstants;
import org.kuali.kfs.sys.context.SpringContext;
import org.kuali.rice.core.api.config.property.ConfigurationService;
import org.kuali.rice.core.api.util.KeyValue;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.Tag;
import java.io.IOException;

/**
 * Renderer which displays a read only field
 */
public class ReadOnlyRenderer extends FieldRendererBase {
    private boolean shouldRenderInquiry = true;

    /**
     * @see org.kuali.kfs.sys.document.web.renderers.Renderer#render(javax.servlet.jsp.PageContext, javax.servlet.jsp.tagext.Tag)
     */
    @Override
    public void render(PageContext pageContext, Tag parentTag) throws JspException {
        JspWriter out = pageContext.getOut();

        try {
            String value = discoverRenderValue();
            out.write(buildBeginSpan());

            if (!StringUtils.isEmpty(value)) {
                if (shouldRenderInquiryLink()) {
                    out.write(buildBeginInquiryLink());
                }
                out.write(value);
                if (shouldRenderInquiryLink()) {
                    out.write(buildEndInquiryLink());
                    out.write(buildNewWindowInquiryLink());
                }
            } else {
                out.write(buildNonBreakingSpace());
            }

            out.write(buildEndSpan());
        } catch (IOException ioe) {
            throw new JspException("Difficulty rendering read only field", ioe);
        }
    }

    /**
     * Clears the persisting tag.
     *
     * @see org.kuali.kfs.sys.document.web.renderers.FieldRendererBase#clear()
     */
    @Override
    public void clear() {
        super.clear();
    }

    /**
     * Generates the HTML for the opening span tag to wrap the displayed value
     *
     * @param propertyPrefix the property path from the form the business object being rendered
     * @return the HTML for the opening span
     */
    protected String buildBeginSpan() {
        StringBuilder beginSpan = new StringBuilder();
        beginSpan.append("<span id=\"");
        beginSpan.append(getFieldName());
        beginSpan.append(".div");
        String fieldStyle = this.getField().getStyleClass();
        if (StringUtils.isNotBlank(fieldStyle)) {
            beginSpan.append("\" class=\"");
            beginSpan.append(fieldStyle);
        }
        beginSpan.append("\">");
        return beginSpan.toString();
    }

    /**
     * Generates the HTML for the closing span tag to wrap the displayed value
     *
     * @return the HTML for the closing span
     */
    protected String buildEndSpan() {
        return "</span>";
    }

    /**
     * Builds the opening anchor tag to make the displayed read only value open up an inquiry screen
     *
     * @return the HTML for the opening inquiry anchor tag
     */
    protected String buildBeginInquiryLink() {
        StringBuilder beginInquiryLink = new StringBuilder();

        if (getField().getInquiryURL() instanceof AnchorHtmlData) {
            AnchorHtmlData htmlData = (AnchorHtmlData) getField().getInquiryURL();

            if (htmlData.getHref().startsWith("http")) {
                beginInquiryLink.append("<a href=\"");
            } else {
                beginInquiryLink.append("<a href=\"");
                beginInquiryLink.append(SpringContext.getBean(ConfigurationService.class).getPropertyValueAsString(KFSConstants.APPLICATION_URL_KEY));
                beginInquiryLink.append("/kr/");
            }

            beginInquiryLink.append(htmlData.getHref());
            beginInquiryLink.append("&mode=modal\" title=\"");
            beginInquiryLink.append(htmlData.getTitle());
            beginInquiryLink.append(" in modal\" data-remodal-target=\"modal\">");

        }

        return beginInquiryLink.toString();
    }

    /**
     * Builds the closing anchor tag for the inquiry link
     *
     * @return the HTML for the closing inquiry anchor tag
     */
    protected String buildEndInquiryLink() {
        if (getField().getInquiryURL() instanceof AnchorHtmlData) {
            return "</a>";
        }
        return "";
    }

    protected String buildNewWindowInquiryLink() {
        StringBuilder inquiryLink = new StringBuilder();
        if (getField().getInquiryURL() instanceof AnchorHtmlData) {
            AnchorHtmlData htmlData = (AnchorHtmlData) getField().getInquiryURL();
            if (htmlData.getHref().startsWith("http")) {
                inquiryLink.append("<a href=\"");
            } else {
                inquiryLink.append("<a href=\"");
                inquiryLink.append(SpringContext.getBean(ConfigurationService.class).getPropertyValueAsString(KFSConstants.APPLICATION_URL_KEY));
                inquiryLink.append("/kr/");
            }

            inquiryLink.append(htmlData.getHref());
            inquiryLink.append("&mode=standalone\" title=\"");
            inquiryLink.append(htmlData.getTitle());
            inquiryLink.append(" in new window\" target=\"blank\" class=\"new-window\">");
            inquiryLink.append("<span class=\"glyphicon glyphicon-new-window\"></span>");
            inquiryLink.append("</a>");


        }
        return inquiryLink.toString();
    }

    /**
     * Determines if this read only field should attempt to display the inquiry link around the rendered value
     *
     * @return true if the inquiry link should be rendered, false otherwise
     */
    protected boolean shouldRenderInquiryLink() {
        return getField().getInquiryURL() != null && !StringUtils.isBlank(((AnchorHtmlData) getField().getInquiryURL()).getHref()) && isInquirableValue(getField().getPropertyValue()) && shouldRenderInquiry;
    }

    /**
     * Determines if the given property value is worthy of having an inquiry for it
     *
     * @param propertyValue the value of the property to potentially render an inquiry for
     * @return true if the value is inquirable; false otherwise
     */
    protected boolean isInquirableValue(String propertyValue) {
        return !StringUtils.isBlank(propertyValue) && !propertyValue.matches("^-*$");
    }

    /**
     * Sets the shouldRenderInquiry attribute value.
     *
     * @param shouldRenderInquiry The shouldRenderInquiry to set.
     */
    public void setShouldRenderInquiry(boolean shouldRenderInquiry) {
        this.shouldRenderInquiry = shouldRenderInquiry;
    }

    /**
     * Dropdowns are typically fields with codes, which may be close to meaningless, with more explanative labels.  Therefore,
     * fields which are drop downs should display the label instead
     *
     * @return the label for the chosen key on the field if possible; otherwise, an empty String
     */
    protected String getValueForDropDown() {
        for (Object keyLabelPairAsObject : getField().getFieldValidValues()) {
            final KeyValue keyLabelPair = (KeyValue) keyLabelPairAsObject;
            if (getField().getPropertyValue().equalsIgnoreCase(keyLabelPair.getKey().toString())) {
                return keyLabelPair.getValue();
            }
        }
        return null;
    }

    /**
     * An algorithm to discover the actual read only value to render.  If this is a drop down, it finds the renderable value for the drop down;
     * if the value is unavailable, it searches for the property in unconverted values
     *
     * @return the value to display
     * <p>
     * KRAD Conversion: Discovering fields values
     */
    protected String discoverRenderValue() {
        String value = getField().getPropertyValue();
        if (getField().getFieldType().equals(Field.DROPDOWN) && !StringUtils.isEmpty(value)) {
            value = getValueForDropDown();
        }

        return value;
    }

    /**
     * @return the HTML for a non-breaking space, so the box isn't all empty
     */
    protected String buildNonBreakingSpace() {
        return "&nbsp;";
    }

    /**
     * Nope, no quick finder here
     *
     * @see org.kuali.kfs.sys.document.web.renderers.FieldRenderer#renderQuickfinder()
     */
    @Override
    public boolean renderQuickfinder() {
        return false;
    }

    /**
     * @see org.kuali.kfs.sys.document.web.renderers.FieldRendererBase#closeNoWrapSpan(javax.servlet.jsp.PageContext, javax.servlet.jsp.tagext.Tag)
     */
    @Override
    public void closeNoWrapSpan(PageContext pageContext, Tag parentTag) throws JspException {
        // do nothing - read onlys don't need "no wrap"
    }

    /**
     * @see org.kuali.kfs.sys.document.web.renderers.FieldRendererBase#openNoWrapSpan(javax.servlet.jsp.PageContext, javax.servlet.jsp.tagext.Tag)
     */
    @Override
    public void openNoWrapSpan(PageContext pageContext, Tag parentTag) throws JspException {
        // do nothing - read onlys don't need "no wrap"
    }

    @Override
    public void renderExplodableLink(PageContext context) throws JspException {
         /* No thanks */
    }


}
