public class CarRentalApplication extends Application {

    //Static access to context and ssl parameters
    private static Application application;
    private static SSLContext sslContext;

    /**
     * Returns the current application object
     *
     * @return application object
     */
    public static Application getApplication() {
        return application;
    }

    /**
     * Returns the current application context
     *
     * @return application context
     */
    public static Context getAppContext() {
        return getApplication().getApplicationContext();
    }

    /**
     * Returns the current SSL parameters
     *
     * @return SSL context parameters
     */
    public static SSLContext getSslContext() {
        return sslContext;
    }

    @Override
    public void onCreate() {
        //At the beginning of the application, a reference to the app is stored and the SSL parameters are initialized
        super.onCreate();
        application = this;

        setupSslTrustStore();
    }

    /**
     * Sets up the SSL trust store, containing the encryption keys for encrypted socket communication
     *
     * The keystore was generated with this tool: http://www.keystore-explorer.org/downloads.php
     */
    private void setupSslTrustStore() {
        try {
            char[] password = "carrental".toCharArray();

            KeyStore keyStore = KeyStore.getInstance("BKS");
            keyStore.load(this.getResources().openRawResource(R.raw.carrental_keystore), password);

            TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
            trustManagerFactory.init(keyStore);

            KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
            keyManagerFactory.init(keyStore, password);

            // Create a SSLContext with the certificate
            sslContext = SSLContext.getInstance("TLS");
            sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), new SecureRandom());
        } catch (NoSuchAlgorithmException | KeyStoreException | IOException | KeyManagementException | CertificateException | UnrecoverableKeyException e) {
            e.printStackTrace();
            Log.e("SSL", "Failed to create SSL context");
        }
    }
} public interface CarRentalApiClient {
    /**
     * Return the list of available branches
     *
     * @return list of branches
     * @throws ApiUnauthorizedException if the request wasn't authenticated or authorized
     * @throws ApiException if there was a general error during the request if there was a general error during the request
     * @throws ApiInvalidParameterException if there was an error with a parameter
     * @throws ApiUnavailableException if the API is unavailable
     */
    List<BranchContract> getBranches() throws ApiUnauthorizedException, ApiException, ApiInvalidParameterException, ApiUnavailableException;

    /**
     * Return the result of the available vehicles with the given criteria
     *
     * @param contract search criteria
     * @return list of available vehicle results
     * @throws ApiUnauthorizedException if the request wasn't authenticated or authorized
     * @throws ApiException if there was a general error during the request
     * @throws ApiInvalidParameterException if there was an error with a parameter
     * @throws ApiUnavailableException if the API is unavailable
     */
    List<BookingSearchResultContract> searchAvailableVehicles(SearchAvailableVehiclesRequestContract contract) throws ApiUnauthorizedException, ApiException, ApiInvalidParameterException, ApiUnavailableException;

    /**
     * Create an user account with the given parameters
     *
     * @param contract account parameters
     * @return created account
     * @throws ApiUnauthorizedException if the request wasn't authenticated or authorized
     * @throws ApiException if there was a general error during the request
     * @throws ApiInvalidParameterException if there was an error with a parameter
     * @throws ApiUnavailableException if the API is unavailable
     */
    UserContract createAccount(CreateAccountRequestContract contract) throws ApiUnauthorizedException, ApiException, ApiInvalidParameterException, ApiUnavailableException;

    /**
     * Returns the current user account details
     *
     * @return user account details
     * @throws ApiUnauthorizedException if the request wasn't authenticated or authorized
     * @throws ApiException if there was a general error during the request
     * @throws ApiInvalidParameterException if there was an error with a parameter
     * @throws ApiUnavailableException if the API is unavailable
     */
    UserContract getAccountDetails() throws ApiUnauthorizedException, ApiException, ApiInvalidParameterException, ApiUnavailableException;

    /**
     * Returns the bookings for the current user in the current branch
     *
     * @return list of bookings for the user and branch
     * @throws ApiUnauthorizedException if the request wasn't authenticated or authorized
     * @throws ApiException if there was a general error during the request
     * @throws ApiInvalidParameterException if there was an error with a parameter
     * @throws ApiUnavailableException if the API is unavailable
     */
    List<BookingContract> getUserBookingsForBranch() throws ApiUnauthorizedException, ApiException, ApiInvalidParameterException, ApiUnavailableException;

    /**
     * Request a vehicle booking with the given criteria
     *
     * @param contract booking criteria
     * @return created booking
     * @throws ApiUnauthorizedException if the request wasn't authenticated or authorized
     * @throws ApiException if there was a general error during the request
     * @throws ApiInvalidParameterException if there was an error with a parameter
     * @throws ApiUnavailableException if the API is unavailable
     */
    BookingContract bookVehicle(CreateBookingContract contract) throws ApiUnauthorizedException, ApiException, ApiInvalidParameterException, ApiUnavailableException;

    /**
     * Returns all the bookings for the current branch
     *
     * @return the branch bookings list
     * @throws ApiUnauthorizedException if the request wasn't authenticated or authorized
     * @throws ApiException if there was a general error during the request
     * @throws ApiInvalidParameterException if there was an error with a parameter
     * @throws ApiUnavailableException if the API is unavailable
     */
    List<BookingContract> getBranchBookings() throws ApiUnauthorizedException, ApiException, ApiInvalidParameterException, ApiUnavailableException;

    /**
     * Sends a shutdown request to the server
     *
     * @return nothing
     * @throws ApiUnauthorizedException if the request wasn't authenticated or authorized
     * @throws ApiException if there was a general error during the request
     * @throws ApiInvalidParameterException if there was an error with a parameter
     * @throws ApiUnavailableException if the API is unavailable
     */
    Void shutdownSystem() throws ApiUnauthorizedException, ApiException, ApiInvalidParameterException, ApiUnavailableException;

    /**
     * Create an user account with the given parameters (requires staff level)
     *
     * @param contract the account parameters
     * @return the created account
     * @throws ApiUnauthorizedException if the request wasn't authenticated or authorized
     * @throws ApiException if there was a general error during the request
     * @throws ApiInvalidParameterException if there was an error with a parameter
     * @throws ApiUnavailableException if the API is unavailable
     */
    UserContract createUser(CreateAccountRequestContract contract)  throws ApiUnauthorizedException, ApiException, ApiInvalidParameterException, ApiUnavailableException;

    /**
     * Create or update a vehicle with the given parameters in the current branch
     *
     * @param contract vehicle parameters
     * @return created or updated vehicle
     * @throws ApiUnauthorizedException if the request wasn't authenticated or authorized
     * @throws ApiException if there was a general error during the request
     * @throws ApiInvalidParameterException if there was an error with a parameter
     * @throws ApiUnavailableException if the API is unavailable
     */
    VehicleContract createOrUpdateVehicle(CreateUpdateVehicleContract contract)  throws ApiUnauthorizedException, ApiException, ApiInvalidParameterException, ApiUnavailableException;

    /**
     * Search vehicles with the given criteria in the current branch
     *
     * @param contract search criteria
     * @return list of vehicles matching the criteria
     * @throws ApiUnauthorizedException if the request wasn't authenticated or authorized
     * @throws ApiException if there was a general error during the request
     * @throws ApiInvalidParameterException if there was an error with a parameter
     * @throws ApiUnavailableException if the API is unavailable
     */
    List<VehicleContract> searchVehicles(SearchVehicleContract contract)  throws ApiUnauthorizedException, ApiException, ApiInvalidParameterException, ApiUnavailableException;

    /**
     * Search users with the given criteria (full text search on email and fullname)
     *
     * @param contract search criteria
     * @return list of users matching the criteria
     * @throws ApiUnauthorizedException if the request wasn't authenticated or authorized
     * @throws ApiException if there was a general error during the request
     * @throws ApiInvalidParameterException if there was an error with a parameter
     * @throws ApiUnavailableException if the API is unavailable
     */
    List<UserContract> searchUser(SearchUserContract contract)  throws ApiUnauthorizedException, ApiException, ApiInvalidParameterException, ApiUnavailableException;

    /**
     * Update a booking status with the given parameters
     *
     * @param contract update parameters
     * @return updated booking
     * @throws ApiUnauthorizedException if the request wasn't authenticated or authorized
     * @throws ApiException if there was a general error during the request
     * @throws ApiInvalidParameterException if there was an error with a parameter
     * @throws ApiUnavailableException if the API is unavailable
     */
    BookingContract changeBookingStatus(ChangeBookingStatusContract contract)  throws ApiUnauthorizedException, ApiException, ApiInvalidParameterException, ApiUnavailableException;

    /**
     * Returns the vehicle moves for the current branch matching the filter criteria
     *
     * @param contract filter criteria
     * @return list of bookings requiring moves
     * @throws ApiUnauthorizedException if the request wasn't authenticated or authorized
     * @throws ApiException if there was a general error during the request
     * @throws ApiInvalidParameterException if there was an error with a parameter
     * @throws ApiUnavailableException if the API is unavailable
     */
    List<BookingContract> getVehiclesMove(GetBranchVehicleMovesContract contract)  throws ApiUnauthorizedException, ApiException, ApiInvalidParameterException, ApiUnavailableException;
} public class OperationCodes {
    //Guest methods
    public final static int GET_BRANCHES                    = 0;
    public final static int SEARCH_AVAIL_VEHICLES           = 1;
    public final static int CREATE_ACCOUNT                  = 2;

    //User methods
    public final static int BOOK_VEHICLE                    = 3;
    public final static int GET_USER_BOOKINGS               = 4;
    public final static int GET_ACCOUNT_DETAILS             = 5;

    //Staff methods
    public final static int CREATE_USER                     = 6;
    public final static int UPDATE_OR_CREATE_VEHICLE        = 7;
    public final static int SEARCH_USER                     = 8;
    public final static int GET_BRANCH_BOOKINGS             = 9;
    public final static int CHANGE_BOOKING_STATUS           = 10;
    public final static int SEARCH_ALL_VEHICLES             = 11;
    public final static int SHUTDOWN_SYSTEM                 = 12;
    public final static int GET_VEHICLE_MOVES               = 13;
} public class BookingContract {
    public int id;
    public String branch;
    public VehicleContract vehicle;
    public VehicleMoveContract vehicleMove;
    public String pickupDate;
    public String returnDate;
    public long daysCount;
    public double price;
    public boolean bookingValidated;
    public boolean requireVehicleMove;
} public class BookingSearchResultContract {
    public boolean requireVehicleMove;
    public VehicleContract vehicle;
    public String pickupDate;
    public String returnDate;
    public long daysCount;
    public double price;
} public class BranchContract {
    public int id;
    public String name;
    public double latitude;
    public double longitude;
} public class ChangeBookingStatusContract {
    public int bookingId;
    public boolean bookingValidated;
} public class CreateAccountRequestContract {
    public String fullName;
    public String emailAddress;
    public String phoneNumber;
    public String password;
    public String address_street;
    public String address_city;
    public String address_postalCode;
    public String address_country;
} public class CreateBookingContract {
    public int vehicleId;
    public int vehicleBranchId;
    public int bookingBranchId;
    public String pickupDate;
    public String returnDate;
    public String creditCardNumber;
    public String creditCardExpirationMonth;
    public String creditCardExpirationYear;
    public String creditCardCvcCode;

    //If this property is used, the action will require staff credentials
    public Integer bookingOwnerUserId;
} public class CreateUpdateVehicleContract {
    public int type;
    public String registrationNumber;
    public int doors;
    public int seats;
    public boolean automaticTransmission;
    public double poundsPerDay;
    public String name;

    //Update-specific properties
    public boolean isUpdateOperation;
    //public int newBranchId;
    public int id;
    public int newStatusId;
} public class GetBranchVehicleMovesContract {
    public boolean outgoing;
} public class SearchAvailableVehiclesRequestContract {
    public int vehicleType;
    public String pickupDate;
    public String returnDate;
} public class SearchUserContract {
    public String searchTerm;
} public class SearchVehicleContract {
    //If this isn't provided, the type id will be used
    public String registrationNumber;
    public int vehicleTypeId;
} public class UserContract {
    public int id;
    public boolean isStaff;
    public String fullName;
    public String emailAddress;
    public String phoneNumber;
} public class VehicleContract {
    public int id;
    public BranchContract branch;
    public int type;
    public int status;
    public String registrationNumber;
    public int doors;
    public int seats;
    public boolean automaticTransmission;
    public double poundsPerDay;
    public String name;
} public class ApiException extends Exception {
    private int _code;

    /**
     * Constructor
     *
     * @param code API error code
     * @param error API error message
     */
    public ApiException(int code, String error) {
        super(error);
        _code = code;
    }

    /**
     * Constructor
     *
     * @param error failure details
     */
    public ApiException(String error) {
        super(error);
    }

    /**
     * Returns the API error code number
     *
     * @return API error code
     */
    public int getCode() {
        return _code;
    }
} public class ApiInvalidParameterException extends Exception {
    /**
     * Constructor
     *
     * @param error failure details
     */
    public ApiInvalidParameterException(String error) {
        super(error);
    }
} public class ApiUnauthorizedException extends Exception {
    /**
     * Constructor
     *
     * @param error failure details
     */
    public ApiUnauthorizedException(String error) {
        super(error);
    }
} public class ApiUnavailableException extends Exception {} public class PreferencesManager {

    //SharedPreferences storage keys
    private static final String PREF_USER_LABEL = "logged_user";
    private static final String PREF_PASSWORD_LABEL = "password_user";
    private static final String PREF_BRANCH_LABEL = "current_branch";
    private static final String PREF_IP_ADDRESS_LABEL = "server_ip";
    private static final String PREF_PORT_LABEL = "server_port";

    //Default values for the connection system
    private static final String DEFAULT_IP_ADDRESS = "161.73.147.225";
    private static final int DEFAULT_PORT = 5106;

    //In-Memory cache, avoids a reload from the shared preferences every time
    private static UserContract currentUser;
    private static BranchContract currentBranch;
    private static String userPassword;
    private static String ipAddress;
    private static Integer port;

    /**
     * Returns the SharedPreferences for the given context
     *
     * @param ctx current context
     * @return SharedPreferences instance
     */
    private static SharedPreferences getSharedPreferences(Context ctx) {
        return PreferenceManager.getDefaultSharedPreferences(ctx);
    }

    /**
     * Updates the current branch
     *
     * @param ctx current context
     * @param contract newly selected branch
     */
    public static void setCurrentBranch(Context ctx, BranchContract contract) {
        SharedPreferences.Editor editor = getSharedPreferences(ctx).edit();
        editor.putString(PREF_BRANCH_LABEL, SerializationUtils.serialize(contract));
        editor.apply();
        currentBranch = contract;
    }

    /**
     * Returns the current branch, loads it from the SharedPreferences if not yet in memory
     *
     * @param ctx current context
     * @return the current branch
     */
    public static BranchContract getCurrentBranch(Context ctx) {
        if (currentBranch == null) {
            currentBranch = SerializationUtils.deserialize(getSharedPreferences(ctx).getString(PREF_BRANCH_LABEL, null), BranchContract.class);
        }

        return currentBranch;
    }

    /**
     * Returns the current authentication state
     *
     * @param ctx current context
     * @return true if logged in, false otherwise
     */
    public static boolean isLoggedIn(Context ctx) {
        UserContract loggedUser = getLoggedUser(ctx);

        return !(loggedUser == null);
    }

    /**
     * Returns the current staff authorization state
     *
     * @param ctx current context
     * @return true if logged in AND staff member, false otherwise
     */
    public static boolean isStaffUser(Context ctx) {
        UserContract loggedUser = getLoggedUser(ctx);

        return loggedUser != null && loggedUser.isStaff;
    }

    /**
     * Returns the current logged user, loads it from the SharedPreferences if not yet in memory
     *
     * @param ctx current context
     * @return the current user if logged in, null otherwise
     */
    public static UserContract getLoggedUser(Context ctx) {
        if (currentUser == null) {
            currentUser = SerializationUtils.deserialize(getSharedPreferences(ctx).getString(PREF_USER_LABEL, null), UserContract.class);
        }

        return currentUser;
    }

    /**
     * Updates the current user
     *
     * @param ctx current context
     * @param user current user
     */
    public static void setLoggedUser(Context ctx, UserContract user) {
        SharedPreferences.Editor editor = getSharedPreferences(ctx).edit();
        editor.putString(PREF_USER_LABEL, SerializationUtils.serialize(user));
        currentUser = user;
        editor.apply();
    }

    /**
     * Remove the current user settings
     *
     * @param ctx current context
     */
    public static void clearSession(Context ctx) {
        SharedPreferences.Editor editor = getSharedPreferences(ctx).edit();
        editor.remove(PREF_USER_LABEL);
        editor.remove(PREF_PASSWORD_LABEL);
        editor.remove(PREF_BRANCH_LABEL);
        currentUser = null;
        userPassword = null;
        currentBranch = null;
        editor.apply();
    }

    /**
     * Change the current user password
     *
     * @param ctx current context
     * @param password new password
     */
    public static void setUserPassword(Context ctx, String password) {
        SharedPreferences.Editor editor = getSharedPreferences(ctx).edit();
        editor.putString(PREF_PASSWORD_LABEL, password);
        editor.apply();
        userPassword = password;
    }

    /**
     * Returns the current user password, loads it if not done yet
     *
     * @param ctx current context
     * @return current password
     */
    public static String getUserPassword(Context ctx) {
        if (userPassword == null) {
            userPassword = getSharedPreferences(ctx).getString(PREF_PASSWORD_LABEL, null);
        }

        return userPassword;
    }

    /**
     * Update head office IP address
     *
     * @param ctx current context
     * @param newIpAddress new IP address
     */
    public static void setHeadOfficeIpAddress(Context ctx, String newIpAddress) {
        SharedPreferences.Editor editor = getSharedPreferences(ctx).edit();
        editor.putString(PREF_IP_ADDRESS_LABEL, newIpAddress);
        ipAddress = newIpAddress;
        editor.apply();
    }

    /**
     * Returns the current head office IP address, loads it if not done yet
     * @param ctx current context
     * @return the current head office IP address
     */
    public static String getHeadOfficeIpAddress(Context ctx) {
        if (ipAddress == null) {
            ipAddress = getSharedPreferences(ctx).getString(PREF_IP_ADDRESS_LABEL, null);

            if (ipAddress == null) {
                setHeadOfficeIpAddress(ctx, DEFAULT_IP_ADDRESS);
            }
        }

        return ipAddress;
    }

    /**
     * Update head office port
     *
     * @param ctx current context
     * @param newPort new port
     */
    public static void setHeadOfficePort(Context ctx, int newPort) {
        SharedPreferences.Editor editor = getSharedPreferences(ctx).edit();
        editor.putInt(PREF_PORT_LABEL, newPort);
        port = newPort;
        editor.apply();
    }

    /**
     * Returns the current head office port, loads it if not done yet
     * @param ctx current context
     * @return the current head office port
     */
    public static int getHeadOfficePort(Context ctx) {
        if (port == null) {
            port = getSharedPreferences(ctx).getInt(PREF_PORT_LABEL, -1);

            // 0 Should not be used as a port anyway.
            if (port <= 0) {
                setHeadOfficePort(ctx, DEFAULT_PORT);
            }
        }

        return port;
    }
} public class SerializationUtils {

    //Static gson object
    private static Gson gsonObject = new Gson();

    /**
     * Serialize the provided object to a json string
     *
     * @param object the object to serialize
     * @param <T> the generic object type
     * @return the serialized json string
     */
    public static <T> String serialize(T object) {
        return gsonObject.toJson(object);
    }

    /**
     * Deserialize the provided string into the given type
     *
     * @param serialized the serialized json string
     * @param type the expected object type
     * @param <T> the generic object type
     * @return the deserialized object
     */
    public static <T> T deserialize(String serialized, Type type) {
        return gsonObject.fromJson(serialized, type);
    }
}
import android.util.Base64;
import com.vehiclerental.CarRentalApplication;
import com.vehiclerental.apiClient.CarRentalApiClient;
import com.vehiclerental.apiClient.OperationCodes;
import com.vehiclerental.contracts.BookingContract;
import com.vehiclerental.contracts.BookingSearchResultContract;
import com.vehiclerental.contracts.BranchContract;
import com.google.gson.reflect.TypeToken;
import com.vehiclerental.contracts.ChangeBookingStatusContract;
import com.vehiclerental.contracts.CreateAccountRequestContract;
import com.vehiclerental.contracts.CreateBookingContract;
import com.vehiclerental.contracts.CreateUpdateVehicleContract;
import com.vehiclerental.contracts.GetBranchVehicleMovesContract;
import com.vehiclerental.contracts.SearchAvailableVehiclesRequestContract;
import com.vehiclerental.contracts.SearchUserContract;
import com.vehiclerental.contracts.SearchVehicleContract;
import com.vehiclerental.contracts.UserContract;
import com.vehiclerental.contracts.VehicleContract;
import com.vehiclerental.exceptions.ApiException;
import com.vehiclerental.exceptions.ApiInvalidParameterException;
import com.vehiclerental.exceptions.ApiUnauthorizedException;
import com.vehiclerental.exceptions.ApiUnavailableException;
import com.vehiclerental.preferences.PreferencesManager;
import com.vehiclerental.utils.SerializationUtils;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Type;
import java.util.List;
/**
 * CarRental
 *
 * This file provides a socket based implementation for the service communication
 */

package com.vehiclerental.apiClient.socketImplementation;




public class CarRentalApiClientSocketImpl implements CarRentalApiClient {

    //Communication details
    private String url;
    private int port;

    /**
     * Constructor
     *
     * @param url server IP or domain
     * @param port server port
     */
    public CarRentalApiClientSocketImpl(String url, int port) {
        this.url = url;
        this.port = port;
    }

    /**
     * Return the list of available branches through a socket connection
     *
     * @return list of branches
     * @throws ApiUnauthorizedException if the request wasn't authenticated or authorized
     * @throws ApiException if there was a general error during the request if there was a general error during the request
     * @throws ApiInvalidParameterException if there was an error with a parameter
     * @throws ApiUnavailableException if the API is unavailable
     */
    @Override
    public List<BranchContract> getBranches() throws ApiUnauthorizedException, ApiException, ApiInvalidParameterException, ApiUnavailableException {
        Type jsonType = new TypeToken<List<BranchContract>>() {}.getType();
        return doRequest(OperationCodes.GET_BRANCHES, null, jsonType);
    }

    /**
     * Return the result of the available vehicles with the given criteria through a socket connection
     *
     * @param contract search criteria
     * @return list of available vehicle results
     * @throws ApiUnauthorizedException if the request wasn't authenticated or authorized
     * @throws ApiException if there was a general error during the request
     * @throws ApiInvalidParameterException if there was an error with a parameter
     * @throws ApiUnavailableException if the API is unavailable
     */
    @Override
    public List<BookingSearchResultContract> searchAvailableVehicles(SearchAvailableVehiclesRequestContract contract) throws ApiUnauthorizedException, ApiException, ApiInvalidParameterException, ApiUnavailableException {
        Type jsonType = new TypeToken<List<BookingSearchResultContract>>() {}.getType();
        return doRequest(OperationCodes.SEARCH_AVAIL_VEHICLES, contract, jsonType);
    }

    /**
     * Create an user account with the given parameters through a socket connection
     *
     * @param contract account parameters
     * @return created account
     * @throws ApiUnauthorizedException if the request wasn't authenticated or authorized
     * @throws ApiException if there was a general error during the request
     * @throws ApiInvalidParameterException if there was an error with a parameter
     * @throws ApiUnavailableException if the API is unavailable
     */
    @Override
    public UserContract createAccount(CreateAccountRequestContract contract) throws ApiUnauthorizedException, ApiException, ApiInvalidParameterException, ApiUnavailableException {
        Type jsonType = new TypeToken<UserContract>() {}.getType();
        return doRequest(OperationCodes.CREATE_ACCOUNT, contract, jsonType);
    }

    /**
     * Returns the current user account details through a socket connection
     *
     * @return user account details
     * @throws ApiUnauthorizedException if the request wasn't authenticated or authorized
     * @throws ApiException if there was a general error during the request
     * @throws ApiInvalidParameterException if there was an error with a parameter
     * @throws ApiUnavailableException if the API is unavailable
     */
    @Override
    public UserContract getAccountDetails() throws ApiUnauthorizedException, ApiException, ApiInvalidParameterException, ApiUnavailableException {
        Type jsonType = new TypeToken<UserContract>() {}.getType();
        return doRequest(OperationCodes.GET_ACCOUNT_DETAILS, null, jsonType);
    }

    /**
     * Returns the bookings for the current user in the current branch through a socket connection
     *
     * @return list of bookings for the user and branch
     * @throws ApiUnauthorizedException if the request wasn't authenticated or authorized
     * @throws ApiException if there was a general error during the request
     * @throws ApiInvalidParameterException if there was an error with a parameter
     * @throws ApiUnavailableException if the API is unavailable
     */
    @Override
    public List<BookingContract> getUserBookingsForBranch() throws ApiUnauthorizedException, ApiException, ApiInvalidParameterException, ApiUnavailableException {
        Type jsonType = new TypeToken<List<BookingContract>>() {}.getType();
        return doRequest(OperationCodes.GET_USER_BOOKINGS, null, jsonType);
    }

    /**
     * Request a vehicle booking with the given criteria through a socket connection
     *
     * @param contract booking criteria
     * @return created booking
     * @throws ApiUnauthorizedException if the request wasn't authenticated or authorized
     * @throws ApiException if there was a general error during the request
     * @throws ApiInvalidParameterException if there was an error with a parameter
     * @throws ApiUnavailableException if the API is unavailable
     */
    @Override
    public BookingContract bookVehicle(CreateBookingContract contract) throws ApiUnauthorizedException, ApiException, ApiInvalidParameterException, ApiUnavailableException {
        Type jsonType = new TypeToken<BookingContract>() {}.getType();
        return doRequest(OperationCodes.BOOK_VEHICLE, contract, jsonType);
    }

    /**
     * Returns all the bookings for the current branch through a socket connection
     *
     * @return the branch bookings list
     * @throws ApiUnauthorizedException if the request wasn't authenticated or authorized
     * @throws ApiException if there was a general error during the request
     * @throws ApiInvalidParameterException if there was an error with a parameter
     * @throws ApiUnavailableException if the API is unavailable
     */
    @Override
    public List<BookingContract> getBranchBookings() throws ApiUnauthorizedException, ApiException, ApiInvalidParameterException, ApiUnavailableException {
        Type jsonType = new TypeToken<List<BookingContract>>() {}.getType();
        return doRequest(OperationCodes.GET_BRANCH_BOOKINGS, null, jsonType);
    }

    /**
     * Sends a shutdown request to the server through a socket connection
     *
     * @return nothing
     * @throws ApiUnauthorizedException if the request wasn't authenticated or authorized
     * @throws ApiException if there was a general error during the request
     * @throws ApiInvalidParameterException if there was an error with a parameter
     * @throws ApiUnavailableException if the API is unavailable
     */
    @Override
    public Void shutdownSystem() throws ApiUnauthorizedException, ApiException, ApiInvalidParameterException, ApiUnavailableException {
        Type jsonType = new TypeToken<Void>() {}.getType();
        return doRequest(OperationCodes.SHUTDOWN_SYSTEM, null, jsonType);
    }

    /**
     * Create an user account with the given parameters through a socket connection (requires staff level)
     *
     * @param contract the account parameters
     * @return the created account
     * @throws ApiUnauthorizedException if the request wasn't authenticated or authorized
     * @throws ApiException if there was a general error during the request
     * @throws ApiInvalidParameterException if there was an error with a parameter
     * @throws ApiUnavailableException if the API is unavailable
     */
    @Override
    public UserContract createUser(CreateAccountRequestContract contract) throws ApiUnauthorizedException, ApiException, ApiInvalidParameterException, ApiUnavailableException {
        Type jsonType = new TypeToken<UserContract>() {}.getType();
        return doRequest(OperationCodes.CREATE_USER, contract, jsonType);
    }

    /**
     * Create or update a vehicle with the given parameters in the current branch through a socket connection
     *
     * @param contract vehicle parameters
     * @return created or updated vehicle
     * @throws ApiUnauthorizedException if the request wasn't authenticated or authorized
     * @throws ApiException if there was a general error during the request
     * @throws ApiInvalidParameterException if there was an error with a parameter
     * @throws ApiUnavailableException if the API is unavailable
     */
    @Override
    public VehicleContract createOrUpdateVehicle(CreateUpdateVehicleContract contract) throws ApiUnauthorizedException, ApiException, ApiInvalidParameterException, ApiUnavailableException {
        Type jsonType = new TypeToken<VehicleContract>() {}.getType();
        return doRequest(OperationCodes.UPDATE_OR_CREATE_VEHICLE, contract, jsonType);
    }

    /**
     * Search vehicles with the given criteria in the current branch through a socket connection
     *
     * @param contract search criteria
     * @return list of vehicles matching the criteria
     * @throws ApiUnauthorizedException if the request wasn't authenticated or authorized
     * @throws ApiException if there was a general error during the request
     * @throws ApiInvalidParameterException if there was an error with a parameter
     * @throws ApiUnavailableException if the API is unavailable
     */
    @Override
    public List<VehicleContract> searchVehicles(SearchVehicleContract contract) throws ApiUnauthorizedException, ApiException, ApiInvalidParameterException, ApiUnavailableException {
        Type jsonType = new TypeToken<List<VehicleContract>>() {}.getType();
        return doRequest(OperationCodes.SEARCH_ALL_VEHICLES, contract, jsonType);
    }

    /**
     * Search users with the given criteria (full text search on email and fullname) through a socket connection
     *
     * @param contract search criteria
     * @return list of users matching the criteria
     * @throws ApiUnauthorizedException if the request wasn't authenticated or authorized
     * @throws ApiException if there was a general error during the request
     * @throws ApiInvalidParameterException if there was an error with a parameter
     * @throws ApiUnavailableException if the API is unavailable
     */
    @Override
    public List<UserContract> searchUser(SearchUserContract contract) throws ApiUnauthorizedException, ApiException, ApiInvalidParameterException, ApiUnavailableException {
        Type jsonType = new TypeToken<List<UserContract>>() {}.getType();
        return doRequest(OperationCodes.SEARCH_USER, contract, jsonType);
    }

    /**
     * Update a booking status with the given parameters through a socket connection
     *
     * @param contract update parameters
     * @return updated booking
     * @throws ApiUnauthorizedException if the request wasn't authenticated or authorized
     * @throws ApiException if there was a general error during the request
     * @throws ApiInvalidParameterException if there was an error with a parameter
     * @throws ApiUnavailableException if the API is unavailable
     */
    @Override
    public BookingContract changeBookingStatus(ChangeBookingStatusContract contract) throws ApiUnauthorizedException, ApiException, ApiInvalidParameterException, ApiUnavailableException {
        Type jsonType = new TypeToken<BookingContract>() {}.getType();
        return doRequest(OperationCodes.CHANGE_BOOKING_STATUS, contract, jsonType);
    }

    /**
     * Returns the vehicle moves for the current branch matching the filter criteria through a socket connection
     *
     * @param contract filter criteria
     * @return list of bookings requiring moves
     * @throws ApiUnauthorizedException if the request wasn't authenticated or authorized
     * @throws ApiException if there was a general error during the request
     * @throws ApiInvalidParameterException if there was an error with a parameter
     * @throws ApiUnavailableException if the API is unavailable
     */
    @Override
    public List<BookingContract> getVehiclesMove(GetBranchVehicleMovesContract contract) throws ApiUnauthorizedException, ApiException, ApiInvalidParameterException, ApiUnavailableException {