org.zebrafish.util.ChartHelper.java Source code

Java tutorial

Introduction

Here is the source code for org.zebrafish.util.ChartHelper.java

Source

/*
 * $Id$
 *
 * @(#)ChartHelper.java 2008/5/7
 *  
 * Copyright (c) 2008 Joseph S. Kuo, Max Chu
 * All Rights Reserved.
 *
 * --LICENSE NOTICE--
 * This file is part of Zebrafish, which is a Java wrapper for Google
 * Chart API.
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 3 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library.  If not, see 
 * <http://www.gnu.org/licenses/>.
 * --LICENSE NOTICE--
 */

package org.zebrafish.util;

import java.text.DecimalFormat;
import java.util.regex.Pattern;

import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.Validate;
import org.apache.commons.lang.math.NumberUtils;
import org.zebrafish.chart.GoogleChart;
import org.zebrafish.feature.DataList;
import org.zebrafish.feature.EncodingType;
import org.zebrafish.field.Color;
import org.zebrafish.field.Data;

public class ChartHelper {
    private static final String SIMPLE_ENCODING = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

    private static final String EXTENDED_ENCODING = SIMPLE_ENCODING + "-.";

    private static final int SIMPLE_ENCODING_LENGTH = SIMPLE_ENCODING.length();

    private static final int EXTENDED_ENCODING_LENGTH = EXTENDED_ENCODING.length();

    private static final Pattern PATTERN_COLOR = Pattern.compile("^[0-9A-Fa-f]{6}$|^[0-9A-Fa-f]{8}$");

    private static DecimalFormat TEXT_ENCODING_FOMART = new DecimalFormat("0.#");

    /**
     * Checks if the given width and height are legal values. See 
     * {@link GoogleChart} for more information. 
     * 
     * @param width the width
     * @param height the height
     * @return ture if the given width and height are legal
     */
    public static boolean checkSize(int width, int height) {
        return width > 0 && width <= 1000 && height > 0 && height <= 1000 && width * height <= 300000;
    }

    /**
     * Checks if the given width and height are legal values for Maps.
     * 
     * @param width the width
     * @param height the height
     * @return true if the given width and height are legal
     */
    public static boolean checkMapSize(int width, int height) {
        return width > 0 && width <= 440 && height > 0 && height <= 220;
    }

    /**
     * Checks if the given <i>RGB</i> is a legal color value or not. See 
     * {@link Color} for more information.
     * 
     * @param rgb a 6-letter or 8-letter string of hexadecimal value
     * @return true if the given <i>RGB</i> value is legal
     */
    public static boolean isColor(String rgb) {
        return StringUtils.isNotBlank(rgb) && PATTERN_COLOR.matcher(rgb).matches();
    }

    /**
     * Encodes data.
     * 
     * @param dataList the data list needed to be encoded
     * @return an encoded string
     */
    public static String encodeData(DataList dataList) {
        StringBuffer sb = new StringBuffer(128);
        StringBuffer sbTmp = new StringBuffer(32);
        EncodingType type = dataList.getType();

        for (Data data : dataList) {
            float[] content = data.getContent();
            if (content == null || content.length == 0) {
                sb.append(type.getMissingValue()).append(type.getSymbol());
                continue;
            }

            if (dataList.isAutoScale()) {
                content = autoDataScale(content, 0, type.getMax());
            }

            sbTmp.setLength(0);
            try {
                for (float f : content) {
                    switch (type) {
                    case TEXT:
                        sbTmp.append(TEXT_ENCODING_FOMART.format(f)).append(",");
                        break;
                    case SIMPLE:
                        sbTmp.append(SIMPLE_ENCODING.charAt(Math.round(f) % SIMPLE_ENCODING_LENGTH));
                        break;
                    case EXTENDED:
                        int k = Math.round(f);
                        sbTmp.append(EXTENDED_ENCODING.charAt(k / EXTENDED_ENCODING_LENGTH));
                        sbTmp.append(EXTENDED_ENCODING.charAt(k % EXTENDED_ENCODING_LENGTH));
                    }
                }

                if (type == EncodingType.TEXT) {
                    sbTmp.deleteCharAt(sbTmp.length() - 1);
                }
                sb.append(sbTmp).append(type.getSymbol());
            } catch (Exception e) {
                sb.append(type.getMissingValue()).append(type.getSymbol());
            }
        }

        return sb.toString();
    }

    /**
     * Scales the given array automatically.
     * 
     * @param array the array needed to be scaled
     * @param start the start of the range
     * @param end the end of the range
     * @return an scaled array
     */
    public static float[] autoDataScale(float[] array, int start, int end) {
        if (ArrayUtils.isEmpty(array)) {
            return array;
        }

        float max = NumberUtils.max(array);
        float min = NumberUtils.min(array);
        int offset = 0;
        if (max > end || min < start) {
            // Sets an offset
            if (min < start) {
                offset = Math.abs((int) Math.floor(min));
            }

            float scale = (float) ((end - start) / (Math.ceil(max) - (min >= start ? start : Math.floor(min))));
            float[] newArray = new float[array.length];
            for (int i = 0; i < array.length; i++) {
                newArray[i] = (array[i] + offset) * (scale >= 1 ? 1 : scale);
            }
            return newArray;
        }
        return array;
    }

    /**
     * Converts the given comma-separated <code>content</code> to a float array.
     * 
     * @param content a comma-separated <code>String</code>  
     * @return a float array
     */
    public static float[] convertStringToFloatArray(String content) {
        String[] contents = content.split(",");
        if (!ArrayUtils.isEmpty(contents)) {
            // creates a float array with the same length, and tries to parse all elements
            float[] array = new float[contents.length];
            int legalValueNumber = 0;
            for (int i = 0; i < contents.length; i++) {
                try {
                    array[legalValueNumber] = Float.parseFloat(contents[i]);
                    legalValueNumber++;
                } catch (Exception e) {
                }
            }

            // if we can't parse all of them, then makes a new array with the correct size 
            if (legalValueNumber < array.length && legalValueNumber > 0) {
                float[] newArray = new float[legalValueNumber];
                System.arraycopy(array, 0, newArray, 0, legalValueNumber);
                return newArray;
            }
            return array;
        }
        return null;
    }

    /**
     * Returns one legal letter specified in the given pattern. If the given 
     * letter is not null, one character and contained in the given pattern then 
     * it returns the letter. Otherwise it returns a empty string if allowEmpty
     * is true or returns the first character of the given pattern instead if
     * allowEmpty is false.
     * 
     * @param pattern the pattern of all legal values
     * @param letter the letter which needs to be checked
     * @param allowEmpty allows to return a empty string if true or return the
     *       first character of the given pattern if false when not found
     * @return one legal letter specified in the given pattern
     * @throws IllegalArgumentException if the given pattern is empty
     */
    public static String getLegalSingleLetter(String pattern, String letter, boolean allowEmpty) {
        Validate.notEmpty(pattern, "The given pattern must not be empty.");

        if (StringUtils.isEmpty(letter) || letter.length() != 1) {
            letter = " ";
        }

        return pattern.contains(letter) ? letter
                : allowEmpty ? StringUtils.EMPTY : StringUtils.EMPTY + pattern.charAt(0);
    }
}