package org.gcube.application.geoportal.service.rest;

import lombok.extern.slf4j.Slf4j;
import org.gcube.application.cms.plugins.faults.InsufficientPrivileges;
import org.gcube.application.cms.plugins.faults.UnrecognizedStepException;
import org.gcube.application.geoportal.common.model.rest.ConfigurationException;
import org.gcube.application.geoportal.service.model.internal.faults.InvalidLockException;
import org.gcube.application.geoportal.service.model.internal.faults.InvalidUserRoleException;
import org.gcube.application.geoportal.service.model.internal.faults.ProjectLockedException;
import org.gcube.application.geoportal.service.model.internal.faults.ProjectNotFoundException;

import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Response.Status;
import java.util.ArrayList;
import java.util.List;

@Slf4j
public abstract class GuardedMethod<T> {

	private static List<Runnable> preoperations=new ArrayList<>();

	public static void addPreoperation(Runnable preoperation){
		preoperations.add(preoperation);
	}




	private T result=null;
	
	public GuardedMethod<T> execute() throws WebApplicationException{
		try {
			if (!preoperations.isEmpty()) {
				log.trace("Running preops (size : {} )", preoperations.size());
				for (Runnable r : preoperations)
					r.run();
			}
			log.trace("Executing actual method..");
			result = run();
			return this;
		}catch (InvalidUserRoleException e){
			log.error("Returning exception ",e);
			throw new WebApplicationException("Invalid Step ID ", e,Status.FORBIDDEN);
		}catch (UnrecognizedStepException e){
			log.error("Returning exception ",e);
			throw new WebApplicationException("Invalid Step ID ", e,Status.BAD_REQUEST);
		}catch (ConfigurationException e){
			log.error("Returning exception ",e);
			throw new WebApplicationException("Environment is not properly configured", e,Status.EXPECTATION_FAILED);
		}catch (InsufficientPrivileges e){
			log.error("Returning exception ",e);
			throw new WebApplicationException("User has insufficient privileges for requested action", e,Status.FORBIDDEN);
		}catch(WebApplicationException e) {
			log.error("Throwing Web Application Exception ", e);
			throw e;
		}catch(ProjectNotFoundException e){
			log.error("Returning exception ",e);
			throw new WebApplicationException("Project not found", e,Status.NOT_FOUND);
		}catch(ProjectLockedException e){
			log.error("Returning exception ",e);
			throw new WebApplicationException("Project is currently locked", e,Status.PRECONDITION_FAILED);
		}catch(InvalidLockException e){
			log.error("Lock exception ",e);
			throw new WebApplicationException("Conflicts found in locks", e,Status.CONFLICT);
		}catch(Throwable t) {
			log.error("Unexpected error ",t);
			throw new WebApplicationException("Unexpected internal error", t,Status.INTERNAL_SERVER_ERROR);
		}
		
	}
	
	public T getResult() {
		return result;
	}
	
	
	protected abstract T run() throws Exception,WebApplicationException;
}
