package ru.yandex.autotests.direct.utils;

import com.sun.xml.ws.client.ClientTransportException;
import org.apache.axis.AxisFault;
import ru.yandex.autotests.direct.utils.model.ApiException;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * Created by IntelliJ IDEA.
 * User: mariabye
 * Date: 22.02.12
 * Time: 19:29
 * To change this template use File | Settings | File Templates.
 */
public final class ReflectionUtils extends ru.yandex.autotests.irt.testutils.ReflectionUtils {

    public static Object invokeMethod(Object object, String methodName, Object param)
            throws DirectUtilsException, AxisFault {
        try {
            Method method = findMethodByName(object.getClass().getDeclaredMethods(), methodName);

            //TODO Времено!
            if (param != null && method.getParameterTypes().length == 0) {
                method = findMethodByName(object.getClass().getDeclaredMethods(), methodName, 1);
            }

            if (param != null)
                return method.invoke(object, param);
            else
                return method.invoke(object);
        } catch (NoSuchMethodException e) {
            throw new DirectUtilsException(String.format("Отсутствует метод %s", methodName), e);
        } catch (InvocationTargetException e) {
            if (e.getTargetException().getClass().getName().equals(AxisFault.class.getName())) {
                throw AxisFault.makeFault(e);
            } else {
                throw new DirectUtilsException(String.format("Ошибка метода %s ", methodName), e);
            }
        } catch (IllegalAccessException e) {
            throw new DirectUtilsException(String.format("Неверный тип параметра для метода %s", methodName), e);
        }
    }

    public static Object invokeMethodV5(Object object, String methodName, Object param)
            throws DirectUtilsException, ApiException {
        try {
            Method method = findMethodByName(object.getClass().getDeclaredMethods(), methodName);

            //TODO Времено!
            if (param != null && method.getParameterTypes().length == 0) {
                method = findMethodByName(object.getClass().getDeclaredMethods(), methodName, 1);
            }

            if (param != null)
                return method.invoke(object, param);
            else
                return method.invoke(object);
        } catch (NoSuchMethodException e) {
            throw new DirectUtilsException(String.format("Отсутствует метод %s", methodName), e);
        } catch (InvocationTargetException e) {
            if (e.getTargetException().getClass().getSimpleName().equals(ApiException.class.getSimpleName())) {
                throw new ApiException(e.getTargetException());
            } else if (e.getTargetException().getClass().getSimpleName()
                    .equals(ClientTransportException.class.getSimpleName())) {
                throw new DirectUtilsException(String.format("Неправильный ответ сервера при вызове метода %s : %s",
                        methodName,
                        new ClientTransportException(e.getTargetException()).getMessage()));
            } else {
                throw new DirectUtilsException(String.format("Ошибка метода %s ", methodName), e);
            }
        } catch (IllegalAccessException e) {
            throw new DirectUtilsException(String.format("Неверный тип параметра для метода %s", methodName), e);
        }
    }

    /**
     * Set bean field with specified value. Could be helpful in parametrized test.
     *
     * @param beanMap bean to update
     * @param setterMethodName method name to invoke on set
     * @param value
     */
    public static void setBeanMapFieldValue(Object beanMap, String setterMethodName, Object value) {
        Method fieldSetter;
        try {
            fieldSetter = ReflectionUtils.findMethodByName(beanMap.getClass().getDeclaredMethods(), setterMethodName);
        } catch (NoSuchMethodException ex) {
            throw new DirectUtilsException("Не удалось найти метод " + setterMethodName + " класса " + beanMap.getClass());
        }
        try {
            fieldSetter.invoke(beanMap, value);
        } catch (IllegalAccessException access) {
            throw new DirectUtilsException("Ошибка доступа к методу " + setterMethodName + " класса " + beanMap.getClass());
        } catch (InvocationTargetException exp) {
            throw new DirectUtilsException("Произошла ошибка при вызове метода" + setterMethodName + " класса " + beanMap.getClass(), exp);
        }
    }
}
