package com.uvigo.mhp.looks;

import java.awt.*;
import java.util.*;
import org.dvb.ui.*;
import org.havi.ui.*;

public class HGraphicLook2 extends HGraphicLook
{
    public static final int ALIGN_LEFT = -1;
    public static final int ALIGN_RIGHT = -2;
    public static final int ALIGN_CENTER = -3;
    public static final int IMAGE_LEFT = -4;
    public static final int IMAGE_RIGHT = -5;
    public static final int IMAGE_TOP = -6;
    public static final int IMAGE_BOTTOM = -7;
    public static final int H_SPACE = 2;
    public static final int V_SPACE = 2;
    
    private static final String LINE_SEPARATOR = "\n";
    
    private int alignment; // {ALIGN_LEFT,ALIGN_RIGHT,ALIGN_CENTER}
    private int imagePosition; // {IMAGE_LEFT,IMAGE_RIGHT, IMAGE_TOP,IMAGE_BOTTOM}
    private int pHeight, pWidth; // preferredSize
    private int labelAreaHeight, labelAreaWidth;
    private int hSpace, vSpace;
    
    private int rowHeight, rowAscent;
    private int[] rowWidth;
    private int rowCount;
    private String[] row;
    private Image image;
    
    public HGraphicLook2()
    {
        this.hSpace=H_SPACE;
        this.vSpace=V_SPACE;
        this.alignment=ALIGN_LEFT;
        this.imagePosition=IMAGE_LEFT;
        image = null;
        rowCount = 0;
        labelAreaHeight = 0;
        labelAreaWidth = 0;
        pHeight = 0;
        pWidth = 0;
    }
    
    public synchronized Dimension getPreferredSize(HVisible visible)
    {
        image=visible.getGraphicContent(HState.NORMAL_STATE);
        initialize(visible.getTextContent(HState.NORMAL_STATE));
        calculatePreferredDimensions(visible);
        return new Dimension(pWidth, pHeight);
    }
    
    public synchronized Dimension getMinimumSize(HVisible visible)
    {
        image=visible.getGraphicContent(HState.NORMAL_STATE);
        initialize(visible.getTextContent(HState.NORMAL_STATE));
        calculatePreferredDimensions(visible);
        return new Dimension(pWidth, pHeight);
    }
    
    public synchronized int getAlignment()
    {
        return alignment;
    }
    
    public synchronized void setAlignment(int alignment)
    {
        this.alignment = alignment;
    }
    
    public int getImagePosition()
    {
        return imagePosition;
    }
    
    public synchronized void setImagePosition(int imagePosition)
    {
        this.imagePosition = imagePosition;
    }
    
    public int getHorizontalSpace()
    {
        return hSpace;
    }
    
    public synchronized void setHorizontalSpace(int space)
    {
        if (space >= 0)
            hSpace = space;
    }
    
    public int getVerticalSpace()
    {
        return vSpace;
    }
    
    public synchronized void setVerticalSpace(int space)
    {
        if (space >= 0)
            vSpace = space;
    }
    
    protected synchronized void calculatePreferredDimensions(HVisible visible)
    {
        Font f = visible.getFont();
        FontMetrics fm = (f != null) ? visible.getFontMetrics(f) : null;
        if (fm != null)
        {
            rowHeight = fm.getHeight();
            rowAscent = fm.getAscent();
        }
        pWidth = pHeight = 0;
        if (fm != null && rowCount > 0)
        {
            for (int i = 0; i < rowCount; i++)
            {
                rowWidth[i] = fm.stringWidth(row[i]);
                if (rowWidth[i] > pWidth)
                    pWidth = rowWidth[i];
            }
            labelAreaHeight = pHeight = rowHeight * rowCount;
            labelAreaWidth = pWidth;
        }
        pWidth += 2 * hSpace;
        pHeight += 2 * vSpace;
        
        Image img=visible.getGraphicContent(HState.NORMAL_STATE);
        if (img != null)
        {
            int h = img.getHeight(visible);
            int w = img.getWidth(visible);
            switch (imagePosition)
            {
                case IMAGE_TOP:
                    if (w > (pWidth - (2 * hSpace)))
                        pWidth = w + (2 * hSpace);
                    if (h > -1)
                        pHeight += h + vSpace;
                    return;
                case IMAGE_BOTTOM:
                    if (w > (pWidth - (2 * hSpace)))
                        pWidth = w + (2 * hSpace);
                    if (h > -1)
                        pHeight += h + vSpace;
                    return;
                case IMAGE_LEFT:
                    if (h > (pHeight - (2 * vSpace)))
                        pHeight = h + (2 * vSpace);
                    if (w > -1)
                        pWidth += w + hSpace;
                    return;
                default: //IMAGE_RIGHT
                    if (h > (pHeight - (2 * vSpace)))
                        pHeight = h + (2 * vSpace);
                    if (w > -1)
                        pWidth += w + hSpace;
                    return;
            }
        }
    }
    
    public void showLook(Graphics g, HVisible visible, int state)
    {
        if (g instanceof DVBGraphics)
        {
            DVBGraphics g2=(DVBGraphics) g;
            DVBAlphaComposite a=DVBAlphaComposite.getInstance(DVBAlphaComposite.SRC_OVER);
            try
            {
                g2.setDVBComposite(a);
            }
            catch(Exception e)
            {
                System.out.println("No se puede aplicar la regla de composici�n");
            }
        }
        
        // Inicializamos el contenido a representar a partir del estado del HVisible
        image=visible.getGraphicContent(state);
        initialize(visible.getTextContent(state));
        calculatePreferredDimensions(visible);
        
        if (visible.getBackgroundMode()==HVisible.BACKGROUND_FILL)
        {
            g.setColor(visible.getBackground());
            g.fillRect(0,0,visible.getSize().width,visible.getSize().height);
        }
        g.setColor(visible.getForeground());
        displayImage(g, visible);
        displayLabel(g, visible);
    }
    
    protected synchronized void initialize(String label)
    {
        if (label==null) label="";
        
        String lbl = processEscapeSequences(label);
        StringTokenizer t = new StringTokenizer(lbl, LINE_SEPARATOR);
        rowCount = t.countTokens();
        row = new String[rowCount];
        rowWidth = new int[rowCount];
        for (int i = 0; i < rowCount; i++)
            row[i] = t.nextToken();
    }
    
    protected void displayLabel(Graphics g, HVisible visible)
    {
        if (rowCount < 1)
            return;
        int x = hSpace;
        int y = vSpace;
        if (image != null)
        {
            int h = image.getHeight(visible);
            int w = image.getWidth(visible);
            if (h > -1 && w > -1)
            {
                switch (imagePosition)
                {
                    case IMAGE_TOP:
                        if (alignment == ALIGN_CENTER)
                            x = (visible.getSize().width - labelAreaWidth) / 2;
                        else if (alignment == ALIGN_RIGHT)
                            x = visible.getSize().width - labelAreaWidth - hSpace;
                        y += h + vSpace;
                        break;
                    case IMAGE_LEFT:
                        if (alignment == ALIGN_CENTER)
                            x += w + hSpace + ((visible.getSize().width - pWidth) / 2);
                        else if (alignment == ALIGN_RIGHT)
                            x = visible.getSize().width - labelAreaWidth - hSpace;
                        else
                            x += w + hSpace;
                        y += (visible.getSize().height - pHeight) / 2;
                        if (h>labelAreaHeight)
                            y += (h - labelAreaHeight) / 2;
                        break;
                    case IMAGE_RIGHT:
                        if (alignment == ALIGN_CENTER)
                            x += (visible.getSize().width - pWidth) / 2;
                        else if (alignment == ALIGN_RIGHT)
                            x += visible.getSize().width - pWidth;
                        y += (visible.getSize().height - pHeight) / 2;
                        if (h>labelAreaHeight)
                            y += (h - labelAreaHeight) / 2;
                        break;
                    default://IMAGE_BOTTOM
                        if (alignment == ALIGN_CENTER)
                            x = (visible.getSize().width - labelAreaWidth) / 2;
                        else if (alignment == ALIGN_RIGHT)
                            x = visible.getSize().width - labelAreaWidth - hSpace;
                        y = (visible.getSize().height - pHeight) + vSpace;
                        break;
                }
            }
        }
        else
        {
            if (alignment == ALIGN_CENTER)
                x += (visible.getSize().width - pWidth) / 2;
            else if (alignment == ALIGN_RIGHT)
                x = visible.getSize().width - labelAreaWidth - hSpace;
            y += (visible.getSize().height - pHeight) / 2;
        }
        
        y += rowAscent;
        for (int i = 0; i < rowCount; i++, y += rowHeight)
        {
            int adjX = x;
            switch (alignment)
            {
                case ALIGN_LEFT:
                    break;
                case ALIGN_RIGHT:
                    adjX += labelAreaWidth - rowWidth[i];
                    break;
                default: //ALIGN_CENTER:
                    adjX += (labelAreaWidth - rowWidth[i]) / 2;
                    break;
            }
            g.drawString(row[i], adjX, y);
        }
    }
    
    protected void displayImage(Graphics g, HVisible visible)
    {
        if (image == null)
            return;
        int h = image.getHeight(visible);
        int w = image.getWidth(visible);
        int x = hSpace, y = vSpace;
        switch (imagePosition)
        {
            case IMAGE_TOP:
                if (alignment == ALIGN_CENTER)
                    x = (visible.getSize().width - w) / 2;
                else if (alignment == ALIGN_RIGHT)
                    x = visible.getSize().width - hSpace - w;
                break;
            case IMAGE_LEFT:
                if (alignment == ALIGN_CENTER)
                {
                    if (rowCount > 0) // se requiere margen para el texto
                        x += (visible.getSize().width - pWidth) / 2;
                    else
                        x = (visible.getSize().width - w) / 2;
                }
                else if (alignment == ALIGN_RIGHT)
                {
                    x += visible.getSize().width - pWidth;
                    if (rowCount == 0) // no se requiere margen para el texto
                        x += hSpace;
                }
                
                y+=(visible.getSize().height-h)/2;
                //y += (visible.getSize().height - pHeight) / 2;
                break;
            case IMAGE_RIGHT:
                if (alignment == ALIGN_CENTER)
                {
                    if (rowCount > 0) // text margin required
                        x += labelAreaWidth + hSpace +
                        ((visible.getSize().width - pWidth) / 2);
                    else
                        x = (visible.getSize().width - w) / 2;
                }
                else if (alignment == ALIGN_RIGHT)
                    x = visible.getSize().width - w - hSpace;
                else
                {
                    x += labelAreaWidth + hSpace;
                    if (rowCount == 0) // no se requiere margen para el texto
                        x -= hSpace;
                }
                
                y+=(visible.getSize().height-h)/2;
                //y += (visible.getSize().height - pHeight) / 2;
                break;
            default: //IMAGE_BOTTOM
                if (alignment == ALIGN_CENTER)
                    x = (visible.getSize().width - w) / 2;
                else if (alignment == ALIGN_RIGHT)
                    x = visible.getSize().width - hSpace - w;
                y = labelAreaHeight + (2 * vSpace);
                y += visible.getSize().height - pHeight;
                break;
        }
        g.drawImage(image, x, y, visible);
    }
    
    protected String processEscapeSequences(String in)
    {
        StringBuffer out = new StringBuffer(in.length());
        int j = 0;
        for (int i = 0; i < in.length(); i++, j++)
        {
            switch (in.charAt(i))
            {
                case '\\':
                    switch (in.charAt(i + 1))
                    {
                        case 'n':
                            out.insert(j, '\n');
                            break;
                        case 't':
                            out.insert(j, '\t');
                            break;
                        case 'b':
                            out.insert(j, '\b');
                            break;
                        case 'r':
                            out.insert(j, '\r');
                            break;
                        case 'f':
                            out.insert(j, '\f');
                            break;
                        case '\\':
                            out.insert(j, '\\');
                            break;
                        case '\'':
                            out.insert(j, '\'');
                            break;
                        case '\"':
                            out.insert(j, '\"');
                            break;
                        default:
                            if (Character.isDigit(in.charAt(i + 1)))
                            {
                                String octStr = in.substring(i + 1, i + 4);
                                int octValue = Integer.parseInt(octStr);
                                out.insert(j, Character.forDigit(octValue, 8));
                                i += 2; // salta 2 caracteres por el numero octal
                            }
                            else
                                return null;
                            break;
                    }
                    i++; // salta un caracter mas por la barra invertida
                    break;
                default:
                    out.insert(j, in.charAt(i)); // no hay interpretacion especial
                    break;
            }
        }
        out.setLength(j);
        return out.toString();
    }
}