/*
 * Java-Gnome Bindings Library
 *
 * Copyright 1998-2004 the Java-Gnome Team, all rights reserved.
 *
 * The Java-Gnome bindings library is free software distributed under
 * the terms of the GNU Library General Public License version 2.
 */

package org.gnu.pango;

import org.gnu.glib.Boxed;
import org.gnu.glib.GObject;
import org.gnu.glib.MemStruct;
import org.gnu.glib.Handle;

/**
 * While complete access to the layout capabilities of Pango is provided using
 * the detailed interfaces for itemization and shaping, using that functionality
 * directly involves writing a fairly large amount of code. The objects and
 * functions in this structure provide a high-level driver for formatting entire
 * paragraphs of text at once.
 * 
 * <p>
 * The PangoLayout structure represents and entire paragraph of text. It is
 * initialized with a PangoContext, UTF-8 string and set of attributes for that
 * string. Once that is done, the set of formatted lines can be extracted from
 * the object, the layout can be rendered, and conversion between logical
 * character positions within the layout's text, and the physical position of
 * the resulting glyphs can be made.
 */
public class Layout extends GObject {

    /**
     * Construct a new Layout with the given Context.
     * 
     * @param context
     *            The context to use for the Layout construction.
     */
    public Layout(Context context) {
        super(Layout.pango_layout_new(context.getHandle()));
    }

    /**
     * Construct a new Layout that is a copy of the provided Layout.
     * 
     * @param layout
     */
    public Layout(Layout layout) {
        super(pango_layout_copy(layout.getHandle()));
    }

    /**
     * Construct a new Layout with a handle that has been returned from a native
     * call.
     * 
     * @param handle
     *            The handle to the native resource.
     */
    public Layout(Handle handle) {
        super(handle);
    }

    /**
     * Static factory method that should only be used interally by Java-Gnome.
     */
    public static Layout getLayoutFromHandle(Handle handle) {
        if (handle == null) {
            return null;
        }

        Layout obj = (Layout) GObject.getGObjectFromHandle(handle);

        if (obj == null) {
            obj = new Layout(handle);
        }

        return obj;
    }

    /**
     * Retrieve the Context used for this Layout.
     */
    public Context getContext() {
        Handle hndl = pango_layout_get_context(getHandle());
        return Context.getContextFromHandle(hndl);
    }

    /**
     * Forces recomputation of any state in the Layout that might depend on the
     * layout's context. This method should be called if you make changes to the
     * context subsequent to creating the layout
     * 
     */
    public void contextChanged() {
        pango_layout_context_changed(getHandle());
    }

    /**
     * Set the text of the layout.
     */
    public void setText(String text) {
        pango_layout_set_text(getHandle(), text, text.length());
    }

    /**
     * Gets the text in the layout.
     */
    public String getText() {
        return pango_layout_get_text(getHandle());
    }

    /**
     * Sets the layout text and attribute list from marked-up text (see markup
     * format). Replaces the current text and attribute list.
     * 
     * <p>
     * If accelMarker is nonzero, the given character will mark the character
     * following it as an accelerator. For example, the accel marker might be an
     * ampersand or underscore. All characters marked as an accelerator will
     * receive a {@link Underline#LOW} attribute. Two accelMarker characters
     * following each other produce a single literal accelMarker character.
     * 
     * @param markup
     *            some marked-up text
     * @param accelMarker :
     *            marker for accelerators in the text
     */
    public void setMarkup(String markup, char accelMarker) {
        pango_layout_set_markup_with_accel(getHandle(), markup,
                markup.length(), (byte) accelMarker, (byte) '0');
    }

    /**
     * Same as {@link #setMarkup(String, char)}, but the markup text isn't
     * scanned for accelerators.
     */
    public void setMarkup(String markup) {
        pango_layout_set_markup(getHandle(), markup, markup.length());
    }

    /**
     * Sets the text attributes for a layout object
     */
    public void setAttributes(AttrList attributes) {
        pango_layout_set_attributes(getHandle(), attributes.getHandle());
    }

    /**
     * Gets the attribute list for the layout, if any
     */
    public AttrList getAttributes() {
        Handle hndl = pango_layout_get_attributes(getHandle());
        return AttrList.getAttrListFromHandle(hndl);
    }

    /**
     * Set the default font description for the layout. If no font description
     * is set on the layout, the font description from the layout's context is
     * used.
     */
    public void setFontDescription(FontDescription desc) {
        pango_layout_set_font_description(getHandle(), desc.getHandle());
    }

    /**
     * Sets the width to which the lines of the PangoLayout should be wrapped.
     */
    public void setWidth(int width) {
        pango_layout_set_width(getHandle(), width);
    }

    /**
     * Gets the width to which the lines of the PangoLayout should be wrapped.
     */
    public int getWidth() {
        return pango_layout_get_width(getHandle());
    }

    /**
     * Sets the wrap style; the wrap style only has an effect if a width is set
     * on the layout with {@link #setWidth(int)}To turn off wrapping, set the
     * width to -1.
     * 
     * @deprecated
     */
    public void setWrapStyle(WrapMode wrap) {
        setWrap(wrap);
    }

    /**
     * Get the wrap mode for the layout.
     * 
     * @deprecated
     */
    public WrapMode getWrapMode() {
        return getWrap();
    }

    /**
     * Sets the wrap style; the wrap style only has an effect if a width is set
     * on the layout with {@link #setWidth(int)}To turn off wrapping, set the
     * width to -1.
     */
    public void setWrap(WrapMode wrap) {
        pango_layout_set_wrap(getHandle(), wrap.getValue());
    }

    /**
     * Get the wrap mode for the layout.
     */
    public WrapMode getWrap() {
        return WrapMode.intern(pango_layout_get_wrap(getHandle()));
    }

    /**
     * Sets the amount by which the first line should be shorter than the rest
     * of the lines. This may be negative, in which case the subsequent lines
     * will be shorter than the first line. (However, in either case, the entire
     * width of the layout will be given by the value
     */
    public void setIndent(int indent) {
        pango_layout_set_indent(getHandle(), indent);
    }

    /**
     * Gets the amount by which the first line should be shorter than the rest
     * of the lines.
     */
    public int getIndent() {
        return pango_layout_get_indent(getHandle());
    }

    /**
     * Gets the amount of spacing between the lines of the layout.
     * 
     * @return the spacing (in thousandths of a device unit)
     */
    public int getSpacing() {
        return pango_layout_get_spacing(getHandle());
    }

    /**
     * Sets the amount of spacing between the lines of the layout.
     */
    public void setSpacing(int spacing) {
        pango_layout_set_spacing(getHandle(), spacing);
    }

    /**
     * Sets whether or not each complete line should be stretched to fill the
     * entire width of the layout. This stretching is typically done by adding
     * whitespace, but for some scripts (such as Arabic), the justification is
     * done by extending the characters.
     * 
     * @deprecated
     */
    public void setJustification(boolean justify) {
        setJustify(justify);
    }

    /**
     * Gets whether or not each complete line should be stretched to fill the
     * entire width of the layout.
     * 
     * @deprecated
     */
    public boolean getJustified() {
        return getJustify();
    }

    /**
     * Sets whether or not each complete line should be stretched to fill the
     * entire width of the layout. This stretching is typically done by adding
     * whitespace, but for some scripts (such as Arabic), the justification is
     * done by extending the characters.
     */
    public void setJustify(boolean justify) {
        pango_layout_set_justify(getHandle(), justify);
    }

    /**
     * Gets whether or not each complete line should be stretched to fill the
     * entire width of the layout.
     */
    public boolean getJustify() {
        return pango_layout_get_justify(getHandle());
    }

    /**
     * Sets the alignment for the layout (how partial lines are positioned
     * within the horizontal space available.)
     */
    public void setAlignment(Alignment alignment) {
        pango_layout_set_alignment(getHandle(), alignment.getValue());
    }

    /**
     * Gets the alignment for the layout (how partial lines are positioned
     * within the horizontal space available.)
     */
    public Alignment getAlignment() {
        return Alignment.intern(pango_layout_get_alignment(getHandle()));
    }

    /**
     * Sets the tabs to use for layout, overriding the default tabs (by default,
     * tabs are every 8 spaces).
     */
    public void setTabs(TabArray tabs) {
        pango_layout_set_tabs(getHandle(), tabs.getHandle());
    }

    /**
     * Gets the current TabArray used by this layout. If no TabArray has been
     * set, then the default tabs are in use and <tt>null</tt> is returned.
     * Default tabs are every 8 spaces.
     */
    public TabArray getTabs() {
        Handle hndl = pango_layout_get_tabs(getHandle());
        if (hndl != null) {
            Boxed box = Boxed.getBoxedFromHandle(hndl);
            if (box == null) {
                return new TabArray(hndl);
            } else {
                return (TabArray) box;
            }
        }
        return null;
    }

    /**
     * If setting is TRUE, do not treat newlines and similar characters as
     * paragraph separators; instead, keep all text in a single paragraph, and
     * display a glyph for paragraph separator characters. Used when you want to
     * allow editing of newlines on a single text line.
     */
    public void setSingleParagraphMode(boolean setting) {
        pango_layout_set_single_paragraph_mode(getHandle(), setting);
    }

    /**
     * Obtains the value set by {@link #setSingleParagraphMode}.
     */
    public boolean getSingleParagraphMode() {
        return pango_layout_get_single_paragraph_mode(getHandle());
    }

    /**
     * Retrieve the count of lines for the layout
     */
    public int getLineCount() {
        return pango_layout_get_line_count(getHandle());
    }

    /**
     * Retrieves a particular line from a Layout.
     * 
     * @param line
     *            the index of a line, which must be between 0 and
     *            pango_layout_get_line_count(layout) - 1, inclusive.
     * @return the requested LayoutLine.
     */
    public LayoutLine getLine(int line) {
        Handle hndl = pango_layout_get_line(getHandle(), line);
        if (hndl != null) {
            MemStruct mem = MemStruct.getMemStructFromHandle(hndl);
            if (mem == null) {
                return new LayoutLine(hndl);
            } else {
                return (LayoutLine) mem;
            }
        }
        return null;
    }

    /**
     * Converts from an index within a Layout to the onscreen position
     * corresponding to the grapheme at that index, which is represented as
     * rectangle. Note that pos->x is always the leading edge of the grapheme
     * and pos->x + pos->width the trailing edge of the grapheme. If the
     * directionality of the grapheme is right-to-left, then pos->width will be
     * negative.
     * 
     * @param index
     */
    public Rectangle indexToPos(int index) {
        return Rectangle.getRectangleFromHandle(pango_layout_index_to_pos(
                getHandle(), index));
    }

    /**
     * Given an index within a layout, determines the positions that of the
     * strong cursor if the insertion point is at that index. The position of
     * each cursor is stored as a zero-width rectangle. The strong cursor
     * location is the location where characters of the directionality equal to
     * the base direction of the layout are inserted.
     * 
     * @param index
     */
    public Rectangle getStrongCursorPosition(int index) {
        return Rectangle
                .getRectangleFromHandle(pango_layout_get_cursor_pos_strong(
                        getHandle(), index));
    }

    /**
     * Given an index within a layout, determines the positions that of the weak
     * cursor if the insertion point is at that index. The position of each
     * cursor is stored as a zero-width rectangle. The weak cursor location is
     * the location where characters of the directionality opposite to the base
     * direction of the layout are inserted.
     * 
     * @param index
     */
    public Rectangle getWeakCursorPosition(int index) {
        return Rectangle
                .getRectangleFromHandle(pango_layout_get_cursor_pos_weak(
                        getHandle(), index));
    }

    /**
     * Return the logical height of the Layout in Pango units.
     */
    public int getHeight() {
        int[] width = new int[1];
        int[] height = new int[1];
        pango_layout_get_size(getHandle(), width, height);
        return height[0];
    }

    /**
     * Return the logical width of the Layout in device units.
     */
    public int getPixelWidth() {
        int[] width = new int[1];
        int[] height = new int[1];
        pango_layout_get_pixel_size(getHandle(), width, height);
        return width[0];
    }

    /**
     * Return the logical height of the Layout in device units.
     */
    public int getPixelHeight() {
        int[] width = new int[1];
        int[] height = new int[1];
        pango_layout_get_pixel_size(getHandle(), width, height);
        return height[0];
    }

    native static final protected int pango_layout_get_type();

    native static final protected Handle pango_layout_new(Handle context);

    native static final protected Handle pango_layout_copy(Handle src);

    native static final protected Handle pango_layout_get_context(Handle layout);

    native static final protected void pango_layout_set_attributes(
            Handle layout, Handle attrs);

    native static final protected Handle pango_layout_get_attributes(
            Handle layout);

    native static final protected void pango_layout_set_text(Handle layout,
            String text, int length);

    native static final protected String pango_layout_get_text(Handle layout);

    native static final protected void pango_layout_set_markup(Handle layout,
            String markup, int length);

    native static final protected void pango_layout_set_markup_with_accel(
            Handle layout, String markup, int length, byte accelMarker,
            byte accelChar);

    native static final protected void pango_layout_set_font_description(
            Handle layout, Handle desc);

    native static final protected void pango_layout_set_width(Handle layout,
            int width);

    native static final protected int pango_layout_get_width(Handle layout);

    native static final protected void pango_layout_set_wrap(Handle layout,
            int wrap);

    native static final protected int pango_layout_get_wrap(Handle layout);

    native static final protected void pango_layout_set_indent(Handle layout,
            int indent);

    native static final protected int pango_layout_get_indent(Handle layout);

    native static final protected void pango_layout_set_spacing(Handle layout,
            int spacing);

    native static final protected int pango_layout_get_spacing(Handle layout);

    native static final protected void pango_layout_set_justify(Handle layout,
            boolean justify);

    native static final protected boolean pango_layout_get_justify(Handle layout);

    native static final protected void pango_layout_set_alignment(
            Handle layout, int alignment);

    native static final protected int pango_layout_get_alignment(Handle layout);

    native static final protected void pango_layout_set_tabs(Handle layout,
            Handle tabs);

    native static final protected Handle pango_layout_get_tabs(Handle layout);

    native static final protected void pango_layout_set_single_paragraph_mode(
            Handle layout, boolean setting);

    native static final protected boolean pango_layout_get_single_paragraph_mode(
            Handle layout);

    native static final protected void pango_layout_context_changed(
            Handle layout);

    native static final protected Handle pango_layout_index_to_pos(
            Handle layout, int index);

    native static final protected Handle pango_layout_get_cursor_pos_strong(
            Handle layout, int index);

    native static final protected Handle pango_layout_get_cursor_pos_weak(
            Handle layout, int index);

    native static final protected void pango_layout_move_cursor_visually(
            Handle layout, boolean strong, int oldIndex, int oldTrailing,
            int direction, int[] newIndex, int[] newTrailing);

    native static final protected boolean pango_layout_xy_to_index(
            Handle layout, int x, int y, int[] index, int[] trailing);

    native static final protected void pango_layout_get_extents(Handle layout,
            Handle inkRect, Handle logicalRect);

    native static final protected void pango_layout_get_pixel_extents(
            Handle layout, Handle inkRect, Handle logicalRect);

    native static final protected void pango_layout_get_size(Handle layout,
            int[] width, int[] height);

    native static final protected void pango_layout_get_pixel_size(
            Handle layout, int[] width, int[] height);

    native static final protected int pango_layout_get_line_count(Handle layout);

    native static final protected Handle pango_layout_get_line(Handle layout,
            int line);

}
