/*
* Copyright 2004-2016 EPAM Systems
*
* This file is part of JDI project.
*
* JDI is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* JDI is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with JDI. If not, see <http://www.gnu.org/licenses/>.
*/
package com.epam.jdi.uitests.gui.sikuli.elements;
import com.epam.commons.LinqUtils;
import com.epam.commons.pairs.Pairs;
import com.epam.jdi.uitests.core.interfaces.base.IBaseElement;
import com.epam.jdi.uitests.core.interfaces.base.IComposite;
import com.epam.jdi.uitests.gui.sikuli.elements.base.CheckBox;
import com.epam.jdi.uitests.gui.sikuli.elements.composite.Page;
import com.epam.jdi.uitests.gui.sikuli.elements.enums.ContextType;
import com.epam.jdi.uitests.gui.sikuli.elements.pageobjects.annotations.*;
import com.epam.jdi.uitests.gui.sikuli.elements.pageobjects.annotations.elements.JPage;
import org.sikuli.script.Pattern;
import org.sikuli.script.Screen;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import static com.epam.commons.LinqUtils.foreach;
import static com.epam.commons.ReflectionUtils.*;
import static com.epam.commons.StringUtils.LINE_BREAK;
import static com.epam.commons.TryCatchUtil.tryGetResult;
import static com.epam.jdi.uitests.core.settings.JDIData.APP_VERSION;
import static com.epam.jdi.uitests.core.settings.JDISettings.exception;
import static java.lang.String.format;
import static java.lang.reflect.Modifier.isStatic;
/*
*
* Created by Roman_Iovlev on 6/10/2015.
*/
public abstract class CascadeInit implements IBaseElement {
public static boolean firstInstance = true;
public static void InitElements(Object parent, String driverName) {
if (parent.getClass().getName().contains("$")) return;
Object parentInstance = null;
Class<?> parentType = parent.getClass();
boolean firstInstanceCreated = false;
if (firstInstance) {
parentInstance = getParentInstance(parentType);
firstInstanceCreated = true;
}
initSubElements(parent, parentInstance, driverName);
if (isClass(parentType, Page.class) && parentType.isAnnotationPresent(JPage.class))
GuiAnnotationsUtil.fillPageFromAnnotation((Page) parent, parentType.getAnnotation(JPage.class), null);
if (firstInstanceCreated)
firstInstance = true;
}
private static Object getParentInstance(Class<?> parentType) {
firstInstance = false;
BaseElement.createFreeInstance = true;
Object parentInstance = tryGetResult(parentType::newInstance);
BaseElement.createFreeInstance = false;
return parentInstance;
}
private static void initSubElements(Object parent, Object parentInstance, String driverName) {
foreach(deepGetFields(parent, IBaseElement.class),
field -> setElement(parent, parentInstance, field, driverName));
}
private static List<Field> deepGetFields(Class<?> clazz) {
List<Field> result = new ArrayList<>();
if (isInterface(clazz, IBaseElement.class))
result.addAll(deepGetFields(clazz.getSuperclass()));
result.addAll(Arrays.asList(clazz.getDeclaredFields()));
return result;
}
public static List<Field> deepGetFields(Object obj, Class<?> type) {
return LinqUtils.where(deepGetFields(obj.getClass()), field -> !isStatic(field.getModifiers()) && (isClass(field, type) || isInterface(field, type)));
}
public static void initPages(Class<?> parentType, String driverName) {
foreach(getStaticFields(parentType, BaseElement.class),
field -> setElement(parentType, field, driverName));
}
public static void initPages(Screen site, String driverName) {
InitElements(site, driverName);
}
private static void setElement(Class<?> parentType, Field field, String driverName) {
try {
Class<?> type = field.getType();
BaseElement instance;
if (isClass(type, Page.class)) {
instance = (BaseElement) getValueField(field, null);
if (instance == null)
instance = (BaseElement) type.newInstance();
fillPage(instance, field, parentType);
} else {
instance = createChildFromFieldStatic(parentType, field, type, driverName);
instance.function = GuiAnnotationsUtil.getFunction(field);
}
instance.setName(field);
if (instance.getClass().getSimpleName().equals(""))
instance.setTypeName(type.getSimpleName());
instance.setParentName(parentType.getClass().getSimpleName());
field.set(null, instance);
if (isInterface(field, IComposite.class))
InitElements(instance, driverName);
} catch (Exception ex) {
throw exception("Error in setElement for field '%s' with parent '%s'", field.getName(), parentType.getClass().getSimpleName() + LINE_BREAK + ex.getMessage());
}
}
private static String getClassName(Object obj) {
return obj == null ? "NULL Class" : obj.getClass().getSimpleName();
}
public static void setElement(Object parent, Object parentInstance, Field field, String driverName) {
try {
Class<?> type = field.getType();
if (parentInstance == null)
parentInstance = parent;
BaseElement instance;
if (isClass(type, Page.class)) {
instance = (BaseElement) getValueField(field, parentInstance);
if (instance == null)
instance = (BaseElement) type.newInstance();
fillPage(instance, field, parent != null ? parent.getClass() : null);
} else {
instance = createChildFromField(parent, parentInstance, field, type, driverName);
instance.function = GuiAnnotationsUtil.getFunction(field);
}
instance.setName(field);
instance.avatar.setDriverName(driverName);
if (instance.getClass().getSimpleName().equals(""))
instance.setTypeName(type.getSimpleName());
instance.setParentName(getClassName(parent));
field.set(parent, instance);
if (isInterface(field, IComposite.class))
InitElements(instance, driverName);
} catch (Exception ex) {
throw exception("Error in setElement for field '%s' with parent '%s'", field.getName(),
getClassName(parent) + LINE_BREAK + ex.getMessage());
}
}
private static void fillPage(BaseElement instance, Field field, Class<?> parentType) {
if (field.isAnnotationPresent(JPage.class))
GuiAnnotationsUtil.fillPageFromAnnotation((Page) instance, field.getAnnotation(JPage.class), parentType);
}
private static BaseElement createChildFromFieldStatic(Class<?> parentClass, Field field, Class<?> type, String driverName) {
BaseElement instance = (BaseElement) getValueField(field, null);
if (instance == null)
try {
instance = getElementInstance(type, field.getName(), getNewPattern(field), driverName, field);
} catch (Exception ex) {
throw exception(format("Can't create child for parent '%s' with type '%s'",
parentClass.getSimpleName(), field.getType().getSimpleName()));
}
else if (instance.getPattern() == null)
instance.avatar.pattern = getNewPattern(field);
if (type != null) {
Pattern frameBy = GuiAnnotationsUtil.getPattern(type.getDeclaredAnnotation(JLocation.class),
type.getDeclaredAnnotation(JOffset.class));
if (frameBy != null)
instance.avatar.context.add(ContextType.Frame, frameBy);
}
instance.avatar.setSimilarity(GuiAnnotationsUtil.getSimilarity(field.getAnnotation(JLocation.class)));
if (field.getAnnotation(JRegion.class) != null) {
instance.avatar.setRectangle(GuiAnnotationsUtil.getRectangle(field.getAnnotation(JRegion.class)));
instance.avatar.setX(GuiAnnotationsUtil.getX(field.getAnnotation(JRegion.class)));
instance.avatar.setY(GuiAnnotationsUtil.getY(field.getAnnotation(JRegion.class)));
instance.avatar.setW(GuiAnnotationsUtil.getWight(field.getAnnotation(JRegion.class)));
instance.avatar.setH(GuiAnnotationsUtil.getHeight(field.getAnnotation(JRegion.class)));
}
return instance;
}
private static BaseElement createChildFromField(Object parent, Object parentInstance, Field field, Class<?> type, String driverName) {
BaseElement instance = (BaseElement) getValueField(field, parentInstance);
CheckBox d = null;
if (instance == null)
try {
instance = getElementInstance(type, field.getName(), getNewPattern(field), driverName, field);
} catch (Exception ex) {
throw exception(
format("Can't create child for parent '%s' with type '%s'",
parentInstance.getClass().getSimpleName(), field.getType().getSimpleName()));
}
else if (instance.getPattern() == null)
instance.avatar.pattern = getNewPattern(field);
instance.avatar.context = (isBaseElement(parent))
? ((BaseElement) parent).avatar.context.copy()
: new Pairs<>();
if (type != null) {
Pattern frameBy = GuiAnnotationsUtil.getPattern(type.getDeclaredAnnotation(JLocation.class),
type.getDeclaredAnnotation(JOffset.class));
if (frameBy != null)
instance.avatar.context.add(ContextType.Frame, frameBy);
}
if (isBaseElement(parent)) {
Pattern parentLocator = ((BaseElement) parent).getPattern();
if (parentLocator != null)
instance.avatar.context.add(ContextType.Locator, parentLocator);
}
if (field.getAnnotation(JLocation.class) != null)
instance.avatar.setSimilarity(GuiAnnotationsUtil.getSimilarity(field.getAnnotation(JLocation.class)));
if (field.getAnnotation(JRegion.class) != null) {
instance.avatar.setRectangle(GuiAnnotationsUtil.getRectangle(field.getAnnotation(JRegion.class)));
instance.avatar.setX(GuiAnnotationsUtil.getX(field.getAnnotation(JRegion.class)));
instance.avatar.setY(GuiAnnotationsUtil.getY(field.getAnnotation(JRegion.class)));
instance.avatar.setW(GuiAnnotationsUtil.getWight(field.getAnnotation(JRegion.class)));
instance.avatar.setH(GuiAnnotationsUtil.getHeight(field.getAnnotation(JRegion.class)));
}
return instance;
}
private static boolean isBaseElement(Object obj) {
return isClass(obj.getClass(), BaseElement.class);
}
private static BaseElement getElementInstance(Class<?> type, String fieldName, Pattern newPattern, String driverName, Field field) {
try {
if (!type.isInterface()) {
BaseElement instance;
if (MapClassToAnnotation.mapForConstructor.get(type) != null)
instance = MapClassToAnnotation.getMapForConstructor().get(type).value.apply(field);
else
instance = (BaseElement) type.newInstance();
instance.avatar.pattern = newPattern;
instance.avatar.setDriverName(driverName);
return instance;
}
throw exception("Unknown interface: " + type +
". Add relation interface -> class in VIElement.InterfaceTypeMap");
} catch (Exception ex) {
throw exception("Error in getElementInstance for field '%s' with type '%s'", fieldName, type.getSimpleName() +
LINE_BREAK + ex.getMessage());
}
}
private static Pattern getNewPattern(Field field) {
try {
Pattern pattern = null;
String locatorGroup = APP_VERSION;
if (locatorGroup != null) {
JLocation jLocation = field.getAnnotation(JLocation.class);
JOffset jOffset = field.getAnnotation(JOffset.class);
if (jLocation != null && locatorGroup.equals(jLocation.group()))
pattern = GuiAnnotationsUtil.getPattern(jLocation, jOffset);
}
return (pattern != null)
? pattern
: GuiAnnotationsUtil.getPattern(field.getAnnotation(JLocation.class),
field.getAnnotation(JOffset.class));
} catch (Exception ex) {
throw exception("Error in get patter for type '%s'", field.getType().getName() +
LINE_BREAK + ex.getMessage());
}
}
}