package de.tum.in.tumcampusapp.activities;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.widget.SwipeRefreshLayout;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.Spinner;
import android.widget.TextView;
import java.text.NumberFormat;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import de.tum.in.tumcampusapp.R;
import de.tum.in.tumcampusapp.activities.generic.ActivityForAccessingTumOnline;
import de.tum.in.tumcampusapp.adapters.ExamListAdapter;
import de.tum.in.tumcampusapp.auxiliary.NetUtils;
import de.tum.in.tumcampusapp.auxiliary.Utils;
import de.tum.in.tumcampusapp.models.tumo.Exam;
import de.tum.in.tumcampusapp.models.tumo.ExamList;
import de.tum.in.tumcampusapp.tumonline.TUMOnlineConst;
/**
* Activity to show the user's grades/exams passed.
*/
public class GradesActivity extends ActivityForAccessingTumOnline<ExamList> {
private static final String[] GRADES = {"1,0", "1,3", "1,4", "1,7", "2,0", "2,3", "2,4", "2,7", "3,0", "3,3", "3,4", "3,7", "4,0", "4,3", "4,4", "4,7", "5,0"};
private final NumberFormat format = NumberFormat.getInstance(Locale.FRANCE);
private static int lastChoice;
private TextView averageTx;
private double averageGrade;
private String columnChartContent;
private MenuItem columnMenuItem;
private MenuItem pieMenuItem;
private ExamList examList;
private ListView lvGrades;
private String pieChartContent;
private SwipeRefreshLayout mSwipeRefreshLayout;
private Spinner spFilter;
private boolean isFetched;
public GradesActivity() {
super(TUMOnlineConst.EXAMS, R.layout.activity_grades);
}
/**
* Builds HTML string showing a column chart
*
* @param filteredExamList List of exams
* @return content string
*/
String buildColumnChartContentString(List<Exam> filteredExamList) {
Map<String, Integer> gradeDistribution = calculateGradeDistribution(filteredExamList);
StringBuilder datas = new StringBuilder(1024);
// Build data string
for (int i = 0; i < GRADES.length; i++) {
datas.append("['")
.append(GRADES[i]).append("', ")
.append(gradeDistribution.get(GRADES[i]))
.append(']');
if (i != GRADES.length - 1) {
datas.append(',');
}
}
// Build content String
return "<html>"
+ " <head>"
+ " <script type=\"text/javascript\" src=\"https://www.google.com/jsapi\"></script>"
+ " <script type=\"text/javascript\">"
+ " google.load(\"visualization\", \"1\", {packages:[\"corechart\"]});"
+ " google.setOnLoadCallback(drawChart);"
+ " function drawChart() {"
+ " var data = google.visualization.arrayToDataTable(["
+ " ['Grade', 'Quantity'],"
+ datas
+ " ]);"
+ " var options = {"
+ " title: 'Grades of "
+ filteredExamList.get(0).getProgramID()
+ "',"
// + " legend: {position: 'none'}"
+ " };"
+ " var chart = new google.visualization.ColumnChart(document.getElementById('chart_div'));"
+ " chart.draw(data, options);"
+ " }"
+ " </script>"
+ " </head>"
+ " <body>"
+ " <div id=\"chart_div\" style=\"width: 1000px; height: 500px;\"></div>"
+ " </body>" + "</html>";
}
/**
* Builds HTML string showing a pie chart
*
* @param filteredExamList List of exams
* @return content string
*/
String buildPieChartContentString(List<Exam> filteredExamList) {
Map<String, Integer> gradeDistrubution = calculateGradeDistribution(filteredExamList);
StringBuilder datas = new StringBuilder(1024);
// build data String
for (int i = 0; i < GRADES.length; i++) {
datas.append("['")
.append(GRADES[i]).append("', ")
.append(gradeDistrubution.get(GRADES[i]))
.append(']');
if (i != GRADES.length - 1) {
datas.append(',');
}
}
// build content String
return "<html>"
+ " <head>"
+ " <script type=\"text/javascript\" src=\"https://www.google.com/jsapi\"></script>"
+ " <script type=\"text/javascript\">"
+ " google.load(\"visualization\", \"1\", {packages:[\"corechart\"]});"
+ " google.setOnLoadCallback(drawChart);"
+ " function drawChart() {"
+ " var data = google.visualization.arrayToDataTable(["
+ " ['Grade', 'Quantity'],"
+ datas
+ " ]);"
+ " var options = {"
+ " title: 'Grades of "
+ filteredExamList.get(0).
getProgramID()
+ "'"
+ " };"
+ " var chart = new google.visualization.PieChart(document.getElementById('chart_div'));"
+ " chart.draw(data, options);"
+ " }"
+ " </script>"
+ " </head>"
+ " <body>"
+ " <div id=\"chart_div\" style=\"width: 1000px; height: 500px;\"></div>"
+ " </body>" + "</html>";
}
/**
* Calculates the average grade of the given exams
*
* @param filteredExamList List of exams
* @return Average grade
*/
Double calculateAverageGrade(List<Exam> filteredExamList) {
//List<Exam> removedDoubles = removeDuplicates(filteredExamList);
double weightedGrade = 0.0;
double creditSum = 0.0;
for (Exam item : filteredExamList) {
creditSum += Double.valueOf(item.getCredits());
try {
weightedGrade += format.parse(item.getGrade()).doubleValue()
* Double.valueOf(item.getCredits());
} catch (NumberFormatException | ParseException e) {
Utils.log(e);
}
}
return weightedGrade / creditSum;
}
/**
* Calculates grade distribution
*
* @param filteredExamList List of exams
* @return HashMap with grade to grade count mapping
*/
Map<String, Integer> calculateGradeDistribution(
List<Exam> filteredExamList) {
Map<String, Integer> gradeDistribution = new HashMap<>(128);
for (Exam item : filteredExamList) {
// increment hash value
int curCount = gradeDistribution.containsKey(item.getGrade()) ? gradeDistribution
.get(item.getGrade()) : 0;
gradeDistribution.put(item.getGrade(), curCount + 1);
}
return gradeDistribution;
}
/**
* Initialize the spinner for choosing between the study programs.
*/
private void initSpinner() {
// set Spinner data
List<String> filters = new ArrayList<>();
filters.add(getString(R.string.all_programs));
// get all program ids from the results
for (int i = 0; i < examList.getExams().size(); i++) {
String item = examList.getExams().get(i).getProgramID();
if (filters.indexOf(item) == -1) {
filters.add(item);
}
}
// init the spinner
ArrayAdapter<String> spinnerArrayAdapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_checked, filters);
spFilter.setAdapter(spinnerArrayAdapter);
spFilter.setSelection(lastChoice);
// handle if program choice is changed
spFilter.setOnItemSelectedListener(new OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
String filter = spFilter.getItemAtPosition(arg2).toString();
lastChoice = arg2;
if (filter.equals(getString(R.string.all_programs))) {
// display all grades
lvGrades.setAdapter(new ExamListAdapter(
GradesActivity.this, examList.getExams()));
averageTx.setVisibility(View.GONE);
// convert exam list
List<Exam> convertedList = new ArrayList<>();
for (int i = 0; i < examList.getExams().size(); i++) {
Exam item = examList.getExams().get(i);
convertedList.add(item);
}
// build chart Content for corresponding list
columnChartContent = buildColumnChartContentString(convertedList);
pieChartContent = buildPieChartContentString(convertedList);
} else {
// do filtering according to selected program
List<Exam> filteredExamList = new ArrayList<>();
for (int i = 0; i < examList.getExams().size(); i++) {
Exam item = examList.getExams().get(i);
if (item.getProgramID().equals(filter)) {
filteredExamList.add(item);
}
}
// list view gets filtered list
lvGrades.setAdapter(new ExamListAdapter(
GradesActivity.this, filteredExamList));
columnChartContent = buildColumnChartContentString(filteredExamList);
pieChartContent = buildPieChartContentString(filteredExamList);
averageGrade = Math.round(calculateAverageGrade(filteredExamList) * 1000.0) / 1000.0;
averageTx.setText(String.format("%s: %s",
getResources().getString(R.string.average_grade), averageGrade));
averageTx.setVisibility(View.VISIBLE);
}
}
@Override
public void onNothingSelected(AdapterView<?> arg0) {
// select ALL
spFilter.setSelection(0);
lvGrades.setAdapter(new ExamListAdapter(GradesActivity.this,
examList.getExams()));
}
});
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
lvGrades = (ListView) findViewById(R.id.lstGrades);
spFilter = (Spinner) findViewById(R.id.spFilter);
averageTx = (TextView) findViewById(R.id.avgGrade);
mSwipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.swipeRefreshLayout);
mSwipeRefreshLayout.setOnRefreshListener(this);
mSwipeRefreshLayout.setColorSchemeResources(R.color.color_primary, R.color.tum_A100, R.color.tum_A200);
requestFetch();
}
@Override
protected void requestFetch() {
super.requestFetch();
mSwipeRefreshLayout.setRefreshing(true);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
getMenuInflater().inflate(R.menu.menu_activity_grades, menu);
columnMenuItem = menu.findItem(R.id.columnChart);
pieMenuItem = menu.findItem(R.id.pieChart);
return true;
}
/**
* Handle the response by de-serializing it into model entities.
*
* @param rawResponse Raw text response
*/
@Override
public void onFetch(ExamList rawResponse) {
examList = rawResponse;
// initialize the program choice spinner
initSpinner();
// Displays results in view
lvGrades.setAdapter(new ExamListAdapter(this, examList.getExams()));
showLoadingEnded();
// enabling the Menu options after first fetch
isFetched = true;
// update the action bar to display the enabled menu options
this.invalidateOptionsMenu();
mSwipeRefreshLayout.setRefreshing(false);
}
@Override
public void onFetchError(String errorReason) {
super.onFetchError(errorReason);
Utils.log("Noten failed due to: " + errorReason);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
Intent intent;
if (NetUtils.isConnected(this)) {
int i = item.getItemId();
if (i == R.id.columnChart) {
intent = new Intent(this, GradeChartActivity.class);
intent.putExtra("chartContent", columnChartContent);
startActivity(intent);
return true;
} else if (i == R.id.pieChart) {
intent = new Intent(this, GradeChartActivity.class);
intent.putExtra("chartContent", pieChartContent);
startActivity(intent);
return true;
} else {
isFetched = false;
return super.onOptionsItemSelected(item);
}
} else {
showError(R.string.no_internet_connection);
averageTx.setVisibility(View.GONE);
return true;
}
}
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
// enable Menu Items after fetching grades
columnMenuItem = menu.findItem(R.id.columnChart);
columnMenuItem.setEnabled(isFetched);
pieMenuItem = menu.findItem(R.id.pieChart);
pieMenuItem.setEnabled(isFetched);
return super.onPrepareOptionsMenu(menu);
}
/**
* Removes duplicate exams from the list
*
* @param filteredExamList List of exams
* @return List with duplicate items removed
List<Exam> removeDuplicates(List<Exam> filteredExamList) {
List<Exam> removedDoubles = new ArrayList<>();
// find and remove duplicates
for (int i = 0; i < filteredExamList.size(); i++) {
Exam item1 = filteredExamList.get(i);
boolean insert = true;
for (Exam item2 : filteredExamList) {
if (item1.getCourse().equals(item2.getCourse())) {
Utils.logv("Double = " + item1.getCourse());
try {
if (format.parse(item1.getGrade()).doubleValue() > format
.parse(item2.getGrade()).doubleValue()) {
insert = false;
}
} catch (ParseException e) {
Utils.log(e);
}
}
}
if (insert) {
removedDoubles.add(item1);
}
}
return removedDoubles;
}*/
}