/*
 * NCSA Data To Knowledge (D2K) Project
 * Automated Learning Group
 * National Center for Supercomputing Applications
 * University of Illinois at Urbana-Champaign
 * 605 E. Springfield, Champaign, IL 61820
 *
 * d2k@ncsa.uiuc.edu
 *
 * Copyright 2003, Board of Trustees of the University of Illinois,
 * All Rights Reserved
 *
 * NCSA Data To Knowledge (D2K) software, source code, binary code, and Java-byte 
 * code including D2K modules and D2K itineraries (hereafter, Software) is 
 * copyrighted by the Board of Trustees of the University of Illinois (UI),
 * and ownership remains with the UI.
 *
 * Prior to receiving this Software Source Code, You must have agreed to a
 * non-exclusive, non-transferable, restricted License of Software with UI for
 * limited Research Use and/or Internal Business Use. The terms of that License
 * control the use of this Software Source Code. For the sake of convenience, 
 * certain provisions of that License are stated here. However, in the event
 * of any real or perceived differences between the terms of the License and the
 * statements made herein, the License controls.  
 *
 * You may not distribute the Software including the Binary Code and this Source
 * Code to third parties.
 *
 * You may make Derivative Works. You are encouraged to provide information to 
 * UI regarding Derivative Works and your experience with Software. However, if
 * You make any Derivative Work based on or derived from the Software, then You
 * will: (1) clearly notify users that such Derivative Work is a modified version
 * and uses or is derived from the original NCSA Data To Knowledge (D2K)
 * developed at UI, and include specific language in that notice as provided for
 * in the License, and (2) acknowledge via citation and provide UI with a copy of
 * any report or publication using the Software or Derivative Work.
 *
 * If You wish to make Commercial Use of the Software or Derivative Works, then
 * You should contact the UI, c/o NCSA, to negotiate an appropriate license for
 * such Commercial Use. Commercial Use includes sale, lease, license,
 * distribution or otherwise making the Software or Derivative Works available to
 * third parties, which includes, but is not limited to, integration of all or
 * part of the Software or Derivative Work into a product for sale or license by
 * or on behalf of You to third parties.
 *
 * UI MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY
 * PURPOSE. IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY. THE UI
 * SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY THE USERS OF THIS SOFTWARE.
 *
 * By using or copying this Software, You agree to abide by the copyright law
 * and all other applicable laws of the U.S. including, but not limited to,
 * export control laws, and the terms of the License. UI shall have the right
 * to terminate its license with You immediately upon Your breach of, or
 * non-compliance with, any of its terms. You may be held legally responsible
 * for any copyright infringement that is caused or encouraged by Your failure
 * to abide by the terms of the License.
 */

package ncsa.d2k.modules.core.vis.widgets;

import ncsa.d2k.modules.core.datatype.table.*;
import ncsa.d2k.modules.core.datatype.table.basic.*;

import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.text.*;
import javax.swing.*;

/**
   A simple pie chart.  The data must be in a VerticalTable.  The x value
   of the DataSet must contain the index of the label column, and the y
   value must contain the index of the numerical column.
*/
public class PieChart extends Chart {

   private int max_legend_rows = 5;

   /**
      Create a new PieChart that normalizes the data.  Each item
      will be represented as a fraction of 1.0
   */
   public PieChart(Table vt, DataSet ds, GraphSettings gs, boolean normalize,
      int maxLegendRows) {
      this(vt, ds, gs, maxLegendRows);

      DoubleColumn dc = new DoubleColumn(bins);
      ObjectColumn oc = new ObjectColumn(bins);
      Column []cols = new Column[2];
      cols[0] = oc;
      cols[1] = dc;
      for (int i = 0; i < bins; i++) {
         oc.setObject(table.getObject(i, set.x), i);
      }

      double total = 0;
      for(int i = 0; i < bins; i++)
         total += table.getDouble(i, set.y);

      for(int i = 0; i < bins; i++) {
         double val = table.getDouble(i, set.y);
         dc.setDouble((double)(val/total), i);
      }

      table = (Table)DefaultTableFactory.getInstance().createTable(cols);
   }

   /**
      Create a new PieChart with the data already normalized.
   */
   public PieChart(Table vt, DataSet ds, GraphSettings gs) {
      super(vt, ds, gs);

      setBackground(Color.white);

      title = settings.title;
   }

   /**
      Create a new PieChart with the data already normalized.
   */
   public PieChart(Table vt, DataSet ds, GraphSettings gs, int maxLegendRows) {
      super(vt, ds, gs);

      if (maxLegendRows > 0)
         max_legend_rows = maxLegendRows;

      setBackground(Color.white);

      title = settings.title;
   }

   /**
      Paint the charts and the legend.
   */
   public void paintComponent(Graphics g) {
      super.paintComponent(g);
      Graphics2D g2 = (Graphics2D) g;
      g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
         RenderingHints.VALUE_ANTIALIAS_ON);

      font = g2.getFont();
      metrics = getFontMetrics(font);
      fontheight = metrics.getHeight();
      fontascent = metrics.getAscent();

      graphwidth = getWidth();
      graphheight = getHeight();

      // Determine offsets
      initOffsets();

      resize();

      if(settings.displaylegend)
         drawLegend(g2);
      if (settings.displaytitle)
         drawTitle(g2);
      drawDataSet(g2, set);
   }

   public void initOffsets() {
      // Offsets of axis
      leftoffset = largespace;
      rightoffset = 65;
      //bottomoffset = 65;
      //topoffset = 65;

      // Offset of legend
      if (!settings.displaylegend) {
         legendheight = 0;
      }
      else {
         String[] names;
         if (table.getNumRows() < max_legend_rows)
            names = new String[table.getNumRows()];
         else
            names = new String[max_legend_rows];

         names[0] = table.getString(0, 0);
         legendwidth = metrics.stringWidth(names[0]);
         for (int index=1; index < table.getNumRows() && index < max_legend_rows; index++) {
            String s = table.getString(index, 0);
            int stringwidth = metrics.stringWidth(s);
            if (stringwidth > legendwidth)
               legendwidth = stringwidth;
         }

         legendwidth += 4*smallspace+samplecolorsize;

         if (table.getNumRows() <= max_legend_rows)
            legendheight = ((names.length)*fontheight)+
               (fontheight-samplecolorsize);
         else
            legendheight = ((names.length + 1)*fontheight)+
               (fontheight-samplecolorsize);

         legendleftoffset = leftoffset;
         legendtopoffset = legendheight+2*smallspace;
      }
    }

   public void resize() {
      leftoffset = graphwidth*(.125);
      topoffset = fontheight+4;
      graphwidth = (.75)*graphwidth;
      graphheight = (.75)*graphheight;
      if(settings.displaylegend) {
         if(graphheight > (getHeight()-legendtopoffset-topoffset-smallspace))
            graphheight = getHeight()-legendtopoffset - topoffset - smallspace;
      }
   }

   /**
      Draw the chart.
   */
   public void drawDataSet(Graphics2D g2, DataSet set) {

         // draw chart
      int angle = 0;
      for (int count = 0; count < bins; count++) {

         double ratio = table.getDouble(count, 1);

         if (count == bins - 1)
            drawArc(g2, leftoffset, topoffset+2,
               graphwidth, graphheight, angle,
               (int)(360 - angle), getColor(count));
         else
            drawArc(g2, leftoffset, topoffset+2,
               graphwidth, graphheight, angle,
               (int)(360*ratio), getColor(count));

         angle += (int)(360*ratio);
      }
   }

   /**
      Draw a slice of the pie chart.
   */
   public void drawArc(Graphics2D g2, double x, double y, double w, double h,
      double start, double end, Color color) {
         g2.setColor(color);
         g2.fill(new Arc2D.Double(x, y, w, h, start, end, Arc2D.PIE));
   }

   /**
      Draw the title of the pie chart.
   */
   public void drawTitle(Graphics2D g2) {
      int stringwidth = metrics.stringWidth(title);
      double x = (getWidth()-stringwidth)/2;
      double y = (topoffset)/2;

      g2.drawString(title, (int) x, (int) y);
   }

   /**
      Draw the legend for the chart.
      TO DO: Put multiple columns in the legend, right now the items are
      listed in one column
   */
   public void drawLegend(Graphics2D g2) {
      Color previouscolor = g2.getColor();

      double x = legendleftoffset;
      double y = getHeight()-legendtopoffset;

      g2.setColor(Color.black);

      g2.draw(new Rectangle.Double(x, y, legendwidth, legendheight));

      x += smallspace;
      y += fontheight-samplecolorsize;

      for (int index=0; index < table.getNumRows() && index < max_legend_rows; index++) {
         g2.setColor(getColor(index));
         g2.fill(new Rectangle.Double(x, y, samplecolorsize, samplecolorsize));
         y += fontheight;
      }

      g2.setColor(previouscolor);

      x = legendleftoffset;
      y = getHeight()-legendtopoffset;

      x += 2*smallspace+samplecolorsize;
      y += fontheight;

      int index = 0;
      for (index=0; index < table.getNumRows() && index < max_legend_rows; index++) {
         g2.drawString(table.getString(index, 0), (int) x, (int) y);
         y += fontheight;
      }

      if (index < table.getNumRows()) {
         g2.drawString("...", (int)x, (int)y);
      }

   }
}