controllers.AnyplaceMapping.java Source code

Java tutorial

Introduction

Here is the source code for controllers.AnyplaceMapping.java

Source

/*
 * AnyPlace: A free and open Indoor Navigation Service with superb accuracy!
 *
 * Anyplace is a first-of-a-kind indoor information service offering GPS-less
 * localization, navigation and search inside buildings using ordinary smartphones.
 *
 * Author(s): Lambros Petrou, Kyriakos Georgiou
 *
 * Supervisor: Demetrios Zeinalipour-Yazti
 *
 * URL: https://anyplace.cs.ucy.ac.cy
 * Contact: anyplace@cs.ucy.ac.cy
 *
 * Copyright (c) 2016, Data Management Systems Lab (DMSL), University of Cyprus.
 * All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the Software?), to deal in the
 * Software without restriction, including without limitation the rights to use, copy,
 * modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the
 * following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED AS IS?, WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

package controllers;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import datasources.DatasourceException;
import datasources.ProxyDataSource;
import db_models.*;
import oauth.provider.v2.models.OAuth2Request;
import org.apache.commons.codec.binary.Base64;
import play.mvc.Controller;
import play.mvc.Http;
import play.mvc.Result;
import play.mvc.Results;
import utils.*;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.text.NumberFormat;
import java.text.ParseException;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.zip.GZIPOutputStream;

public class AnyplaceMapping extends Controller {

    private static String verifyOwnerId(String authToken) {

        String gURL = "https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=" + authToken;

        String res = null;

        try {
            res = sendGet(gURL);
        } catch (Exception e) {
            LPLogger.error(e.toString());
            return null;
        }

        if (res != null) {
            try {
                JsonNode json = (ObjectNode) JsonUtils.getJsonTree(res);
                return json.get("user_id") == null ? null : json.get("user_id").textValue();
            } catch (IOException ioe) {
                return null;
            }
        }

        return null;
    }

    private static String appendToOwnerId(String ownerId) {
        return ownerId + "_google";
    }

    // HTTP GET request
    private static String sendGet(String url) throws Exception {

        URL obj = new URL(url);
        HttpURLConnection con = (HttpURLConnection) obj.openConnection();

        // optional default is GET
        con.setRequestMethod("GET");

        int responseCode = con.getResponseCode();

        BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
        String inputLine;
        StringBuffer response = new StringBuffer();

        while ((inputLine = in.readLine()) != null) {
            response.append(inputLine);
        }
        in.close();

        return response.toString();
    }

    public static Result getRadioHeatmap() {
        OAuth2Request anyReq = new OAuth2Request(request(), response());
        if (!anyReq.assertJsonBody()) {
            return AnyResponseHelper.bad_request(AnyResponseHelper.CANNOT_PARSE_BODY_AS_JSON);
        }
        JsonNode json = anyReq.getJsonBody();
        LPLogger.info("AnyplaceMapping::getRadioHeatmap(): " + json.toString());

        try {
            List<JsonNode> radioPoints = ProxyDataSource.getIDatasource().getRadioHeatmap();
            if (radioPoints == null) {
                return AnyResponseHelper.bad_request("Building does not exist or could not be retrieved!");
            }
            ObjectNode res = JsonUtils.createObjectNode();
            res.put("radioPoints", JsonUtils.getJsonFromList(radioPoints));
            return AnyResponseHelper.ok(res, "Successfully retrieved all radio points!");
        } catch (DatasourceException e) {
            return AnyResponseHelper.internal_server_error("Server Internal Error [" + e.getMessage() + "]");
        }
    }

    public static Result getRadioHeatmapByBuildingFloor() {
        OAuth2Request anyReq = new OAuth2Request(request(), response());
        if (!anyReq.assertJsonBody()) {
            return AnyResponseHelper.bad_request(AnyResponseHelper.CANNOT_PARSE_BODY_AS_JSON);
        }

        JsonNode json = anyReq.getJsonBody();
        LPLogger.info("AnyplaceMapping::getRadioHeatmap(): " + json.toString());

        List<String> requiredMissing = JsonUtils.requirePropertiesInJson(json, "buid", "floor");

        if (!requiredMissing.isEmpty()) {
            return AnyResponseHelper.requiredFieldsMissing(requiredMissing);
        }

        String buid = json.path("buid").textValue();
        String floor = json.path("floor").textValue();

        try {
            List<JsonNode> radioPoints = ProxyDataSource.getIDatasource().getRadioHeatmapByBuildingFloor(buid,
                    floor);
            if (radioPoints == null) {
                return AnyResponseHelper.bad_request("Building does not exist or could not be retrieved!");
            }
            ObjectNode res = JsonUtils.createObjectNode();
            res.put("radioPoints", JsonUtils.getJsonFromList(radioPoints));
            try {
                //                if (request().getHeader("Accept-Encoding") != null && request().getHeader("Accept-Encoding").contains("gzip")) {
                return gzippedJSONOk(res.toString());
                //                }
                //                return AnyResponseHelper.ok(res.toString());
            } catch (IOException ioe) {
                return AnyResponseHelper.ok(res, "Successfully retrieved all radio points!");
            }
        } catch (DatasourceException e) {
            return AnyResponseHelper.internal_server_error("Server Internal Error [" + e.getMessage() + "]");
        }
    }

    public static Result deleteRadiosInBox() {
        OAuth2Request anyReq = new OAuth2Request(request(), response());
        if (!anyReq.assertJsonBody()) {
            return AnyResponseHelper.bad_request(AnyResponseHelper.CANNOT_PARSE_BODY_AS_JSON);
        }

        JsonNode json = anyReq.getJsonBody();
        LPLogger.info("AnyplaceMapping::deleteRadiosInBox(): " + json.toString());

        try {
            if (!ProxyDataSource.getIDatasource().deleteRadiosInBox()) {
                return AnyResponseHelper.bad_request("Building already exists or could not be added!");
            }
            return AnyResponseHelper.ok("Success");
        } catch (DatasourceException e) {
            return AnyResponseHelper.internal_server_error("Server Internal Error [" + e.getMessage() + "]");
        }

    }

    /**
     * Adds a new building to the database
     *
     * @return the newly created Building ID is included in the response if success
     */
    public static Result buildingAdd() {

        OAuth2Request anyReq = new OAuth2Request(request(), response());
        if (!anyReq.assertJsonBody()) {
            return AnyResponseHelper.bad_request(AnyResponseHelper.CANNOT_PARSE_BODY_AS_JSON);
        }

        JsonNode json = anyReq.getJsonBody();
        LPLogger.info("AnyplaceMapping::buildingAdd(): " + json.toString());

        List<String> requiredMissing = JsonUtils.requirePropertiesInJson(json, "is_published", "name",
                "description", "url", "address", "coordinates_lat", "coordinates_lon", "access_token");

        if (!requiredMissing.isEmpty()) {
            return AnyResponseHelper.requiredFieldsMissing(requiredMissing);
        }

        // get access token from url and check it against google's service
        if (json.findValue("access_token") == null) {
            return AnyResponseHelper.forbidden("Unauthorized");
        }
        String owner_id = verifyOwnerId(json.findValue("access_token").textValue());
        if (owner_id == null) {
            return AnyResponseHelper.forbidden("Unauthorized");
        }
        owner_id = appendToOwnerId(owner_id);
        ((ObjectNode) json).put("owner_id", owner_id);

        try {
            Building building;
            try {
                building = new Building(json);
            } catch (NumberFormatException e) {
                return AnyResponseHelper.bad_request("Building coordinates are invalid!");
            }
            //System.out.println(building.toValidCouchJson());
            if (!ProxyDataSource.getIDatasource().addJsonDocument(building.getId(), 0, building.toCouchGeoJSON())) {
                return AnyResponseHelper.bad_request("Building already exists or could not be added!");
            }
            ObjectNode res = JsonUtils.createObjectNode();
            res.put("buid", building.getId());
            return AnyResponseHelper.ok(res, "Successfully added building!");
        } catch (DatasourceException e) {
            return AnyResponseHelper.internal_server_error("Server Internal Error [" + e.getMessage() + "]");
        }
    }

    public static Result buildingUpdateCoOwners() {
        OAuth2Request anyReq = new OAuth2Request(request(), response());
        if (!anyReq.assertJsonBody()) {
            return AnyResponseHelper.bad_request(AnyResponseHelper.CANNOT_PARSE_BODY_AS_JSON);
        }
        JsonNode json = anyReq.getJsonBody();
        LPLogger.info("AnyplaceMapping::buildingUpdateCoOwners(): " + json.toString());

        List<String> requiredMissing = JsonUtils.requirePropertiesInJson(json, "buid", "access_token", "co_owners");
        if (!requiredMissing.isEmpty()) {
            return AnyResponseHelper.requiredFieldsMissing(requiredMissing);
        }
        // get access token from url and check it against google's service
        if (json.findValue("access_token") == null) {
            return AnyResponseHelper.forbidden("Unauthorized");
        }
        String owner_id = verifyOwnerId(json.findValue("access_token").textValue());
        if (owner_id == null) {
            return AnyResponseHelper.forbidden("Unauthorized");
        }
        owner_id = appendToOwnerId(owner_id);
        ((ObjectNode) json).put("owner_id", owner_id);

        String buid = json.path("buid").textValue();

        try {
            ObjectNode stored_building = (ObjectNode) ProxyDataSource.getIDatasource().getFromKeyAsJson(buid);
            if (stored_building == null) {
                return AnyResponseHelper.bad_request("Building does not exist or could not be retrieved!");
            }

            if (!isBuildingOwner(stored_building, owner_id)) {
                return AnyResponseHelper.unauthorized("Unauthorized");
            }

            Building building = new Building(stored_building);
            if (!ProxyDataSource.getIDatasource().replaceJsonDocument(building.getId(), 0,
                    building.appendCoOwners(json))) {
                return AnyResponseHelper.bad_request("Building could not be updated!");
            }

            return AnyResponseHelper.ok("Successfully updated building!");
        } catch (DatasourceException e) {
            return AnyResponseHelper.internal_server_error("Server Internal Error [" + e.getMessage() + "]");
        }
    }

    public static Result buildingUpdateOwner() {
        OAuth2Request anyReq = new OAuth2Request(request(), response());
        if (!anyReq.assertJsonBody()) {
            return AnyResponseHelper.bad_request(AnyResponseHelper.CANNOT_PARSE_BODY_AS_JSON);
        }
        JsonNode json = anyReq.getJsonBody();
        LPLogger.info("AnyplaceMapping::buildingUpdateCoOwners(): " + json.toString());

        List<String> requiredMissing = JsonUtils.requirePropertiesInJson(json, "buid", "access_token", "new_owner");
        if (!requiredMissing.isEmpty()) {
            return AnyResponseHelper.requiredFieldsMissing(requiredMissing);
        }
        // get access token from url and check it against google's service
        if (json.findValue("access_token") == null) {
            return AnyResponseHelper.forbidden("Unauthorized");
        }
        String owner_id = verifyOwnerId(json.findValue("access_token").textValue());
        if (owner_id == null) {
            return AnyResponseHelper.forbidden("Unauthorized");
        }
        owner_id = appendToOwnerId(owner_id);
        ((ObjectNode) json).put("owner_id", owner_id);

        String buid = json.path("buid").textValue();

        String newOwner = json.path("new_owner").textValue();
        newOwner = appendToOwnerId(newOwner);

        try {
            ObjectNode stored_building = (ObjectNode) ProxyDataSource.getIDatasource().getFromKeyAsJson(buid);
            if (stored_building == null) {
                return AnyResponseHelper.bad_request("Building does not exist or could not be retrieved!");
            }

            if (!isBuildingOwner(stored_building, owner_id)) {
                return AnyResponseHelper.unauthorized("Unauthorized");
            }

            Building building = new Building(stored_building);
            if (!ProxyDataSource.getIDatasource().replaceJsonDocument(building.getId(), 0,
                    building.changeOwner(newOwner))) {
                return AnyResponseHelper.bad_request("Building could not be updated!");
            }

            return AnyResponseHelper.ok("Successfully updated building!");
        } catch (DatasourceException e) {
            return AnyResponseHelper.internal_server_error("Server Internal Error [" + e.getMessage() + "]");
        }
    }

    /**
     * Update the building information. Building to update is specified by buid
     *
     * @return
     */
    public static Result buildingUpdate() {
        OAuth2Request anyReq = new OAuth2Request(request(), response());
        if (!anyReq.assertJsonBody()) {
            return AnyResponseHelper.bad_request(AnyResponseHelper.CANNOT_PARSE_BODY_AS_JSON);
        }
        JsonNode json = anyReq.getJsonBody();
        LPLogger.info("AnyplaceMapping::buildingUpdate(): " + json.toString());

        List<String> requiredMissing = JsonUtils.requirePropertiesInJson(json, "buid", "access_token");
        if (!requiredMissing.isEmpty()) {
            return AnyResponseHelper.requiredFieldsMissing(requiredMissing);
        }
        // get access token from url and check it against google's service
        if (json.findValue("access_token") == null) {
            return AnyResponseHelper.forbidden("Unauthorized");
        }
        String owner_id = verifyOwnerId(json.findValue("access_token").textValue());
        if (owner_id == null) {
            return AnyResponseHelper.forbidden("Unauthorized");
        }
        owner_id = appendToOwnerId(owner_id);
        ((ObjectNode) json).put("owner_id", owner_id);

        String buid = json.path("buid").textValue();

        try {
            ObjectNode stored_building = (ObjectNode) ProxyDataSource.getIDatasource().getFromKeyAsJson(buid);
            if (stored_building == null) {
                return AnyResponseHelper.bad_request("Building does not exist or could not be retrieved!");
            }

            if (!isBuildingOwner(stored_building, owner_id)) {
                return AnyResponseHelper.unauthorized("Unauthorized");
            }

            // check for values to update
            if (json.findValue("is_published") != null) {
                String is_published = json.path("is_published").textValue();
                if (is_published.equals("true") || is_published.equals("false"))
                    stored_building.put("is_published", json.path("is_published").textValue());
            }
            if (json.findValue("name") != null) {
                stored_building.put("name", json.path("name").textValue());
            }
            if (json.findValue("bucode") != null) {
                stored_building.put("bucode", json.path("bucode").textValue());
            }
            if (json.findValue("description") != null) {
                stored_building.put("description", json.path("description").textValue());
            }
            if (json.findValue("url") != null) {
                stored_building.put("url", json.path("url").textValue());
            }
            if (json.findValue("address") != null) {
                stored_building.put("address", json.path("address").textValue());
            }
            if (json.findValue("coordinates_lat") != null) {
                stored_building.put("coordinates_lat", json.path("coordinates_lat").textValue());
            }
            if (json.findValue("coordinates_lon") != null) {
                stored_building.put("coordinates_lon", json.path("coordinates_lon").textValue());
            }

            AbstractModel building = new Building(stored_building);
            if (!ProxyDataSource.getIDatasource().replaceJsonDocument(building.getId(), 0,
                    building.toCouchGeoJSON())) {
                return AnyResponseHelper.bad_request("Building could not be updated!");
            }

            return AnyResponseHelper.ok("Successfully updated building!");
        } catch (DatasourceException e) {
            return AnyResponseHelper.internal_server_error("Server Internal Error [" + e.getMessage() + "]");
        }
    }

    /**
     * Delete the building specified by buid.
     *
     * @return
     */
    public static Result buildingDelete() {
        OAuth2Request anyReq = new OAuth2Request(request(), response());
        if (!anyReq.assertJsonBody()) {
            return AnyResponseHelper.bad_request(AnyResponseHelper.CANNOT_PARSE_BODY_AS_JSON);
        }
        JsonNode json = anyReq.getJsonBody();
        LPLogger.info("AnyplaceMapping::buildingDelete(): " + json.toString());

        List<String> requiredMissing = JsonUtils.requirePropertiesInJson(json, "buid", "access_token");
        if (!requiredMissing.isEmpty()) {
            return AnyResponseHelper.requiredFieldsMissing(requiredMissing);
        }

        // get access token from url and check it against google's service
        if (json.findValue("access_token") == null) {
            return AnyResponseHelper.forbidden("Unauthorized");
        }
        String owner_id = verifyOwnerId(json.findValue("access_token").textValue());
        if (owner_id == null) {
            return AnyResponseHelper.forbidden("Unauthorized");
        }
        owner_id = appendToOwnerId(owner_id);
        ((ObjectNode) json).put("owner_id", owner_id);

        String buid = json.findPath("buid").textValue();

        try {
            ObjectNode stored_building = (ObjectNode) ProxyDataSource.getIDatasource().getFromKeyAsJson(buid);
            if (stored_building == null) {
                return AnyResponseHelper.bad_request("Building does not exist or could not be retrieved!");
            }

            if (!isBuildingOwner(stored_building, owner_id)) {
                return AnyResponseHelper.unauthorized("Unauthorized");
            }

        } catch (DatasourceException e) {
            return AnyResponseHelper.internal_server_error("Server Internal Error [" + e.getMessage() + "]");
        }

        try {
            // we need to download the pois/floors/connections and all its connections and delete them all
            List<String> all_items_failed = ProxyDataSource.getIDatasource().deleteAllByBuilding(buid);
            if (all_items_failed.size() > 0) {
                // TODO - THINK WHAT TO DO WHEN DELETION FAILS ON SOME ITEMS

                // TODO - MARKING THEM INSIDE THE DB APPENDING A FLAG IN ORDER A TO MAKE THEM
                // TODO - ELIGIBLE FOR ANOTHER SERVICE THAT RUNS EVERY HOUR AND DELETES EVERYTHING

                ObjectNode obj = JsonUtils.createObjectNode();
                obj.put("ids", JsonUtils.getJsonFromList(all_items_failed));
                return AnyResponseHelper.bad_request(obj,
                        "Some items related to the deleted building could not be deleted: "
                                + all_items_failed.size() + " items.");
            }
        } catch (DatasourceException e) {
            return AnyResponseHelper.internal_server_error("Server Internal Error [" + e.getMessage() + "]");
        }

        // delete all the floor plans
        String filePath = AnyPlaceTilerHelper.getRootFloorPlansDirFor(buid);
        try {
            File buidfile = new File(filePath);
            if (buidfile.exists())
                HelperMethods.recDeleteDirFile(buidfile);
        } catch (IOException e) {
            // TODO - what to do on failure
            return AnyResponseHelper.internal_server_error("Server Internal Error [" + e.getMessage()
                    + "] while deleting floor plans." + "\nAll related information is deleted from the database!");
        }
        return AnyResponseHelper.ok("Successfully deleted everything related to building!");
    }

    /**
     * Retrieve all the buildings.
     *
     * @return
     */
    public static Result buildingAll() {
        OAuth2Request anyReq = new OAuth2Request(request(), response());
        if (!anyReq.assertJsonBody()) {
            return AnyResponseHelper.bad_request(AnyResponseHelper.CANNOT_PARSE_BODY_AS_JSON);
        }
        JsonNode json = anyReq.getJsonBody();
        LPLogger.info("AnyplaceMapping::buildingAll(): " + json.toString());

        try {
            List<JsonNode> buildings = ProxyDataSource.getIDatasource().getAllBuildings();
            ObjectNode res = JsonUtils.createObjectNode();
            res.put("buildings", JsonUtils.getJsonFromList(buildings));
            try {
                //                if (request().getHeader("Accept-Encoding") != null && request().getHeader("Accept-Encoding").contains("gzip")) {
                return gzippedJSONOk(res.toString());
                //                }
                //                return AnyResponseHelper.ok(res.toString());
            } catch (IOException ioe) {
                return AnyResponseHelper.ok(res, "Successfully retrieved all buildings!");
            }
        } catch (DatasourceException e) {
            return AnyResponseHelper.internal_server_error("Server Internal Error [" + e.getMessage() + "]");
        }
    }

    public static Result buildingGetOne() {
        OAuth2Request anyReq = new OAuth2Request(request(), response());
        if (!anyReq.assertJsonBody()) {
            return AnyResponseHelper.bad_request(AnyResponseHelper.CANNOT_PARSE_BODY_AS_JSON);
        }
        JsonNode json = anyReq.getJsonBody();
        LPLogger.info("AnyplaceMapping::buildingGet(): " + json.toString());

        List<String> requiredMissing = JsonUtils.requirePropertiesInJson(json, "buid");
        if (!requiredMissing.isEmpty()) {
            return AnyResponseHelper.requiredFieldsMissing(requiredMissing);
        }

        String buid = json.findPath("buid").textValue();

        try {
            JsonNode building = ProxyDataSource.getIDatasource().getFromKeyAsJson(buid);

            if (building != null && building.get("buid") != null && building.get("coordinates_lat") != null
                    && building.get("coordinates_lon") != null && building.get("owner_id") != null
                    && building.get("name") != null && building.get("description") != null
                    && building.get("puid") == null && building.get("floor_number") == null) {

                ((ObjectNode) building).remove("owner_id");
                ((ObjectNode) building).remove("co_owners");

                ObjectNode res = JsonUtils.createObjectNode();
                res.put("building", building);
                try {
                    //                    if (request().getHeader("Accept-Encoding") != null && request().getHeader("Accept-Encoding").contains("gzip")) {
                    return gzippedJSONOk(res.toString());
                    //                    }
                    //                    return AnyResponseHelper.ok(res.toString());
                } catch (IOException ioe) {
                    return AnyResponseHelper.ok(res, "Successfully retrieved all buildings!");
                }
            }

            return AnyResponseHelper.not_found("Building not found.");

        } catch (DatasourceException e) {
            return AnyResponseHelper.internal_server_error("Server Internal Error [" + e.getMessage() + "]");
        }
    }

    public static Result buildingAllByOwner() {
        OAuth2Request anyReq = new OAuth2Request(request(), response());
        if (!anyReq.assertJsonBody()) {
            return AnyResponseHelper.bad_request(AnyResponseHelper.CANNOT_PARSE_BODY_AS_JSON);
        }
        JsonNode json = anyReq.getJsonBody();
        LPLogger.info("AnyplaceMapping::buildingAll(): " + json.toString());

        List<String> requiredMissing = JsonUtils.requirePropertiesInJson(json, "access_token");
        if (!requiredMissing.isEmpty()) {
            return AnyResponseHelper.requiredFieldsMissing(requiredMissing);
        }

        // get access token from url and check it against google's service
        if (json.findValue("access_token") == null) {
            return AnyResponseHelper.forbidden("Unauthorized");
        }
        String owner_id = verifyOwnerId(json.findValue("access_token").textValue());
        if (owner_id == null) {
            return AnyResponseHelper.forbidden("Unauthorized");
        }
        owner_id = appendToOwnerId(owner_id);
        ((ObjectNode) json).put("owner_id", owner_id);

        if (owner_id == null || owner_id.isEmpty()) {
            return AnyResponseHelper.requiredFieldsMissing(requiredMissing);
        }

        try {
            List<JsonNode> buildings = ProxyDataSource.getIDatasource().getAllBuildingsByOwner(owner_id);
            ObjectNode res = JsonUtils.createObjectNode();
            res.put("buildings", JsonUtils.getJsonFromList(buildings));

            try {
                //                if (request().getHeader("Accept-Encoding") != null && request().getHeader("Accept-Encoding").contains("gzip")) {
                return gzippedJSONOk(res.toString());
                //                }
                //                return AnyResponseHelper.ok(res.toString());
            } catch (IOException ioe) {
                return AnyResponseHelper.ok(res, "Successfully retrieved all buildings!");
            }
        } catch (DatasourceException e) {
            return AnyResponseHelper.internal_server_error("Server Internal Error [" + e.getMessage() + "]");
        }
    }

    public static Result buildingByBucode() {
        OAuth2Request anyReq = new OAuth2Request(request(), response());
        if (!anyReq.assertJsonBody()) {
            return AnyResponseHelper.bad_request(AnyResponseHelper.CANNOT_PARSE_BODY_AS_JSON);
        }
        JsonNode json = anyReq.getJsonBody();
        LPLogger.info("AnyplaceMapping::buildingAll(): " + json.toString());

        List<String> requiredMissing = JsonUtils.requirePropertiesInJson(json, "bucode");
        if (!requiredMissing.isEmpty()) {
            return AnyResponseHelper.requiredFieldsMissing(requiredMissing);
        }

        String bucode = json.findValue("bucode").textValue();

        try {
            List<JsonNode> buildings = ProxyDataSource.getIDatasource().getAllBuildingsByBucode(bucode);
            ObjectNode res = JsonUtils.createObjectNode();
            res.put("buildings", JsonUtils.getJsonFromList(buildings));

            try {
                //                if (request().getHeader("Accept-Encoding") != null && request().getHeader("Accept-Encoding").contains("gzip")) {
                return gzippedJSONOk(res.toString());
                //                }
                //                return AnyResponseHelper.ok(res.toString());
            } catch (IOException ioe) {
                return AnyResponseHelper.ok(res, "Successfully retrieved all buildings!");
            }
        } catch (DatasourceException e) {
            return AnyResponseHelper.internal_server_error("Server Internal Error [" + e.getMessage() + "]");
        }
    }

    /**
     * Retrieve all the buildings that are inside the bounding box of the specified coordinates.
     *
     * @return
     */
    public static Result buildingCoordinates() {
        OAuth2Request anyReq = new OAuth2Request(request(), response());
        if (!anyReq.assertJsonBody()) {
            return AnyResponseHelper.bad_request(AnyResponseHelper.CANNOT_PARSE_BODY_AS_JSON);
        }
        JsonNode json = anyReq.getJsonBody();
        LPLogger.info("AnyplaceMapping::buildingCoordinates(): " + json.toString());

        List<String> requiredMissing = JsonUtils.requirePropertiesInJson(json, "coordinates_lat",
                "coordinates_lon");
        if (!requiredMissing.isEmpty()) {
            return AnyResponseHelper.requiredFieldsMissing(requiredMissing);
        }

        try {
            List<JsonNode> buildings = ProxyDataSource.getIDatasource().getAllBuildingsNearMe(
                    Double.parseDouble(json.path("coordinates_lat").textValue()),
                    Double.parseDouble(json.path("coordinates_lon").textValue()));
            ObjectNode res = JsonUtils.createObjectNode();
            res.put("buildings", JsonUtils.getJsonFromList(buildings));
            try {
                //                if (request().getHeader("Accept-Encoding") != null && request().getHeader("Accept-Encoding").contains("gzip")) {
                return gzippedJSONOk(res.toString());
                //                }
                //                return AnyResponseHelper.ok(res.toString());
            } catch (IOException ioe) {
                return AnyResponseHelper.ok(res, "Successfully retrieved all buildings near your position!");
            }
        } catch (DatasourceException e) {
            return AnyResponseHelper.internal_server_error("Server Internal Error [" + e.getMessage() + "]");
        }
    }

    /**
     * Adds a floor to the building denoted by buid
     *
     * @return
     */
    public static Result floorAdd() {
        OAuth2Request anyReq = new OAuth2Request(request(), response());
        if (!anyReq.assertJsonBody()) {
            return AnyResponseHelper.bad_request(AnyResponseHelper.CANNOT_PARSE_BODY_AS_JSON);
        }
        JsonNode json = anyReq.getJsonBody();
        LPLogger.info("AnyplaceMapping::floorAdd(): " + json.toString());

        List<String> requiredMissing = JsonUtils.requirePropertiesInJson(json, "is_published", "buid", "floor_name",
                "description", "floor_number", "access_token");
        if (!requiredMissing.isEmpty()) {
            return AnyResponseHelper.requiredFieldsMissing(requiredMissing);
        }

        // get access token from url and check it against google's service
        if (json.findValue("access_token") == null) {
            return AnyResponseHelper.forbidden("Unauthorized");
        }
        String owner_id = verifyOwnerId(json.findValue("access_token").textValue());
        if (owner_id == null) {
            return AnyResponseHelper.forbidden("Unauthorized");
        }
        owner_id = appendToOwnerId(owner_id);
        ((ObjectNode) json).put("owner_id", owner_id);

        String buid = json.path("buid").textValue();

        try {
            ObjectNode stored_building = (ObjectNode) ProxyDataSource.getIDatasource().getFromKeyAsJson(buid);
            if (stored_building == null) {
                return AnyResponseHelper.bad_request("Building does not exist or could not be retrieved!");
            }

            if (!isBuildingOwner(stored_building, owner_id)) {
                return AnyResponseHelper.unauthorized("Unauthorized");
            }

        } catch (DatasourceException e) {
            return AnyResponseHelper.internal_server_error("Server Internal Error [" + e.getMessage() + "]");
        }

        String floor_number = json.path("floor_number").textValue();

        if (!Floor.checkFloorNumberFormat(floor_number)) {
            return AnyResponseHelper.bad_request("Floor number cannot contain whitespace!");
        }

        try {
            Floor floor = new Floor(json);
            //System.out.println(floor.toValidCouchJson());
            if (!ProxyDataSource.getIDatasource().addJsonDocument(floor.getId(), 0, floor.toValidCouchJson())) {
                return AnyResponseHelper.bad_request("Floor already exists or could not be added!");
            }
            return AnyResponseHelper.ok("Successfully added floor " + floor_number + "!");
        } catch (DatasourceException e) {
            return AnyResponseHelper.internal_server_error("Server Internal Error [" + e.getMessage() + "]");
        }
    }

    /**
     * Update floor information ( floor name, description, is_published )
     *
     * @return
     */
    public static Result floorUpdate() {
        OAuth2Request anyReq = new OAuth2Request(request(), response());
        if (!anyReq.assertJsonBody()) {
            return AnyResponseHelper.bad_request(AnyResponseHelper.CANNOT_PARSE_BODY_AS_JSON);
        }
        JsonNode json = anyReq.getJsonBody();
        LPLogger.info("AnyplaceMapping::floorUpdate(): " + json.toString());

        List<String> requiredMissing = JsonUtils.requirePropertiesInJson(json, "buid", "floor_number",
                "access_token");
        if (!requiredMissing.isEmpty()) {
            return AnyResponseHelper.requiredFieldsMissing(requiredMissing);
        }

        // get access token from url and check it against google's service
        if (json.findValue("access_token") == null) {
            return AnyResponseHelper.forbidden("Unauthorized");
        }
        String owner_id = verifyOwnerId(json.findValue("access_token").textValue());
        if (owner_id == null) {
            return AnyResponseHelper.forbidden("Unauthorized");
        }
        owner_id = appendToOwnerId(owner_id);
        ((ObjectNode) json).put("owner_id", owner_id);

        String buid = json.path("buid").textValue();

        try {
            ObjectNode stored_building = (ObjectNode) ProxyDataSource.getIDatasource().getFromKeyAsJson(buid);
            if (stored_building == null) {
                return AnyResponseHelper.bad_request("Building does not exist or could not be retrieved!");
            }

            if (!isBuildingOwner(stored_building, owner_id)) {
                return AnyResponseHelper.unauthorized("Unauthorized");
            }

        } catch (DatasourceException e) {
            return AnyResponseHelper.internal_server_error("Server Internal Error [" + e.getMessage() + "]");
        }

        String floor_number = json.path("floor_number").textValue();

        if (!Floor.checkFloorNumberFormat(floor_number)) {
            return AnyResponseHelper.bad_request("Floor number cannot contain whitespace!");
        }

        try {
            String fuid = Floor.getId(buid, floor_number);
            ObjectNode stored_floor = (ObjectNode) ProxyDataSource.getIDatasource().getFromKeyAsJson(fuid);
            if (stored_floor == null) {
                return AnyResponseHelper.bad_request("Floor does not exist or could not be retrieved!");
            }

            // check for values to update
            if (json.findValue("is_published") != null) {
                stored_floor.put("is_published", json.path("is_published").textValue());
            }
            if (json.findValue("floor_name") != null) {
                stored_floor.put("floor_name", json.path("floor_name").textValue());
            }
            if (json.findValue("description") != null) {
                stored_floor.put("description", json.path("description").textValue());
            }

            AbstractModel floor = new Floor(stored_floor);
            if (!ProxyDataSource.getIDatasource().replaceJsonDocument(floor.getId(), 0, floor.toValidCouchJson())) {
                return AnyResponseHelper.bad_request("Floor could not be updated!");
            }

            return AnyResponseHelper.ok("Successfully updated floor!");
        } catch (DatasourceException e) {
            return AnyResponseHelper.internal_server_error("Server Internal Error [" + e.getMessage() + "]");
        }
    }

    /**
     * Delete the floor specified by buid and floor_number.
     *
     * @return
     */
    public static Result floorDelete() {
        OAuth2Request anyReq = new OAuth2Request(request(), response());
        if (!anyReq.assertJsonBody()) {
            return AnyResponseHelper.bad_request(AnyResponseHelper.CANNOT_PARSE_BODY_AS_JSON);
        }
        JsonNode json = anyReq.getJsonBody();
        LPLogger.info("AnyplaceMapping::floorDelete(): " + json.toString());

        List<String> requiredMissing = JsonUtils.requirePropertiesInJson(json, "buid", "floor_number",
                "access_token");

        if (!requiredMissing.isEmpty()) {
            return AnyResponseHelper.requiredFieldsMissing(requiredMissing);
        }

        // get access token from url and check it against google's service
        if (json.findValue("access_token") == null) {
            return AnyResponseHelper.forbidden("Unauthorized");
        }
        String owner_id = verifyOwnerId(json.findValue("access_token").textValue());
        if (owner_id == null) {
            return AnyResponseHelper.forbidden("Unauthorized");
        }
        owner_id = appendToOwnerId(owner_id);
        ((ObjectNode) json).put("owner_id", owner_id);

        String buid = json.findPath("buid").textValue();
        String floor_number = json.findPath("floor_number").textValue();

        try {
            ObjectNode stored_building = (ObjectNode) ProxyDataSource.getIDatasource().getFromKeyAsJson(buid);
            if (stored_building == null) {
                return AnyResponseHelper.bad_request("Building does not exist or could not be retrieved!");
            }

            if (!isBuildingOwner(stored_building, owner_id)) {
                return AnyResponseHelper.unauthorized("Unauthorized");
            }

        } catch (DatasourceException e) {
            return AnyResponseHelper.internal_server_error("Server Internal Error [" + e.getMessage() + "]");
        }

        try {
            // we need to download the pois/connections and all its connections and delete them all
            List<String> all_items_failed = ProxyDataSource.getIDatasource().deleteAllByFloor(buid, floor_number);
            if (all_items_failed.size() > 0) {
                // TODO - THINK WHAT TO DO WHEN DELETION FAILS ON SOME ITEMS

                // TODO - MARKING THEM INSIDE THE DB APPENDING A FLAG IN ORDER A TO MAKE THEM
                // TODO - ELIGIBLE FOR ANOTHER SERVICE THAT RUNS EVERY HOUR AND DELETES EVERYTHING

                ObjectNode obj = JsonUtils.createObjectNode();
                obj.put("ids", JsonUtils.getJsonFromList(all_items_failed));
                return AnyResponseHelper.bad_request(obj,
                        "Some items related to the deleted floor could not be deleted: " + all_items_failed.size()
                                + " items.");
            }
        } catch (DatasourceException e) {
            return AnyResponseHelper.internal_server_error("Server Internal Error [" + e.getMessage() + "]");
        }

        // delete the floor plan
        String filePath = AnyPlaceTilerHelper.getFloorPlanFor(buid, floor_number);
        try {
            File floorfile = new File(filePath);
            if (floorfile.exists())
                HelperMethods.recDeleteDirFile(floorfile);
        } catch (IOException e) {
            return AnyResponseHelper.internal_server_error("Server Internal Error [" + e.getMessage()
                    + "] while deleting floor plan." + "\nAll related information is deleted from the database!");
        }
        return AnyResponseHelper.ok("Successfully deleted everything related to the floor!");
    }

    /**
     * Retrieve all the floors of a building.
     *
     * @return
     */
    public static Result floorAll() {
        OAuth2Request anyReq = new OAuth2Request(request(), response());
        if (!anyReq.assertJsonBody()) {
            return AnyResponseHelper.bad_request(AnyResponseHelper.CANNOT_PARSE_BODY_AS_JSON);
        }
        JsonNode json = anyReq.getJsonBody();
        LPLogger.info("AnyplaceMapping::floorAll(): " + json.toString());

        List<String> requiredMissing = JsonUtils.requirePropertiesInJson(json, "buid");
        if (!requiredMissing.isEmpty()) {
            return AnyResponseHelper.requiredFieldsMissing(requiredMissing);
        }

        String buid = json.findPath("buid").textValue();

        try {
            List<JsonNode> buildings = ProxyDataSource.getIDatasource().floorsByBuildingAsJson(buid);
            ObjectNode res = JsonUtils.createObjectNode();
            res.put("floors", JsonUtils.getJsonFromList(buildings));
            try {
                //                if (request().getHeader("Accept-Encoding") != null && request().getHeader("Accept-Encoding").contains("gzip")) {
                return gzippedJSONOk(res.toString());
                //                }
                //                return AnyResponseHelper.ok(res.toString());
            } catch (IOException ioe) {
                return AnyResponseHelper.ok(res, "Successfully retrieved all floors!");
            }
        } catch (DatasourceException e) {
            return AnyResponseHelper.internal_server_error("Server Internal Error [" + e.getMessage() + "]");
        }
    }

    /**
     * Inserts a new Point of Interest at the coordinates passed in
     *
     * @return the newly created POIS ID is included in the response if success
     */
    public static Result poisAdd() {
        OAuth2Request anyReq = new OAuth2Request(request(), response());
        if (!anyReq.assertJsonBody()) {
            return AnyResponseHelper.bad_request(AnyResponseHelper.CANNOT_PARSE_BODY_AS_JSON);
        }
        JsonNode json = anyReq.getJsonBody();
        LPLogger.info("AnyplaceMapping::poisAdd(): " + json.toString());

        List<String> requiredMissing = JsonUtils.requirePropertiesInJson(json, "is_published", "buid", "floor_name",
                "floor_number", "name", "pois_type", "is_door", "is_building_entrance", "coordinates_lat",
                "coordinates_lon", "access_token");
        if (!requiredMissing.isEmpty()) {
            return AnyResponseHelper.requiredFieldsMissing(requiredMissing);
        }
        // get access token from url and check it against google's service
        if (json.findValue("access_token") == null) {
            return AnyResponseHelper.forbidden("Unauthorized");
        }
        String owner_id = verifyOwnerId(json.findValue("access_token").textValue());
        if (owner_id == null) {
            return AnyResponseHelper.forbidden("Unauthorized");
        }
        owner_id = appendToOwnerId(owner_id);
        ((ObjectNode) json).put("owner_id", owner_id);

        String buid = json.path("buid").textValue();

        try {
            ObjectNode stored_building = (ObjectNode) ProxyDataSource.getIDatasource().getFromKeyAsJson(buid);
            if (stored_building == null) {
                return AnyResponseHelper.bad_request("Building does not exist or could not be retrieved!");
            }

            if (!isBuildingOwner(stored_building, owner_id) && !isBuildingCoOwner(stored_building, owner_id)) {
                return AnyResponseHelper.unauthorized("Unauthorized");
            }

        } catch (DatasourceException e) {
            return AnyResponseHelper.internal_server_error("Server Internal Error [" + e.getMessage() + "]");
        }

        try {
            Poi poi = new Poi(json);
            //System.out.println(poi.toValidCouchJson());
            if (!ProxyDataSource.getIDatasource().addJsonDocument(poi.getId(), 0, poi.toCouchGeoJSON())) {
                return AnyResponseHelper.bad_request("Poi already exists or could not be added!");
            }
            ObjectNode res = JsonUtils.createObjectNode();
            res.put("puid", poi.getId());
            return AnyResponseHelper.ok(res, "Successfully added poi!");
        } catch (DatasourceException e) {
            return AnyResponseHelper.internal_server_error("Server Internal Error [" + e.getMessage() + "]");
        }
    }

    /**
     * Update the Point of Interest - specified by PUID - information
     *
     * @return
     */
    public static Result poisUpdate() {
        OAuth2Request anyReq = new OAuth2Request(request(), response());
        if (!anyReq.assertJsonBody()) {
            return AnyResponseHelper.bad_request(AnyResponseHelper.CANNOT_PARSE_BODY_AS_JSON);
        }
        JsonNode json = anyReq.getJsonBody();
        LPLogger.info("AnyplaceMapping::poisUpdate(): " + json.toString());

        List<String> requiredMissing = JsonUtils.requirePropertiesInJson(json, "puid", "buid", "access_token");
        if (!requiredMissing.isEmpty()) {
            return AnyResponseHelper.requiredFieldsMissing(requiredMissing);
        }
        // get access token from url and check it against google's service
        if (json.findValue("access_token") == null) {
            return AnyResponseHelper.forbidden("Unauthorized");
        }
        String owner_id = verifyOwnerId(json.findValue("access_token").textValue());
        if (owner_id == null) {
            return AnyResponseHelper.forbidden("Unauthorized");
        }
        owner_id = appendToOwnerId(owner_id);
        ((ObjectNode) json).put("owner_id", owner_id);

        String puid = json.path("puid").textValue();
        String buid = json.path("buid").textValue();

        try {
            ObjectNode stored_building = (ObjectNode) ProxyDataSource.getIDatasource().getFromKeyAsJson(buid);
            if (stored_building == null) {
                return AnyResponseHelper.bad_request("Building does not exist or could not be retrieved!");
            }

            if (!isBuildingOwner(stored_building, owner_id) && !isBuildingCoOwner(stored_building, owner_id)) {
                return AnyResponseHelper.unauthorized("Unauthorized");
            }

        } catch (DatasourceException e) {
            return AnyResponseHelper.internal_server_error("Server Internal Error [" + e.getMessage() + "]");
        }

        try {
            ObjectNode stored_poi = (ObjectNode) ProxyDataSource.getIDatasource().getFromKeyAsJson(puid);
            if (stored_poi == null) {
                return AnyResponseHelper.bad_request("Building does not exist or could not be retrieved!");
            }

            // check for values to update
            if (json.findValue("is_published") != null) {
                String is_published = json.path("is_published").textValue();
                if (is_published.equals("true") || is_published.equals("false"))
                    stored_poi.put("is_published", json.path("is_published").textValue());
            }
            if (json.findValue("name") != null) {
                stored_poi.put("name", json.path("name").textValue());
            }
            if (json.findValue("description") != null) {
                stored_poi.put("description", json.path("description").textValue());
            }
            if (json.findValue("url") != null) {
                stored_poi.put("url", json.path("url").textValue());
            }
            if (json.findValue("pois_type") != null) {
                stored_poi.put("pois_type", json.path("pois_type").textValue());
            }
            if (json.findValue("is_door") != null) {
                String is_door = json.path("is_door").textValue();
                if (is_door.equals("true") || is_door.equals("false"))
                    stored_poi.put("is_door", json.path("is_door").textValue());
            }
            if (json.findValue("is_building_entrance") != null) {
                String is_building_entrance = json.path("is_building_entrance").textValue();
                if (is_building_entrance.equals("true") || is_building_entrance.equals("false"))
                    stored_poi.put("is_building_entrance", json.path("is_building_entrance").textValue());
            }
            if (json.findValue("image") != null) {
                stored_poi.put("image", json.path("image").textValue());
            }

            if (json.findValue("coordinates_lat") != null) {
                stored_poi.put("coordinates_lat", json.path("coordinates_lat").textValue());
            }

            if (json.findValue("coordinates_lon") != null) {
                stored_poi.put("coordinates_lon", json.path("coordinates_lon").textValue());
            }

            AbstractModel poi = new Poi(stored_poi);
            if (!ProxyDataSource.getIDatasource().replaceJsonDocument(poi.getId(), 0, poi.toCouchGeoJSON())) {
                return AnyResponseHelper.bad_request("Poi could not be updated!");
            }

            return AnyResponseHelper.ok("Successfully updated poi!");
        } catch (DatasourceException e) {
            return AnyResponseHelper.internal_server_error("Server Internal Error [" + e.getMessage() + "]");
        }
    }

    /**
     * Delete the Point of Interest denoted by the requested POIS id
     *
     * @return
     */
    public static Result poisDelete() {
        OAuth2Request anyReq = new OAuth2Request(request(), response());
        if (!anyReq.assertJsonBody()) {
            return AnyResponseHelper.bad_request(AnyResponseHelper.CANNOT_PARSE_BODY_AS_JSON);
        }
        JsonNode json = anyReq.getJsonBody();
        LPLogger.info("AnyplaceMapping::poiDelete(): " + json.toString());

        List<String> requiredMissing = JsonUtils.requirePropertiesInJson(json, "puid", "buid", "access_token");
        if (!requiredMissing.isEmpty()) {
            return AnyResponseHelper.requiredFieldsMissing(requiredMissing);
        }
        // get access token from url and check it against google's service
        if (json.findValue("access_token") == null) {
            return AnyResponseHelper.forbidden("Unauthorized");
        }
        String owner_id = verifyOwnerId(json.findValue("access_token").textValue());
        if (owner_id == null) {
            return AnyResponseHelper.forbidden("Unauthorized");
        }
        owner_id = appendToOwnerId(owner_id);
        ((ObjectNode) json).put("owner_id", owner_id);

        String buid = json.findPath("buid").textValue();
        String puid = json.findPath("puid").textValue();

        try {
            ObjectNode stored_building = (ObjectNode) ProxyDataSource.getIDatasource().getFromKeyAsJson(buid);
            if (stored_building == null) {
                return AnyResponseHelper.bad_request("Building does not exist or could not be retrieved!");
            }

            if (!isBuildingOwner(stored_building, owner_id) && !isBuildingCoOwner(stored_building, owner_id)) {
                return AnyResponseHelper.unauthorized("Unauthorized");
            }

        } catch (DatasourceException e) {
            return AnyResponseHelper.internal_server_error("Server Internal Error [" + e.getMessage() + "]");
        }

        try {
            // we need to download the pois/floors/connections and all its connections and delete them all
            List<String> all_items_failed = ProxyDataSource.getIDatasource().deleteAllByPoi(puid);
            if (all_items_failed.size() > 0) {
                // TODO - THINK WHAT TO DO WHEN DELETION FAILS ON SOME ITEMS

                // TODO - MARKING THEM INSIDE THE DB APPENDING A FLAG IN ORDER A TO MAKE THEM
                // TODO - ELIGIBLE FOR ANOTHER SERVICE THAT RUNS EVERY HOUR AND DELETES EVERYTHING

                ObjectNode obj = JsonUtils.createObjectNode();
                obj.put("ids", JsonUtils.getJsonFromList(all_items_failed));
                return AnyResponseHelper.bad_request(obj,
                        "Some items related to the deleted poi could not be deleted: " + all_items_failed.size()
                                + " items.");
            }
            return AnyResponseHelper.ok("Successfully deleted everything related to the poi!");
        } catch (DatasourceException e) {
            return AnyResponseHelper.internal_server_error("Server Internal Error [" + e.getMessage() + "]");
        }
    }

    /**
     * Retrieve all the pois of a building/floor combination.
     *
     * @return
     */
    public static Result poisByFloor() {
        OAuth2Request anyReq = new OAuth2Request(request(), response());
        if (!anyReq.assertJsonBody()) {
            return AnyResponseHelper.bad_request(AnyResponseHelper.CANNOT_PARSE_BODY_AS_JSON);
        }
        JsonNode json = anyReq.getJsonBody();
        LPLogger.info("AnyplaceMapping::poisByFloor(): " + json.toString());

        List<String> requiredMissing = JsonUtils.requirePropertiesInJson(json, "buid", "floor_number");
        if (!requiredMissing.isEmpty()) {
            return AnyResponseHelper.requiredFieldsMissing(requiredMissing);
        }

        String buid = json.findPath("buid").textValue();
        String floor_number = json.findPath("floor_number").textValue();
        try {
            List<JsonNode> pois = ProxyDataSource.getIDatasource().poisByBuildingFloorAsJson(buid, floor_number);
            ObjectNode res = JsonUtils.createObjectNode();
            res.put("pois", JsonUtils.getJsonFromList(pois));
            try {
                //                if (request().getHeader("Accept-Encoding") != null && request().getHeader("Accept-Encoding").contains("gzip")) {
                return gzippedJSONOk(res.toString());
                //                }
                //                return AnyResponseHelper.ok(res.toString());
            } catch (IOException ioe) {
                return AnyResponseHelper.ok(res,
                        "Successfully retrieved all pois from floor " + floor_number + "!");
            }
        } catch (DatasourceException e) {
            return AnyResponseHelper.internal_server_error("Server Internal Error [" + e.getMessage() + "]");
        }
    }

    /**
     * Retrieve all the pois of a building/floor combination.
     *
     * @return
     */
    public static Result poisByBuid() {
        OAuth2Request anyReq = new OAuth2Request(request(), response());
        if (!anyReq.assertJsonBody()) {
            return AnyResponseHelper.bad_request(AnyResponseHelper.CANNOT_PARSE_BODY_AS_JSON);
        }
        JsonNode json = anyReq.getJsonBody();
        LPLogger.info("AnyplaceMapping::poisByBuid(): " + json.toString());

        List<String> requiredMissing = JsonUtils.requirePropertiesInJson(json, "buid");
        if (!requiredMissing.isEmpty()) {
            return AnyResponseHelper.requiredFieldsMissing(requiredMissing);
        }

        String buid = json.findPath("buid").textValue();
        try {
            List<JsonNode> pois = ProxyDataSource.getIDatasource().poisByBuildingAsJson(buid);
            ObjectNode res = JsonUtils.createObjectNode();
            res.put("pois", JsonUtils.getJsonFromList(pois));
            try {
                //                if (request().getHeader("Accept-Encoding") != null && request().getHeader("Accept-Encoding").contains("gzip")) {
                return gzippedJSONOk(res.toString());
                //                }
                //                return AnyResponseHelper.ok(res.toString());
            } catch (IOException ioe) {
                return AnyResponseHelper.ok(res, "Successfully retrieved all pois from building.");
            }
        } catch (DatasourceException e) {
            return AnyResponseHelper.internal_server_error("Server Internal Error [" + e.getMessage() + "]");
        }
    }

    /**
     * Adds a new connection between two valid Points of Interest - denoted by the pois_a and pois_b -
     *
     * @return
     */
    public static Result connectionAdd() {
        OAuth2Request anyReq = new OAuth2Request(request(), response());
        if (!anyReq.assertJsonBody()) {
            return AnyResponseHelper.bad_request(AnyResponseHelper.CANNOT_PARSE_BODY_AS_JSON);
        }
        JsonNode json = anyReq.getJsonBody();
        LPLogger.info("AnyplaceMapping::connectionAdd(): " + json.toString());

        List<String> requiredMissing = JsonUtils.requirePropertiesInJson(json, "is_published", "pois_a", "floor_a",
                "buid_a", "pois_b", "floor_b", "buid_b", "buid", "edge_type", "access_token");
        if (!requiredMissing.isEmpty()) {
            return AnyResponseHelper.requiredFieldsMissing(requiredMissing);
        }
        // get access token from url and check it against google's service
        if (json.findValue("access_token") == null) {
            return AnyResponseHelper.forbidden("Unauthorized");
        }
        String owner_id = verifyOwnerId(json.findValue("access_token").textValue());
        if (owner_id == null) {
            return AnyResponseHelper.forbidden("Unauthorized");
        }
        owner_id = appendToOwnerId(owner_id);
        ((ObjectNode) json).put("owner_id", owner_id);

        String buid1 = json.path("buid_a").textValue();
        String buid2 = json.path("buid_b").textValue();

        try {
            ObjectNode stored_building = (ObjectNode) ProxyDataSource.getIDatasource().getFromKeyAsJson(buid1);
            if (stored_building == null) {
                return AnyResponseHelper.bad_request("Building does not exist or could not be retrieved!");
            }

            if (!isBuildingOwner(stored_building, owner_id) && !isBuildingCoOwner(stored_building, owner_id)) {
                return AnyResponseHelper.unauthorized("Unauthorized");
            }

            stored_building = (ObjectNode) ProxyDataSource.getIDatasource().getFromKeyAsJson(buid2);
            if (stored_building == null) {
                return AnyResponseHelper.bad_request("Building does not exist or could not be retrieved!");
            }

            if (!isBuildingOwner(stored_building, owner_id) && !isBuildingCoOwner(stored_building, owner_id)) {
                return AnyResponseHelper.unauthorized("Unauthorized");
            }

        } catch (DatasourceException e) {
            return AnyResponseHelper.internal_server_error("Server Internal Error [" + e.getMessage() + "]");
        }

        String edge_type = json.path("edge_type").textValue();
        if (!edge_type.equals(Connection.EDGE_TYPE_ELEVATOR) && !edge_type.equals(Connection.EDGE_TYPE_HALLWAY)
                && !edge_type.equals(Connection.EDGE_TYPE_ROOM) && !edge_type.equals(Connection.EDGE_TYPE_OUTDOOR)
                && !edge_type.equals(Connection.EDGE_TYPE_STAIR)) {
            return AnyResponseHelper.bad_request("Invalid edge type specified.");
        }

        String pois_a = json.path("pois_a").textValue();
        String pois_b = json.path("pois_b").textValue();

        try {
            // Calculate the weight of the connection
            double weight = calculateWeightOfConnection(pois_a, pois_b);
            ((ObjectNode) json).put("weight", Double.toString(weight));
            if (edge_type.equals(Connection.EDGE_TYPE_ELEVATOR) || edge_type.equals(Connection.EDGE_TYPE_STAIR)) {
                // TODO - maybe we must put weight zero
                // TODO - or we must calculate the paths in each floor separately
            }

            Connection conn = new Connection(json);

            if (!ProxyDataSource.getIDatasource().addJsonDocument(conn.getId(), 0, conn.toValidCouchJson())) {
                return AnyResponseHelper.bad_request("Connection already exists or could not be added!");
            }
            ObjectNode res = JsonUtils.createObjectNode();
            res.put("cuid", conn.getId());
            return AnyResponseHelper.ok(res, "Successfully added new connection!");
        } catch (DatasourceException e) {
            return AnyResponseHelper.internal_server_error("Server Internal Error [" + e.getMessage() + "]");
        }
    }

    /**
     * Updates the edge_type of the connection between two Points of Interest - specified by pois_a and pois_b -
     *
     * @return
     */
    public static Result connectionUpdate() {
        OAuth2Request anyReq = new OAuth2Request(request(), response());
        if (!anyReq.assertJsonBody()) {
            return AnyResponseHelper.bad_request(AnyResponseHelper.CANNOT_PARSE_BODY_AS_JSON);
        }
        JsonNode json = anyReq.getJsonBody();
        LPLogger.info("AnyplaceMapping::connectionUpdate(): " + json.toString());

        List<String> requiredMissing = JsonUtils.requirePropertiesInJson(json, "pois_a", "pois_b", "buid_a",
                "buid_b", "access_token");
        if (!requiredMissing.isEmpty()) {
            return AnyResponseHelper.requiredFieldsMissing(requiredMissing);
        }
        // get access token from url and check it against google's service
        if (json.findValue("access_token") == null) {
            return AnyResponseHelper.forbidden("Unauthorized");
        }
        String owner_id = verifyOwnerId(json.findValue("access_token").textValue());
        if (owner_id == null) {
            return AnyResponseHelper.forbidden("Unauthorized");
        }
        owner_id = appendToOwnerId(owner_id);
        ((ObjectNode) json).put("owner_id", owner_id);

        String buid1 = json.path("buid_a").textValue();
        String buid2 = json.path("buid_b").textValue();

        try {
            ObjectNode stored_building = (ObjectNode) ProxyDataSource.getIDatasource().getFromKeyAsJson(buid1);
            if (stored_building == null) {
                return AnyResponseHelper.bad_request("Building does not exist or could not be retrieved!");
            }

            if (!isBuildingOwner(stored_building, owner_id) && !isBuildingCoOwner(stored_building, owner_id)) {
                return AnyResponseHelper.unauthorized("Unauthorized");
            }

            stored_building = (ObjectNode) ProxyDataSource.getIDatasource().getFromKeyAsJson(buid2);
            if (stored_building == null) {
                return AnyResponseHelper.bad_request("Building does not exist or could not be retrieved!");
            }

            if (!isBuildingOwner(stored_building, owner_id) && !isBuildingCoOwner(stored_building, owner_id)) {
                return AnyResponseHelper.unauthorized("Unauthorized");
            }

        } catch (DatasourceException e) {
            return AnyResponseHelper.internal_server_error("Server Internal Error [" + e.getMessage() + "]");
        }

        try {
            String pois_a = json.path("pois_a").textValue();
            String pois_b = json.path("pois_b").textValue();

            String cuid = Connection.getId(pois_a, pois_b);
            ObjectNode stored_conn = (ObjectNode) ProxyDataSource.getIDatasource().getFromKeyAsJson(cuid);
            if (stored_conn == null) {
                return AnyResponseHelper.bad_request("Connection does not exist or could not be retrieved!");
            }

            // check for values to update
            if (json.findValue("is_published") != null) {
                String is_published = json.path("is_published").textValue();
                if (is_published.equals("true") || is_published.equals("false"))
                    stored_conn.put("is_published", json.path("is_published").textValue());
            }
            if (json.findValue("edge_type") != null) {
                String edge_type = json.path("edge_type").textValue();
                if (!edge_type.equals(Connection.EDGE_TYPE_ELEVATOR)
                        && !edge_type.equals(Connection.EDGE_TYPE_HALLWAY)
                        && !edge_type.equals(Connection.EDGE_TYPE_ROOM)
                        && !edge_type.equals(Connection.EDGE_TYPE_OUTDOOR)
                        && !edge_type.equals(Connection.EDGE_TYPE_STAIR)) {
                    return AnyResponseHelper.bad_request("Invalid edge type specified.");
                }
                stored_conn.put("edge_type", edge_type);
            }

            Connection conn = new Connection(stored_conn);
            if (!ProxyDataSource.getIDatasource().replaceJsonDocument(conn.getId(), 0, conn.toValidCouchJson())) {
                return AnyResponseHelper.bad_request("Connection could not be updated!");
            }

            return AnyResponseHelper.ok("Successfully updated connection!");
        } catch (DatasourceException e) {
            return AnyResponseHelper.internal_server_error("Server Internal Error [" + e.getMessage() + "]");
        }
    }

    /**
     * Deletes the connection between two Points of Interest - denoted by pois_a and pois_b -
     *
     * @return
     */
    public static Result connectionDelete() {
        OAuth2Request anyReq = new OAuth2Request(request(), response());
        if (!anyReq.assertJsonBody()) {
            return AnyResponseHelper.bad_request(AnyResponseHelper.CANNOT_PARSE_BODY_AS_JSON);
        }
        JsonNode json = anyReq.getJsonBody();
        LPLogger.info("AnyplaceMapping::poiDelete(): " + json.toString());

        List<String> requiredMissing = JsonUtils.requirePropertiesInJson(json, "pois_a", "pois_b", "buid_a",
                "buid_b", "access_token");
        if (!requiredMissing.isEmpty()) {
            return AnyResponseHelper.requiredFieldsMissing(requiredMissing);
        }
        // get access token from url and check it against google's service
        if (json.findValue("access_token") == null) {
            return AnyResponseHelper.forbidden("Unauthorized");
        }
        String owner_id = verifyOwnerId(json.findValue("access_token").textValue());
        if (owner_id == null) {
            return AnyResponseHelper.forbidden("Unauthorized");
        }
        owner_id = appendToOwnerId(owner_id);
        ((ObjectNode) json).put("owner_id", owner_id);

        String buid1 = json.path("buid_a").textValue();
        String buid2 = json.path("buid_b").textValue();

        try {
            ObjectNode stored_building = (ObjectNode) ProxyDataSource.getIDatasource().getFromKeyAsJson(buid1);
            if (stored_building == null) {
                return AnyResponseHelper.bad_request("Building does not exist or could not be retrieved!");
            }
            if (!isBuildingOwner(stored_building, owner_id) && !isBuildingCoOwner(stored_building, owner_id)) {
                return AnyResponseHelper.unauthorized("Unauthorized");
            }

            stored_building = (ObjectNode) ProxyDataSource.getIDatasource().getFromKeyAsJson(buid2);
            if (stored_building == null) {
                return AnyResponseHelper.bad_request("Building does not exist or could not be retrieved!");
            }
            if (!isBuildingOwner(stored_building, owner_id) && !isBuildingCoOwner(stored_building, owner_id)) {
                return AnyResponseHelper.unauthorized("Unauthorized");
            }

        } catch (DatasourceException e) {
            return AnyResponseHelper.internal_server_error("Server Internal Error [" + e.getMessage() + "]");
        }

        String pois_a = json.path("pois_a").textValue();
        String pois_b = json.path("pois_b").textValue();
        try {
            String cuid = Connection.getId(pois_a, pois_b);
            // we need to download the pois/floors/connections and all its connections and delete them all
            List<String> all_items_failed = ProxyDataSource.getIDatasource().deleteAllByConnection(cuid);

            if (all_items_failed == null) {
                LPLogger.info("AnyplaceMapping::connectionDelete(): " + cuid + " not found.");
                return AnyResponseHelper.bad_request("POI Connection not found");
            }

            if (all_items_failed.size() > 0) {
                // TODO - THINK WHAT TO DO WHEN DELETION FAILS ON SOME ITEMS

                // TODO - MARKING THEM INSIDE THE DB APPENDING A FLAG IN ORDER A TO MAKE THEM
                // TODO - ELIGIBLE FOR ANOTHER SERVICE THAT RUNS EVERY HOUR AND DELETES EVERYTHING

                ObjectNode obj = JsonUtils.createObjectNode();
                obj.put("ids", JsonUtils.getJsonFromList(all_items_failed));
                return AnyResponseHelper.bad_request(obj,
                        "Some items related to the deleted connection could not be deleted: "
                                + all_items_failed.size() + " items.");
            }
            return AnyResponseHelper.ok("Successfully deleted everything related to the connection!");
        } catch (DatasourceException e) {
            return AnyResponseHelper.internal_server_error("Server Internal Error [" + e.getMessage() + "]");
        }
    }

    /**
     * Retrieve all the pois of a building/floor combination.
     *
     * @return
     */
    public static Result connectionsByFloor() {
        OAuth2Request anyReq = new OAuth2Request(request(), response());
        if (!anyReq.assertJsonBody()) {
            return AnyResponseHelper.bad_request(AnyResponseHelper.CANNOT_PARSE_BODY_AS_JSON);
        }
        JsonNode json = anyReq.getJsonBody();
        LPLogger.info("AnyplaceMapping::poisByFloor(): " + json.toString());

        List<String> requiredMissing = JsonUtils.requirePropertiesInJson(json, "buid", "floor_number");
        if (!requiredMissing.isEmpty()) {
            return AnyResponseHelper.requiredFieldsMissing(requiredMissing);
        }

        String buid = json.findPath("buid").textValue();
        String floor_number = json.findPath("floor_number").textValue();
        try {
            List<JsonNode> pois = ProxyDataSource.getIDatasource().connectionsByBuildingFloorAsJson(buid,
                    floor_number);
            ObjectNode res = JsonUtils.createObjectNode();
            res.put("connections", JsonUtils.getJsonFromList(pois));
            try {
                //                if (request().getHeader("Accept-Encoding") != null && request().getHeader("Accept-Encoding").contains("gzip")) {
                return gzippedJSONOk(res.toString());
                //                }
                //                return AnyResponseHelper.ok(res.toString());
            } catch (IOException ioe) {
                return AnyResponseHelper.ok(res,
                        "Successfully retrieved all pois from floor " + floor_number + "!");
            }
        } catch (DatasourceException e) {
            return AnyResponseHelper.internal_server_error("Server Internal Error [" + e.getMessage() + "]");
        }
    }

    private static double calculateWeightOfConnection(String pois_a, String pois_b) throws DatasourceException {

        double lat_a = 0, lon_a = 0, lat_b = 0, lon_b = 0;

        NumberFormat nf = NumberFormat.getInstance(Locale.ENGLISH);

        JsonNode pa = ProxyDataSource.getIDatasource().getFromKeyAsJson(pois_a);
        if (pa == null) {
            lat_a = 0.0;
            lon_a = 0.0;
        } else {
            // everything is ok
            try {
                lat_a = nf.parse(pa.path("coordinates_lat").textValue()).doubleValue();
                lon_a = nf.parse(pa.path("coordinates_lon").textValue()).doubleValue();
            } catch (ParseException e) {
                e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
            }
        }

        JsonNode pb = ProxyDataSource.getIDatasource().getFromKeyAsJson(pois_b);
        if (pb == null) {
            lat_b = 0.0;
            lon_b = 0.0;
        } else {
            // everything is ok
            try {
                lat_b = nf.parse(pb.path("coordinates_lat").textValue()).doubleValue();
                lon_b = nf.parse(pb.path("coordinates_lon").textValue()).doubleValue();
            } catch (ParseException e) {
                e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
            }
        }

        return GeoPoint.getDistanceBetweenPoints(lat_a, lon_a, lat_b, lon_b, "K");
    }

    /**
     * Returns the floor plan (png) for the requested building floor in binary format.
     * Used by the Android client  - NOT ANYMORE
     *
     * @param buid         Building id
     * @param floor_number floor number inside the above building
     * @return the file or an error
     */
    public static Result serveFloorPlanBinary(String buid, String floor_number) {
        OAuth2Request anyReq = new OAuth2Request(request(), response());
        if (!anyReq.assertJsonBody()) {
            return AnyResponseHelper.bad_request(AnyResponseHelper.CANNOT_PARSE_BODY_AS_JSON);
        }
        JsonNode json = anyReq.getJsonBody();
        LPLogger.info("AnyplaceMapping::serveFloorPlan(): " + json.toString());

        String filePath = AnyPlaceTilerHelper.getFloorPlanFor(buid, floor_number);
        LPLogger.info("requested: " + filePath);

        try {
            File file = new java.io.File(filePath);
            if (!file.exists() || !file.canRead()) {
                return AnyResponseHelper.bad_request(
                        "Requested floor plan does not exist or cannot be read! (" + floor_number + ")");
            }
            InputStream a = new FileInputStream(file);
            return ok(a);
        } catch (FileNotFoundException e) {
            // cannot get in here i think cause of the check if canRead()
            return AnyResponseHelper.internal_server_error("Could not read floor plan.");
        }
    }

    /**
     * Returns the floor plan tiles in a .zip file for the requested building floor.
     * Used by the Android client.
     *
     * @param buid         Building id
     * @param floor_number floor number inside the above building
     * @return the file or an error
     */
    public static Result serveFloorPlanTilesZip(String buid, String floor_number) {
        OAuth2Request anyReq = new OAuth2Request(request(), response());
        if (!anyReq.assertJsonBody()) {
            return AnyResponseHelper.bad_request(AnyResponseHelper.CANNOT_PARSE_BODY_AS_JSON);
        }
        JsonNode json = anyReq.getJsonBody();
        LPLogger.info("AnyplaceMapping::serveFloorPlanTilesZip(): " + json.toString());

        if (!Floor.checkFloorNumberFormat(floor_number)) {
            return AnyResponseHelper.bad_request("Floor number cannot contain whitespace!");
        }

        String filePath = AnyPlaceTilerHelper.getFloorTilesZipFor(buid, floor_number);
        LPLogger.info("requested: " + filePath);

        try {
            File file = new java.io.File(filePath);
            if (!file.exists() || !file.canRead()) {
                return AnyResponseHelper.bad_request(
                        "Requested floor plan does not exist or cannot be read! (" + floor_number + ")");
            }
            InputStream a = new FileInputStream(file);
            return ok(a);
        } catch (FileNotFoundException e) {
            // cannot get in here i think cause of the check if canRead()
            return AnyResponseHelper.internal_server_error("Could not read floor plan.");
        }
    }

    /**
     * Returns the floor plan tiles .zip file LINK for the requested building floor.
     * Used by the Developers API.
     *
     * @param buid         Building id
     * @param floor_number floor number inside the above building
     * @return the file or an error
     */
    public static Result serveFloorPlanTilesZipLink(String buid, String floor_number) {
        OAuth2Request anyReq = new OAuth2Request(request(), response());
        if (!anyReq.assertJsonBody()) {
            return AnyResponseHelper.bad_request(AnyResponseHelper.CANNOT_PARSE_BODY_AS_JSON);
        }
        JsonNode json = anyReq.getJsonBody();
        LPLogger.info("AnyplaceMapping::serveFloorPlanTilesZipLink(): " + json.toString());

        if (!Floor.checkFloorNumberFormat(floor_number)) {
            return AnyResponseHelper.bad_request("Floor number cannot contain whitespace!");
        }
        String filePath = AnyPlaceTilerHelper.getFloorTilesZipFor(buid, floor_number);

        LPLogger.info("requested: " + filePath);

        File file = new java.io.File(filePath);

        if (!file.exists() || !file.canRead()) {
            return AnyResponseHelper
                    .bad_request("Requested floor plan does not exist or cannot be read! (" + floor_number + ")");
        }

        ObjectNode res = JsonUtils.createObjectNode();
        res.put("tiles_archive", AnyPlaceTilerHelper.getFloorTilesZipLinkFor(buid, floor_number));

        return AnyResponseHelper.ok(res, "Successfully fetched link for the tiles archive!");
    }

    /**
     * Returns the file requested from inside the floor plan folder
     * for the requested building floor.
     * Used by web-clients.
     *
     * @param path The file to download
     * @return the file or an error
     */
    public static Result serveFloorPlanTilesStatic(String buid, String floor_number, String path) {
        //        OAuth2Request anyReq = new OAuth2Request(request(), response());
        //        if( !anyReq.assertJsonBody() ){
        //            return AnyResponseHelper.bad_request(AnyResponseHelper.CANNOT_PARSE_BODY_AS_JSON);
        //        }
        //        JsonNode json = anyReq.getJsonBody();
        //        LPLogger.info("AnyplaceMapping::serveFloorPlanTilesStatic(): " + json.toString());

        LPLogger.info("AnyplaceMapping::serveFloorPlanTilesStatic(): " + buid + ":" + floor_number + ":" + path);

        if (path == null || buid == null || floor_number == null || path.trim().isEmpty() || buid.trim().isEmpty()
                || floor_number.trim().isEmpty()) {
            return notFound();
        }

        String filePath;
        if (path.equals(AnyPlaceTilerHelper.FLOOR_TILES_ZIP_NAME)) {
            filePath = AnyPlaceTilerHelper.getFloorTilesZipFor(buid, floor_number);
        } else {
            filePath = AnyPlaceTilerHelper.getFloorTilesDirFor(buid, floor_number) + path;
        }

        LPLogger.info("static requested: " + filePath);

        try {
            File file = new java.io.File(filePath);
            if (!file.exists() || !file.canRead()) {
                return AnyResponseHelper.not_found("File requested not found");
            }
            InputStream a = new FileInputStream(file);
            return ok(a);
        } catch (FileNotFoundException e) {
            // cannot get in here i think cause of the check if canRead()
            return AnyResponseHelper.internal_server_error("Could not read floor plan.");
        }
    }

    /**
     * Returns the floorplan in base64 form. Used by the Anyplace websites
     *
     * @param buid
     * @param floor_number
     * @return
     */
    public static Result serveFloorPlanBase64(String buid, String floor_number) {
        OAuth2Request anyReq = new OAuth2Request(request(), response());
        if (!anyReq.assertJsonBody()) {
            return AnyResponseHelper.bad_request(AnyResponseHelper.CANNOT_PARSE_BODY_AS_JSON);
        }
        JsonNode json = anyReq.getJsonBody();
        LPLogger.info("AnyplaceMapping::serveFloorPlanBase64(): " + json.toString());

        String filePath = AnyPlaceTilerHelper.getFloorPlanFor(buid, floor_number);
        LPLogger.info("requested: " + filePath);

        File file = new java.io.File(filePath);
        try {
            if (!file.exists() || !file.canRead()) {
                return AnyResponseHelper.bad_request(
                        "Requested floor plan does not exist or cannot be read! (" + floor_number + ")");
            }
            try {
                String s = encodeFileToBase64Binary(filePath);
                try {
                    //                    if (request().getHeader("Accept-Encoding") != null && request().getHeader("Accept-Encoding").contains("gzip")) {
                    return gzippedOk(s);
                    //                    }
                    //                    return AnyResponseHelper.ok(s);
                } catch (IOException ioe) {
                    return ok(s);
                }
            } catch (IOException e) {
                return AnyResponseHelper.bad_request(
                        "Requested floor plan cannot be encoded in base64 properly! (" + floor_number + ")");
            }
        } catch (Exception e) {
            // cannot get in here i think cause of the check if canRead()
            return AnyResponseHelper.internal_server_error("Unknown server error during floor plan delivery!");
        }
    }

    private static String encodeFileToBase64Binary(String fileName) throws IOException {

        File file = new File(fileName);
        byte[] bytes = loadFile(file);
        byte[] encoded = Base64.encodeBase64(bytes);
        String encodedString = new String(encoded);

        return encodedString;
    }

    private static byte[] loadFile(File file) throws IOException, FileNotFoundException {
        InputStream is = new FileInputStream(file);

        long length = file.length();
        if (length > Integer.MAX_VALUE) {
            // File is too large
        }
        byte[] bytes = new byte[(int) length];

        int offset = 0;
        int numRead = 0;
        while (offset < bytes.length && (numRead = is.read(bytes, offset, bytes.length - offset)) >= 0) {
            offset += numRead;
        }

        if (offset < bytes.length) {
            throw new IOException("Could not completely read file " + file.getName());
        }

        is.close();
        return bytes;
    }

    /**
     * Uploads a floor plan file and stores it at the server system.
     * If another floorplan exists for this floor we overwrite it.
     * <p>
     * Needs a field:
     * floorplan: the floor plan file
     * json: The json document
     *
     * @return
     */
    public static Result floorPlanUpload() {
        OAuth2Request anyReq = new OAuth2Request(request(), response());

        Http.MultipartFormData body = anyReq.getMultipartFormData();
        if (body == null) {
            return AnyResponseHelper.bad_request("Invalid request type - Not Multipart!");
        }

        Http.MultipartFormData.FilePart floorplan;
        floorplan = body.getFile("floorplan");
        if (floorplan == null) {
            return AnyResponseHelper.bad_request("Cannot find the floor plan file in your request!");
        }

        Map<String, String[]> urlenc = body.asFormUrlEncoded();
        String json_str = urlenc.get("json")[0];
        //System.out.println("json: " + json_str);

        if (json_str == null) {
            return AnyResponseHelper.bad_request("Cannot find json in the request!");
        }

        JsonNode json = null;
        try {
            json = JsonUtils.getJsonTree(json_str);
        } catch (IOException e) {
            return AnyResponseHelper.bad_request("Cannot parse json in the request!");
        }
        LPLogger.info("Floorplan Request[json]: " + json.toString());
        LPLogger.info("Floorplan Request[floorplan]: " + floorplan.getFile().getAbsolutePath());

        //// Request has the required parts so now process the json data
        List<String> requiredMissing = JsonUtils.requirePropertiesInJson(json, "buid", "floor_number",
                "bottom_left_lat", "bottom_left_lng", "top_right_lat", "top_right_lng");
        if (!requiredMissing.isEmpty()) {
            return AnyResponseHelper.requiredFieldsMissing(requiredMissing);
        }

        String buid = json.path("buid").textValue();
        String floor_number = json.path("floor_number").textValue();

        String bottom_left_lat = json.path("bottom_left_lat").textValue();
        String bottom_left_lng = json.path("bottom_left_lng").textValue();
        String top_right_lat = json.path("top_right_lat").textValue();
        String top_right_lng = json.path("top_right_lng").textValue();

        String fuid = Floor.getId(buid, floor_number);
        try {
            ObjectNode stored_floor = (ObjectNode) ProxyDataSource.getIDatasource().getFromKeyAsJson(fuid);
            if (stored_floor == null) {
                return AnyResponseHelper.bad_request("Floor does not exist or could not be retrieved!");
            }

            // update the Floor document in couchbase to include the floor plan's coordinates
            stored_floor.put("bottom_left_lat", bottom_left_lat);
            stored_floor.put("bottom_left_lng", bottom_left_lng);
            stored_floor.put("top_right_lat", top_right_lat);
            stored_floor.put("top_right_lng", top_right_lng);

            if (!ProxyDataSource.getIDatasource().replaceJsonDocument(fuid, 0, stored_floor.toString())) {
                return AnyResponseHelper.bad_request("Floor plan could not be updated in the database!");
            }
        } catch (DatasourceException e) {
            return AnyResponseHelper.internal_server_error("Error while reading from our backend service!");
        }

        /////////////////////////////////////////////////////////////////////////////////////////////
        // store the new floor plan on the server
        File floor_file;
        try {
            floor_file = AnyPlaceTilerHelper.storeFloorPlanToServer(buid, floor_number, floorplan.getFile());
        } catch (AnyPlaceException e) {
            // TODO - I should put the old couchbase object in the database
            return AnyResponseHelper.bad_request("Cannot save floor plan on the server!");
        }

        /////////////////////////////////////////////////////////////////////////////////////////////
        // Now we should start the tiling process in order to create the tiles for the floor plan
        String top_left_lat = top_right_lat;
        String top_left_lng = bottom_left_lng;
        try {
            AnyPlaceTilerHelper.tileImage(floor_file, top_left_lat, top_left_lng);
        } catch (AnyPlaceException e) {
            // TODO - I should put the old couchbase object in the database
            return AnyResponseHelper.bad_request("Could not create floor plan tiles on the server!");
        }

        LPLogger.info("Successfully tiled [" + floor_file.toString() + "]");
        return AnyResponseHelper.ok("Successfully updated floor plan!");
    }

    public static Result addAccount() {
        // create the Request and check it
        OAuth2Request anyReq = new OAuth2Request(request(), response());
        if (!anyReq.assertJsonBody()) {
            return AnyResponseHelper.bad_request(AnyResponseHelper.CANNOT_PARSE_BODY_AS_JSON);
        }
        JsonNode json = anyReq.getJsonBody();
        LPLogger.info("AnyplaceAccounts::addAccount():: ");

        // check if there is any required parameter missing
        List<String> notFound = JsonUtils.requirePropertiesInJson(json, "access_token", "type");
        if (!notFound.isEmpty()) {
            return AnyResponseHelper.requiredFieldsMissing(notFound);
        }

        // get access token from url and check it against google's service
        if (json.findValue("access_token") == null) {
            return AnyResponseHelper.forbidden("Unauthorized");
        }
        String owner_id = verifyOwnerId(json.findValue("access_token").textValue());
        if (owner_id == null) {
            return AnyResponseHelper.forbidden("Unauthorized");
        }
        owner_id = appendToOwnerId(owner_id);
        ((ObjectNode) json).put("owner_id", owner_id);

        Account newAccount = new Account(json);
        try {
            if (!ProxyDataSource.getIDatasource().addJsonDocument(newAccount.getId(), 0,
                    newAccount.toValidCouchJson())) {
                return AnyResponseHelper.ok("Returning user.");
            }
            ObjectNode res = JsonUtils.createObjectNode();
            return AnyResponseHelper.ok("New user.");
        } catch (DatasourceException e) {
            return AnyResponseHelper.internal_server_error("Server Internal Error [" + e.getMessage() + "]");
        }
    }

    private static boolean isBuildingOwner(ObjectNode building, String userId) {

        // Check if owner
        if (building != null && building.get("owner_id") != null
                && building.get("owner_id").textValue().equals(userId)) {
            return true;
        }

        return false;
    }

    private static boolean isBuildingCoOwner(ObjectNode building, String userId) {

        JsonNode cws = null;

        if (building != null && (cws = building.get("co_owners")) != null) {
            Iterator<JsonNode> it = cws.elements();
            while (it.hasNext()) {
                if (it.next().textValue().equals(userId)) {
                    return true;
                }
            }
        }

        return false;
    }

    // TODO: Move to util class

    /**
     * Should check if Request Headers accept gzip encoding
     * <p>
     * Creates a response with a gzipped string. Changes the content-type.
     */
    private static Results.Status gzippedJSONOk(final String body) throws IOException {
        final ByteArrayOutputStream gzip = gzip(body);
        response().setHeader("Content-Encoding", "gzip");
        response().setHeader("Content-Length", gzip.size() + "");
        response().setHeader("Content-Type", "application/json");
        return ok(gzip.toByteArray());
    }

    private static Results.Status gzippedOk(final String body) throws IOException {
        final ByteArrayOutputStream gzip = gzip(body);
        response().setHeader("Content-Encoding", "gzip");
        response().setHeader("Content-Length", gzip.size() + "");
        return ok(gzip.toByteArray());
    }

    //solution from James Ward for Play 1 and every request: https://gist.github.com/1317626
    private static ByteArrayOutputStream gzip(final String input) throws IOException {
        final InputStream inputStream = new ByteArrayInputStream(input.getBytes());
        final ByteArrayOutputStream stringOutputStream = new ByteArrayOutputStream((int) (input.length() * 0.75));
        final OutputStream gzipOutputStream = new GZIPOutputStream(stringOutputStream);

        final byte[] buf = new byte[5000];
        int len;
        while ((len = inputStream.read(buf)) > 0) {
            gzipOutputStream.write(buf, 0, len);
        }

        inputStream.close();
        gzipOutputStream.close();

        return stringOutputStream;
    }

}