/*
 * This source file is subject to the license that is bundled with this package in the file LICENSE.
 */
package com.montealegreluis.yelpv3;

import org.apache.http.impl.client.HttpClientBuilder;
import org.json.JSONArray;
import org.json.JSONObject;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Yelp {
    private final String clientId;
    private final String clientSecret;
    private final YelpClient yelpClient;
    private final YelpURIs yelpURIs;
    private AccessToken token;

    public Yelp(String clientId, String clientSecret) {
        yelpClient = new YelpClient(HttpClientBuilder.create().build());
        yelpURIs = new YelpURIs();
        this.clientId = clientId;
        this.clientSecret = clientSecret;
    }

    public Yelp(String clientID, String clientSecret, AccessToken token) {
        this(clientID, clientSecret);
        this.token = token;
    }

    public AccessToken token() {
        if (token == null) authenticate();

        return token;
    }

    public List<Business> search(SearchCriteria criteria) {
        try {
            yelpClient.getFrom(yelpURIs.searchBy(criteria), accessToken());
            return parseResults(new JSONObject(yelpClient.responseBody()));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public Business searchById(String id) {
        try {
            yelpClient.getFrom(yelpURIs.businessBy(id), accessToken());
            return Business.from(new JSONObject(yelpClient.responseBody()));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    private void authenticate() {
        try {
            yelpClient.postTo(yelpURIs.authentication(), authenticationParameters());
            token = createAccessToken(yelpClient.responseBody());
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    private String accessToken() {
        if (token == null || token.isExpired()) authenticate();

        return token.accessToken();
    }

    private List<Business> parseResults(JSONObject results) {
        List<Business> businesses = new ArrayList<>();
        JSONArray jsonArray = results.getJSONArray("businesses");

        for (int i = 0; i < jsonArray.length(); i++)
            businesses.add(Business.from(jsonArray.getJSONObject(i)));

        return businesses;
    }

    private AccessToken createAccessToken(String jsonResponse) throws IOException {
        JSONObject token = new JSONObject(jsonResponse);

        return AccessToken.fromYELP(
            token.getString("access_token"),
            token.getString("token_type"),
            token.getLong("expires_in")
        );
    }

    private Map<String, String> authenticationParameters() throws UnsupportedEncodingException {
        Map<String, String> parameters = new HashMap<>();
        parameters.put("grant_type", "client_credentials");
        parameters.put("client_id", clientId);
        parameters.put("client_secret", clientSecret);
        return parameters;
    }
}

@@ -693,20 +693,73 @@
     
-yelpClient =
+this(%0A            clientId,%0A            clientSecret,%0A           
  new
@@ -805,17 +805,17 @@
 build())
-;
+,
 %0A       
@@ -819,34 +819,290 @@
     
-yelpURIs = new YelpURIs();
+    new YelpURIs()%0A        );%0A    %7D%0A%0A    public Yelp(String clientID, String clientSecret, AccessToken token) %7B%0A        this(clientID, clientSecret);%0A        this.token = token;%0A    %7D%0A%0A    public Yelp(String clientId, String clientSecret, YelpClient yelpClient, YelpURIs yelpURIs) %7B
 %0A   
@@ -1170,24 +1170,96 @@
 ientSecret;%0A
+        this.yelpClient = yelpClient;%0A        this.yelpURIs = yelpURIs;%0A
     %7D%0A%0A    p
@@ -1261,32 +1261,41 @@
     public Yelp(
+%0A        
 String clientID,
@@ -1284,34 +1284,42 @@
   String clientI
-D,
+d,%0A       
  String clientSe
@@ -1315,32 +1315,98 @@
 ng clientSecret,
+%0A        YelpClient yelpClient,%0A        YelpURIs yelpURIs,%0A       
  AccessToken tok
@@ -1399,32 +1399,37 @@
 ccessToken token
+%0A    
 ) %7B%0A        this
@@ -1428,33 +1428,33 @@
     this(clientI
-D
+d
 , clientSecret);
@@ -1443,32 +1443,54 @@
 Id, clientSecret
+, yelpClient, yelpURIs
 );%0A        this.

Allow the injection of client and urls