/*****************************************************************
BioZen
Copyright (C) 2011 The National Center for Telehealth and
Technology
Eclipse Public License 1.0 (EPL-1.0)
This library is free software; you can redistribute it and/or
modify it under the terms of the Eclipse Public License as
published by the Free Software Foundation, version 1.0 of the
License.
The Eclipse Public License is a reciprocal license, under
Section 3. REQUIREMENTS iv) states that source code for the
Program is available from such Contributor, and informs licensees
how to obtain it in a reasonable manner on or through a medium
customarily used for software exchange.
Post your updates and modifications to our GitHub or email to
t2@tee2.org.
This library is distributed WITHOUT ANY WARRANTY; without
the implied warranty of MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE. See the Eclipse Public License 1.0 (EPL-1.0)
for more details.
You should have received a copy of the Eclipse Public License
along with this library; if not,
visit http://www.opensource.org/licenses/EPL-1.0
*****************************************************************/
package com.t2.compassionMeditation;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import org.achartengine.ChartFactory;
import org.achartengine.chart.PointStyle;
import org.achartengine.model.XYMultipleSeriesDataset;
import org.achartengine.model.XYSeries;
import org.achartengine.renderer.XYMultipleSeriesRenderer;
import org.achartengine.renderer.XYSeriesRenderer;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.ActivityInfo;
import android.graphics.Color;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.preference.PreferenceManager;
import android.text.format.DateFormat;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.LinearLayout.LayoutParams;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;
import au.com.bytecode.opencsv.CSVWriter;
import bz.org.t2health.lib.activity.BaseActivity;
import com.j256.ormlite.dao.Dao;
import com.j256.ormlite.stmt.QueryBuilder;
import com.lowagie.text.Document;
import com.lowagie.text.DocumentException;
import com.lowagie.text.Paragraph;
import com.lowagie.text.pdf.BaseFont;
import com.lowagie.text.pdf.PdfContentByte;
import com.lowagie.text.pdf.PdfWriter;
import com.t2.R;
import com.t2.compassionDB.BioSession;
import com.t2.compassionDB.BioUser;
import com.t2.compassionUtils.MathExtra;
import com.t2.filechooser.FileChooser;
public class ViewSessionsActivity extends BaseActivity
implements OnItemLongClickListener, OnClickListener{
private static final String TAG = "BFDemo";
private static final String mActivityVersion = "1.0";
public static final String EXTRA_TIME_START = "timeStart";
public static final String EXTRA_CALENDAR_FIELD = "calendarField";
public static final String EXTRA_CALENDAR_FIELD_INCREMENT = "calendarFieldIncrement";
public static final String EXTRA_REVERSE_DATA = "reverseData";
private static final String KEY_NAME = "categories_";
private static final int EXPORT_SUCCESS = 1;
private static final int EXPORT_FAILED = 0;
String mResultsFileName;
private ProgressDialog mProgressDialog;
private static ViewSessionsActivity instance;
private DisplayMetrics displayMetrics = new DisplayMetrics();
private View mDeviceChartView;
private static final int DIRECTION_PREVIOUS = -1;
private static final int DIRECTION_NONE = 0;
private static final int DIRECTION_NEXT = 1;
/**
* Currently selected user name (as selected at the start of the session)
*/
private String mCurrentBioUserName;
/**
* BioUser associated with currently selected user name (as selected at the start of the session)
*/
private BioUser mCurrentBioUser = null;
private Dao<BioUser, Integer> mBioUserDao;
private Dao<BioSession, Integer> mBioSessionDao;
/**
* UI ListView for sessions list
*/
private ListView sessionKeysList;
/**
* Ordered list of session keys associated with the currently selected user
*
*/
private ArrayList<SessionsKeyItem> sessionKeyItems = new ArrayList<SessionsKeyItem>();
/**
* Ordered list of BioSessions associated with the currently selected user
*
* note that we keep this list only so we can reference the currently selected session for deletion
*/
private ArrayList<BioSession> sessionItems = new ArrayList<BioSession>();
/**
* Index of currently selected session
* @see sessionItems
*/
private int mSelectedId;
protected Calendar startCal;
protected Calendar endCal;
protected int calendarField; // index of calandar parameter (Defaults to day of month)
protected int calendarFieldIncrement;
private TextView monthNameTextView;
SimpleDateFormat monthNameFormatter;
Spinner mBandOfInterestSpinner;
Spinner mCategorySpinner;
private ArrayList<String> mCurrentCategories;
/**
* Currently selected category
*/
private String mSelectedCategoryName = "";
/**
* Index of currently selected category
*/
private int mSelectedCategory;
private ArrayList<KeyItem> keyItems = new ArrayList<KeyItem>();
protected SharedPreferences sharedPref;
protected int mBandOfInterest = 0;
public class MyOnItemSelectedListener implements OnItemSelectedListener {
public void onItemSelected(AdapterView<?> parent,
View view, int pos, long id) {
SharedPref.putInt(instance, BioZenConstants.PREF_BAND_OF_INTEREST_REVIEW , pos);
mBandOfInterest = pos;
generateChart(DIRECTION_NEXT);
}
public void onNothingSelected(AdapterView parent) {
// Do nothing.
}
}
public class MyCategorySelectedListener implements OnItemSelectedListener {
public void onItemSelected(AdapterView<?> parent,
View view, int pos, long id) {
mSelectedCategoryName = mCurrentCategories.get(pos);
updateListView();
generateChart(DIRECTION_NEXT);
}
public void onNothingSelected(AdapterView parent) {
// Do nothing.
}
}
/**
* Adapter used to provide list of views for the sessionKeyItems list
* @see sessionKeyItems
*/
private SessionsKeyItemAdapter sessionKeysAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRequestedOrientation (ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
instance = this;
sharedPref = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.view_sessions_layout);
monthNameTextView = (TextView) this.findViewById(R.id.monthName);
mProgressDialog = new ProgressDialog(this);
mProgressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
mProgressDialog.setMessage("Exporting data");
mProgressDialog.setCancelable(false);
mCurrentBioUserName = SharedPref.getString(this, "SelectedUser", "");
sessionKeysList = (ListView) this.findViewById(R.id.listViewSessionKeys);
sessionKeysList.setOnItemLongClickListener(this);
Intent intent = this.getIntent();
// calendarField = intent.getIntExtra(EXTRA_CALENDAR_FIELD, Calendar.HOUR_OF_DAY);
calendarField = intent.getIntExtra(EXTRA_CALENDAR_FIELD, Calendar.DAY_OF_MONTH);
// Set up current categories and specifically the selected category
// BEFORE updateListView and generateChart so the specified category(s) can
// be filtered
mCurrentCategories = getCategories("categories");
mCurrentCategories.add("All");
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,android.R.layout.simple_spinner_item, mCurrentCategories);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
mCategorySpinner = (Spinner) findViewById(R.id.spinnerCategorySpinner);
mCategorySpinner.setAdapter(adapter) ;
mCategorySpinner.setOnItemSelectedListener(new MyCategorySelectedListener());
mSelectedCategory = mCurrentCategories.size() - 1; // all
mCategorySpinner.setSelection(mSelectedCategory);
mSelectedCategoryName = mCurrentCategories.get(mSelectedCategory);
setCalendarResolution();
setupCalendars();
updateListView();
this.findViewById(R.id.monthMinusButton).setOnClickListener(this);
this.findViewById(R.id.monthPlusButton).setOnClickListener(this);
this.monthNameTextView.setOnClickListener(this);
// Get the list of band names from the first session (All of the session key names will be the same)
if (sessionItems.size() >= 1) {
BioSession session = sessionItems.get(0);
ArrayAdapter<String> adapter1 = new ArrayAdapter<String>(this,android.R.layout.simple_spinner_item, session.keyItemNames);
adapter1.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
mBandOfInterestSpinner = (Spinner) findViewById(R.id.spinnerBandOfInterest);
mBandOfInterestSpinner.setAdapter(adapter1) ;
mBandOfInterestSpinner.setOnItemSelectedListener(new MyOnItemSelectedListener());
mBandOfInterestSpinner.setSelection(SharedPref.getInt(this, BioZenConstants.PREF_BAND_OF_INTEREST_REVIEW ,
mBandOfInterest));
}
generateChart(DIRECTION_NEXT);
}
private Handler fileExportCompleteHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
// Hide the progress dialog.
hideProgressDialog();
if(msg.what == EXPORT_SUCCESS) {
//onDataExported(exportFileUris);
AlertDialog.Builder alert1 = new AlertDialog.Builder(instance);
alert1.setMessage("Do you want to email the results?");
alert1.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
Uri uri = Uri.fromFile(new File(Environment.getExternalStorageDirectory(), mResultsFileName));
Intent i = new Intent(Intent.ACTION_SEND);
i.setType("text/plain");
i.putExtra(Intent.EXTRA_EMAIL , new String[]{"scott.coleman@tee2.org"});
i.putExtra(Intent.EXTRA_SUBJECT, "session results: " + mResultsFileName);
// i.putExtra(Intent.EXTRA_TEXT , o.getName());
i.putExtra(Intent.EXTRA_STREAM, uri);
try {
startActivity(Intent.createChooser(i, "Send mail..."));
} catch (android.content.ActivityNotFoundException ex) {
Toast.makeText(instance, "There are no email clients installed.", Toast.LENGTH_SHORT).show();
}
}
});
alert1.setNegativeButton("No", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
}
});
alert1.show();
} else if(msg.what == EXPORT_FAILED) {
AlertDialog.Builder alert1 = new AlertDialog.Builder(instance);
alert1.setMessage("Could not create results file");
alert1.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
}
});
alert1.show();
}
}
};
protected void showProgressDialog() {
this.mProgressDialog.show();
}
protected void hideProgressDialog() {
this.mProgressDialog.hide();
}
@Override
protected void onDestroy() {
super.onDestroy();
}
@Override
protected void onStart() {
super.onStart();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
this.getMenuInflater().inflate(R.menu.menu_review, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.itemCreatePdf) {
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
showProgressDialog();
CreatePdf();
}
else {
AlertDialog.Builder alertWarning = new AlertDialog.Builder(this);
alertWarning.setMessage("There is no SD card mounted, please insert SD card and try again");
alertWarning.setPositiveButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
}
});
alertWarning.show();
}
return true;
}
else if (item.getItemId() == R.id.itemCreateCsv) {
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
showProgressDialog();
CreateCSV();
}
else {
AlertDialog.Builder alertWarning = new AlertDialog.Builder(this);
alertWarning.setMessage("There is no SD card mounted, please insert SD card and try again");
alertWarning.setPositiveButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
}
});
alertWarning.show();
}
return true;
}
return true;
}
static class SessionsKeyItem {
public long id;
public String title1;
public String title2;
public int color;
public boolean visible;
public boolean reverseData = false;
public SessionsKeyItem(long id, String title1, String title2) {
this.id = id;
this.title1 = title1;
this.title2 = title2;
}
public SessionsKeyItem(long id, String title1, String title2, int color) {
this.id = id;
this.title1 = title1;
this.title2 = title2;
this.color = color;
}
public HashMap<String,Object> toHashMap() {
HashMap<String,Object> data = new HashMap<String,Object>();
data.put("id", id);
data.put("title1", title1);
data.put("title2", title2);
data.put("color", color);
data.put("visible", visible);
return data;
}
}
class SessionsKeyItemAdapter extends ArrayAdapter<SessionsKeyItem> {
public static final int VIEW_TYPE_ONE_LINE = 1;
public static final int VIEW_TYPE_TWO_LINE = 2;
private LayoutInflater layoutInflater;
private int layoutId;
public SessionsKeyItemAdapter(Context context, int viewType,
List<SessionsKeyItem> objects) {
super(context, viewType, objects);
layoutInflater = (LayoutInflater)context.getSystemService(LAYOUT_INFLATER_SERVICE);
if(viewType == VIEW_TYPE_TWO_LINE) {
layoutId = R.layout.list_item_result_key_2;
} else {
layoutId = R.layout.list_item_result_key_1;
}
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if(convertView == null) {
convertView = layoutInflater.inflate(layoutId, null);
}
final int buttonposition = position;
final SessionsKeyItem item = this.getItem(position);
TextView tv1 = (TextView)convertView.findViewById(R.id.text1);
TextView tv2 = (TextView)convertView.findViewById(R.id.text2);
Button button = (Button) convertView.findViewById(R.id.buttonViewDetails);
View keyBox = convertView.findViewById(R.id.keyBox);
if(tv1 != null) {
tv1.setText(item.title1);
}
if(tv2 != null) {
tv2.setText(item.title2);
}
if(button != null) {
button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
mSelectedId = buttonposition;
showSessionDetails();
}
});
}
if(keyBox != null) {
keyBox.setBackgroundColor(item.color);
}
return convertView;
}
}
@Override
public boolean onItemLongClick(AdapterView<?> arg0, View arg1, int arg2,
long arg3) {
mSelectedId = arg2;
AlertDialog.Builder alert = new AlertDialog.Builder(instance);
alert.setTitle("Choose Activity");
alert.setPositiveButton("View Details", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
showSessionDetails();
}
});
alert.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
}
});
alert.setNeutralButton("Delete Session", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
AlertDialog.Builder alert2 = new AlertDialog.Builder(instance);
alert2.setMessage("Are you sure?");
alert2.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
try {
sessionKeyItems.get(mSelectedId);
mBioSessionDao.delete(sessionItems.get(mSelectedId));
setupCalendars();
updateListView();
generateChart(DIRECTION_NEXT);
} catch (SQLException e) {
Log.e(TAG, "Error deleting user" + e.toString());
}
}
});
alert2.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
}
});
alert2.show();
}
});
alert.show();
return false;
}
/**
* Populates sessionItems and sessionKeyItems with session from the currently selected user
* then uses the adapter to populate the list view with that data
*/
private void updateListView() {
// Retrieve the BuiUser object associated with object mSelectedUserName
try {
mBioUserDao = getHelper().getBioUserDao();
mBioSessionDao = getHelper().getBioSessionDao();
QueryBuilder<BioUser, Integer> builder = mBioUserDao.queryBuilder();
builder.where().eq(BioUser.NAME_FIELD_NAME, mCurrentBioUserName);
builder.limit(1);
List<BioUser> list = mBioUserDao.query(builder.prepare());
if (list.size() >= 1) {
mCurrentBioUser = list.get(0);
}
else {
Log.e(TAG, "General Database error" + mCurrentBioUserName);
}
} catch (SQLException e) {
Log.e(TAG, "Can't find user: " + mCurrentBioUserName , e);
}
// Fill the collections sessionItems, and sessionKeyItems with session data from the current user
sessionItems.clear();
sessionKeyItems.clear();
long startTime = startCal.getTimeInMillis();
long endTime = endCal.getTimeInMillis();
if (mCurrentBioUser != null) {
for (BioSession session: mCurrentBioUser.getSessions()) {
if (session.time >= startTime && session.time <= endTime ) {
if (!mSelectedCategoryName.equalsIgnoreCase("all")) {
// See if this item should be filtered out
if (!session.category.equalsIgnoreCase(mSelectedCategoryName)) continue;
}
SimpleDateFormat sdf = new SimpleDateFormat("MM-dd-yy HH:mm:ss", Locale.US);
String title = sdf.format(new Date(session.time));
try {
String categoryInitial = "(" + session.category.charAt(0) + ")";
title += categoryInitial;
} catch (IndexOutOfBoundsException e) {
}
int color;
if (session.precentComplete >= 100) {
color = Color.GREEN;
}
else {
color = Color.YELLOW;
}
SessionsKeyItem item = new SessionsKeyItem(1,title , "", color);
sessionKeyItems.add(item);
sessionItems.add(session);
}
}
}
sessionKeysAdapter = new SessionsKeyItemAdapter(this, 1, sessionKeyItems);
sessionKeysList.setAdapter(sessionKeysAdapter);
}
private void showSessionDetails() {
AlertDialog.Builder alert2 = new AlertDialog.Builder(instance);
BioSession session = sessionItems.get(mSelectedId);
String sessionDetails = "";
sessionDetails += "Completion: " + session.precentComplete + "%\n";
sessionDetails += "Length: " + secsToHMS(session.secondsCompleted) + "\n";
sessionDetails += "Background Parameter: " + session.keyItemNames[mBandOfInterest] + "\n";
sessionDetails += " Min: " + session.minFilteredValue[mBandOfInterest] + "\n";
sessionDetails += " Max: " + session.maxFilteredValue[mBandOfInterest] + "\n";
sessionDetails += " Avg: " + session.avgFilteredValue[mBandOfInterest] + "\n";
sessionDetails += "Comments: " + session.comments + "\n";
sessionDetails += "Category: " + session.category+ "\n";
sessionDetails += "Log file: " + session.logFileName+ "\n";
alert2.setMessage(sessionDetails);
alert2.show();
}
private String secsToHMS(int time) {
long secs = time;
long hours = secs / 3600;
secs = secs % 3600;
long mins = secs / 60;
secs = secs % 60;
return hours + ":" + mins + ":" + secs;
}
@Override
public void onClick(View v) {
switch(v.getId()) {
case R.id.monthMinusButton:
monthMinusButtonPressed();
break;
case R.id.monthPlusButton:
monthPlusButtonPressed();
break;
case R.id.monthName:
calendarResolutionButtonPressed();
break;
}
}
double getXValueBasedOnResolution(long sessionTime) {
int i;
Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(sessionTime);
i = cal.get(calendarField);
int day = cal.get(Calendar.DAY_OF_MONTH);
int dayofWeek = cal.get(Calendar.DAY_OF_WEEK);
int hour = cal.get(Calendar.HOUR_OF_DAY);
int minute = cal.get(Calendar.MINUTE);
float value = 0;;
switch (calendarField) {
case Calendar.DAY_OF_MONTH:
value = day + (float) hour/24 + (float) minute/60;
break;
case Calendar.HOUR_OF_DAY:
value = (float) hour + (float) minute/60;
break;
default:
break;
}
return (double) value;
}
private void generateChart(int direction) {
XYMultipleSeriesDataset dataSet = new XYMultipleSeriesDataset();
XYMultipleSeriesRenderer renderer = new XYMultipleSeriesRenderer();
// XYSeries minSeries = new XYSeries("minSeries");
XYSeries avgSeries = new XYSeries("avgSeries");
// XYSeries maxSeries = new XYSeries("maxSeries");
LinearLayout layout = (LinearLayout) findViewById(R.id.deviceChart);
if (mDeviceChartView != null) {
layout.removeView(mDeviceChartView);
}
// LineChart chart = new LineChart(dataSet, renderer);
// RangeBarChart chart = new RangeBarChart(dataSet, renderer, BarChart.Type.DEFAULT);
// mDeviceChartView = new OffsetGraphicalChartView(this, chart);
// mDeviceChartView = ChartFactory.getRangeBarChartView(this, dataSet, renderer, BarChart.Type.DEFAULT );
mDeviceChartView = ChartFactory.getLineChartView(this, dataSet, renderer);
layout.addView(mDeviceChartView, new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
long startTime = startCal.getTimeInMillis();
long endTime = endCal.getTimeInMillis();
double maxChartValue = 0;
// Get the data points
for (BioSession session : sessionItems) {
if (session.time >= startTime && session.time <= endTime ) {
double chartYMin = session.minFilteredValue[mBandOfInterest];
double chartYAvg = session.avgFilteredValue[mBandOfInterest];
double chartYMax = session.maxFilteredValue[mBandOfInterest];
if (chartYMin > maxChartValue) maxChartValue = chartYMin;
if (chartYAvg > maxChartValue) maxChartValue = chartYAvg;
if (chartYMax > maxChartValue) maxChartValue = chartYMax;
double chartXValue = getXValueBasedOnResolution(session.time);
// minSeries.add(chartXValue, chartYMin );
avgSeries.add(chartXValue, chartYAvg );
// maxSeries.add(chartXValue, chartYMax );
}
}
// XYSeriesRenderer minSeriesRenderer = new XYSeriesRenderer();
// minSeriesRenderer.setColor(Color.YELLOW);
// minSeriesRenderer.setPointStyle(PointStyle.CIRCLE);
// minSeriesRenderer.setFillPoints(false);
// minSeriesRenderer.setLineWidth(0 * displayMetrics.density);
// renderer.addSeriesRenderer(minSeriesRenderer);
// dataSet.addSeries(minSeries);
//
XYSeriesRenderer avgSeriesRenderer = new XYSeriesRenderer();
avgSeriesRenderer.setColor(Color.RED);
avgSeriesRenderer.setPointStyle(PointStyle.CIRCLE);
avgSeriesRenderer.setFillPoints(true);
avgSeriesRenderer.setLineWidth(2 * displayMetrics.density);
renderer.addSeriesRenderer(avgSeriesRenderer);
dataSet.addSeries(avgSeries);
// XYSeriesRenderer maxSeriesRenderer = new XYSeriesRenderer();
// maxSeriesRenderer.setColor(Color.YELLOW);
// maxSeriesRenderer.setPointStyle(PointStyle.CIRCLE);
// maxSeriesRenderer.setFillPoints(false);
// maxSeriesRenderer.setLineWidth(0 * displayMetrics.density);
// renderer.addSeriesRenderer(maxSeriesRenderer);
// dataSet.addSeries(maxSeries);
// only contine making the chart if there is data in the series.
if(dataSet.getSeriesCount() > 0) {
// Make the renderer for the weekend blocks
Calendar weekendCal = Calendar.getInstance();
weekendCal.setTimeInMillis(System.currentTimeMillis());
int lastDayOfMonth = weekendCal.getActualMaximum(calendarField);
// int lastDayOfMonth = weekendCal.getActualMaximum(Calendar.DAY_OF_MONTH);
renderer.setShowGrid(false);
renderer.setAxesColor(Color.WHITE);
renderer.setLabelsColor(Color.WHITE);
renderer.setAntialiasing(true);
renderer.setShowLegend(false);
renderer.setYLabels(0);
renderer.setXLabels(15);
renderer.setYAxisMax(maxChartValue);
renderer.setYAxisMin(0.00);
renderer.setXAxisMin(1.00);
renderer.setXAxisMax(lastDayOfMonth);
renderer.setZoomEnabled(true, false);
renderer.setPanEnabled(true, false);
renderer.setLegendHeight(10);
renderer.setMargins(new int[] {0,5,10, 0});
}
} // End generateChart
protected void monthMinusButtonPressed() {
startCal.add(calendarFieldIncrement, -1);
endCal.add(calendarFieldIncrement, -1);
this.monthNameTextView.setText(monthNameFormatter.format(startCal.getTime()));
updateListView();
generateChart(DIRECTION_PREVIOUS);
}
protected void monthPlusButtonPressed() {
startCal.add(calendarFieldIncrement, 1);
endCal.add(calendarFieldIncrement, 1);
this.monthNameTextView.setText(monthNameFormatter.format(startCal.getTime()));
updateListView();
generateChart(DIRECTION_NEXT);
}
void setupCalendars() {
long startTime = Calendar.getInstance().getTimeInMillis();
startCal = Calendar.getInstance();
startCal.setTimeInMillis(MathExtra.roundTime(startTime, calendarField));
startCal.set(calendarField, startCal.getMinimum(calendarField));
endCal = Calendar.getInstance();
endCal.setTimeInMillis(startCal.getTimeInMillis());
endCal.add(calendarFieldIncrement, 1);
monthNameTextView.setText(monthNameFormatter.format(startCal.getTime()));
}
void calendarResolutionButtonPressed() {
String[] items = {"Day of Month", "Hour of Day" };
AlertDialog.Builder alert = new AlertDialog.Builder(instance);
alert.setTitle("Set Calandar Resolution");
alert.setItems(items, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
switch (which) {
case 0:
calendarField = Calendar.DAY_OF_MONTH;
break;
case 1:
calendarField = Calendar.HOUR_OF_DAY;
break;
}
setCalendarResolution();
// We must reset the start and end calendars
setupCalendars();
updateListView();
generateChart(DIRECTION_NEXT);
}
});
alert.show();
}
void setCalendarResolution() {
switch (calendarField) {
case Calendar.DAY_OF_MONTH:
calendarFieldIncrement = Calendar.MONTH;
monthNameFormatter = new SimpleDateFormat("MMMM, yyyy");
break;
case Calendar.HOUR_OF_DAY:
monthNameFormatter = new SimpleDateFormat("dd-MMMM-yyyy");
calendarFieldIncrement = Calendar.DATE;
break;
default:
break;
}
}
private ArrayList<String> getCategories(String keySuffix) {
String[] idsStrArr = SharedPref.getValues(
sharedPref,
KEY_NAME+keySuffix,
",",
new String[0]
);
return new ArrayList<String>(Arrays.asList(idsStrArr));
}
public RegressionResult calculateRegression(ArrayList<RegressionItem> inArray)
{
RegressionResult result = new RegressionResult();
int count = inArray.size();
double sumY = 0.0;
double sumX = 0.0;
double sumXY = 0.0;
double sumX2 = 0.0;
double sumY2 = 0.0;
for(int l=0;l<count;l++)
{
RegressionItem item = inArray.get(l);
sumX += item.xValue;
sumY += item.yValue;
sumXY += (item.xValue * item.yValue);
sumX2 += (item.xValue * item.xValue);
sumY2 += (item.yValue * item.yValue);
}
result.slope = ((count * sumXY) - sumX * sumY) / ((count * sumX2) - (sumX * sumX));
result.intercept = ((sumY - (result.slope * sumX))/count);
result.correlation = Math.abs((count * sumXY) - (sumX * sumY)) / (Math.sqrt((count * sumX2 - sumX * sumX) * (count * sumY2 - (sumY * sumY))));
return result;
}
/**
* Create a PDF file based on the contents of the graph
*/
void CreateCSV() {
// Run the export on a separate thread.
new Thread(new Runnable() {
@Override
public void run() {
Date calendar = Calendar.getInstance().getTime();
mResultsFileName = "BioZenResults_" ;
mResultsFileName += (calendar.getYear() + 1900) + "-" + (calendar.getMonth() + 1) + "-" + calendar.getDate() + "_";
mResultsFileName += calendar.getHours()+ "-" + calendar.getMinutes() + "-" + calendar.getSeconds() + ".csv";
File outputFile = new File(android.os.Environment.getExternalStorageDirectory() + java.io.File.separator + mResultsFileName);
try {
CSVWriter writer = new CSVWriter(new FileWriter(outputFile, true));
long startTime = startCal.getTimeInMillis();
long endTime = endCal.getTimeInMillis();
BioSession tmpSession = sessionItems.get(0);
int maxKeys = tmpSession.keyItemNames.length;
float chartYAvg;
SimpleDateFormat simpleDateFormat;
simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
String prettyStartDate = simpleDateFormat.format(startCal.getTime());
String prettyEndDate = simpleDateFormat.format(endCal.getTime());
writer.writeNext(new String[]{
"Start Date",
prettyStartDate,
"End Date",
prettyEndDate
});
ArrayList<String> lineArrayList = new ArrayList<String>();
// Loop through all of the the keys
for (int key = 0; key < maxKeys; key++) {
String keyName = "";
lineArrayList.clear();
// Mke two passes at the session items. The first pass
// get's the times only and the second pass gets the values
// Pass 1
int count = 0;
for (BioSession session : sessionItems) {
keyName = session.keyItemNames[key];
if (count++ == 0) {
lineArrayList.add(keyName + " times");
}
if (session.time >= startTime && session.time <= endTime ) {
// long time = session.time;
// Calendar cal = Calendar.getInstance();
// cal.setTimeInMillis(time);
SimpleDateFormat sdf = new SimpleDateFormat("MM-dd-yy HH:mm:ss", Locale.US);
String timePoint = sdf.format(new Date(session.time));
lineArrayList.add(timePoint);
} // End if (session.time >= startTime && session.time <= endTime )
} // End for (BioSession session : sessionItems)
String[] lineArray = (String[]) lineArrayList.toArray(new String[lineArrayList.size()]);
writer.writeNext(lineArray);
lineArrayList.clear();
// Pass 2
count = 0;
for (BioSession session : sessionItems) {
keyName = session.keyItemNames[key];
if (count++ == 0) {
lineArrayList.add(keyName + " values");
}
if (session.time >= startTime && session.time <= endTime ) {
chartYAvg = session.avgFilteredValue[key];
lineArrayList.add(Float.toString(chartYAvg));
} // End if (session.time >= startTime && session.time <= endTime )
} // End for (BioSession session : sessionItems)
// tokensOnThisLine.toArray(new String[tokensOnThisLine.size()]);
lineArray = (String[]) lineArrayList.toArray(new String[lineArrayList.size()]);
writer.writeNext(lineArray);
}
writer.close();
fileExportCompleteHandler.sendEmptyMessage(EXPORT_SUCCESS);
} catch (IOException e) {
Log.e(TAG, e.toString());
fileExportCompleteHandler.sendEmptyMessage(EXPORT_FAILED);
e.printStackTrace();
}
}
}).start();
}
/**
* Create a PDF file based on the contents of the graph
*/
void CreatePdf() {
// Run the export on a separate thread.
new Thread(new Runnable() {
@Override
public void run() {
Document document = new Document();
try {
Date calendar = Calendar.getInstance().getTime();
mResultsFileName = "BioZenResults_" ;
mResultsFileName += (calendar.getYear() + 1900) + "-" + (calendar.getMonth() + 1) + "-" + calendar.getDate() + "_";
mResultsFileName += calendar.getHours()+ "-" + calendar.getMinutes() + "-" + calendar.getSeconds() + ".pdf";
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(android.os.Environment.getExternalStorageDirectory() + java.io.File.separator + mResultsFileName));
document.open();
PdfContentByte contentByte = writer.getDirectContent();
BaseFont baseFont = BaseFont.createFont(BaseFont.HELVETICA, BaseFont.CP1252, BaseFont.NOT_EMBEDDED);
// Note top of PDF = 900
float chartWidth = 332;
float chartHeight = 45;
float spaceHeight = chartHeight + 30;
int horizontalPos = 180;
float verticalPos = 780;
// Write document header
contentByte.beginText();
contentByte.setFontAndSize(baseFont, 20);
contentByte.showTextAligned(PdfContentByte.ALIGN_CENTER, "T2 BioZen Report", 300, 800, 0);
contentByte.showTextAligned(PdfContentByte.ALIGN_CENTER, "Generated on: " + calendar.toLocaleString(), 300, 770, 0);
contentByte.endText();
contentByte.setLineWidth(1f);
verticalPos -= spaceHeight;
long startTime = startCal.getTimeInMillis();
long endTime = endCal.getTimeInMillis();
float maxChartValue = 0;
float chartYAvg;
BioSession tmpSession = sessionItems.get(0);
int maxKeys = tmpSession.keyItemNames.length;
// Loop through all of the the keys
for (int key = 0; key < maxKeys; key++) {
//Draw a border rect
contentByte.setRGBColorStrokeF(0,0,0);
contentByte.setLineWidth(1f);
contentByte.rectangle(horizontalPos, verticalPos, chartWidth, chartHeight);
contentByte.stroke();
// Write band name
contentByte.beginText();
contentByte.setFontAndSize(baseFont, 12);
BioSession tmpSession1 = sessionItems.get(0);
contentByte.showTextAligned(PdfContentByte.ALIGN_RIGHT, tmpSession1.keyItemNames[key], 170, (verticalPos+(chartHeight/2))-5, 0);
contentByte.endText();
maxChartValue = 0;
// First find the max Y
for (BioSession session : sessionItems) {
if (session.time >= startTime && session.time <= endTime ) {
chartYAvg = session.avgFilteredValue[key];
if (chartYAvg > maxChartValue)
maxChartValue = chartYAvg;
}
}
float lastY = -1;
float xIncrement = 0;
if (sessionItems.size() > 0) {
xIncrement = chartWidth / sessionItems.size();
}
float yIncrement = 0;
if (maxChartValue > 0) {
yIncrement = chartHeight / maxChartValue;
}
float highValue= 0;
int highTime = 0;
float highY = 0;
float highX = 0;
int lowTime = 0;
float lowY = 100;
float lowX = chartWidth;
float lowValue = maxChartValue;
int lCount = 0;
String keyName = "";
ArrayList<RegressionItem> ritems = new ArrayList<RegressionItem>();
// Loop through the session points of this key
String rawYValues = "";
for (BioSession session : sessionItems) {
keyName = session.keyItemNames[key];
if (session.time >= startTime && session.time <= endTime ) {
chartYAvg = session.avgFilteredValue[key];
rawYValues += chartYAvg + ", ";
if(lastY < 0)
lastY = (float) chartYAvg;
contentByte.setLineWidth(3f);
contentByte.setRGBColorStrokeF(255,0,0);
float graphXFrom = horizontalPos + (lCount * xIncrement);
float graphYFrom = verticalPos + (lastY * yIncrement);
float graphXTo = (horizontalPos + ((lCount + 1) * xIncrement));
float graphYTo = verticalPos + (chartYAvg * yIncrement);
// Log.e(TAG, "[" + graphXFrom + ", " + graphYFrom + "] to [" + graphXTo + ", " + graphYTo + "]");
// Draw the actual graph
contentByte.moveTo(graphXFrom, graphYFrom);
contentByte.lineTo(graphXTo, graphYTo);
contentByte.stroke();
//Add regression Item
ritems.add(new RegressionItem(lCount, (chartYAvg*yIncrement)));
if(chartYAvg > highValue)
{
highValue = chartYAvg;
highY = graphYTo;
highX = graphXTo;
highTime = (int) (session.time / 1000);
}
if(chartYAvg < lowValue)
{
lowValue = chartYAvg;
lowY = graphYTo;
lowX = graphXTo;
lowTime = (int) (session.time / 1000);
}
lCount++;
lastY = (float) chartYAvg;
} // End if (session.time >= startTime && session.time <= endTime )
} // End for (BioSession session : sessionItems)
//Draw high low dates
if (highY != 0 && lowY != 0) {
SimpleDateFormat dateFormat = new SimpleDateFormat("MM/dd/yy");
String hDate = dateFormat.format(new Date((long) highTime * 1000L));
String lDate = dateFormat.format(new Date((long) lowTime * 1000L));
contentByte.beginText();
contentByte.setFontAndSize(baseFont, 8);
contentByte.showTextAligned(PdfContentByte.ALIGN_CENTER, hDate, highX, highY, 0);
contentByte.showTextAligned(PdfContentByte.ALIGN_CENTER, lDate, lowX, lowY, 0);
contentByte.endText();
}
//Draw Regression Line
RegressionResult regression = calculateRegression(ritems);
contentByte.saveState();
contentByte.setRGBColorStrokeF(0,0,250);
contentByte.setLineDash(3, 3, 0);
contentByte.moveTo(horizontalPos,verticalPos+(float)regression.intercept);
contentByte.lineTo(horizontalPos+chartWidth,(float) ((verticalPos+regression.intercept)+(float) (regression.slope * (chartWidth/xIncrement))));
contentByte.stroke();
contentByte.restoreState();
contentByte.setRGBColorStrokeF(0,0,0);
// Log.e(TAG, keyName + ": [" + rawYValues + "]");
// Get ready for the next key (and series of database points )
verticalPos -= spaceHeight;
if (verticalPos < 30) {
document.newPage();
verticalPos = 780 - spaceHeight;
}
} // End for (int key = 0; key < maxKeys; key++)
//document.add(new Paragraph("You can also write stuff directly tot he document like this!"));
} catch (DocumentException de) {
System.err.println(de.getMessage());
Log.e(TAG, de.toString());
} catch (IOException ioe) {
System.err.println(ioe.getMessage());
Log.e(TAG, ioe.toString());
} catch (Exception e) {
System.err.println(e.getMessage());
Log.e(TAG, e.toString());
}
// step 5: we close the document
document.close();
fileExportCompleteHandler.sendEmptyMessage(EXPORT_SUCCESS);
}
}).start();
}
public class RegressionItem
{
public double xValue =0;
public double yValue =0;
RegressionItem(double xv, double yv)
{
xValue = xv;
yValue = yv;
}
}
public class RegressionResult
{
public double slope =0;
public double intercept =0;
public double correlation = 0;
}
}