/*
 * Label.java
 *
 * Created on June 12, 2006, 4:21 PM
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package usda.weru.util.table;

import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.HeadlessException;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.Transparency;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.PixelGrabber;
import javax.swing.ImageIcon;
import org.apache.log4j.Logger;
import org.jdom.Element;

/**
 *
 * @author Joseph Levin
 */
public class Label implements XmlObject{
    private static final transient Logger logger = Logger.getLogger(Label.class);
    protected String c_text;
    protected Image c_image;
    protected CellStyle c_cellStyle;
    protected WepsTableMeta c_meta;
    protected int c_spanRows = 0;
    protected int c_spanColumns = 0;
    protected String c_imageAngleText; 
    protected double c_imageAngle = 0;
    protected Image c_rotatedImage;
    
    /**
     * Create a new Label and associate it with the given WepsTableMeta.
     * @param meta The WepsTableMeta this Label will belong to.
     */
    public Label(WepsTableMeta meta) {
        c_meta = meta;
        init();
    }
    
    private void init(){
        
    }
    
    /**
     * Load configuration information about this label from a jdom Element.
     * @param node An org.jdom.Element containing configuration information for this Label.
     */
    public void fromXml(Element node){
        if (node == null) return;
        loadText(node);        
        loadCellStyle(node);
        loadImage(node);        //Image needs to come after cell style so we cen set the renderer if needed.
        loadSpanRows(node);
        loadSpanColumns(node);
    }
    
    private void loadCellStyle(Element node){
        Element styleNode = node.getChild(WepsTableEnum.XML_style);
        if (styleNode == null) return;
        String cellId = null;
        cellId = styleNode.getTextTrim();

        if (cellId != null && cellId.length() > 0){
            c_cellStyle = c_meta.getCellStyle(cellId);
        }
        else{
            c_cellStyle = new CellStyle(c_meta);
            c_cellStyle.fromXml(styleNode);
        }    
    }
    
    private void loadSpanRows(Element node){
        String number = node.getAttributeValue(WepsTableEnum.XML_spanrows);
        try{
            c_spanRows = Integer.parseInt(number);     
        }
        catch(NumberFormatException nfe){
            c_spanRows = 0;
        }
    }
    
    private void loadSpanColumns(Element node){
        String number = node.getAttributeValue(WepsTableEnum.XML_spancolumns);
        try{
            c_spanColumns = Integer.parseInt(number);            
        }
        catch(NumberFormatException nfe){
            c_spanColumns = 0;
        }
    }
    
    private void loadText(Element node){
        String text = node.getChildText(WepsTableEnum.XML_text);
        if (text == null){
            text = node.getValue();
        }
        c_text = text;
    }
    
    private void loadImage(Element node){
        String imagePath = node.getChildTextTrim(WepsTableEnum.XML_image);
        if (imagePath == null || imagePath.length() == 0) return;
        try{            
            Image image = Toolkit.getDefaultToolkit().getImage(imagePath);
            c_image = image;
            c_imageAngleText = node.getChild(WepsTableEnum.XML_image).getAttributeValue(WepsTableEnum.XML_angle);            
        }
        catch(Exception e){
            logger.debug("Unable to load label image.", e);
        }
    }
    
    /**
     * Return the number of rows this Label spans.
     * @return The number of rows.
     */
    public int getSpanRows(){
        return c_spanRows;
    }
    
    /**
     * Return the number of columns this Label spans.
     * @return The number of Columns.
     */
    public int getSpanColumns(){
        return c_spanColumns;
    }
    
    /**
     * Return the CellStyle used by this Label.
     * @return The CellStyle used.
     */
    public CellStyle getCellStyle(){
        return c_cellStyle;        
    }
    
    /**
     * Return the value of the given cell.
     * @param table The WepsTable to be queried.
     * @param rowIndex The row to be queried.
     * @param columnIndex The column to be queried.
     * @return The value of the cell at [rowIndex, columnIndex].
     */
    public Object getObject(WepsTable table, int rowIndex, int columnIndex){
        if (c_image != null){
            //Return an image, 
            if (c_imageAngleText != null && c_imageAngleText.length() > 0){
                //Rotate the image
                rotateImage(table, rowIndex, columnIndex);
            }
            if (c_rotatedImage != null){
                return c_rotatedImage;
            }
            return c_image;
        }
        else{
            return c_text;
        }
    }
    
    protected  void rotateImage(WepsTable table, int rowIndex, int columnIndex){
        String angleText = table.getMeta().parse(c_imageAngleText, table, rowIndex, columnIndex).toString();        
        try{
            double angle = Double.parseDouble(angleText);
            if (angle != c_imageAngle){

                BufferedImage bimage = toBufferedImage(c_image, angle);                                
                
                c_rotatedImage = Toolkit.getDefaultToolkit().createImage(bimage.getSource());
               
                
            }
        }
        catch(Exception e){}
    }
    
    /**
     * Return the text contained in this Label.
     * @return The text contained in this label.
     */
    public String getText(){
        return c_text;
    }
     
    // This method returns a buffered image with the contents of an image
    //Code from http://javaalmanac.com/egs/java.awt.image/Image2Buf.html?l=rel
    /**
     * Convert the supplied image to a BufferedImage.
     * @param image The Image to be converted.
     * @param rotate The amount the image needs to be rotated in degrees.
     * @return The converted image.
     */
    public static BufferedImage toBufferedImage(Image image, double rotate) {
        if (image instanceof BufferedImage) {
            return (BufferedImage)image;
        }
        else if(image == null){
            return null;
        }
    
        // This code ensures that all the pixels in the image are loaded
        image = new ImageIcon(image).getImage();
    
        // Determine if the image has transparent pixels; for this method's
        // implementation, see e661 Determining If an Image Has Transparent Pixels
        boolean hasAlpha = hasAlpha(image);
    
        // Create a buffered image with a format that's compatible with the screen
        BufferedImage bimage = null;
        GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
        try {
            // Determine the type of transparency of the new buffered image
            int transparency = Transparency.OPAQUE;
            if (hasAlpha) {
                transparency = Transparency.BITMASK;
            }
    
            // Create the buffered image
            GraphicsDevice gs = ge.getDefaultScreenDevice();
            GraphicsConfiguration gc = gs.getDefaultConfiguration();
            bimage = gc.createCompatibleImage(
                image.getWidth(null), image.getHeight(null), transparency);
        } catch (HeadlessException e) {
            // The system does not have a screen
        }
    
        if (bimage == null) {
            // Create a buffered image using the default color model
            int type = BufferedImage.TYPE_INT_RGB;
            if (hasAlpha) {
                type = BufferedImage.TYPE_INT_ARGB;
            }
            bimage = new BufferedImage(image.getWidth(null), image.getHeight(null), type);
        }
    
        // Copy image to buffered image
        Graphics2D g = bimage.createGraphics();
        if (rotate != 0){
            AffineTransform at = new AffineTransform();
            int x = bimage.getWidth() / 2;
            int y = bimage.getHeight() / 2;    
            at.rotate(Math.toRadians(rotate), x, y);
            g.transform(at);
        }
    
        // Paint the image onto the buffered image
        g.drawImage(image, 0, 0, null);     
        g.dispose();
    
        return bimage;
    }
    
    // This method returns true if the specified image has transparent pixels
    //Code from http://javaalmanac.com/egs/java.awt.image/HasAlpha.html
    /**
     * Check if the supplied image supports alpha.
     * @param image The image to be tested.
     * @return <b>true</b> if the image supports alpha, <b>false</b> otherwise.
     */
    public static boolean hasAlpha(Image image) {
        // If buffered image, the color model is readily available
        if (image instanceof BufferedImage) {
            BufferedImage bimage = (BufferedImage)image;
            return bimage.getColorModel().hasAlpha();
        }
    
        // Use a pixel grabber to retrieve the image's color model;
        // grabbing a single pixel is usually sufficient
         PixelGrabber pg = new PixelGrabber(image, 0, 0, 1, 1, false);
        try {
            pg.grabPixels();
        } catch (InterruptedException e) {
        }
    
        // Get the image's color model
        ColorModel cm = pg.getColorModel();
        return cm.hasAlpha();
    }
    
}
