package in.cdac.medinfo.csnotk.csnoserv.corsfilter;

import static in.cdac.medinfo.csnotk.csnoserv.CSnoServResource.prop;

import java.io.IOException;

import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.FilterConfig;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.annotation.WebFilter;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

/**
 * Provide Functionality to add HTTP Headers to every request
 *
 */
@WebFilter(urlPatterns = { "/api/search/*", "/api/lookup/*", "/api/add/*", "/api/explore/*", "/api/map/*",
		"/api/disb/*" }) // URI other then this must not be served
public class CORSFilter implements Filter {

	private static final String accessControlAllowMethods = "GET,POST,OPTIONS"; // only methods to be allowed
	private static String accessControlAllowCredentials = "false"; // Default value must be false
	private static String accessControlAllowHeaders = "access-control-allow-origin"; // value must be present to allow
																						// options request
	private static final String accessControlRequestHeaders = "access-control-allow-origin";
	private static String accessControlAllowOrigin = ""; // origin to be set via properties file or dynamically by
	private static String authorization = "authorization";
	private static String xRequestedWith = "X-Requested-With";
	private static String origin = "origin";

	/**
	 * To GET Access-Control-Allow-Methods Header value
	 *
	 * @return accessControlAllowMethods {@link String} HTTP Header
	 *         accessControlAllowMethods value
	 */
	public String getAccessControlAllowMethods() {
		return accessControlAllowMethods;
	}

	/**
	 * To GET AccessControlAllowCredentials Header value
	 *
	 * @return accessControlAllowCredentials {@link String} HTTP Header
	 *         accessControlAllowCredentials value
	 */
	public String getAccessControlAllowCredentials() {
		return accessControlAllowCredentials;
	}

	/**
	 * To SET AccessControlAllowCredentials Header value
	 *
	 * @param accessControlAllowCredentials {@link String} HTTP Header
	 *                                      accessControlAllowCredentials value
	 */
	public void setAccessControlAllowCredentials(String accessControlAllowCredentials) {
		if (accessControlAllowCredentials.equalsIgnoreCase("true")) // Checking property file for credential value
			CORSFilter.accessControlAllowCredentials = accessControlAllowCredentials;
		else
			CORSFilter.accessControlAllowCredentials = "false";
	}

	/**
	 * To GET AccessControlAllowHeaders Header value
	 *
	 * @return AccessControlAllowHeaders {@link String} HTTP Header
	 *         AccessControlAllowHeaders value
	 */
	public String getAccessControlAllowHeaders() {
		return accessControlAllowHeaders;
	}

	/**
	 * To GET AccessControlRequestHeaders Header value
	 *
	 * @return AccessControlRequestHeaders {@link String} HTTP Header
	 *         AccessControlAllowOrigin value
	 */
	public String getAccessControlRequestHeaders() {
		return accessControlRequestHeaders;
	}

	/**
	 * To GET AccessControlAllowOrigin Header value
	 *
	 * @return AccessControlAllowOrigin {@link String} HTTP Header
	 *         AccessControlAllowOrigin value
	 */
	public String getAccessControlAllowOrigin() {
		return accessControlAllowOrigin;
	}
	/**
	 * To SET AccessControlAllowCredentials Header value
	 *
	 * @param setAccessControlAllowHeaders {@link String} HTTP Header
	 *                                      setAccessControlAllowHeaders value
	 */
	public static void setAccessControlAllowHeaders(String accessControlAllowHeaders) {
		CORSFilter.accessControlAllowHeaders = accessControlAllowHeaders;
	}

	/**
	 * To GET AccessControlAllowOrigin Header("authorization") value
	 *  @return AccessControlAllowHeaders {@link String} HTTP Header
	 *         AccessControlAllowHeaders(authorization) value
	 */
	public static String getAuthorization() {
		return authorization;
	}

	/**
	 * To GET AccessControlAllowOrigin Header("xRequestedWith") value
	 * @return AccessControlAllowHeaders {@link String} HTTP Header
	 *         AccessControlAllowHeaders(xRequestedWith) value
	 */
	public static String getxRequestedWith() {
		return xRequestedWith;
	}

	/**
	 * To GET AccessControlAllowHeader Header("origin") value
	 * @return AccessControlAllowHeaders {@link String} HTTP Header
	 *         AccessControlAllowHeaders(origin) value
	 */
	public static String getOrigin() {
		return origin;
	}

	/**
	 * To SET AccessControlAllowOrigin Header value
	 *
	 * @param accessControlAllowCredentials {@link String} HTTP Header
	 *                                      accessControlAllowOrigin value
	 */
	public void setAccessControlAllowOrigin(String accessControlAllowOrigin) {
		if (accessControlAllowOrigin != null && !accessControlAllowOrigin.isEmpty()) // set value if it is non empty
																						// else use default
			CORSFilter.accessControlAllowOrigin = accessControlAllowOrigin;
	}

	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain Chain)
			throws IOException, ServletException {
		HttpServletRequest httpServletRequest = (HttpServletRequest) request;
		HttpServletResponse httpResponse = (HttpServletResponse) response;
		if ((prop.getProperty("accessControlAllowOrigin") != null
				&& prop.getProperty("accessControlAllowOrigin").isEmpty()) || getAccessControlAllowOrigin().isEmpty()) {
			setAccessControlAllowOrigin(httpServletRequest.getHeader("Origin"));
		}
		httpResponse.addHeader("Access-Control-Allow-Origin", getAccessControlAllowOrigin()); // setting header value before request get served

		Chain.doFilter(request, response);
		// adding header before return of options response
		httpResponse.addHeader("Access-Control-Allow-Credentials", getAccessControlAllowCredentials());
		httpResponse.addHeader("Access-Control-Allow-Methods", getAccessControlAllowMethods());
		httpResponse.addHeader("Access-Control-Allow-Headers", getAccessControlAllowHeaders());
		httpResponse.addHeader("Access-Control-Request-Headers", getAccessControlRequestHeaders());

	}

	@Override
	public void init(FilterConfig arg0) throws ServletException {
		// setting CORS values
		if (prop.getProperty("accessControlAllowCredentials") == null) { // check property file if value present
			setAccessControlAllowCredentials(getAccessControlAllowCredentials()); // store default value of Header
		} else {
			setAccessControlAllowCredentials(prop.getProperty("accessControlAllowCredentials")); // setting Header value from property file
		}
		if (prop.getProperty("accessControlAllowOrigin") == null) { // check property file if value present
			setAccessControlAllowOrigin(getAccessControlAllowOrigin()); // store default value of Header
		} else {
			setAccessControlAllowOrigin(prop.getProperty("accessControlAllowOrigin")); // setting Header value from property file
		}
		if ("true".equalsIgnoreCase(prop.getProperty("authorization"))) { // check property file if value present
			setAccessControlAllowHeaders(getAccessControlAllowHeaders() + "," + "authorization"); // store default value of Header  authorization
		}
		if ("true".equalsIgnoreCase(prop.getProperty("xRequestedWith"))) { // check property file if value present
			setAccessControlAllowHeaders(getAccessControlAllowHeaders() + "," + "x-Requested-With"); // store default value of Header xRequestedWith
		}
		if ("true".equalsIgnoreCase(prop.getProperty("origin"))) { // check property file if value present
			setAccessControlAllowHeaders(getAccessControlAllowHeaders() + "," + "origin"); // store default value of Header origin
		}
		if ("true".equalsIgnoreCase(prop.getProperty("ContentType"))) { // check property file if value present
			setAccessControlAllowHeaders(getAccessControlAllowHeaders() + "," + "Content-Type"); // store default value of Header Content-Type
		}

	}

	@Override
	public void destroy() {
	}

}
