package pt.rupeal.invoicexpress.server;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.protocol.BasicHttpContext;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import pt.rupeal.invoicexpress.MainActivity;
import pt.rupeal.invoicexpress.R;
import pt.rupeal.invoicexpress.activities.AuthenticationActivity;
import pt.rupeal.invoicexpress.enums.RoleEnum;
import pt.rupeal.invoicexpress.model.AccountDetailsModel;
import pt.rupeal.invoicexpress.model.AccountModel;
import pt.rupeal.invoicexpress.model.AccountsModel;
import pt.rupeal.invoicexpress.utils.InvoiceXpressException;
import pt.rupeal.invoicexpress.utils.InvoiceXpressError.InvoiceXpressErrorType;
import android.accounts.Account;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import android.widget.Toast;
public class AuthenticationRestHandler extends AsyncTask<String, Void, AccountsModel> {
private String username;
private String password;
private StringBuffer responseXml;
public AuthenticationRestHandler(Context context) {
this.context = context;
}
@Override
protected AccountsModel doInBackground(String... params) {
username = params[0];
password = params[1];
AccountsModel accounts = new AccountsModel();
try {
// Login
// the login pai operation will return all associated accounts
HttpPost httpPost = new HttpPost(InvoiceXpress.LOGIN_URL);
StringEntity entity = new StringEntity(buildXmlRequest(), "UTF-8");
entity.setContentType("application/xml; charset=utf-8");
httpPost.setEntity(entity);
DefaultHttpClient httpClient = new DefaultHttpClient(InvoiceXpress.getHttpParameters());
HttpResponse response = httpClient.execute(httpPost, new BasicHttpContext());
BufferedReader reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent(), "UTF-8"));
responseXml = new StringBuffer();
String line;
while ((line = reader.readLine()) != null) {
responseXml.append(line);
}
if(response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
// log
if(InvoiceXpress.DEBUG) {
Log.d(this.getClass().getCanonicalName(), "Status Code: " + response.getStatusLine().getStatusCode());
Log.d(this.getClass().getCanonicalName(), responseXml.toString());
}
// return
return accounts;
}
// log
if(InvoiceXpress.DEBUG) {
Log.d(this.getClass().getCanonicalName(), responseXml.toString());
}
List<AccountModel> accountsList = getAccounts(responseXml.toString());
// set accounts list
accounts.setAccounts(accountsList);
// set active account. it will be the first none blocked account
AccountModel activeAccount = getActiveAccount(accountsList);
// if there are no active account return error
if(activeAccount == null) {
throw new InvoiceXpressException(context, R.string.error_account_blocked);
}
accounts.setAccountActive(activeAccount);
// start account details request
HttpGet httpGet = new HttpGet(
buildRequestHttpGet(accounts.getAccountActive().getUrl(),
accounts.getAccountActive().getApiKey()));
httpClient = new DefaultHttpClient(InvoiceXpress.getHttpParameters());
response = httpClient.execute(httpGet, new BasicHttpContext());
reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent(), "UTF-8"));
StringBuffer responseString = new StringBuffer();
line = "";
while ((line = reader.readLine()) != null) {
responseString.append(line);
}
if(InvoiceXpress.DEBUG) {
Log.d(this.getClass().getCanonicalName(), responseString.toString());
}
// set account details
accounts.setAccountDetailsActive(getAccountDetails(responseString.toString()));
// create a new account
Account[] androidAccounts = InvoiceXpress.getInstance().getInvoiceXpressAccount();
if(androidAccounts == null || androidAccounts.length == 0) {
Account account = new Account(username, InvoiceXpress.ACCOUNT_ANDROID_INVOICEXPRESS_TYPE);
InvoiceXpress.getInstance().getAccountManager().addAccountExplicitly(account, password, null);
}
// set accounts
InvoiceXpress.getInstance().setAccounts(accounts);
} catch (UnsupportedEncodingException e) {
Log.e(AuthenticationRestHandler.class.getCanonicalName(), e.getMessage(), e);
setError(R.string.error_cant_login_unexpected, InvoiceXpressErrorType.ERROR);
} catch (ClientProtocolException e) {
Log.e(AuthenticationRestHandler.class.getCanonicalName(), e.getMessage(), e);
setError(R.string.error_cant_login_unexpected, InvoiceXpressErrorType.ERROR);
} catch (IOException e) {
Log.e(AuthenticationRestHandler.class.getCanonicalName(), e.getMessage(), e);
setError(R.string.error_cant_login_unexpected, InvoiceXpressErrorType.ERROR);
} catch (InvoiceXpressException e) {
Log.e(AuthenticationRestHandler.class.getCanonicalName(), e.getMessage());
setError(e.getMessage(), InvoiceXpressErrorType.ERROR);
}
return accounts;
}
private List<AccountModel> getAccounts(String xml) throws InvoiceXpressException {
List<AccountModel> accounts = new ArrayList<AccountModel>();
InvoiceXpressParser parser = new InvoiceXpressParser(context);
Document documentDomElement = parser.getDomElement(xml);
if(documentDomElement == null) {
throw new InvoiceXpressException(context, R.string.error_bad_credentials);
}
try {
NodeList accountsNodeList = documentDomElement.getElementsByTagName("account");
for (int i = 0; i < accountsNodeList.getLength(); i++) {
Node accountNode = accountsNodeList.item(i);
AccountModel accountModel = new AccountModel();
accountModel.setId(parser.getValue((Element) accountNode, "id"));
accountModel.setName(parser.getValue((Element) accountNode, "name"));
accountModel.setUrl(parser.getValue((Element) accountNode, "url"));
accountModel.setApiKey(parser.getValue((Element) accountNode, "api_key"));
accountModel.setState(parser.getValue((Element) accountNode, "state"));
// roles
NodeList rolesNodeList = ((Element) accountNode).getElementsByTagName("role");
int rolesLength = rolesNodeList.getLength();
List<RoleEnum> roles = new ArrayList<RoleEnum>(rolesLength);
for (int j = 0; j < rolesNodeList.getLength(); j++) {
Node item = rolesNodeList.item(j);
roles.add(RoleEnum.getRoleEnum(parser.getElementValue(item)));
}
accountModel.setRoles(roles);
accountModel.setBlocked(Boolean.parseBoolean(parser.getValue((Element) accountNode, "blocked")));
accounts.add(accountModel);
}
} catch(Exception e) {
throw new InvoiceXpressException(context, R.string.error_cant_login_unexpected);
}
return accounts;
}
private AccountModel getActiveAccount(List<AccountModel> accounts) {
for (AccountModel account : accounts) {
if(!account.isBlocked()) {
return account;
}
}
return null;
}
private MessageFormat xmlRequest = new MessageFormat (
"<credentials>" +
"<login>{0}</login>" +
"<password>{1}</password>" +
"</credentials>");
private String buildXmlRequest() throws InvoiceXpressException {
Object[] args = {username, password};
String xmlRequestFormated = xmlRequest.format(args);
// log
if(InvoiceXpress.DEBUG) {
Log.d(this.getClass().getCanonicalName(), xmlRequestFormated);
}
return xmlRequestFormated;
}
private String buildRequestHttpGet(String url, String apiKey) {
StringBuffer request = new StringBuffer(url + "/account_data");
request.append(".xml");
request.append("?api_key=" + apiKey);
// log
if(InvoiceXpress.DEBUG) {
Log.d(this.getClass().getCanonicalName(), request.toString());
}
return request.toString();
}
private AccountDetailsModel getAccountDetails(String xml_response) throws InvoiceXpressException {
InvoiceXpressParser parser = new InvoiceXpressParser(context);
Document documentDomElement = parser.getDomElement(xml_response);
AccountDetailsModel accountDetail = new AccountDetailsModel();
NodeList nodeList = documentDomElement.getElementsByTagName("account");
Element elem = (Element) nodeList.item(0);
accountDetail.setPlan(parser.getValue(elem, "plan"));
accountDetail.setEntity(parser.getValue(elem, "organization_name"));
accountDetail.setName(parser.getValue(elem, "name"));
accountDetail.setPhone(parser.getValue(elem, "phone"));
accountDetail.setFax(parser.getValue(elem, "fax"));
accountDetail.setEmail(parser.getValue(elem, "email"));
accountDetail.setAddress(parser.getValue(elem, "address"));
accountDetail.setCity(parser.getValue(elem, "city"));
accountDetail.setPostalCode(parser.getValue(elem, "postal_code"));
accountDetail.setLocale(parser.getValue(elem, "locale"));
accountDetail.setCountry(parser.getValue(elem, "country"));
accountDetail.setBlocked(Boolean.parseBoolean(parser.getValue(elem, "blocked")));
Node currency = parser.getNode(elem, "currency");
accountDetail.setCurrencyName(parser.getValue((Element) currency, "name"));
accountDetail.setCurrencySymbol(parser.getValue((Element) currency, "symbol"));
return accountDetail;
}
private static final String BAD_CREDENTIALS = "bad credentials";
@Override
protected void onPostExecute(AccountsModel result) {
super.onPostExecute(result);
if(existsError()) {
processError(R.string.error_cant_login_unexpected);
return;
}
if(BAD_CREDENTIALS.equals(responseXml.toString())) {
processError(R.string.error_bad_credentials);
return;
}
if(result.getAccounts().isEmpty()) {
processError(R.string.error_there_arent_active_accounts);
return;
}
// clean all documents, contacts and dash board data
InvoiceXpress.getInstance().clear();
// if the context is MainActivity then the application just need to initialize the action bar
if(context instanceof MainActivity) {
((MainActivity) context).initActionBar();
} else if(context instanceof AuthenticationActivity) {
// else the execution of web service is called from Authentication activity
// the application has to start main activity and finish the authentication activity
AuthenticationActivity activity = (AuthenticationActivity) context;
activity.setResult(Activity.RESULT_OK, new Intent());
// finish activity
activity.finish();
}
}
private void processError(int errorMessageId) {
// show error message
Toast.makeText(context, errorMessageId, Toast.LENGTH_LONG).show();
if(context instanceof MainActivity) {
// show authentication activity
// get android account
Account[] accounts = InvoiceXpress.getInstance().getInvoiceXpressAccount();
if(accounts.length > 0) {
// remove accounts data
InvoiceXpress.getInstance().getAccounts().clear();
InvoiceXpress.getInstance().getAccounts().addAll(new ArrayList<AccountModel>());
InvoiceXpress.getInstance().setActiveAccount(null);
InvoiceXpress.getInstance().setActiveAccountDetails(null);
// remove android invoiceXpress account
InvoiceXpress.getInstance().getAccountManager().removeAccount(accounts[0], null, null);
// start authentication activity
Intent intent = new Intent(context, AuthenticationActivity.class);
((MainActivity) context).startActivityForResult(intent, 1);
}
}
}
}