package org.maxkey.client.oauth.model;

import java.io.*;
import java.util.Map;

import org.maxkey.client.utils.Preconditions;

/**
 * Represents an OAuth 2 Access token.
 * <p>
 * http://tools.ietf.org/html/rfc6749#section-5.1
 *
 * @see <a href="https://tools.ietf.org/html/rfc6749#section-4.1.4">OAuth 2 Access Token Specification</a></p>
 */
public class Token implements Serializable {
	private static final long serialVersionUID = 715000866082812683L;

	/*
	 * for return from Provider
	 */
	private  String rawResponse;
	private  Map<String, Object> responseObject;

	/*
	 * for OAuth 1.0a & OAuth 2.0
	 */
	/**
     * access_token
     * <p>
     * REQUIRED. The access token issued by the authorization server.</p>
     */
	private String access_token;
	
	private String token;
	private String secret;
	/**
     * refresh_token
     * <p>
     * OPTIONAL. The refresh token, which can be used to obtain new access tokens using the same authorization grant as
     * described in http://tools.ietf.org/html/rfc6749#section-6</p>
     */
	private String refresh_token;
	/**
     * expires_in
     * <p>
     * RECOMMENDED. The lifetime in seconds of the access token. For example, the value "3600" denotes that the access
     * token will expire in one hour from the time the response was generated. If omitted, the authorization server
     * SHOULD provide the expiration time via other means or document the default value.</p>
     */
	private String expires_in;

	 /**
     * scope
     * <p>
     * OPTIONAL, if identical to the scope requested by the client; otherwise, REQUIRED. The scope of the access token
     * as described by http://tools.ietf.org/html/rfc6749#section-3.3</p>
     */
    private String scope;
    
	private String signature;
	/*
	 * for OpenID Connect
	 */
	 /**
     * token_type
     * <p>
     * REQUIRED. The type of the token issued as described in http://tools.ietf.org/html/rfc6749#section-7.1 Value is
     * case insensitive.</p>
     */
	private String token_type;
	
	private String id_token;
	
	/**
	 * https://self-issued.me
	 */
	private String sub_jwk;
	/*
	 * for error
	 */
	private String error;
	private String error_description;

	
	/**
	 * 
	 */
	public Token() {
		rawResponse = null;
	}

	/**
	 * Default constructor
	 * 
	 * @param token
	 *            token value. Can't be null.
	 * @param secret
	 *            token secret. Can't be null.
	 */
	public Token(String token, String secret) {
		this(token, secret, null);
	}

	public Token(String token, String secret, String rawResponse) {
		Preconditions.checkNotNull(token, "Token can't be null");
		Preconditions.checkNotNull(secret, "Secret can't be null");

		this.token = token;
		this.secret = secret;
		this.rawResponse = rawResponse;
		this.responseObject = null;
	}

	public Token(String token, String secret, String rawResponse,
			Map<String, Object> responseObject) {
		this.token = token;
		this.secret = secret;
		this.rawResponse = rawResponse;
		this.responseObject = responseObject;
	}

	public String getAccess_token() {
		if(access_token==null||access_token.equals("")){
			access_token=this.token;
		}
		
		return access_token;
	}

	public void setAccess_token(String access_token) {
		this.access_token = access_token;
	}

	public Map<String, Object> getResponseObject() {
		return responseObject;
	}

	public void setResponseObject(Map<String, Object> responseObject) {
		this.responseObject = responseObject;
	}

	public String getToken() {
		if(token==null){
			token=this.access_token;
		}
		return token;
	}

	public void setToken(String token) {
		this.token = token;
	}

	public String getSecret() {
		return secret;
	}

	public void setSecret(String secret) {
		this.secret = secret;
	}

	public String getRefresh_token() {
		return refresh_token;
	}

	public void setRefresh_token(String refresh_token) {
		this.refresh_token = refresh_token;
	}

	public String getExpires_in() {
		return expires_in;
	}

	public void setExpires_in(String expires_in) {
		this.expires_in = expires_in;
	}

	public String getSignature() {
		return signature;
	}

	public void setSignature(String signature) {
		this.signature = signature;
	}

	public String getToken_type() {
		return token_type;
	}

	public void setToken_type(String token_type) {
		this.token_type = token_type;
	}

	public String getId_token() {
		return id_token;
	}

	public void setId_token(String id_token) {
		this.id_token = id_token;
	}

	public String getSub_jwk() {
		return sub_jwk;
	}

	public void setSub_jwk(String sub_jwk) {
		this.sub_jwk = sub_jwk;
	}

	public String getError() {
		return error;
	}

	public void setError(String error) {
		this.error = error;
	}

	public String getError_description() {
		return error_description;
	}

	public void setError_description(String error_description) {
		this.error_description = error_description;
	}

	public void setRawResponse(String rawResponse) {
		this.rawResponse = rawResponse;
	}
	
	public String getScope() {
		return scope;
	}

	public void setScope(String scope) {
		this.scope = scope;
	}

	public String getRawResponse() {
		if (rawResponse == null) {
			throw new IllegalStateException(
					"This token object was not constructed by scribe and does not have a rawResponse");
		}
		return rawResponse;
	}

	@Override
	public String toString() {
		return "Token [rawResponse=" + rawResponse + ", responseObject="
				+ responseObject + ", access_token=" + access_token
				+ ", token=" + token + ", secret=" + secret
				+ ", refresh_token=" + refresh_token + ", expires_in="
				+ expires_in + ", signature=" + signature + ", token_type="
				+ token_type + ", id_token=" + id_token + ", sub_jwk="
				+ sub_jwk + ", error=" + error + ", error_description="
				+ error_description + "]";
	}

	/**
	 * Returns true if the token is empty (token = "", secret = "")
	 */
	public boolean isEmpty() {
		return "".equals(this.token) && "".equals(this.secret);
	}

	/**
	 * Factory method that returns an empty token (token = "", secret = "").
	 * 
	 * Useful for two legged OAuth.
	 */
	public static Token empty() {
		return new Token("", "");
	}

	@Override
	public boolean equals(Object o) {
		if (this == o)
			return true;
		if (o == null || getClass() != o.getClass())
			return false;

		Token that = (Token) o;
		return token.equals(that.token) && secret.equals(that.secret);
	}

	@Override
	public int hashCode() {
		return 31 * token.hashCode() + secret.hashCode();
	}
}
