package de.hfu.studiportal.network;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Color;
import android.media.RingtoneManager;
import android.os.AsyncTask;
import android.preference.PreferenceManager;
import android.support.v4.app.NotificationCompat;
import android.util.Log;
import de.hfu.funfpunktnull.R;
import de.hfu.studiportal.data.Exam;
import de.hfu.studiportal.data.StudiportalData;
import de.hfu.studiportal.view.DialogHost;
import de.hfu.studiportal.view.ExamActivity;
import de.hfu.studiportal.view.MainActivity;
public class RefreshTask extends AsyncTask<Void, Void, Exception> {
private final String URL_LOGIN = "https://studi-portal.hs-furtwangen.de/qisserver/rds?state=user&type=1&category=auth.login&startpage=portal.vm&breadCrumbSource=portal";
private final String URL_LOGOUT = "https://studi-portal.hs-furtwangen.de/qisserver/rds?state=user&type=4&re=last&category=auth.logout&breadCrumbSource=portal";
private final String URL_FETCH_ASI = "https://studi-portal.hs-furtwangen.de/qisserver/rds?state=change&type=1&moduleParameter=studyPOSMenu&nextdir=change&next=menu.vm&subdir=applications&xml=menu&purge=y&navigationPosition=functions%2CstudyPOSMenu&breadcrumb=studyPOSMenu&topitem=functions&subitem=studyPOSMenu";
private final String URL_OBSERVE = "https://studi-portal.hs-furtwangen.de/qisserver/rds?state=htmlbesch&moduleParameter=Student&menuid=notenspiegel&breadcrumb=notenspiegel&breadCrumbSource=menu&asi=%s";
private final String USER_NAME;
private final String PASSWORD;
private final Context CONTEXT;
public RefreshTask(Context c, String userName, String password) {
this.CONTEXT = c;
this.USER_NAME = userName;
this.PASSWORD = password;
}
public RefreshTask(Context c) {
this.CONTEXT = c;
SharedPreferences sp = this.getSharedPreferences();
this.USER_NAME = sp.getString(this.getStringResource(R.string.preference_user), "");
this.PASSWORD = sp.getString(this.getStringResource(R.string.preference_password), "");
}
@Override
protected void onPreExecute() {
super.onPreExecute();
this.showProgressDialog(this.getStringResource(R.string.text_connecting));
}
@Override
protected Exception doInBackground(Void... params) {
//Declare Client and occuredException
HttpClient client = null;
Exception occuredException = null;
//Try 3 times
for(int i=0; i<3; i++) {
try {
//Create client
client = new DefaultHttpClient();
//Login
this.showProgressDialog(this.getStringResource(R.string.text_logging_in));
Log.i(this.getClass().getSimpleName(), this.getStringResource(R.string.text_logging_in));
this.login(client);
// Fetch asi
String asi = this.getAsi(client);
//Check for change
this.showProgressDialog(this.getStringResource(R.string.text_checking_update));
Log.i(this.getClass().getSimpleName(),this.getStringResource(R.string.text_checking_update));
boolean changed = this.checkDataChange(client, asi);
//If no change -> save a NoChnageException in occuredException
if(!changed) {
occuredException = new NoChangeException();
}
//Update last_check
getSharedPreferences().edit().putLong(getStringResource(R.string.preference_last_check), System.currentTimeMillis()).apply();
//No error -> cancel (no further trys)
break;
} catch (Exception e) {
//Something went wrong. Print stack trace and save
e.printStackTrace();
occuredException = e;
//Try again, but show error
this.showProgressDialog(getStringResource(R.string.exception_general));
try {
Thread.sleep(1000);
} catch (InterruptedException e1) {
}
} finally {
//try to Log out
try {
this.showProgressDialog(this.getStringResource(R.string.text_logging_out));
Log.i(this.getClass().getSimpleName(),this.getStringResource(R.string.text_logging_out));
this.logout(client);
} catch(Exception e) {
e.printStackTrace();
}
}
}
//Return exception (should be null or NoChangeException)
return occuredException;
}
@Override
protected void onPostExecute(Exception result) {
super.onPostExecute(result);
Context c = this.getContext();
if(c instanceof DialogHost) {
((DialogHost) c).cancelProgressDialog();
if(result != null) {
((DialogHost) c).showErrorDialog(result);
}
} else if(result != null && result instanceof LoginException){
this.notifyAboutError(result);
}
}
private void login(HttpClient client) throws Exception {
//Check Preference
if(this.PASSWORD.length() == 0 || this.USER_NAME.length() == 0)
throw new LoginException(this.getStringResource(R.string.exception_no_user_password));
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2);
nameValuePairs.add(new BasicNameValuePair("asdf", this.USER_NAME));
nameValuePairs.add(new BasicNameValuePair("fdsa", this.PASSWORD));
nameValuePairs.add(new BasicNameValuePair("submit", "Anmelden"));
//Load page (aka log in)
String response = this.sendPost(client, this.URL_LOGIN, nameValuePairs);
//Login failed
if(response.contains("Anmeldung fehlgeschlagen")) {
Log.i(this.getClass().getSimpleName(), "Login failed.");
throw new LoginException(getStringResource(R.string.exception_wrong_user_password));
}
}
private String getAsi(HttpClient client) throws Exception {
//Load page (aka log in)
String response = this.sendPost(client, this.URL_FETCH_ASI, new ArrayList<NameValuePair>());
//Find asi
int asiLength = ";asi=".length();
int start = response.indexOf(";asi=") + asiLength;
int end = response.indexOf("\"", start);
if(start == asiLength) {
throw new IOException("asi could not be extracted");
}
return response.substring(start, end);
}
private boolean checkDataChange(HttpClient client, String asi) throws Exception {
String response = this.sendGet(client, String.format(this.URL_OBSERVE, asi));
int start = response.indexOf("<table cellspacing=\"0\" cellpadding=\"5\" border=\"0\" align=\"center\" width=\"100%\">");
int end = response.indexOf("</table>", start);
String table = response.substring(start, end);
//Create StudiportalData, Compare to saved one and savethe new one
StudiportalData sd = new StudiportalData(table);
List<Exam> changed = sd.findChangedExams(this.getSharedPreferences(), getStringResource(R.string.preference_last_studiportal_data));
sd.save(this.getSharedPreferences(), getStringResource(R.string.preference_last_studiportal_data));
//Compare
boolean isChanged = changed.size() > 0;
if(isChanged) {
this.notifyAboutChange(changed);
}
return isChanged;
}
private void logout(HttpClient client) throws Exception {
this.sendGet(client, this.URL_LOGOUT);
}
private SharedPreferences getSharedPreferences() {
return PreferenceManager.getDefaultSharedPreferences(this.getContext());
}
public Context getContext() {
return this.CONTEXT;
}
private String getStringResource(int id) {
return this.getContext().getResources().getString(id);
}
private String sendPost(HttpClient client, String url, List<NameValuePair> params) throws Exception {
// Create a new HttpClient and Post Header
HttpPost httppost = new HttpPost(url);
httppost.setEntity(new UrlEncodedFormEntity(params));
// Execute HTTP Post Request
HttpResponse response = client.execute(httppost);
String responseString = new BasicResponseHandler().handleResponse(response);
return responseString;
}
private String sendGet(HttpClient client, String url) throws Exception {
// Create a new HttpClient and Post Header
HttpGet httppost = new HttpGet(url);
// Execute HTTP Post Request
HttpResponse response = client.execute(httppost);
String responseString = new BasicResponseHandler().handleResponse(response);
return responseString;
}
private void showNotification(String title, String text, int id, Intent resultIntent) {
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(this.getContext())
.setSmallIcon(R.drawable.ic_notification)
.setContentTitle(title)
.setContentText(text);
// The stack builder object will contain an artificial back stack for the
// started Activity.
// This ensures that navigating backward from the Activity leads out of
// your application to the Home screen.
PendingIntent pendingIntent = PendingIntent.getActivity(this.getContext(), id, resultIntent, PendingIntent.FLAG_UPDATE_CURRENT);
mBuilder.setContentIntent(pendingIntent);
mBuilder.setAutoCancel(true);
mBuilder.setVibrate(new long[] { 1000, 1000, 1000, 1000, 1000 });
//LED
mBuilder.setLights(Color.GREEN, 3000, 3000);
//Ton
mBuilder.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION));
NotificationManager mNotificationManager =
(NotificationManager) this.getContext().getSystemService(Context.NOTIFICATION_SERVICE);
// mId allows you to update the notification later on.
mNotificationManager.notify(id, mBuilder.build());
}
private void notifyAboutChange(List<Exam> changed) {
boolean showGrade = this.getSharedPreferences().getBoolean(
this.getStringResource(R.string.preference_show_grade_in_notification), true);
boolean notifyAboutChange = this.getSharedPreferences().getBoolean(
this.getStringResource(R.string.preference_notify_about_change), true);
if(!notifyAboutChange)
return;
for(Exam e: changed) {
Intent intent = new Intent(this.getContext(), ExamActivity.class);
intent.putExtra(ExamActivity.ARG_EXAM, e);
String subtitle = null;
if(showGrade) {
if(e.getGrade() != null && e.getGrade().length() > 0) {
subtitle = String.format("%s - %s", e.getGrade(), e.getStateName(this.getContext()));
} else {
subtitle = e.getStateName(this.getContext());
}
} else {
subtitle = this.getStringResource(R.string.text_touch_to_show_grade);
}
this.showNotification(e.getName(), subtitle, e.getId(), intent);
}
}
private void notifyAboutError(Exception e) {
this.showNotification(this.getStringResource(R.string.text_error), e.getMessage(), 1, new Intent(this.getContext(), MainActivity.class));
}
private void showProgressDialog(String text) {
if(this.CONTEXT instanceof DialogHost) {
((DialogHost) this.CONTEXT).showIndeterminateProgressDialog(this.getStringResource(R.string.text_refresh), text);
}
}
}