package org.omnetpp.common.largetable;

import org.eclipse.jface.viewers.StyledString;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StyleRange;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.TextLayout;
import org.eclipse.swt.graphics.TextStyle;

/**
 * Base class for LargeTable row renderers.
 *
 * @author andras
 */
public abstract class AbstractLargeTableRowRenderer implements ILargeTableRowRenderer {
    protected static final int CELL_HORIZONTAL_MARGIN = 4;
    protected static final int VERTICAL_SPACING = 0;
    protected static final int HORIZONTAL_SPACING = 0;

    /**
     * Returns the styled string to be used by drawCell() to paint the contents of the given cell.
     * GC and alignment are those of the drawCell() call, passed here for extracting color,
     * font, or size information if necessary.
     */
    public StyledString getStyledText(int rowIndex, int columnIndex, GC gc, int alignment) {
        String text = getText(rowIndex, columnIndex);
        return new StyledString(text);
    }

    /**
     * Returns the indentation (in pixels) of the icon/text of the given cell.
     */
    public abstract int getIndentation(int rowIndex, int columnIndex);

    /**
     * Returns the icon of the given cell, or null. The icon is drawn to the left of the cell.
     */
    public abstract Image getImage(int rowIndex, int columnIndex);

    public int getRowHeight(GC gc) {
        int fontHeight = gc.getFontMetrics().getHeight();
        return fontHeight + 3;
    }

    @Override
    public void drawCell(GC gc, int rowIndex, int columnIndex, int columnWidth, int alignment, boolean selected) {
        int x = CELL_HORIZONTAL_MARGIN + getIndentation(rowIndex, columnIndex);

        Image image = getImage(rowIndex, columnIndex);
        if (image != null) {
            gc.drawImage(image, x, (getRowHeight(gc) - image.getBounds().height) / 2);
            x += image.getBounds().width + HORIZONTAL_SPACING;
        }

        StyledString styledString = getStyledText(rowIndex, columnIndex, gc, alignment);
        final Color foregroundColor = gc.getForeground();
        if (selected) {
            styledString.setStyle(0, styledString.length(), new StyledString.Styler() {
                @Override
                public void applyStyles(TextStyle textStyle) {
                    textStyle.foreground = foregroundColor;
                }
            });
        }
        drawStyledString(gc, styledString, x, VERTICAL_SPACING / 2, columnWidth, alignment);
    }

    protected void drawStyledString(GC gc, StyledString styledString, int x, int y, int cellWidth, int alignment) {
        TextLayout textLayout = new TextLayout(gc.getDevice());
        textLayout.setText(styledString.getString());
        for (StyleRange styleRange : styledString.getStyleRanges())
            textLayout.setStyle(styleRange, styleRange.start, styleRange.start + styleRange.length - 1);

        // not using textLayout.setWidth and textLayout.setAlignment because those would
        // unconditionally wrap (and hyphenate) the text, instead of clipping (or eliding)
        int alignmentOffset = 0;
        if (alignment != SWT.LEFT) {
            int textWidth = textLayout.getBounds().width; // may be costly
            int availableWidth  = cellWidth - CELL_HORIZONTAL_MARGIN - x;
            switch (alignment) {
            case SWT.RIGHT: alignmentOffset = availableWidth - textWidth; break;
            case SWT.CENTER: alignmentOffset = (availableWidth - textWidth) / 2; break;
            }
        }

        //textLayout.draw(gc, x + Math.max(0, alignmentOffset), y);
        textLayout.draw(gc, x + alignmentOffset, y);
        textLayout.dispose();
    }
}


