class ColumnValuesFrequency implements AttributeColumnsManipulator {

    public static final int MAX_PIE_CHART_CATEGORIES = 100;

    @Override
    public void execute(Table table, Column column) {
    }

    @Override
    public String getName() {
        return NbBundle.getMessage(ColumnValuesFrequency.class, "ColumnValuesFrequency.name");
    }

    @Override
    public String getDescription() {
        return NbBundle.getMessage(ColumnValuesFrequency.class, "ColumnValuesFrequency.description");
    }

    @Override
    public boolean canManipulateColumn(Table table, Column column) {
        AttributeColumnsController ac = Lookup.getDefault().lookup(AttributeColumnsController.class);
        return ac.getTableRowsCount(table) > 0;//Make sure that there is at least 1 row
    }

    @Override
    public AttributeColumnsManipulatorUI getUI(Table table, Column column) {
        return new ColumnValuesFrequencyUI();
    }

    @Override
    public int getType() {
        return 100;
    }

    @Override
    public int getPosition() {
        return 0;
    }

    @Override
    public Image getIcon() {
        return ImageUtilities.loadImage("DataLaboratoryPlugin/frequency-list.png", false);
    }

    public String getReportHTML(Table table, Column column, Map<Object, Integer> valuesFrequencies, JFreeChart pieChart,
                                Dimension dimension) {
        AttributeColumnsController ac = Lookup.getDefault().lookup(AttributeColumnsController.class);
        int totalValuesCount = ac.getTableRowsCount(table);
        ArrayList<Object> values = new ArrayList<>(valuesFrequencies.keySet());

        //Try to sort the values when they are comparable. (All objects of the set will have the same type) and not null:
        if (!values.isEmpty() && values.get(0) instanceof Comparable) {
            Collections.sort(values, new Comparator<Object>() {

                @Override
                public int compare(Object o1, Object o2) {
                    //Check for null objects because some comparables can't handle them (like Float...)
                    if (o1 == null) {
                        if (o2 == null) {
                            return 0;
                        } else {
                            return -1;//Null lesser than anything
                        }
                    } else if (o2 == null) {
                        if (o1 == null) {
                            return 0;
                        } else {
                            return 1;//Anything greater than null
                        }
                    } else {
                        return ((Comparable) o1).compareTo(o2);
                    }
                }
            });
        }

        final StringBuilder sb = new StringBuilder();

        sb.append("<html>");
        sb.append(NbBundle.getMessage(ColumnValuesFrequency.class, "ColumnValuesFrequency.report.header",
            HTMLEscape.stringToHTMLString(column.getTitle())));
        sb.append("<hr>");
        sb.append("<ol>");

        for (Object value : values) {
            writeValue(sb, value, valuesFrequencies, totalValuesCount);
        }
        sb.append("</ol>");
        sb.append("<hr>");

        if (!values.isEmpty() && values.size() <=
            MAX_PIE_CHART_CATEGORIES) {//Do not show pie chart if there are more than 100 different values
            try {
                if (pieChart != null) {
                    writePieChart(sb, pieChart, dimension);
                }
            } catch (IOException ex) {
                Exceptions.printStackTrace(ex);
            }
        } else {
            sb.append(
                NbBundle.getMessage(ColumnValuesFrequency.class, "ColumnValuesFrequency.report.piechart.not-shown"));
        }

        sb.append("</html>");
        return sb.toString();
    }

    private void writeValue(final StringBuilder sb, final Object value, final Map<Object, Integer> valuesFrequencies,
                            final float totalValuesCount) {
        int frequency = valuesFrequencies.get(value);

        sb.append("<li>");
        sb.append("<b>");
        if (value != null) {
            sb.append(HTMLEscape.stringToHTMLString(AttributeUtils.print(value)));
        } else {
            sb.append("null");
        }
        sb.append("</b> - ");
        sb.append(frequency);
        sb.append(" (");
        sb.append(frequency / totalValuesCount * 100);
        sb.append("%");
        sb.append(" )");
        sb.append("</li>");
    }

    public Map<Object, Integer> buildValuesFrequencies(Table table, Column column) {
        AttributeColumnsController ac = Lookup.getDefault().lookup(AttributeColumnsController.class);
        return ac.calculateColumnValuesFrequencies(table, column);
    }

    public JFreeChart buildPieChart(final Map<Object, Integer> valuesFrequencies) {
        final ArrayList<Object> values = new ArrayList<>(valuesFrequencies.keySet());
        DefaultPieDataset pieDataset = new DefaultPieDataset();

        for (Object value : values) {
            pieDataset.setValue(value != null ? "'" + AttributeUtils.print(value) + "'" : "null",
                valuesFrequencies.get(value));
        }

        JFreeChart chart = ChartFactory.createPieChart(
            NbBundle.getMessage(ColumnValuesFrequency.class, "ColumnValuesFrequency.report.piechart.title"), pieDataset,
            false, true, false);
        return chart;
    }

    private void writePieChart(final StringBuilder sb, JFreeChart chart, Dimension dimension) throws IOException {<FILL_FUNCTION_BODY>}
}


        TempDir tempDir = TempDirUtils.createTempDir();
        String fileName = "frequencies-pie-chart.png";
        File file = tempDir.createFile(fileName);
        String imageFile = "<center><img src=\"file:" + file.getAbsolutePath() + "\"</img></center>";
        ChartUtilities.saveChartAsPNG(file, chart, dimension != null ? dimension.width : 1000,
            dimension != null ? dimension.height : 1000);

        sb.append(imageFile);
    
<no_super_class>