// Path: src/main/java/com/lookfirst/wepay/api/Token.java
// @Data
// public class Token implements Serializable {
// 	private static final long serialVersionUID = 1L;
// 
// 	/** The unique user ID of the user */
// 	private String userId;
// 	/** The access token that you can use to make calls on behalf of the user */
// 	private String accessToken;
// 	/** The token type - for now only "BEARER" is supported */
// 	private String tokenType;
// 	/** How much time till the access_token expires. If NULL or not present, the access token will be valid until the user revokes the access_token */
// 	private String expiresIn;
// }
// 
// Path: src/main/java/com/lookfirst/wepay/api/req/TokenRequest.java
// @Data
// @EqualsAndHashCode(callSuper=false)
// public class TokenRequest extends WePayRequest<Token> {
// 
// 	public static final String ENDPOINT = "/oauth2/token";
// 
// 	/** Yes	The client ID issued to the app by WePay - see your client ID on your app screen */
// 	private Long clientId;
// 	/** Yes	The uri the user will be redirected to after authorization. Must be the same as passed in /v2/oauth2/authorize */
// 	private String redirectUri;
// 	/** Yes	The client secret issued to the app by WePay - see your client secret on your app screen */
// 	private String clientSecret;
// 	/** Yes	The code returned by /v2/oauth2/authorize */
// 	private String code;
// 
// 	/** */
// 	@Override
// 	public String getEndpoint() {
// 		return "/oauth2/token";
// 	}
// 
// }
// 
// Path: src/main/java/com/lookfirst/wepay/api/req/WePayRequest.java
// public abstract class WePayRequest<T> {
// 	@JsonIgnore
// 	public abstract String getEndpoint();
// }
// 
// Path: src/main/java/com/lookfirst/wepay/util/DataProvider.java
// public interface DataProvider {
// 	InputStream getData(String uri, String postJson, String token) throws IOException;
// }


import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.lookfirst.wepay.api.Token;
import com.lookfirst.wepay.api.req.TokenRequest;
import com.lookfirst.wepay.api.req.WePayRequest;
import com.lookfirst.wepay.util.DataProvider;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.ParameterizedType;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.List;
package com.lookfirst.wepay;



/**
 * Implements a way to communicate with the WePayApi.
 *
 * https://www.wepay.com/developer/reference
 *
 * @author Jon Scott Stevens
 * @author Jeff Schnitzer
 */
@Slf4j
@NoArgsConstructor
public class WePayApi {

	/**
	 * Scope fields
	 * Passed into Wepay::getAuthorizationUri as array
	 *
	 * https://stage.wepay.com/developer/reference/permissions
	 */
	@AllArgsConstructor
	public enum Scope {
		MANAGE_ACCOUNTS		("manage_accounts"),	// Open and interact with accounts
		VIEW_BALANCE		("view_balance"),		// View account balances
		COLLECT_PAYMENTS	("collect_payments"),	// Create and interact with checkouts
		REFUND_PAYMENTS		("refund_payments"),	// Refund checkouts
		VIEW_USER			("view_user"),			// Get details about authenticated user
		PREAPPROVE_PAYMENTS	("preapprove_payments"),// preapproval
		SEND_MONEY			("send_money");			// /disbursement & /transfer

		private String scope;

		public static List<Scope> getAll() {
			return Arrays.asList(values());
		}

		public String toString() {
			return scope;
		}
	}

	/** */
	public static final ObjectMapper MAPPER = new ObjectMapper();
	static {
		// For the UserDetails bean (an others), we send an empty bean.
		MAPPER.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
		// Makes for nice java property/method names
		MAPPER.setPropertyNamingStrategy(PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES);
		// If wepay adds properties, we shouldn't blow up
		MAPPER.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
		// Don't send null properties to wepay
		MAPPER.setSerializationInclusion(JsonInclude.Include.NON_NULL);

		// This saves us the mess of enums that conflict with java keywords (eg Checkout.State.new_)
		MAPPER.enable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING);
		MAPPER.enable(DeserializationFeature.READ_ENUMS_USING_TO_STRING);
	}

	/** */
	private static final String STAGING_URL = "https://stage.wepayapi.com/v2";
	private static final String PROD_URL = "https://wepayapi.com/v2";

	/** */
	private String currentUrl;

	/** */
	@Getter @Setter
	private WePayKey key;

	/** Timeout in milliseconds */
	@Getter @Setter
	int timeout;

	/** Number of retries if the connection fails */
	@Getter @Setter
	int retries;

	/** For unit testing. */
// Path: src/main/java/com/lookfirst/wepay/api/Token.java
// @Data
// public class Token implements Serializable {
// 	private static final long serialVersionUID = 1L;
// 
// 	/** The unique user ID of the user */
// 	private String userId;
// 	/** The access token that you can use to make calls on behalf of the user */
// 	private String accessToken;
// 	/** The token type - for now only "BEARER" is supported */
// 	private String tokenType;
// 	/** How much time till the access_token expires. If NULL or not present, the access token will be valid until the user revokes the access_token */
// 	private String expiresIn;
// }
// 
// Path: src/main/java/com/lookfirst/wepay/api/req/TokenRequest.java
// @Data
// @EqualsAndHashCode(callSuper=false)
// public class TokenRequest extends WePayRequest<Token> {
// 
// 	public static final String ENDPOINT = "/oauth2/token";
// 
// 	/** Yes	The client ID issued to the app by WePay - see your client ID on your app screen */
// 	private Long clientId;
// 	/** Yes	The uri the user will be redirected to after authorization. Must be the same as passed in /v2/oauth2/authorize */
// 	private String redirectUri;
// 	/** Yes	The client secret issued to the app by WePay - see your client secret on your app screen */
// 	private String clientSecret;
// 	/** Yes	The code returned by /v2/oauth2/authorize */
// 	private String code;
// 
// 	/** */
// 	@Override
// 	public String getEndpoint() {
// 		return "/oauth2/token";
// 	}
// 
// }
// 
// Path: src/main/java/com/lookfirst/wepay/api/req/WePayRequest.java
// public abstract class WePayRequest<T> {
// 	@JsonIgnore
// 	public abstract String getEndpoint();
// }
// 
// Path: src/main/java/com/lookfirst/wepay/util/DataProvider.java
// public interface DataProvider {
// 	InputStream getData(String uri, String postJson, String token) throws IOException;
// }


// Path: src/main/java/com/lookfirst/wepay/WePayApi.java
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.lookfirst.wepay.api.Token;
import com.lookfirst.wepay.api.req.TokenRequest;
import com.lookfirst.wepay.api.req.WePayRequest;
import com.lookfirst.wepay.util.DataProvider;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.ParameterizedType;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.List;

package com.lookfirst.wepay;



/**
 * Implements a way to communicate with the WePayApi.
 *
 * https://www.wepay.com/developer/reference
 *
 * @author Jon Scott Stevens
 * @author Jeff Schnitzer
 */
@Slf4j
@NoArgsConstructor
public class WePayApi {

	/**
	 * Scope fields
	 * Passed into Wepay::getAuthorizationUri as array
	 *
	 * https://stage.wepay.com/developer/reference/permissions
	 */
	@AllArgsConstructor
	public enum Scope {
		MANAGE_ACCOUNTS		("manage_accounts"),	// Open and interact with accounts
		VIEW_BALANCE		("view_balance"),		// View account balances
		COLLECT_PAYMENTS	("collect_payments"),	// Create and interact with checkouts
		REFUND_PAYMENTS		("refund_payments"),	// Refund checkouts
		VIEW_USER			("view_user"),			// Get details about authenticated user
		PREAPPROVE_PAYMENTS	("preapprove_payments"),// preapproval
		SEND_MONEY			("send_money");			// /disbursement & /transfer

		private String scope;

		public static List<Scope> getAll() {
			return Arrays.asList(values());
		}

		public String toString() {
			return scope;
		}
	}

	/** */
	public static final ObjectMapper MAPPER = new ObjectMapper();
	static {
		// For the UserDetails bean (an others), we send an empty bean.
		MAPPER.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
		// Makes for nice java property/method names
		MAPPER.setPropertyNamingStrategy(PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES);
		// If wepay adds properties, we shouldn't blow up
		MAPPER.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
		// Don't send null properties to wepay
		MAPPER.setSerializationInclusion(JsonInclude.Include.NON_NULL);

		// This saves us the mess of enums that conflict with java keywords (eg Checkout.State.new_)
		MAPPER.enable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING);
		MAPPER.enable(DeserializationFeature.READ_ENUMS_USING_TO_STRING);
	}

	/** */
	private static final String STAGING_URL = "https://stage.wepayapi.com/v2";
	private static final String PROD_URL = "https://wepayapi.com/v2";

	/** */
	private String currentUrl;

	/** */
	@Getter @Setter
	private WePayKey key;

	/** Timeout in milliseconds */
	@Getter @Setter
	int timeout;

	/** Number of retries if the connection fails */
	@Getter @Setter
	int retries;

	/** For unit testing. */
	private DataProvider dataProvider;