/*
 * JPanelStyleSample.java
 *
 * Created on February 18, 2006, 12:46 PM
 */

package it.businesslogic.ireport.gui.style;

import it.businesslogic.ireport.Box;
import it.businesslogic.ireport.IReportFont;
import it.businesslogic.ireport.ReportElement;
import it.businesslogic.ireport.Style;
import it.businesslogic.ireport.gui.MainFrame;
import it.businesslogic.ireport.util.Java2DUtil;
import it.businesslogic.ireport.util.Misc;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.Stroke;
import java.awt.font.FontRenderContext;
import java.awt.font.LineBreakMeasurer;
import java.awt.font.TextAttribute;
import java.awt.font.TextLayout;
import java.awt.geom.AffineTransform;
import java.text.AttributedCharacterIterator;
import java.text.AttributedString;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.StringTokenizer;


/**
 *
 * @author  gtoffoli
 */
public class JPanelStyleSample extends javax.swing.JPanel {
    
    private Style style = null;
    
    static public Rotation ROTATION_NONE;
    static public Rotation ROTATION_LEFT;
    static public Rotation ROTATION_RIGHT;
  
   static
   { 
     ROTATION_NONE = new Rotation("None", 0);
     ROTATION_LEFT = new Rotation("Left", 1);
     ROTATION_RIGHT = new Rotation("Right", 2);
   }
    
    
    /** Creates new form JPanelStyleSample */
    public JPanelStyleSample() {
        initComponents();
    }

    public Style getStyle() {
        return style;
    }

    public void setStyle(Style style) {
        this.style = style;
        this.repaint();
    }
    
    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    // <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:initComponents
    private void initComponents() {

        setLayout(null);

    }// </editor-fold>//GEN-END:initComponents
    
    
    // Variables declaration - do not modify//GEN-BEGIN:variables
    // End of variables declaration//GEN-END:variables
    
    
    public void paint(Graphics g)
    {
        super.paint(g);
        Graphics2D g2 = (Graphics2D)g;
        
        if (getStyle() == null) return;
        
        if (this.getSize().getWidth() <= 10) return;
        if (this.getSize().getHeight() <= 10) return;
        
        int x=5;
        int y=5;
        int width = (int)this.getSize().getWidth()-10;
        int heigth = (int)this.getSize().getHeight()-10;

        if (MainFrame.getMainInstance().getProperties().getProperty("Antialias","true").equals("false"))
        {
        
            g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                    RenderingHints.VALUE_ANTIALIAS_OFF);
            g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL,
                    RenderingHints.VALUE_STROKE_PURE);
            g2.setRenderingHint(RenderingHints.KEY_DITHERING,
                    RenderingHints.VALUE_DITHER_DISABLE);
        }
        else
        {
        
            g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                    RenderingHints.VALUE_ANTIALIAS_ON);
            g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL,
                    RenderingHints.VALUE_STROKE_DEFAULT);
            g2.setRenderingHint(RenderingHints.KEY_DITHERING,
                    RenderingHints.VALUE_DITHER_ENABLE);
        }
        
        int round = Integer.parseInt( getStyle().getAttributeString(Style.ATTRIBUTE_radius, "0"));
        round *= 2;
        
        // 1. Draw backgrouns...
        Color c = getStyle().getAttributeColor(Style.ATTRIBUTE_backcolor, null);
        String transparent = getStyle().getAttributeString(Style.ATTRIBUTE_mode, "Transparent");
        if (c != null && !transparent.equals("Transparent"))
        {
            g2.setColor(c);
            g2.fillRoundRect(x,y,width,heigth,round,round);
        }
        
        // 1. Draw border...
        c = getStyle().getAttributeColor(Style.ATTRIBUTE_forecolor, null);
        Stroke stroke = ReportElement.getPenStroke(getStyle().getAttributeString(Style.ATTRIBUTE_pen, "Thin"), 1);
        
        if (c != null && stroke != null)
        {
            g2.setStroke(stroke);
            g2.setColor(c);
            g2.drawRoundRect(x,y,width,heigth,round,round);
        }
        
        
        
        Box box = new Box();
        
        if (style.getAttributeString(style.ATTRIBUTE_border, null, true) != null) 
            box.setBorder(  style.getAttributeString(style.ATTRIBUTE_border, null, true) );
        if (style.getAttributeColor(style.ATTRIBUTE_borderColor, null, true) != null) 
            box.setBorderColor(  style.getAttributeColor(style.ATTRIBUTE_borderColor, null, true));
        if (style.getAttributeString(style.ATTRIBUTE_padding, null, true) != null) 
            box.setPadding( Integer.parseInt( style.getAttributeString(style.ATTRIBUTE_padding, null, true) ));

        if (style.getAttributeString(style.ATTRIBUTE_topBorder, null, true) != null) 
            box.setTopBorder(  style.getAttributeString(style.ATTRIBUTE_topBorder, null, true) );
        if (style.getAttributeColor(style.ATTRIBUTE_topBorderColor, null, true) != null) 
            box.setTopBorderColor(  style.getAttributeColor(style.ATTRIBUTE_topBorderColor, null, true));
        if (style.getAttributeString(style.ATTRIBUTE_topPadding, null, true) != null) 
            box.setTopPadding( Integer.parseInt( style.getAttributeString(style.ATTRIBUTE_topPadding, null, true) ));

        if (style.getAttributeString(style.ATTRIBUTE_leftBorder, null, true) != null) 
            box.setLeftBorder(  style.getAttributeString(style.ATTRIBUTE_leftBorder, null, true) );
        if (style.getAttributeColor(style.ATTRIBUTE_leftBorderColor, null, true) != null) 
            box.setLeftBorderColor(  style.getAttributeColor(style.ATTRIBUTE_leftBorderColor, null, true));
        if (style.getAttributeString(style.ATTRIBUTE_leftPadding, null, true) != null) 
            box.setLeftPadding( Integer.parseInt( style.getAttributeString(style.ATTRIBUTE_leftPadding, null, true) ));

        if (style.getAttributeString(style.ATTRIBUTE_rightBorder, null, true) != null) 
            box.setRightBorder(  style.getAttributeString(style.ATTRIBUTE_rightBorder, null, true) );
        if (style.getAttributeColor(style.ATTRIBUTE_rightBorderColor, null, true) != null) 
            box.setRightBorderColor(  style.getAttributeColor(style.ATTRIBUTE_rightBorderColor, null, true));
        if (style.getAttributeString(style.ATTRIBUTE_rightPadding, null, true) != null) 
            box.setRightPadding( Integer.parseInt( style.getAttributeString(style.ATTRIBUTE_rightPadding, null, true) ));

        if (style.getAttributeString(style.ATTRIBUTE_bottomBorder, null, true) != null) 
            box.setBottomBorder(  style.getAttributeString(style.ATTRIBUTE_bottomBorder, null, true) );
        if (style.getAttributeColor(style.ATTRIBUTE_bottomBorderColor, null, true) != null) 
            box.setBottomBorderColor(  style.getAttributeColor(style.ATTRIBUTE_bottomBorderColor, null, true));
        if (style.getAttributeString(style.ATTRIBUTE_bottomPadding, null, true) != null) 
            box.setBottomPadding( Integer.parseInt( style.getAttributeString(style.ATTRIBUTE_bottomPadding, null, true) ));


        int ax = x;
        int ay = y;
        int bx = x+width;
        int by = y+heigth;

        Stroke newBoxStroke = null;

        if (box.getLeftBorderColor() != null)
        {
            g2.setColor(box.getLeftBorderColor());
        }
        else
        {
            g2.setColor( g2.getBackground());
        }

        if ((newBoxStroke = ReportElement.getPenStroke(box.getLeftBorder(), 1)) != null)
        {
            g2.setStroke(newBoxStroke);
            g2.drawLine(x, y, x+width, y+heigth);
        }

        //else g.setStroke(oldStroke);
        if (box.getTopBorderColor() != null)
        {
            g2.setColor(box.getTopBorderColor());
        }
        else
        {
            g2.setColor(g2.getBackground());
        }

        if ((newBoxStroke = ReportElement.getPenStroke(box.getTopBorder(), 1)) != null)
        {
            g2.setStroke(newBoxStroke);
            g2.drawLine(ax, ay, bx, ay);
        }

        if (box.getRightBorderColor() != null)
        {
            g2.setColor(box.getRightBorderColor());
        }
        else
        {
            g2.setColor( g2.getBackground());
        }

        if ((newBoxStroke = ReportElement.getPenStroke(box.getRightBorder(), 1)) != null)
        {
            g2.setStroke(newBoxStroke);
            g2.drawLine(bx, ay, bx, by);
        }

        if (box.getBottomBorderColor() != null)
        {
            g2.setColor(box.getBottomBorderColor());
        }
        else
        {
            g2.setColor(g2.getBackground());
        }

        if ((newBoxStroke = ReportElement.getPenStroke(box.getBottomBorder(), 1)) != null)
        {
            g2.setStroke(newBoxStroke);
            g2.drawLine(ax, by, bx, by);
        }

        renderText(g2, "This is a\ntest", getStyle(), new Box(), width, heigth);

    }
    
    public static IReportFont createIreportFont(Style myStyle) {
        
        if (myStyle.getAttribute("style.font") != null)
        {
            return (IReportFont)myStyle.getAttribute("style.font");
        }
        
        
        IReportFont ir = new IReportFont();
        
        if (!myStyle.getAttributes().containsKey("style.font") )
        {
            ir.setBold( myStyle.getAttributeBoolean( myStyle.ATTRIBUTE_isBold, false));
            ir.setFontName( myStyle.getAttributeString( myStyle.ATTRIBUTE_fontName, ir.getFontName()));
            ir.setFontSize( myStyle.getAttributeInteger( myStyle.ATTRIBUTE_fontSize,ir.getFontSize()));
            ir.setItalic( myStyle.getAttributeBoolean( myStyle.ATTRIBUTE_isItalic, false));

            ir.setPdfEmbedded( myStyle.getAttributeBoolean( myStyle.ATTRIBUTE_isPdfEmbedded, false));
            ir.setPdfEncoding( myStyle.getAttributeString( myStyle.ATTRIBUTE_pdfEncoding,  ir.getPdfEncoding()));
            ir.setStrikeTrought( myStyle.getAttributeBoolean( myStyle.ATTRIBUTE_isStrikeThrough, false));

            // TODO = We have to understand what kind of font is this...
            ir.setPDFFontName( myStyle.getAttributeString( myStyle.ATTRIBUTE_pdfFontName, ir.getPDFFontName()));
            ir.setUnderline( myStyle.getAttributeBoolean( myStyle.ATTRIBUTE_isUnderline, false));   
        }
        return ir;
    }    
        
    
     private class TextReportElementLayout {
       private TextLayout layout;
       private float x;
       private float y;


       private TextReportElementLayout(TextLayout layout, float x, float y) {
           this.layout = layout;
           this.x = x;
           this.y = y;
       }


       void drawWithOffset(Graphics2D g2, float yOffset) {
           layout.draw(g2, x, y + yOffset);
       }
   }
     
    /**
     * Render text
     */
   
    public void renderText(Graphics2D g, String str, Style s, Box box, int width, int height)
    {
        
        IReportFont ir = createIreportFont(s);
        Font font = ir.getJavaAWTFont();
        
        double zoom_factor = 1.0;
        int x_shift_origin = 0;
        int y_shift_origin = 0;
        
      //System.out.println(new java.util.Date() + " Print text " + this.getText() + " " +  x_shift_origin +" " +y_shift_origin);
      ArrayList               textLayouts;
      float                   x, y;
      TextReportElementLayout textReportElementLayout;
      AffineTransform         transform;
      
      Point position = new Point(5,5);
      //x_shift_origin -= 10;
      //y_shift_origin -= 10;      
      
      g.setColor( s.getAttributeColor( s.ATTRIBUTE_forecolor, Color.BLACK ) );
      
      // Set font to default font....
      //Font oldFont = g.getFont();
      
          
        // Code for rotation by gt (taked by jasperreports...
        
      
        int gfx_x = position.x + box.getLeftPadding()-x_shift_origin;
        int gfx_y = position.y + box.getTopPadding()-y_shift_origin;
        int gfx_width = width - box.getLeftPadding() - box.getRightPadding();
        int gfx_height = height - box.getTopPadding() - box.getBottomPadding();

        
      Java2DUtil.setClip(g,
 //     0,0, 3000,3000);      
      gfx_x,
      gfx_y,
      gfx_width,
      gfx_height);
       
        double angle = 0;
        double angle_restore = 0;

        
        // Apply the transformation "rotation"
         // - Do nothing when rotate = "none"
         transform = null;
         if(s.getAttributeString( s.ATTRIBUTE_rotation, "None" ).equals(ROTATION_LEFT.getName()))
         {
           transform = new AffineTransform();
           transform.rotate(-Math.PI / 2, gfx_x, gfx_y);
           transform.translate(-gfx_height, -gfx_height);
           gfx_y = position.y-y_shift_origin + height;
           gfx_width = height;
           gfx_height = width;
           Java2DUtil.setTransform(g, transform);
         }
         else if(s.getAttributeString( s.ATTRIBUTE_rotation, "None" ).equals(ROTATION_RIGHT.getName()))
         {
           transform = new AffineTransform();
           transform.rotate(Math.PI / 2, gfx_x, gfx_y);
           transform.translate(0, -gfx_width);
           gfx_x = position.x-x_shift_origin + width;
           gfx_width = height;
           gfx_height = width;
           
           Java2DUtil.setTransform(g, transform);
         }
        
        
        // End code for rotation by gt
                
      // We must center the text..
      
/*
                Rectangle orgClipBounds = g.getClipBounds();
                g.setClip(getZoomedDim(position.x)-x_shift_origin,
            getZoomedDim(position.y)-y_shift_origin,
            getZoomedDim(width),
            getZoomedDim(height));
 */
      
      if (str != null && str.length() > 0)
      {
         int zoomedFieldHeight = gfx_height;
         String allText = Misc.treatNewLineChars(str);
         float formatWidth = (float)gfx_width;
         float verticalOffset = 0f;
         
         
         FontRenderContext fontRenderContext = g.getFontRenderContext();
         java.util.Map fontAttributes = font.getAttributes();
         fontAttributes.put(TextAttribute.SIZE, new Float(ir.getFontSize() ) );
         fontAttributes.put(TextAttribute.FAMILY, ir.getFontName() );
         if (ir.isBold())
         {
            fontAttributes.put(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD);
         }
         if (ir.isItalic())
         {
            fontAttributes.put(TextAttribute.POSTURE, TextAttribute.POSTURE_OBLIQUE);
         }
         if (ir.isUnderline())
         {
            fontAttributes.put(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON);
         }
         if (ir.isStrikeTrought())
         {
            fontAttributes.put(TextAttribute.STRIKETHROUGH, TextAttribute.STRIKETHROUGH_ON);
         }
         
         float lineSpacing = 1f;
         String lineSpacingName = s.getAttributeString( s.ATTRIBUTE_lineSpacing, "Single" );
         if (lineSpacingName.equals("Single")) lineSpacing = 1f;
         else if (lineSpacingName.equals("1_1_2")) lineSpacing = 1.5f;
         else if (lineSpacingName.equals("Double")) lineSpacing = 2f;
         
         AttributedString atext;
         AttributedCharacterIterator paragraph;
         int paragraphStart;
         int paragraphEnd;
         LineBreakMeasurer lineMeasurer;
         TextLayout layout = null;
         
         
         String paragr_text = "";
         boolean isMaxHeightReached = false;
         
         StringTokenizer tkzer = new StringTokenizer(allText, "\n");
         
         float drawPosY = 0;
         float drawPosX = 0;
        
         paragr_text = "";
         isMaxHeightReached = false;
         
         tkzer = new StringTokenizer(allText, "\n");


         textLayouts = new ArrayList();
        
         // Calculate the layouts. (But don't draw yet because we don't know yet
         //   the offset which is needed if we align the text "middle" or "bottom")
         while(tkzer.hasMoreTokens() && !isMaxHeightReached)
         {
            paragr_text = tkzer.nextToken();
            
            atext = new AttributedString(paragr_text, fontAttributes);
            paragraph = atext.getIterator();
            paragraphStart = paragraph.getBeginIndex();
            paragraphEnd = paragraph.getEndIndex();
            lineMeasurer = new LineBreakMeasurer(paragraph, fontRenderContext);
            lineMeasurer.setPosition(paragraphStart);
            
            layout = null;
            while (lineMeasurer.getPosition() < paragraphEnd && !isMaxHeightReached)
            {
               layout = lineMeasurer.nextLayout(formatWidth);
               
               drawPosY += layout.getLeading() + lineSpacing * layout.getAscent();
               
               if (drawPosY + layout.getDescent() <= zoomedFieldHeight+1)
               {
                  if (s.getAttributeString( s.ATTRIBUTE_hAlign, "Left" ).equals("Justify"))
                  {
                     if (layout.isLeftToRight())
                     {
                        drawPosX = 0;
                     }
                     else
                     {
                        drawPosX = formatWidth - layout.getAdvance();
                     }
                     if (lineMeasurer.getPosition() < paragraphEnd)
                     {
                        layout = layout.getJustifiedLayout(formatWidth);
                     }
                  }
                  else if (s.getAttributeString( s.ATTRIBUTE_hAlign, "Left" ).equals("Right"))
                  {
                     if (layout.isLeftToRight())
                     {
                        drawPosX = formatWidth - layout.getAdvance();
                     }
                     else
                     {
                        drawPosX = formatWidth;
                     }
                  }
                  else if (s.getAttributeString( s.ATTRIBUTE_hAlign, "Left" ).equals("Center"))
                  {
                     drawPosX = (formatWidth - layout.getAdvance()) / 2;
                  }
                  else //if (this.getAlign().equals("Left"))
                  {
                     if (layout.isLeftToRight())
                     {
                        drawPosX = 0;
                     }
                     else
                     {
                        drawPosX = formatWidth - layout.getAdvance();
                     }
                  }
                
                  x = drawPosX + gfx_x; //getZoomedDim(position.x)-x_shift_origin;
                  y = drawPosY + gfx_y; //getZoomedDim(position.y)-y_shift_origin;
                  textReportElementLayout = new TextReportElementLayout(layout, x, y);
                  textLayouts.add(textReportElementLayout);


                  drawPosY += layout.getDescent();
               }
               else
               {
                  drawPosY -= layout.getLeading() + lineSpacing * layout.getAscent();
                  isMaxHeightReached = true;
               }
            }
         }


         // Calculate the offset when aligning the text.
         float textHeight = drawPosY;
         if (s.getAttributeString( s.ATTRIBUTE_vAlign, "Top" ).equals("Top"))
         {
             verticalOffset = 0f;
         }
         else if (s.getAttributeString( s.ATTRIBUTE_vAlign, "Top" ).equals("Middle"))
         {
            verticalOffset = ((float)zoomedFieldHeight- textHeight) / 2f;
         }
         else if (s.getAttributeString( s.ATTRIBUTE_vAlign, "Top" ).equals("Bottom"))
         {
            verticalOffset = (float)zoomedFieldHeight - (float)textHeight;
         }

         

         /*
         
         */
      
         // Now draw the text according to the calculated layouts.
         for(Iterator i=textLayouts.iterator(); i.hasNext();)
         {
           textReportElementLayout = (TextReportElementLayout) i.next();
           textReportElementLayout.drawWithOffset(g, verticalOffset);
         }


         if(transform != null)
         {
           // Undo the transformation "rotation"
           Java2DUtil.resetTransform(g);
         }

         
                    /*
                    int txt_width = g.getFontMetrics().stringWidth( this.getText() )/2;
                    int txt_height = g.getFontMetrics().getHeight();
                     
                    StringTokenizer st = new StringTokenizer(getText(),"\n");
                    while( st.hasMoreElements())
                    {
                     String line = st.nextToken();
                      float formatWidth = (float) this.getWidth();
                     g.drawString(line,
                        (float)(getZoomedDim(position.x)-x_shift_origin),
                        getZoomedDim(position.y)-y_shift_origin +  verticalOffset); //, zoomed_width, getZoomedDim(band.getHeight()
                     
                        verticalOffset += g.getFontMetrics().getHeight();
                    }
                     */
         //g.drawLine(0, getZoomedDim(y)+10-vertical_scroll -  txt_height - getZoomedDim(band.getHeight()/2),  700,getZoomedDim(y)+10-vertical_scroll -  txt_height - getZoomedDim(band.getHeight()/2));
         //g.drawLine(0, getZoomedDim(y)+10-vertical_scroll +  txt_height - getZoomedDim(band.getHeight()/2),  700,getZoomedDim(y)+10-vertical_scroll +  txt_height - getZoomedDim(band.getHeight()/2));
         
      }
      
      
      
      //g.setClip(null);
      //g.setClip(orgClipBounds);
         
      Java2DUtil.resetClip(g);

   }
    
    static class Rotation {
       static private ArrayList rotations;
       private String name;
       private int number;


       Rotation(String name, int number) {
           this.name = name;
           this.number = number;
           rotations = new ArrayList();
           rotations.add(this);
       }


       public int getNumber() {
         return number;
       }


       public String getName() {
           return name;
       }


       public String toString() {
           return getName();
       }
   }
    
    static List getRotations() {
       return Rotation.rotations;
   }
}
