package com.capgemini.reports.templates;

import com.capgemini.framework.common.StringHelper;
import lombok.Getter;

import java.util.Map;

/**
 * Represents a Cell in a jrxml Grid Template.<br>
 * A Cell may be a static textfield, a dynamic Parameter textfield, or a dynamic Field textfield.
 */
@Getter
public final class Cell {
    // Parameters and field declarations
    private static final String REPORT_FIELD_BEGIN = "\n    <field name=\"";
    private static final String REPORT_PARAMETER_BEGIN = "\n    <parameter name=\"";
    private static final String REPORT_FIELD_OR_PARAM_END = "\" class=\"java.lang.String\"/>";

    // Text elements to create a Cell
    private static final String BEGIN_TEXTFIELD = "\n            <textField>";
    private static final String BEGIN_TEXTFIELD_STRETCH_WITH_OVERFLOW = "\n            <textField isStretchWithOverflow=\"true\">";
    private static final String BEGIN_STATICTEXT = "\n            <staticText>";
    private static final String BEGIN_STATICTEXT_STRETCH_WITH_OVERFLOW = "\n            <staticText isStretchWithOverflow=\"true\">";
    private static final String BEGIN_ELEMENT = "\n                <reportElement";
    private static final String STRETCH_TYPE = " stretchType=\"RelativeToTallestObject\"";
    private static final String BEGIN_XPOS = " x=\"";
    private static final String X_TO_Y = "\" y=\"";
    private static final String Y_TO_WIDTH = "\" width=\"";
    private static final String HEIGHT = "\" height=\"";
    private static final String END_ELEMENT = "\"/>";
    private static final String HTML_MARKUP_BEGIN = "\n                <textElement";
    private static final String HTML_MARKUP_END = " markup=\"html\">\n";
    private static final String END_TEXTELEMENT = "\n                </textElement>";
    private static final String BEGIN_FIELD = "\n                <textFieldExpression><![CDATA[$F{";
    private static final String BEGIN_PARAMETER = "\n                <textFieldExpression><![CDATA[$P{";
    private static final String BEGIN_VARIABLE = "\n                <textFieldExpression><![CDATA[$V{";
    private static final String END_EXPRESSION = "}]]></textFieldExpression>";
    private static final String BEGIN_TEXT = "\n                <text><![CDATA[";
    private static final String BEGIN_STYLE = " style =\"";
    private static final String END_TEXT = "]]></text>";
    private static final String END_TEXTFIELD = "\n            </textField>";
    private static final String END_STATICTEXT = "\n            </staticText>";

    // Make a nice box af any textField
    private static final String BOX_L1 = "\n                <box leftPadding=\"5\">";
    private static final String BOX_L2 = "\n                    <topPen lineWidth=\"0.5\"/>";
    private static final String BOX_L3 = "\n                    <leftPen lineWidth=\"0.5\"/>";
    private static final String BOX_L4 = "\n                    <bottomPen lineWidth=\"0.5\"/>";
    private static final String BOX_L5 = "\n                    <rightPen lineWidth=\"0.5\"/>";
    private static final String BOX_L6 = "\n                </box>";


    // Final Cell properties
    private final boolean dynamic;
    private final boolean isHeader;
    private final boolean isStretchWithOverflow;
    private final String content;
    private final String xPosition;
    private final String yPosition;
    private final String width;

    private final CellFormat format;
    private String nameStyle;

    // The Cell height may vary, do not make this final
    private int height;

    private static final String END_STYLE = "\"";

    /**
     * Creates a <i>static</i> textfield, with fixed text content (Cannot stretch with overflow).
     * 
     * <pre>
     * < textField>}
     *     < reportElement x="0" y="0" width="100" height="20"/>
     *     < textFieldExpression>< ![CDATA[Some text content]]>< /textFieldExpression>}
     * < /textField>
     * </pre>
     * 
     * @param content the text content as a {@link String}
     * @param height the Cell height
     * @param width the Cell width
     * @param xPosition the Cell horizontal position
     * @param yPosition the Cell vertical position
     * @param format this cell's format
     * @return a properly built {@link Cell}
     */
    public static Cell makeStaticCell(final String content, final int height, final int width, final int xPosition, final int yPosition,
            final CellFormat format) {
        return new Cell(content, false, true, false, height, width, xPosition, yPosition, format);
    }

    /**
     * Creates a dynamic <i>Field</i> textfield, whose content will be replaced using the value with a matching key in the field {@link Map}.<br>
     * Exemple:
     * 
     * <pre>
     * < textField>
     *     < reportElement x="0" y="0" width="100" height="20"/>
     *     < textFieldExpression>< ![CDATA[$F{FIELD_KEY_HERE}]]>< /textFieldExpression>
     * < /textField>
     * </pre>
     * 
     * @param fieldKey the field key as a {@link String}
     * @param height the Cell height
     * @param width the Cell width
     * @param stretchWithOverflow if true, the cell will expand downwards to shall all the text inside it
     * @param xPosition the Cell horizontal position
     * @param yPosition the Cell vertical position
     * @param format this cell's format
     * @return a properly built {@link Cell}
     */
    public static Cell makeFieldCell(final String fieldKey, final int height, final int width, final boolean stretchWithOverflow,
            final int xPosition, final int yPosition, final CellFormat format) {
        return new Cell(fieldKey, true, false, stretchWithOverflow, height, width, xPosition, yPosition, format);
    }


    /**
     * Creates a dynamic <i>Parameter</i> textfield, whose content will be replaced using the value with a matching key in the parameters {@link Map}. <br>
     * Exemple:
     * 
     * <pre>
     * < textField>
     *     < reportElement x="0" y="0" width="100" height="20"/>
     *     < textFieldExpression>< ![CDATA[$P{PARAMETER_KEY_HERE}]]>< /textFieldExpression>
     * < /textField>
     * </pre>
     * 
     * @param parameterKey the parameter key as a {@link String}
     * @param height the Cell height
     * @param width the Cell width
     * @param stretchWithOverflow if true, the cell will expand downwards to shall all the text inside it
     * @param xPosition the Cell horizontal position
     * @param yPosition the Cell vertical position
     * @param format this cell's format
     * @return a properly built {@link Cell}
     */
    public static Cell makeParameterCell(final String parameterKey, final int height, final int width, final boolean stretchWithOverflow,
            final int xPosition, final int yPosition, final CellFormat format) {
        return new Cell(parameterKey, true, true, stretchWithOverflow, height, width, xPosition, yPosition, format);
    }

    private Cell(final String content, final boolean dynamic, final boolean isHeader, final boolean stretchWithOverflow, final int height,
            final int width, final int xPosition, final int yPosition, final CellFormat format) {
        this.content = content;
        this.dynamic = dynamic;
        this.isHeader = isHeader;
        this.isStretchWithOverflow = dynamic && stretchWithOverflow; // can only use stretch With Overflow in dynamic cell
        this.height = height;
        this.width = String.valueOf(width);
        this.xPosition = String.valueOf(xPosition);
        this.yPosition = String.valueOf(yPosition);
        this.format = format == null ? new CellFormat() : format;
    }

    /**
     * Adds some extra height to this Cell, increasing its height towards the bottom.
     * 
     * @param extraHeight the extra height, in pixels
     */
    public void addHeight(final int extraHeight) {
        this.height += extraHeight;
    }

    /**
     * Generates a cell declaration for a jrxml template.
     * 
     * @return a String containing the full cell template
     */
    public String makeCell() {
        String heightStr = String.valueOf(height);
        String alignmentStr = format.getAlignment();
        String color = format.getColor();
        String bold = format.getIsBold();
        String aLignementVertical = format.getVerticalAligement();
        if (dynamic) {
            if (nameStyle != null) {
                return StringHelper.concatToString(isStretchWithOverflow ? BEGIN_TEXTFIELD_STRETCH_WITH_OVERFLOW : BEGIN_TEXTFIELD, BEGIN_ELEMENT,
                        isStretchWithOverflow ? STRETCH_TYPE : "", BEGIN_STYLE, nameStyle, END_STYLE, BEGIN_XPOS, xPosition, X_TO_Y, yPosition,
                        Y_TO_WIDTH, width, HEIGHT, heightStr, END_ELEMENT, BOX_L1, BOX_L2, BOX_L3, BOX_L4, BOX_L5, BOX_L6, HTML_MARKUP_BEGIN,
                        alignmentStr, HTML_MARKUP_END, END_TEXTELEMENT, BEGIN_FIELD, content, END_EXPRESSION, END_TEXTFIELD);

            }
            else {
                return StringHelper.concatToString(isStretchWithOverflow ? BEGIN_TEXTFIELD_STRETCH_WITH_OVERFLOW : BEGIN_TEXTFIELD, BEGIN_ELEMENT,
                        isStretchWithOverflow ? STRETCH_TYPE : "", BEGIN_XPOS, xPosition, X_TO_Y, yPosition, Y_TO_WIDTH, width, HEIGHT, heightStr,
                        END_ELEMENT, BOX_L1, BOX_L2, BOX_L3, BOX_L4, BOX_L5, BOX_L6, HTML_MARKUP_BEGIN, alignmentStr, HTML_MARKUP_END,
                        END_TEXTELEMENT, isHeader ? BEGIN_PARAMETER : BEGIN_FIELD, content, END_EXPRESSION, END_TEXTFIELD);
            }
        }
        else {
            return StringHelper.concatToString(isStretchWithOverflow ? BEGIN_STATICTEXT_STRETCH_WITH_OVERFLOW : BEGIN_STATICTEXT, BEGIN_ELEMENT,
                    isStretchWithOverflow ? STRETCH_TYPE : "", BEGIN_XPOS, xPosition, X_TO_Y, yPosition, Y_TO_WIDTH, width, HEIGHT, heightStr, color,
                    END_ELEMENT, BOX_L1, BOX_L2, BOX_L3, BOX_L4, BOX_L5, BOX_L6, HTML_MARKUP_BEGIN, alignmentStr, aLignementVertical,
                    HTML_MARKUP_END, bold, END_TEXTELEMENT, BEGIN_TEXT, content, END_TEXT, END_STATICTEXT);
        }

    }

    /**
     * Returns a declaration of this cell's Field key, if it is a dynamic field.
     * 
     * @return the {@link String} key
     */
    public String getFieldsDeclaration() {
        if (!this.isDynamic() || this.isHeader) {
            return "";
        }
        else {
            return REPORT_FIELD_BEGIN + content + REPORT_FIELD_OR_PARAM_END;
        }
    }

    /**
     * Returns a declaration of this cell's Parameter key, if it is a dynamic parameter.
     * 
     * @return the {@link String} key
     */
    public String getParametersDeclaration() {
        if (!this.isDynamic() || !this.isHeader) {
            return "";
        }
        else {
            return REPORT_PARAMETER_BEGIN + content + REPORT_FIELD_OR_PARAM_END;
        }
    }

    /**
     * Gives the Cell a style by the provided name.
     * 
     * @param aNameStyle the name of the style. Use null to remove style.
     */
    public void setNameStyle(final String aNameStyle) {
        nameStyle = aNameStyle;
    }
}
