package com.ecep.contract.ui;

import java.util.HashMap;
import java.util.Locale;
import java.util.function.BiConsumer;
import java.util.logging.Level;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;

import com.ecep.contract.Message;
import com.ecep.contract.MessageHolder;
import com.ecep.contract.SpringApp;
import com.ecep.contract.ds.company.service.CompanyService;
import com.ecep.contract.ds.other.service.EmployeeService;
import com.ecep.contract.ds.other.service.SysConfService;
import com.ecep.contract.model.Employee;
import com.ecep.contract.util.BeanContext;
import com.ecep.contract.util.DefaultBeanContext;

import lombok.Getter;
import lombok.Setter;

public abstract class Tasker<T> implements java.util.concurrent.Callable<T>, BeanContext {
    private static final Logger logger = LoggerFactory.getLogger(Tasker.class);
    @Setter
    protected java.util.function.Predicate<Message> messageHandler;
    @Setter
    private java.util.function.Predicate<String> titleHandler;
    @Setter
    private BiConsumer<String, Object> propertyHandler;
    @Setter
    private BiConsumer<Long, Long> progressHandler;
    @Getter
    @Setter
    private Locale locale = Locale.getDefault();
    private BeanContext beanContext;
    @Setter
    private Employee currentUser;
    @Setter
    @Getter
    private boolean cancelled = false;

    public Tasker() {
        beanContext = new DefaultBeanContext();
    }

    public SysConfService getConfService() {
        return getCachedBean(SysConfService.class);
    }

    public CompanyService getCompanyService() {
        return getCachedBean(CompanyService.class);
    }

    public EmployeeService getEmployeeService() {
        return getCachedBean(EmployeeService.class);
    }

    public <K> K getBean(Class<K> requiredType) throws BeansException {
        return beanContext.getBean(requiredType);
    }

    public <K> K getCachedBean(Class<K> requiredType) {
        return beanContext.getCachedBean(requiredType);
    }

    public Employee getCurrentUser() {
        return currentUser;
    }

    @Override
    public T call() throws Exception {
        MessageHolderImpl holder = new MessageHolderImpl(this);
        try {
            return execute(holder);
        } catch (Exception e) {
            holder.error(e.getMessage());
            logger.error(e.getMessage(), e);
            throw e;
        }
    }

    protected abstract T execute(MessageHolder holder) throws Exception;

    protected void updateMessage(String message) {
        updateMessage(Level.INFO, message);
    }

    public void updateTitle(String title) {
        if (titleHandler != null) {
            if (titleHandler.test(title)) {
                return;
            }
        }
        updateMessage(Level.INFO, title);
    }

    protected void updateMessage(Level level, String message) {
        if (messageHandler != null) {
            if (messageHandler.test(new Message(level, message))) {
                return;
            }
        }
    }

    public void updateProgress(long current, long total) {
        if (progressHandler != null) {
            progressHandler.accept(current, total);
        }
    }

    public void updateProgress(double current, double total) {
        updateProgress((long) (current * 1000), (long) (total * 1000));
    }

    public void updateProperty(String property, Object value) {
        if (propertyHandler != null) {
            propertyHandler.accept(property, value);
        }
    }
}
