/** Copyright 2012 Fahad Al-Khameesi, Madeleine Appert, Niklas Logren, Arild Matsson and Jonathan Orr�. This file is part of Bibbla. Bibbla is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Bibbla is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Bibbla. If not, see <http://www.gnu.org/licenses/>. **/ package dat255.grupp06.bibbla.backend; import java.util.AbstractMap; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import android.annotation.SuppressLint; import dat255.grupp06.bibbla.backend.tasks.*; import dat255.grupp06.bibbla.model.*; import dat255.grupp06.bibbla.utils.*; import dat255.grupp06.bibbla.model.Library; import dat255.grupp06.bibbla.utils.Callback; import dat255.grupp06.bibbla.utils.Message; import dat255.grupp06.bibbla.utils.Session; /** * @author Niklas Logren */ @SuppressLint({ "NewApi", "NewApi" }) public final class Backend implements IBackend { public final static int MAX_CONNECTION_ATTEMPTS = 5; public final static int CONNECTION_TIMEOUT = 2000; private Settings settings; private Session session; // Cached results. private Map<String,Book> detailedViews = new HashMap<String, Book>(); private Map<Entry<String, Integer>,List<Book>> searchResults = new HashMap<Entry<String, Integer>,List<Book>>(); private List<Book> reservations; private List<Book> loanedBooks; private List<Library> libraries; private Integer debt; /** * Creates a new instance of our Backend. * Initialises a new session and fetches settings. */ public Backend() { settings = new Settings(); session = new Session(); } public void getUserName(Callback frontendCallback) throws CredentialsMissingException { final UserNameJob job = new UserNameJob(settings.getCredentials(), session); Task task = new Task(frontendCallback) { @Override protected Void doInBackground(String... params) { message = job.run(); return null; } }; task.execute(); } public void fetchUserDebt(final Callback frontendCallback) throws CredentialsMissingException { fetchUserDebt(frontendCallback, false); } public boolean isLoggedIn() { return session.isActive(); } public void fetchUserDebt(final Callback frontendCallback, boolean refresh) throws CredentialsMissingException { // Return cached result if it's available. if (!refresh && (debt!=null)) { Message message = new Message(); message.obj = debt; frontendCallback.handleMessage(message); } // Run the job. else { Callback backendCallback = new Callback() { @Override public void handleMessage(Message message) { Backend.this.fetchDebtDone(message, frontendCallback); } }; final MyDebtJob job = new MyDebtJob(settings.getCredentials(), session); // Create a new Task and define its body. Task task = new Task(backendCallback) { @Override // The code that's run in the Task (on new thread). protected Void doInBackground(String... params) { message = job.run(); return null; } }; // Start the task. task.execute(); } } /** * Gets called by the when debt is fetched * @param message - a message containing debt and error message * @param callback - callback object */ private void fetchDebtDone(Message message, Callback callback) { debt = (Integer) message.obj; callback.handleMessage(message); } public void search(final String s, final int page, final Callback frontendCallback) { // Create the key identifying this list of search results. // Consists of the search string and page number. final Map.Entry<String,Integer> key = new AbstractMap.SimpleEntry<String, Integer>(s, page); // Return cached result if it's available. if(searchResults.containsKey(key)) { Message message = new Message(); message.obj = searchResults.get(key); frontendCallback.handleMessage(message); } // Run the job. else{ Callback backendCallback = new Callback() { @Override public void handleMessage(Message message) { Backend.this.fetchSearchResultsDone(message, frontendCallback, key); } }; // Create a new Task and define its body. Task task = new Task(backendCallback) { @Override // The code that's run in the Task (on new thread). protected Void doInBackground(String... params) { SearchJob job = new SearchJob(s,page); message = job.run(); return null; } }; // Start the task. task.execute(); } } /** * Gets called when the search results have been fetched * @param message - message containing search results and error messages * @param callback * @param entry */ private void fetchSearchResultsDone(Message message, Callback callback, Entry<String, Integer> entry) { searchResults.put(entry, (List<Book>) message.obj); callback.handleMessage(message); } public void fetchDetailedView(final Book book, final Callback frontendCallback) { fetchDetailedView(book, frontendCallback, false); } public void fetchDetailedView(final Book book, final Callback frontendCallback, boolean refresh) { // Return cached result if it's available. if (detailedViews.containsKey(book.getUrl()) && !refresh) { Message message = new Message(); message.obj = detailedViews.get(book.getUrl()); frontendCallback.handleMessage(message); } // Run the job. else { detailedViews.clear(); // Create a new callback, which saves the result before passing it on to frontend. Callback backendCallback = new Callback() { @Override public void handleMessage(Message message) { Backend.this.fetchDetailedViewDone(message, frontendCallback); } }; // Create a new Task and define its body. Task task = new Task(backendCallback) { @Override // The code that's run in the Task (on new thread). protected Void doInBackground(String... params) { DetailedViewJob job = new DetailedViewJob(book); message = job.run(); return null; } }; // Start the task. task.execute(); } } /** * Is called when fetchDetailedView is done. * Saves the result in a member variable, and then passes it on to frontend. * * @param message - the message returned from fetchDetailedView. * @param frontendCallback - the callback object which will be called * when fetching detailed view is done. */ private void fetchDetailedViewDone(Message message, Callback frontendCallback) { // Save results for caching. detailedViews.put(((Book) message.obj).getUrl() ,(Book) message.obj); frontendCallback.handleMessage(message); } public void fetchReservations(final Callback frontendCallback) throws CredentialsMissingException { fetchReservations(frontendCallback, false); } public void fetchReservations(final Callback frontendCallback, boolean refresh) throws CredentialsMissingException { // Return cached result if it's available. if (!refresh && (reservations!=null)) { Message message = new Message(); message.obj = reservations; frontendCallback.handleMessage(message); } // Run the job. else { reservations = null; // Create a new callback, which saves the result before passing it on to frontend. Callback backendCallback = new Callback(){ @Override public void handleMessage(Message message) { Backend.this.fetchReservationsDone(message, frontendCallback); } }; final MyReservationsJob job = new MyReservationsJob( settings.getCredentials(), session); Task task = new Task(backendCallback) { @Override protected Void doInBackground(String... arg0) { message = job.run(); return null; } }; task.execute(); } } /** * Is called when fetchReservations is done. * Saves the result in a member variable, and then passes it on to frontend. * * @param message - the message returned from fetchReservations. * @param frontendCallback - the callback object which will be called * when fetching reservations is done. */ private void fetchReservationsDone(Message message, Callback callback){ reservations = (List<Book>) message.obj; callback.handleMessage(message); } public void fetchLoans(final Callback frontendCallback) throws CredentialsMissingException { fetchLoans(frontendCallback, false); } public void fetchLoans(final Callback frontendCallback, boolean refresh) throws CredentialsMissingException { // Return cached result if it's available. if (!refresh && (loanedBooks!=null)) { Message message = new Message(); message.obj = loanedBooks; frontendCallback.handleMessage(message); } // Run the job. else { loanedBooks = null; // Create a new callback, which saves the result before passing it on to frontend. Callback backendCallback = new Callback() { @Override public void handleMessage(Message message) { Backend.this.fetchLoanedBooksDone(message, frontendCallback); } }; final MyBooksJob job = new MyBooksJob(settings.getCredentials(), session); // Create a new Task and define its body. Task task = new Task(backendCallback) { @Override // The code that's run in the Task (on new thread). protected Void doInBackground(String... params) { message = job.run(); return null; } }; // Start the task. task.execute(); } } /** * Is called when fetchDetailedView is done. * Saves the result in a member variable, and then passes it on to frontend. * * @param message - the message returned from fetchDetailedView. * @param frontendCallback - the callback object which will be called * when fetching loaned books is done. */ public void fetchLoanedBooksDone(Message message, Callback callback){ loanedBooks = (List<Book>) message.obj; callback.handleMessage(message); } public void reserve(final Book book, final String libraryCode, final Callback frontendCallback) throws CredentialsMissingException { final ReserveJob job = new ReserveJob(book, libraryCode, settings.getCredentials(), session); // Create a new Task and define its body. Task task = new Task(frontendCallback) { @Override // The code that's run in the Task (on new thread). protected Void doInBackground(String... params) { message = job.run(); return null; } }; // Start the task. task.execute(); } public void unreserve(final Book book, final Callback frontendCallback) throws CredentialsMissingException { final UnreserveJob job = new UnreserveJob(book, settings.getCredentials(), session); // Create a new Task and define its body. Task task = new Task(frontendCallback) { @Override // The code that's run in the Task (on new thread). protected Void doInBackground(String... params) { message = job.run(); return null; } }; // Start the task. task.execute(); } public void unreserve(final List<Book> books, final Callback frontendCallback) throws CredentialsMissingException { final UnreserveJob job = new UnreserveJob(books, settings.getCredentials(), session); // Create a new Task and define its body. Task task = new Task(frontendCallback) { @Override // The code that's run in the Task (on new thread). protected Void doInBackground(String... params) { message = job.run(); return null; } }; // Start the task. task.execute(); } public void unreserve(final Callback frontendCallback) throws CredentialsMissingException { final UnreserveJob job = new UnreserveJob(settings.getCredentials(), session); // Create a new Task and define its body. Task task = new Task(frontendCallback) { @Override // The code that's run in the Task (on new thread). protected Void doInBackground(String... params) { message = job.run(); return null; } }; // Start the task. task.execute(); } public void renew(final Book book, final Callback frontendCallback) throws CredentialsMissingException { final RenewJob job = new RenewJob(book, settings.getCredentials(), session); // Create a new Task and define its body. Task task = new Task(frontendCallback) { @Override // The code that's run in the Task (on new thread). protected Void doInBackground(String... params) { message = job.run(); return null; } }; // Start the task. task.execute(); } public void renew(final List<Book> books, final Callback frontendCallback) throws CredentialsMissingException { final RenewJob job = new RenewJob(books, settings.getCredentials(), session); // Create a new Task and define its body. Task task = new Task(frontendCallback) { @Override // The code that's run in the Task (on new thread). protected Void doInBackground(String... params) { message = job.run(); return null; } }; // Start the task. task.execute(); } public void renew(final Callback frontendCallback) throws CredentialsMissingException { final RenewJob job = new RenewJob(settings.getCredentials(), session); // Create a new Task and define its body. Task task = new Task(frontendCallback) { @Override // The code that's run in the Task (on new thread). protected Void doInBackground(String... params) { message = job.run(); return null; } }; // Start the task. task.execute(); } public void logOut(){ session = new Session(); settings = new Settings(); this.debt = 0; } /** * Save credentials * @param cred - Login credentials */ public void saveCredentials(Credentials cred) { if (cred != null) { settings.setName(cred.name); settings.setCode(cred.card); settings.setPin(cred.pin); } } public void libInfo(final Callback frontendCallback) { libInfo(frontendCallback, false); } /** * Searches backend for the library information. * * @param frontendCallback - the callback object which will be called * when fetching library information is done. * @param refresh - should we run the job directly, and bypass caching? */ public void libInfo(final Callback frontendCallback, boolean refresh) { if(libraries != null && !refresh){ Message message = new Message(); message.obj = libraries; frontendCallback.handleMessage(message); } else{ Callback backendCallback = new Callback(){ @Override public void handleMessage(Message message) { Backend.this.fetchLibInfoDone(message ,frontendCallback); } }; // Create a new Task and define its body. Task task = new Task(backendCallback) { @Override // The code that's run in the Task (on new thread). protected Void doInBackground(String... params) { LibInfoJob job = new LibInfoJob(); message = job.run(); return null; } }; // Start the task. task.execute(); } } /** * Is called when libInfo is done. * Saves the result in a member variable, and then passes it on to frontend. * * @param message - the message returned from libInfo. * @param frontendCallback - the callback object which will be called * when fetching library information is done. */ private void fetchLibInfoDone(Message message, Callback callback) { libraries = (List<Library>) message.obj; callback.handleMessage(message); } }