package com.andreicerbu; import com.andreicerbu.exceptions.*; import com.andreicerbu.items.database.TableDeposit; import com.andreicerbu.json.JsonFields; import org.json.JSONArray; import org.json.JSONObject; import java.sql.*; import java.util.*; import static com.andreicerbu.json.JsonFields.listOfDeposits; public class Algorithm { JSONObject order = null; Integer id_user = null; String name = null; Float lat_coord = null; Float long_coord = null; JSONObject routeJson = null; JSONObject destination = null; JSONArray deposits = null; List listOfDeposits = new ArrayList<>(); Map mapProductIdToName = new HashMap<>(); public Algorithm(JSONObject order) throws SQLException, ProductUnavailableAnymoreException { this.order = new JSONObject(order.toString()); this.id_user = this.order.getInt(JsonFields.id_user); this.order.remove(JsonFields.id_user); run(); } private void getUserInformation(Connection conn) throws SQLException{ PreparedStatement pstmt = conn.prepareStatement("SELECT * FROM users WHERE id = ?"); pstmt.setInt(1, id_user); ResultSet resultSet = pstmt.executeQuery(); resultSet.next(); name = resultSet.getString("username"); lat_coord = resultSet.getFloat(JsonFields.lat_coord); long_coord = resultSet.getFloat(JsonFields.long_coord); destination = new JSONObject(); destination.put(JsonFields.id_user, id_user); destination.put(JsonFields.name, name); destination.put(JsonFields.lat_coord, lat_coord); destination.put(JsonFields.long_coord, long_coord); } private void getDeposits(Connection conn) throws SQLException{ PreparedStatement pstmt = conn.prepareStatement("SELECT * FROM deposits"); ResultSet resultSet = pstmt.executeQuery(); while(resultSet.next()){ listOfDeposits.add(new TableDeposit( resultSet.getInt("id"), resultSet.getString("name"), resultSet.getFloat("lat_coord"), resultSet.getFloat("long_coord") )); } listOfDeposits.sort(new Comparator() { @Override public int compare(TableDeposit d1, TableDeposit d2) { return (int) (findDistanceBetweenCoord(d2.getLat_coord(), d2.getLong_coord(), lat_coord, long_coord) - findDistanceBetweenCoord(d1.getLat_coord(), d1.getLong_coord(), lat_coord, long_coord)); } }); } private float findDistanceBetweenCoord(Float x1, Float y1, Float x2, Float y2){ return (float) Math.sqrt( Math.pow((x2 - x1), 2) + Math.pow((y2 - y1), 2) ); } private void getProductNames(Connection conn) throws SQLException { JSONArray products = new JSONArray(order.get(JsonFields.listOfProducts).toString()); Statement stmt = conn.createStatement(); ResultSet resultSet = stmt.executeQuery("SELECT id, name FROM products"); while (resultSet.next()) { int id_product = resultSet.getInt("id"); String name = resultSet.getString("name"); for (int index = 0; index < products.length(); index++) { JSONObject item = products.getJSONObject(index); if(id_product == item.getInt(JsonFields.id_product)){ mapProductIdToName.put(id_product, name); break; } } } } private void createRoute(Connection conn) throws SQLException, ProductUnavailableAnymoreException { deposits = new JSONArray(); JSONArray products = new JSONArray(order.get(JsonFields.listOfProducts).toString()); PreparedStatement pstmt; for(TableDeposit deposit : listOfDeposits){//we take each deposit JSONObject depositJSON = new JSONObject(createDepositJSONForRoute(deposit).toString()); JSONArray listOfProductsJSON = depositJSON.getJSONArray(JsonFields.listOfProducts); pstmt = conn.prepareStatement("SELECT * FROM prod_in_depo WHERE id_deposit = ?"); pstmt.setInt(1, deposit.getId_deposit()); ResultSet resultSet = pstmt.executeQuery();//we take all the products that exists in a deposit while(resultSet.next()){ int id_product = resultSet.getInt("id_product"); int quantity = resultSet.getInt("quantity"); String name = mapProductIdToName.get(id_product); for(int index = 0; index < products.length(); index++){//iterate through our order JSONObject item = products.getJSONObject(index); JSONObject itemForList = new JSONObject(); if(item.getInt(JsonFields.id_product) == id_product){ itemForList.put(JsonFields.id_product, id_product); itemForList.put(JsonFields.name, name); int newQuantity = item.getInt(JsonFields.quantity) - quantity; if(newQuantity > 0){ item.put(JsonFields.quantity, newQuantity); itemForList.put(JsonFields.quantity, quantity); }else{ itemForList.put(JsonFields.quantity, item.getInt(JsonFields.quantity)); products.remove(index); } listOfProductsJSON.put(itemForList); } } } if(!depositJSON.getJSONArray(JsonFields.listOfProducts).isEmpty()) { deposits.put(depositJSON); } if(products.isEmpty()){ return; } } if(!products.isEmpty()){ throw new ProductUnavailableAnymoreException("One of the chosen products is not available anymore"); } } private JSONObject createDepositJSONForRoute(TableDeposit deposit){ JSONObject depositJSON = new JSONObject(); depositJSON.put(JsonFields.id_deposit, deposit.getId_deposit()); depositJSON.put(JsonFields.name, deposit.getName()); depositJSON.put(JsonFields.lat_coord, deposit.getLat_coord()); depositJSON.put(JsonFields.long_coord, deposit.getLong_coord()); depositJSON.put(JsonFields.listOfProducts, new JSONArray()); depositJSON.put(JsonFields.distance, findDistanceBetweenCoord(lat_coord, long_coord, deposit.getLat_coord(), deposit.getLong_coord())); return depositJSON; } private void createJsonRoute(){ routeJson = new JSONObject(); routeJson.put(JsonFields.destination, destination); routeJson.put(JsonFields.listOfDeposits, deposits); routeJson.put(JsonFields.listOfProducts, order.getJSONArray(JsonFields.listOfProducts)); } private synchronized void run() throws SQLException, ProductUnavailableAnymoreException{ Connection conn = Database.getConnection(); getUserInformation(conn); getDeposits(conn); getProductNames(conn); createRoute(conn); createJsonRoute(); } public JSONObject getRouteJson() { return routeJson; } }