/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package com.essar.mes.service.framework.aspect;

import com.essar.mes.service.framework.Service;
import com.essar.mes.service.framework.ServiceTemplate;
import com.essar.mes.service.framework.ServiceValidator;
import com.essar.mes.service.framework.annotations.parser.BeanTagParser;
import com.essar.mes.service.framework.annotations.parser.BeanUtil;
import java.lang.reflect.Method;
import java.util.Date;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

/**
 *
 * @author dhaval
 */
@Aspect
public class ServiceInvokeAspect implements ApplicationContextAware{

    private ApplicationContext beanContext;

    @Around("execution (* com.essar.mes.services.inventory.*ServiceImpl.*(..))")
    public Object invokeService(ProceedingJoinPoint joinPoint){
        BeanTagParser tagParser = new BeanTagParser();
        BeanUtil beanUtil = new BeanUtil();

        try {
            System.out.println("Service Called..." + joinPoint.getTarget().getClass().getSimpleName() + "." + joinPoint.getSignature().getName());
            ServiceTemplate baseService = (ServiceTemplate) joinPoint.getTarget();

            Service service = new Service();
            service.setId(String.valueOf(System.currentTimeMillis()));
            service.setCallTime(new Date());
            service.setClassName(joinPoint.getTarget().getClass().getSimpleName());
            service.setMethodName(joinPoint.getSignature().getName());
            service.setArgument(joinPoint.getArgs());

            System.out.println("Begin Logging...");
            baseService.getLogger().logService(service);
            System.out.println("Logging End...");

            System.out.println("Begin Validating...");
            String[] validators = tagParser.getValidators(joinPoint.getTarget(), joinPoint.getSignature().getName());
            if (validators.length > 0) {
                for (String validatorName : validators) {
                    ServiceValidator validator = (ServiceValidator) beanContext.getBean(validatorName);
                    validator.validate(service);
                }
            } else {
                baseService.getValidator().validate(service);
            }
            System.out.println("Validation End...");

            System.out.println("Begin Logging Validations...");
            baseService.getLogger().logServiceValidation(service);
            System.out.println("End Logging Validations...");

            Object result = null;
            if (!service.getValidationErrors().isEmpty()) {
                Method method = tagParser.getErrorResultMethod(joinPoint.getTarget(), joinPoint.getSignature().getName());
                service.setReturnTime(new Date());

                if (method != null) {
                    result = beanUtil.invokeMethod(joinPoint.getTarget(), method, new Object[]{service});
                }else{
                    throw new IllegalStateException("No Error Result Method Found for Service - " + service.getClassName());
                }
            } else {
                System.out.println("Begin Translation...");
                baseService.getTranslator().translate(service);
                System.out.println("End Translation...");

                System.out.println("Calling Service...");
                result = joinPoint.proceed();
                service.setReturnTime(new Date());
                System.out.println("End Calling Service...");
            }
            service.setResult(result);

            System.out.println("Begin Logging Return Result...");
            baseService.getLogger().logResult(service);
            System.out.println("End Logging Return Result...");

            System.out.println("Begin Return Validation...");
            if (validators.length > 0) {
                for (String validatorName : validators) {
                    ServiceValidator validator = (ServiceValidator) beanContext.getBean(validatorName);
                    validator.validateResult(service);
                }
            } else {
                baseService.getValidator().validateResult(service);
            }
            System.out.println("End Return Validation...");

            System.out.println("Begin Logging Return Result...");
            baseService.getLogger().logResultValidation(service);
            System.out.println("End Logging Return Result...");

            return result;
        } catch (Throwable e) {
            e.printStackTrace();
            return null;
        }
    }

    public void setApplicationContext(ApplicationContext context) throws BeansException {
        beanContext = context;
    }


}
