/**
*
* The MIT License
*
* Copyright (c) 2011 the original author or authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.googlecode.charts4j.parameters;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.util.List;
import java.util.Locale;
import com.googlecode.charts4j.Data;
import com.googlecode.charts4j.DataEncoding;
import com.googlecode.charts4j.collect.Lists;
/**
* Class for building data parameter string for the Google Chart API.
*
* @author Julien Chastang (julien.c.chastang at gmail dot com)
*/
final class DataParameter extends AbstractParameter {
/** The Google Chart API data parameter. */
private static final String URL_PARAMETER_KEY = "chd";
/** The decimal formatter. */
private final DecimalFormat decimalFormatter = new DecimalFormat("##0.0", new DecimalFormatSymbols(Locale.US));
/** The Constant EXTENDED_ENCODING_CHARS. */
private static final char[] EXTENDED_ENCODING_CHARS = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i',
'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '.'};
/** The Constant SIMPLE_ENCODING_CHARS. */
private static final char[] SIMPLE_ENCODING_CHARS = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i',
'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
/** The Constant EXTENDED_ENCODING. */
private static final String[] EXTENDED_ENCODING = new String[4096];
/** The Constant SIMPLE_ENCODING. */
private static final String[] SIMPLE_ENCODING = new String[62];
static { // Fill the encoding arrays in static block.
int cnt = 0;
for (int i = 0; i < EXTENDED_ENCODING_CHARS.length; i++) {
for (int j = 0; j < EXTENDED_ENCODING_CHARS.length; j++) {
EXTENDED_ENCODING[cnt++] = EXTENDED_ENCODING_CHARS[i] + "" + EXTENDED_ENCODING_CHARS[j];
}
}
cnt = 0;
for (int i = 0; i < SIMPLE_ENCODING_CHARS.length; i++) {
SIMPLE_ENCODING[cnt++] = SIMPLE_ENCODING_CHARS[i] + "";
}
}
/** The datas. */
private final List<Data> datas = Lists.newLinkedList();
/** The data encoding. */
private DataEncoding dataEncoding = DataEncoding.EXTENDED;
/**
* Instantiates a new data parameter.
*/
DataParameter() {
super();
}
/**
* Adds the data.
*
* @param data
* the data
*/
void addData(final Data data) {
datas.add(data);
}
/**
* Gets the data encoding.
*
* @return the data encoding
*/
DataEncoding getDataEncoding() {
return dataEncoding;
}
/**
* Sets the data encoding.
*
* @param dataEncoding
* the new data encoding
*/
void setDataEncoding(final DataEncoding dataEncoding) {
this.dataEncoding = dataEncoding;
}
/**
* Extended encoding.
*
* @param data
* the data
*
* @return the string
*/
private String extendedEncoding(final double[] data) {
if (data == null || data.length == 0) {
return "";
}
final StringBuilder encodedData = new StringBuilder();
for (double datum : data) { // The following cast to int is safe.
final int index = (int) ((datum >= Data.MIN_VALUE && datum <= Data.MAX_VALUE) ? Math.round((datum / Data.MAX_VALUE) * (EXTENDED_ENCODING.length - 1)) : -1);
encodedData.append((index < 0 || index > (EXTENDED_ENCODING.length - 1)) ? "__" : EXTENDED_ENCODING[index]);
}
return encodedData.toString();
}
/**
* Simple encoding.
*
* @param data
* the data
*
* @return the string
*/
private String simpleEncoding(final double[] data) {
if (data == null || data.length == 0) {
return "";
}
final StringBuilder encodedData = new StringBuilder();
for (double datum : data) { // The following cast to int is safe.
int index = (int) ((datum >= Data.MIN_VALUE && datum <= Data.MAX_VALUE) ? Math.round((datum / Data.MAX_VALUE) * (SIMPLE_ENCODING.length - 1)) : -1);
encodedData.append((index < 0 || index > (SIMPLE_ENCODING.length - 1)) ? "_" : SIMPLE_ENCODING[index]);
}
return encodedData.toString();
}
/**
* Text encoding.
*
* @param data
* the data
*
* @return the string
*/
private String textEncoding(final double[] data) {
if (data == null || data.length == 0) {
return "";
}
final StringBuilder encodedData = new StringBuilder();
int count = 0;
for (double datum : data) {
encodedData.append(count++ > 0 ? "," : "").append(datum >= Data.MIN_VALUE && datum <= Data.MAX_VALUE ? decimalFormatter.format(datum) : "-1");
}
return encodedData.toString();
}
/**
* {@inheritDoc}
*/
@Override
public String getKey() {
return URL_PARAMETER_KEY;
}
/**
* {@inheritDoc}
*/
@Override
public String getValue() {
final StringBuilder sb = new StringBuilder(dataEncoding + "");
final String seperator = dataEncoding.equals(DataEncoding.TEXT) ? "|" : ",";
int cnt = 0;
for (Data data : datas) {
final String dataString = dataEncoding.equals(DataEncoding.SIMPLE) ? simpleEncoding(data.getData()) : dataEncoding.equals(DataEncoding.TEXT) ? textEncoding(data.getData()) : extendedEncoding(data.getData());
sb.append(cnt++ > 0 ? seperator : "").append(dataString);
}
return sb.toString();
}
}