package com.smash.revolance.ui.model.element.api;
/*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Revolance-UI-Model
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Copyright (C) 2012 - 2013 RevoLance
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/gpl-3.0.html>.
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
/*
This file is part of Revolance.
Revolance is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Revolance is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Revolance UI Suite. If not, see <http://www.gnu.org/licenses/>.
*/
import com.smash.revolance.ui.model.bot.Bot;
import com.smash.revolance.ui.model.helper.BotHelper;
import com.smash.revolance.ui.model.helper.ImageHelper;
import com.smash.revolance.ui.model.helper.UserHelper;
import com.smash.revolance.ui.model.page.api.Page;
import com.smash.revolance.ui.model.page.api.PageBean;
import com.smash.revolance.ui.model.user.User;
import org.apache.log4j.Level;
import org.openqa.selenium.Dimension;
import org.openqa.selenium.Point;
import org.openqa.selenium.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.*;
import java.util.List;
/**
* User: wsmash
* Date: 26/01/13
* Time: 23:59
*/
public class Element implements Comparable<Element>
{
private ElementBean bean = new ElementBean( this );
private BufferedImage img;
public Element()
{
}
public Element(Page page, WebElement element)
{
this();
setPage( page );
setTag( element.getTagName() );
setDim( element.getSize() );
setPos( element.getLocation() );
setClz( element.getAttribute( "class" ) );
setId( element.getAttribute( "id" ) );
}
public void setAlt(String alt)
{
this.bean.setAlt( alt );
}
public void setBackground(String img)
{
bean.setBg( img );
}
public static String getBg(String tag, WebElement element)
{
String bg = "";
if ( !tag.contentEquals( "img" ) )
{
bg = element.getCssValue( "background-image" );
if ( bg.contentEquals( "none" ) )
{
bg = element.getCssValue( "background-url" );
}
} else
{
bg = element.getAttribute( "src" );
}
if ( bg == null || bg.contentEquals( "none" ) )
{
bg = "";
}
if ( !bg.isEmpty() )
{
//TODO: use standard image format instead of css/uri
if ( !bg.contains( "url" )
&& !bg.contains( "http" )
&& !bg.contains( ImageHelper.BASE64_IMAGE_PNG ) )
{
bg = "";
}
}
return bg;
}
public static Class<? extends Element> getImplementation(WebElement element)
{
String tag = element.getTagName();
if ( tag == null )
{
tag = "";
}
String type = element.getAttribute( "type" );
if ( type == null )
{
type = "";
}
String txt = element.getText();
if ( txt == null )
{
txt = "";
}
if (isALink(tag, txt))
{
return Link.class;
}
else if (isAButton(tag, type))
{
return Button.class;
}
else if (isAnInput(tag, type))
{
return Input.class;
}
else if (isAData(tag, txt))
{
return Data.class;
}
else if (isAnImage(element, tag))
{
return Image.class;
}
else
{
return null;
}
}
private static boolean isAnImage(WebElement element, String tag)
{
return !getBg( tag, element ).isEmpty();
}
private static boolean isAData(String tag, String txt)
{
return !txt.trim().isEmpty() &&
( tag.contentEquals( "li" ) || tag.contentEquals( "p" )
|| tag.contentEquals( "label" ) || tag.startsWith( "h" ) );
}
private static boolean isAnInput(String tag, String type)
{
return tag.contentEquals( "input" ) && ( !type.contentEquals( "submit" ) && !type.contentEquals( "button" ) );
}
private static boolean isAButton(String tag, String type)
{
return ( tag.contentEquals( "input" )
&& ( type.contentEquals( "submit" ) || type.contentEquals( "button" ) ) )
|| ( tag.contentEquals( "button" ) );
}
private static boolean isALink(String tag, String txt)
{
return tag.contentEquals( "a" ) && !txt.isEmpty();
}
public Element(PageBean pageBean, ElementBean bean)
{
this.bean = bean;
setPage( new Page( pageBean ) );
}
protected void setImplementation(String implementation)
{
this.bean.setImpl( implementation );
}
public boolean click() throws Exception
{
if ( isClickable() )
{
UserHelper.browseTo( getUser(), getUrl() );
getBot().getUser().getLogger().log(Level.INFO, "Clicking on '" + getContent() + "'" );
try
{
_click( getBot() );
getBot().getUser().getLogger().log(Level.INFO, "Clicking on '" + getContent() + "' [Done]" );
setHref( getBot().getCurrentUrl() );
setClicked( true );
}
catch (Exception e)
{
setBroken( true );
getBot().getUser().getLogger().log(Level.ERROR, "Clicking on '" + getContent() + "' [Failed]" );
getBot().getUser().getLogger().log(Level.ERROR, e);
}
}
return hasBeenClicked();
}
private void _click(Bot bot) throws Exception
{
WebElement element = BotHelper.findMatchingElement( bot, this );
if ( element != null )
{
try
{
String disabled = element.getAttribute( "disabled" );
if ( disabled == null )
{
element.click(); // Can thow an ex
}
}
catch (UnhandledAlertException e)
{
UserHelper.handleAlert( getUser() );
_click( bot );
}
}
}
public boolean isIncluded(Element element)
{
return element.getBean().isIncluded( getBean() );
}
public Rectangle getLocation()
{
return bean.getLocation();
}
//-- Beginning of setters / getters
public void setId(String id)
{
bean.setId( id );
}
public String getId()
{
return bean.getId();
}
public String getHref()
{
if ( !bean.isExternal() )
{
// The url is relative to the domain
return getUser().getDomain() + bean.getHref();
} else
{
return bean.getHref();
}
}
public void setHref(String href)
{
if ( href.startsWith( getUser().getDomain() ) )
{
// The url is relative to the domain
href = href.substring( getUser().getDomain().length() );
bean.setHref( href );
} else
{
// The url is absolute
bean.setExternal( true );
bean.setHref( href );
}
}
public boolean hasBeenClicked()
{
return bean.hasBeenClicked();
}
public void setTag(String tag)
{
bean.setTag( tag );
}
public String getTag()
{
return bean.getTag();
}
public String getClz()
{
return bean.getClz();
}
public void setClz(String clz)
{
bean.setClz( clz );
}
public Dimension getDim()
{
return bean.getDim();
}
public void setDim(Dimension dim)
{
bean.setDim( dim );
}
public Point getPos()
{
return bean.getPos();
}
public void setPos(Point pos)
{
bean.setPos( pos );
}
public void setType(String type)
{
bean.setType( type );
}
public String getType()
{
return bean.getType();
}
public void setText(String txt)
{
bean.setText( txt );
}
public String getText()
{
return bean.getText();
}
public Page getPage()
{
return bean.getPage().getInstance();
}
public int getArea()
{
return bean.getArea();
}
public void setValue(String value)
{
bean.setValue( value );
}
public String getValue()
{
return bean.getValue();
}
public boolean isBroken()
{
return bean.isBroken();
}
public void setBroken(boolean b)
{
bean.setBroken( b );
}
//-- Enf of basic setters / getters
// Caption feature
public BufferedImage getImage() throws Exception
{
if ( img == null )
{
img = ImageHelper.decodeToImage( getCaption() );
}
return img;
}
public String getCaption()
{
return bean.getCaption();
}
public void takeScreenShot() throws Exception
{
if ( getArea() > 0 )
{
if ( getPage().getUser().isPageScreenshotEnabled() && getPage().getUser().isPageElementScreenshotEnabled() )
{
int x = getPos().getX();
int y = getPos().getY();
int w = getDim().getWidth();
int h = getDim().getHeight();
BufferedImage pageImg = getPage().getImage();
BufferedImage croppedImg = ImageHelper.cropImage( pageImg, x, y, w, h, getBot().getXScale(), getBot().getYScale() );
bean.setCaption( ImageHelper.encodeToString( croppedImg ) );
bean.setDim( new Dimension( croppedImg.getWidth(), croppedImg.getHeight() ) );
// Remove the element caption from the page caption
pageImg = ImageHelper.eraseRect( pageImg, x, y, w, h, getBot().getXScale(), getBot().getYScale() );
getPage().setCaption( ImageHelper.encodeToString( pageImg ) );
}
}
}
@Override
public int compareTo(Element element)
{
return bean.compareTo( element.getBean() );
}
public void setPage(Page page)
{
bean.setPage( page.getBean() );
}
public boolean isClickable()
{
if ( bean.getImpl().contentEquals( "Link" ) )
{
if ( !getUser().wantsToFollowLinks() )
{
return false;
}
else
{
return !getUser().getExcludedLinks().contains( getContent() );
}
}
else if ( bean.getImpl().contentEquals( "Button" ) )
{
if ( !getUser().wantsToFollowButtons() )
{
return false;
}
else
{
return !getUser().getExcludedButtons().contains( getContent() );
}
}
else
{
return true;
}
}
public static boolean isVisible(WebElement element)
{
return element.isDisplayed();
}
public String toJson() throws IOException
{
return bean.toJson();
}
// For convenience only
public User getUser()
{
return getPage().getUser();
}
public Bot getBot() throws Exception
{
return getUser().getBot();
}
public WebDriver getBrowser() throws Exception
{
return getBot().getBrowser();
}
public String getUrl()
{
return getPage().getUrl();
}
public void delete() throws Exception
{
// nothing to be done
}
public String toString()
{
return bean.toString();
}
public static boolean isIncluded(ElementBean element, Rectangle rectangle)
{
return element.getLocation().contains( rectangle );
}
public static boolean isIncluded(WebElement element, Rectangle rectangle)
{
Point topleft = element.getLocation();
Dimension dim = element.getSize();
Rectangle rectangleRef = new Rectangle( topleft.getX(), topleft.getY(), dim.getWidth(), dim.getHeight() );
return rectangleRef.contains( rectangle );
}
public static List<Element> filterClickableElementBeans(List<ElementBean> elements)
{
List<Element> filteredElements = new ArrayList<Element>();
for ( ElementBean element : elements )
{
if ( element.getInstance().isClickable() )
{
filteredElements.add( element.getInstance() );
}
}
return filteredElements;
}
public static List<Element> filterClickableElements(List<Element> elements)
{
List<Element> filteredElements = new ArrayList();
for ( Element element : elements )
{
if ( element.isClickable() )
{
filteredElements.add( element );
}
}
return filteredElements;
}
/*
public static WebElement filterElementByText(List<WebElement> elements, String text) throws Exception
{
for(WebElement element : elements)
{
String txt = element.getText();
String value = element.getAttribute( "value" );
if( txt.contentEquals( text ) || value.contentEquals( txt ))
{
return element;
}
}
throw new Exception( "Unable to find element with text/value matching '" + text + "'." );
}
*/
public static ElementBean filterElementByText(List<ElementBean> elements, String text) throws Exception
{
for ( ElementBean element : elements )
{
if ( element.getContent().contentEquals( text ) )
{
return element;
}
}
return null;
}
public static List<ElementBean> filterElementsByText(List<ElementBean> elements, String... textList) throws Exception
{
List<ElementBean> matchingElements = new ArrayList<ElementBean>();
for ( ElementBean element : elements )
{
for ( String txt : textList )
{
if ( element.getContent().contentEquals( txt ) )
{
matchingElements.add( element );
break;
}
}
}
return matchingElements;
}
public static List<ElementBean> filterElementsByImpls(List<ElementBean> elements, String... implementations)
{
List<ElementBean> matchingElements = new ArrayList<ElementBean>();
for ( ElementBean element : elements )
{
for ( String implementation : implementations )
{
if ( element.getImpl().contentEquals( implementation ) )
{
matchingElements.add( element );
break;
}
}
}
return matchingElements;
}
public static List<ElementBean> filterElementsByLocations(List<ElementBean> elements, Rectangle... locations)
{
List<ElementBean> matchingElements = new ArrayList<ElementBean>();
for ( ElementBean element : elements )
{
for ( Rectangle location : locations )
{
if ( element.getLocation().contains( location ) )
{
matchingElements.add( element );
break;
}
}
}
return matchingElements;
}
public static WebElement filterElementByLocation(List<WebElement> elements, Rectangle rectangle) throws Exception
{
for ( WebElement element : elements )
{
if ( Element.isIncluded( element, rectangle ) )
{
return element;
}
}
throw new Exception( "Unable to find element at location " + rectangle.toString() + "." );
}
public void setClicked(boolean clicked)
{
bean.setClicked( clicked );
}
public ElementBean getBean()
{
return bean;
}
public void setDisabled(boolean b)
{
bean.setDisabled( b );
}
public void setTarget(String target)
{
this.bean.setTarget( target );
}
public String getTarget()
{
return bean.getTarget();
}
public String getContent()
{
return bean.getContent();
}
public static Element buildElement(ElementBean elementBean)
{
Element element = null;
if ( elementBean.getImpl().contentEquals( "Link" ) )
{
element = new Link( elementBean );
} else if ( elementBean.getImpl().contentEquals( "Button" ) )
{
element = new Button( elementBean );
}
return element;
}
public boolean equals(Element element) throws IOException
{
return getBean().equals( element.getBean() );
}
public static List<Element> filterImages(List<Element> elements)
{
List<Element> images = new ArrayList<Element>();
for ( Element element : elements )
{
if ( element instanceof com.smash.revolance.ui.model.element.api.Image )
{
images.add( element );
}
}
return images;
}
public String getBackground()
{
return bean.getBg();
}
public boolean isDisabled()
{
return bean.isDisabled();
}
public static void filterElementsIncludedInEachOthers(List<Element> content, double pageArea, double threshold)
{
Collections.sort( content, new Comparator<Element>()
{
@Override
public int compare(Element o1, Element o2)
{
if ( o1.getArea() > o2.getArea() )
{
return -1;
}
else if(o1.getArea() < o2.getArea())
{
return 1;
}
else
{
return 0;
}
}
} );
List<Element> hudgeBlocs = new ArrayList<Element>();
for ( Element bloc : Data.filterData( content ) )
{
if ( bloc.getArea() > pageArea * threshold )
{
hudgeBlocs.add( bloc );
}
}
List<Element> toBeRemoved = new ArrayList<Element>();
for ( Element hudgeBloc : hudgeBlocs )
{
List<Element> elements = getElementsIn( hudgeBlocs, hudgeBloc );
if ( !elements.isEmpty() )
{
toBeRemoved.add( hudgeBloc );
}
}
hudgeBlocs.removeAll( toBeRemoved );
for ( Element hudgeBloc : hudgeBlocs )
{
List<Element> matchingElements = getElementsIn( content, hudgeBloc );
if ( !matchingElements.isEmpty() )
{
content.remove( hudgeBloc );
}
}
}
public static boolean isElementsAndBlocContentMatching(List<Element> matchingElements, Element hudgeBloc)
{
// Does those elements can substitute the content of the bloc?
List<String> blocContent = Arrays.asList( hudgeBloc.getContent().split( "\\n" ) );
for ( Element element : matchingElements )
{
List<String> matchingElementsContent = Arrays.asList( element.getContent().split( "\\n" ) );
for ( String matchingElementContent : matchingElementsContent )
{
if ( blocContent.contains( matchingElementContent ) )
{
blocContent.remove( element.getContent() );
}
}
}
return blocContent.isEmpty();
}
public static List<Element> getElementsIn(List<Element> contentToFilter, Element hudgeBloc)
{
List<Element> matchingElements = new ArrayList<Element>();
// What are the elements included in the bloc?
for ( Element element : contentToFilter )
{
if ( element != hudgeBloc
&& !element.getContent().isEmpty()
&& hudgeBloc.isIncluded( element ) )
{
matchingElements.add( element );
}
}
return matchingElements;
}
public static Element getBiggestElement(List<Element> elements)
{
if ( elements == null )
{
return null;
}
if ( elements.isEmpty() )
{
return null;
}
int maxArea = 0;
Element pageElement = null;
for ( Element element : elements )
{
if ( element.getArea() > maxArea )
{
pageElement = element;
maxArea = element.getArea();
}
}
return pageElement;
}
}