package org.ovirt.mobile.movirt.util.message;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.androidannotations.annotations.Background;
import org.androidannotations.annotations.Bean;
import org.androidannotations.annotations.EBean;
import org.androidannotations.annotations.RootContext;
import org.androidannotations.annotations.UiThread;
import org.ovirt.mobile.movirt.Broadcasts;
import org.ovirt.mobile.movirt.R;
import org.ovirt.mobile.movirt.auth.properties.manager.AccountPropertiesManager;
import org.ovirt.mobile.movirt.auth.properties.property.CertHandlingStrategy;
import org.ovirt.mobile.movirt.model.ConnectionInfo;
import org.ovirt.mobile.movirt.provider.ProviderFacade;
import org.ovirt.mobile.movirt.rest.dto.ErrorBody;
import org.ovirt.mobile.movirt.ui.MainActivity_;
import org.ovirt.mobile.movirt.util.NotificationHelper;
import org.ovirt.mobile.movirt.util.ObjectUtils;
import org.ovirt.mobile.movirt.util.preferences.SharedPreferencesHelper;
import org.springframework.web.client.HttpClientErrorException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Collection;
@EBean(scope = EBean.Scope.Singleton)
public class MessageHelper {
private static final String TAG = MessageHelper.class.getSimpleName();
private ObjectMapper mapper = new ObjectMapper();
@RootContext
Context context;
@Bean
ProviderFacade provider;
@Bean
NotificationHelper notificationHelper;
@Bean
AccountPropertiesManager propertiesManager;
@Bean
SharedPreferencesHelper sharedPreferencesHelper;
@UiThread(propagation = UiThread.Propagation.REUSE)
public void showToast(String msg) {
Toast.makeText(context, msg, Toast.LENGTH_LONG).show();
}
public String createMessage(HttpClientErrorException ex) {
String result = "";
try {
String responseBody = ex.getResponseBodyAsString();
if (!TextUtils.isEmpty(responseBody)) {
result = ex.getMessage() + ": " + responseBody;
ErrorBody errorBody = mapper.readValue(ex.getResponseBodyAsByteArray(), ErrorBody.class);
if (errorBody.fault != null) {
result = ex.getMessage() + " " + errorBody.fault.reason + " " + errorBody.fault.detail;
} else {
ErrorBody.Fault fault = mapper.readValue(ex.getResponseBodyAsByteArray(), ErrorBody.Fault.class);
if (fault != null) {
result = ex.getMessage() + " " + fault.reason + " " + fault.detail;
}
}
}
} catch (Exception f) {
result = f.getMessage();
}
if (TextUtils.isEmpty(result)) {
result = ex.getMessage();
}
return result;
}
public void showError(String message) {
showError(new Message(message));
}
public void showError(Throwable message) {
showError(new Message(ObjectUtils.throwableToString(message)));
}
public void showError(ErrorType type, Throwable message) {
showError(new Message(type, ObjectUtils.throwableToString(message)));
}
public void showError(ErrorType type, String message) {
showError(new Message(type, message));
}
public void showError(ErrorType type, String message, String header) {
showError(new Message(type, message, header));
}
public void showError(ErrorType type, Throwable message, String header) {
showError(new Message(type, ObjectUtils.throwableToString(message), header));
}
/**
* @see Message for default values to understand behaviour of overloaded methods
* broadcasts error and logs it
*/
@Background
public void showError(Message message) {
if (message == null) {
throw new IllegalArgumentException("null message");
}
ErrorType errorType = message.getType();
String header = message.getHeader();
String detail = message.getDetail();
Integer logPriority = message.getLogPriority();
String finalMessage;
switch (message.getType()) {
case REST_MINOR:
case REST_MAJOR:
finalMessage = context.getString(R.string.rest_request_failed, getConnectionDetails() + detail);
break;
default:
finalMessage = header == null ? detail :
context.getString(R.string.message_detailed_info, header, detail);
break;
}
if (logPriority == null) {
logPriority = errorType.getDefaultLogPriority();
}
showError(errorType, logPriority, finalMessage);
}
@Background
public void resetMinorErrors() {
updateConnectionInfo(true);
}
private void showError(ErrorType errorType, Integer logPriority, String msg) {
Log.println(logPriority, TAG, msg);
boolean failedRepeatedly = false;
if (errorType.isConnectionType()) {
ConnectionInfo connectionInfo = updateConnectionInfo(false, errorType.isNotifiable(), msg);
failedRepeatedly = connectionInfo.getState() == ConnectionInfo.State.FAILED_REPEATEDLY;
}
Intent intent = new Intent(Broadcasts.ERROR_MESSAGE);
intent.putExtra(Broadcasts.Extras.ERROR_REASON, msg);
intent.putExtra(Broadcasts.Extras.REPEATED_MINOR_ERROR, failedRepeatedly && errorType.isMinorType());
context.sendBroadcast(intent);
}
private String getConnectionDetails() {
String token = propertiesManager.peekAuthToken();
if (token == null) {
token = context.getString(R.string.rest_error_detail_token_missing);
}
StringBuilder certificate = new StringBuilder();
String apiUrl = propertiesManager.getApiUrl();
if (apiUrl != null) {
try {
URL url = new URL(apiUrl);
CertHandlingStrategy certHandlingStrategy = propertiesManager.getCertHandlingStrategy();
if (url.getProtocol().equalsIgnoreCase("https")) {
certificate.append("\n").append(context.getString(R.string.rest_error_detail_certificate_strategy,
certHandlingStrategy.toString()));
}
if (certHandlingStrategy == CertHandlingStrategy.TRUST_CUSTOM) {
boolean hasCert = propertiesManager.getCertificateChain().length > 0;
certificate.append("\n\t")
.append(context.getString(hasCert ? R.string.rest_error_detail_certificate_stored :
R.string.rest_error_detail_certificate_missing));
}
} catch (MalformedURLException e) {
apiUrl = context.getString(R.string.rest_error_detail_malformed_url, e.getMessage());
}
} else {
apiUrl = context.getString(R.string.rest_error_detail_missing_url);
}
return context.getString(R.string.rest_error_details,
apiUrl, propertiesManager.getUsername(), token, certificate.toString());
}
private ConnectionInfo updateConnectionInfo(boolean success) {
return updateConnectionInfo(success, false, null);
}
private ConnectionInfo updateConnectionInfo(boolean success, boolean notifiable, String description) {
ConnectionInfo connectionInfo;
ConnectionInfo.State state;
boolean prevFailed = false;
boolean configured = sharedPreferencesHelper.isConnectionNotificationEnabled();
Collection<ConnectionInfo> connectionInfos = provider.query(ConnectionInfo.class).all();
int size = connectionInfos.size();
if (size != 0) {
connectionInfo = connectionInfos.iterator().next();
ConnectionInfo.State lastState = connectionInfo.getState();
if (lastState == ConnectionInfo.State.FAILED || lastState == ConnectionInfo.State.FAILED_REPEATEDLY) {
prevFailed = true;
}
} else {
connectionInfo = new ConnectionInfo();
}
if (!success) {
state = prevFailed ? ConnectionInfo.State.FAILED_REPEATEDLY : ConnectionInfo.State.FAILED;
} else {
state = ConnectionInfo.State.OK;
description = null;
}
connectionInfo.setDescription(description);
connectionInfo.updateWithCurrentTime(state);
//update in DB
if (size != 0) {
provider.batch().update(connectionInfo).apply();
} else {
provider.batch().insert(connectionInfo).apply();
}
//show Notification
if (notifiable && !success && !prevFailed && configured) {
Intent resultIntent = new Intent(context, MainActivity_.class);
resultIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent resultPendingIntent =
PendingIntent.getActivity(
context,
0,
resultIntent,
0
);
notificationHelper.showConnectionNotification(
context, resultPendingIntent, connectionInfo);
}
return connectionInfo;
}
}