/*
CanZE
Take a closer look at your ZE car
Copyright (C) 2015 - The CanZE Team
http://canze.fisch.lu
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or any
later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package lu.fisch.canze.widgets;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import lu.fisch.awt.Color;
import lu.fisch.awt.Graphics;
import java.lang.reflect.Type;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import lu.fisch.canze.activities.MainActivity;
import lu.fisch.canze.actors.Field;
import lu.fisch.canze.actors.Fields;
import lu.fisch.canze.database.CanzeDataSource;
import lu.fisch.canze.fragments.MainFragment;
import lu.fisch.canze.interfaces.DrawSurfaceInterface;
/**
*
* @author robertfisch
*/
public class Plotter extends Drawable {
protected ArrayList<Double> values = new ArrayList<>();
//protected ArrayList<Double> minValues = new ArrayList<>();
//protected ArrayList<Double> maxValues = new ArrayList<>();
protected ArrayList<String> sids = new ArrayList<>();
public Plotter() {
super();
}
public Plotter(int x, int y, int width, int height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
// test
}
public Plotter(DrawSurfaceInterface drawSurface, int x, int y, int width, int height) {
this.drawSurface=drawSurface;
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
public void setValue(int index, double value)
{
values.set(index, value);
//if(value<minValues.get(index)) minValues.set(index,value);
//if(value>maxValues.get(index)) maxValues.set(index,value);
}
@Override
public void setValue(int value) {
super.setValue(value);
//addValue(value);
}
@Override
public void draw(Graphics g) {
// black border
g.setColor(Color.BLACK);
g.drawRect(x, y, width, height);
// calculate fill height
int fillHeight = (int) ((value-min)/(double)(max-min)*(height-1));
int barWidth = width-Math.max(g.stringWidth(min+""),g.stringWidth(max+""))-10-10;
int spaceAlt = Math.max(g.stringWidth(minAlt+""),g.stringWidth(maxAlt+""))+10+10;
// reduce with if second y-axe is used
if (minAlt==-1 && maxAlt==-1)
{
spaceAlt=0;
}
barWidth-=spaceAlt;
// what is the graph height
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
int graphHeight = height-g.stringHeight(sdf.format(Calendar.getInstance().getTime()))-5;
// draw the ticks
if(minorTicks>0 || majorTicks>0)
{
int toTicks = minorTicks;
if(toTicks==0) toTicks=majorTicks;
double accel = (double)height/((max-min)/(double)toTicks);
double ax,ay,bx,by;
int actual = min;
int sum = 0;
for(double i=height; i>=0; i-=accel)
{
if(minorTicks>0)
{
g.setColor(Color.GRAY);
ax = x+width-barWidth-5;
ay = y+i;
bx = x+width-barWidth;
by = y+i;
g.drawLine((int)ax, (int)ay, (int)bx, (int)by);
}
// draw majorTicks
if(majorTicks!=0 && sum % majorTicks == 0) {
if(majorTicks>0)
{
g.setColor(Color.GRAY_LIGHT);
ax = x+width-barWidth-10;
ay = y+i;
bx = x+width;
by = y+i;
g.drawLine((int)ax, (int)ay, (int)bx, (int)by);
g.setColor(Color.GRAY);
ax = x+width-barWidth-10;
ay = y+i;
bx = x+width-barWidth;
by = y+i;
g.drawLine((int)ax, (int)ay, (int)bx, (int)by);
}
// draw String
if(showLabels)
{
g.setColor(Color.GRAY);
String text = (actual)+"";
double sw = g.stringWidth(text);
bx = x+width-barWidth-16-sw;
by = y+i;
g.drawString(text, (int)(bx), (int)(by+g.stringHeight(text)*(1-i/height)));
}
actual+=majorTicks;
}
sum+=minorTicks;
}
}
// draw the horizontal grid
/*
g.setColor(getIntermediate());
long start = Calendar.getInstance().getTimeInMillis()/1000;
int interval = 60/timeSale;
for(long x=width-(start%interval)-spaceAlt; x>=width-barWidth-spaceAlt; x-=interval)
{
g.drawLine(x, 1, x, graphHeight + 5);
}
*/
/*
MainActivity.debug("Values "+values.size());
MainActivity.debug("Values min "+minValues.size());
MainActivity.debug("Values max "+maxValues.size());/**/
// draw the graph
g.drawRect(x+width-barWidth, y, barWidth, height);
// min & max
/*
if(minValues.size()>0)
{
double w = (double) barWidth/minValues.size();
double h = (double) getHeight()/(getMax()-getMin()+1);
double lastX = Double.NaN;
double lastY = Double.NaN;
g.setColor(Color.GREEN_DARK);
for(int i=0; i<minValues.size(); i++)
{
double mx = w/2+i*w;
double my = getHeight()-(minValues.get(i)-getMin())*h;
if(minValues.get(i)==getMin())
my = getHeight()-(values.get(i)-getMin())*h;
int rayon = 2;
g.fillOval(getX()+getWidth()-barWidth+(int)mx-rayon,getY()+(int)my-rayon,2*rayon+1,2*rayon+1);
if(i>0)
{
g.drawLine(getX()+getWidth()-barWidth+(int)lastX,
getY()+(int)lastY,
getX()+getWidth()-barWidth+(int)mx,
getY()+(int)my);
}
lastX=mx;
lastY=my;
}
}
if(maxValues.size()>0)
{
double w = (double) barWidth/maxValues.size();
double h = (double) getHeight()/(getMax()-getMin()+1);
double lastX = Double.NaN;
double lastY = Double.NaN;
g.setColor(Color.BLUE);
for(int i=0; i<maxValues.size(); i++)
{
double mx = w/2+i*w;
double my = getHeight()-(maxValues.get(i)-getMin())*h;
int rayon = 2;
g.fillOval(getX()+getWidth()-barWidth+(int)mx-rayon,getY()+(int)my-rayon,2*rayon+1,2*rayon+1);
if(i>0)
{
g.drawLine(getX()+getWidth()-barWidth+(int)lastX,
getY()+(int)lastY,
getX()+getWidth()-barWidth+(int)mx,
getY()+(int)my);
}
lastX=mx;
lastY=my;
}
}
*/
// values
//MainActivity.debug("PLOTTER SIZE: "+values.size());
if(values.size()>0)
{
double w = (double) barWidth/values.size();
double h = (double) getHeight()/(getMax()-getMin());
double lastX = Double.NaN;
double lastY = Double.NaN;
g.setColor(Color.RED);
for(int i=0; i<values.size(); i++)
{
//MainActivity.debug("Value "+i+": "+values.get(i));
//MainActivity.debug("Value "+i+": "+values.get(i)+" Max: "+getMax()+" Min: "+getMin()+" height: "+getHeight()+" h: "+h);
double mx = w/2+i*w;
double my = getHeight()-(values.get(i)-getMin())*h;
int rayon = 2;
g.fillOval(getX()+getWidth()-barWidth+(int)mx-rayon,getY()+(int)my-rayon,2*rayon+1,2*rayon+1);
if(i>0)
{
g.drawLine(getX()+getWidth()-barWidth+(int)lastX,
getY()+(int)lastY,
getX()+getWidth()-barWidth+(int)mx,
getY()+(int)my);
}
lastX=mx;
lastY=my;
}
}
// draw the title
if(title!=null && !title.equals(""))
{
g.setColor(Color.BLUE);
g.setTextSize(20);
int th = g.stringHeight(title);
int tx = getX()+width-barWidth+8;
int ty = getY()+th+4;
g.drawString(title,tx,ty);
}
}
@Override
public void onFieldUpdateEvent(Field field) {
// only take data fofr valid cars
//MainActivity.debug("Plotter: "+field.getSID()+" --> "+field.getValue());
//MainActivity.debug("Car = "+MainActivity.car+" / "+field.getCar()+" / "+field.isCar(MainActivity.car));
if(field.isCar(MainActivity.car)) {
String sid = field.getSID();
//MainActivity.debug("!! Plotter: "+sid+" --> "+field.getValue());
int index = sids.indexOf(sid);
if (index == -1) {
sids.add(sid);
values.add(field.getValue());
//minValues.add(CanzeDataSource.getInstance().getMin(sid));
//maxValues.add(CanzeDataSource.getInstance().getMax(sid));
} else setValue(index, field.getValue());
// only repaint if the last field has been updated
//if(index==sids.size()-1)
super.onFieldUpdateEvent(field);
}
}
/* --------------------------------
* Serialization
\ ------------------------------ */
@Override
public void loadValuesFromDatabase() {
super.loadValuesFromDatabase();
values.clear();
//maxValues.clear();
//minValues.clear();
for(int s=0; s<sids.size(); s++) {
String sid = sids.get(s);
values.add(CanzeDataSource.getInstance().getLast(sid));
//maxValues.add(CanzeDataSource.getInstance().getMax(sid));
//minValues.add(CanzeDataSource.getInstance().getMin(sid));
}
}
@Override
public String dataToJson() {
Gson gson = new Gson();
ArrayList<ArrayList<Double>> data = new ArrayList<>();
data.add((ArrayList<Double>) values.clone());
//data.add((ArrayList<Double>) minValues.clone());
//data.add((ArrayList<Double>) maxValues.clone());
return gson.toJson(data);
}
@Override
public void dataFromJson(String json) {
Gson gson = new Gson();
Type fooType = new TypeToken<ArrayList<ArrayList<Double>>>() {}.getType();
ArrayList<ArrayList<Double>> data = gson.fromJson(json, fooType);
values = data.get(0);
//minValues=data.get(1);
//maxValues=data.get(2);
}
public void setValues(ArrayList<Double> values) {
this.values = values;
}
}