package com.framework.site.data.xml;
import com.framework.site.config.SiteSessionManager;
import com.framework.site.data.Ships;
import com.framework.site.pages.core.CruiseShipsPage;
import com.framework.utils.error.PreConditions;
import com.framework.utils.io.FileFinder;
import com.framework.utils.xml.XmlParseException;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import org.apache.commons.lang3.RandomUtils;
import org.apache.commons.lang3.SystemUtils;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
import org.joda.time.DateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.SAXException;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import java.io.*;
import java.net.Inet4Address;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
/**
* Created with IntelliJ IDEA ( LivePerson : www.liveperson.com )
*
* Package: com.framework.site.data
*
* Name : SmartRandomShipCard
*
* User : solmarkn / Dani Vainstein
*
* Date : 2015-01-12
*
* Time : 04:16
*/
public class SmartRandomShipCard
{
//region SmartRandomShipCard - Variables Declaration and Initialization Section.
private static final Logger logger = LoggerFactory.getLogger( SmartRandomShipCard.class );
private File source = null;
private List<XmlShipCard> xmlShipCards;
private Set<String> uniqueIdController = Sets.newHashSet();
private List<XmlShipCard> selectedCards = Lists.newArrayListWithCapacity( 3 );
private Properties props;
//endregion
//region SmartRandomShipCard - Constructor Methods Section
public SmartRandomShipCard( String fileName ) throws IOException
{
this( fileName, null );
}
public SmartRandomShipCard( String fileName, Ships exclude ) throws IOException
{
PreConditions.checkNotNullNotBlankOrEmpty( fileName, "fileName is either null, empty or blank" );
if( null != exclude )
{
uniqueIdController.add( exclude.getId() );
}
logger.debug( "searching file < {} >", fileName );
Path startingDir = Paths.get( SystemUtils.USER_DIR );
FileFinder finder = new FileFinder( fileName );
Files.walkFileTree( startingDir, finder );
Set<String> files = finder.getFiles();
for( String path : files )
{
if( path.contains( "target" ) ) continue;
this.source = new File( path ); break;
}
if( source == null )
{
throw new FileNotFoundException( "Could not locate < " + fileName + " > in < " + SystemUtils.USER_DIR + " >" );
}
logger.info( "file < {} > was located at < {} >", fileName, source.getAbsoluteFile() );
}
//endregion
//region SmartRandomShipCard - Public Methods Section
public List<XmlShipCard> getSelectedCards()
{
return selectedCards;
}
public Properties getProps()
{
return props;
}
public File getSource()
{
return source;
}
public void parse() throws ParserConfigurationException, SAXException, IOException
{
PreConditions.checkNotNull( source, "The source file is null" );
logger.info( "parsing xml source file ..." );
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser saxParser = factory.newSAXParser();
ShipCardContentHandler contentHandler = new ShipCardContentHandler( source.getCanonicalPath() );
saxParser.parse( source, contentHandler );
this.xmlShipCards = contentHandler.getXmlShipCards();
this.props = contentHandler.getProperties();
logger.info( "End parsing. < {} > xml ships where selected for locale < {} >",
xmlShipCards.size(), SiteSessionManager.get().getCurrentLocale().getDisplayCountry() );
}
@SuppressWarnings ( "ForLoopReplaceableByForEach" )
public void selectXmlCard( CruiseShipsPage.SelectRandom first,
CruiseShipsPage.SelectRandom second,
CruiseShipsPage.SelectRandom third )
{
PreConditions.checkNotNull( first, "first cannot be null" );
PreConditions.checkNotNull( second, "second cannot be null. use NONE instead" );
PreConditions.checkNotNull( third, "third cannot be null. use NONE instead" );
PreConditions.checkState( ! first.equals( CruiseShipsPage.SelectRandom.NONE ), "first value cannot be None." );
List<CruiseShipsPage.SelectRandom> selections = Lists.newArrayList( first, second, third );
for( CruiseShipsPage.SelectRandom selection : selections )
{
if( selection.equals( CruiseShipsPage.SelectRandom.NONE ) )
{
logger.info( "skipping ship selection ...." );
continue;
}
if( selection.equals( CruiseShipsPage.SelectRandom.LAST_SELECTED )
|| selection.equals( CruiseShipsPage.SelectRandom.LESS_TIMES_SELECTED )
|| selection.equals( CruiseShipsPage.SelectRandom.MOST_TIME_SELECTED )
|| selection.equals( CruiseShipsPage.SelectRandom.OLDER_SELECTED ) )
{
orderBy( selection );
for( int i = 0; i < xmlShipCards.size(); i ++ )
{
XmlShipCard shipCard = xmlShipCards.get( i );
if( ! uniqueIdController.contains( shipCard.getShipId() ) )
{
uniqueIdController.add( shipCard.getShipId() );
logger.info( "selected ship < {} > using < {} > selection mode", shipCard.getShipDescription(), selection.name() );
selectedCards.add( shipCard );
break;
}
}
}
else if( selection.equals( CruiseShipsPage.SelectRandom.RANDOM ) )
{
boolean selected = false;
while( ! selected )
{
int random = RandomUtils.nextInt( 0, xmlShipCards.size() - 1 );
XmlShipCard shipCard = xmlShipCards.get( random );
if( ! uniqueIdController.contains( shipCard.getShipId() ) )
{
uniqueIdController.add( shipCard.getShipId() );
logger.info( "selected ship < {} > using < {} > selection mode", shipCard.getShipDescription(), selection.name() );
selectedCards.add( shipCard );
selected = true;
}
}
}
}
try
{
props.setProperty( "last-updated", DateTime.now().toString( "yyyy-MMM-dd HH:mm:ss" ) );
props.setProperty( "updater-user", SystemUtils.USER_NAME );
props.setProperty( "updater-host", Inet4Address.getLocalHost().toString() );
updateCardInfoAndSave();
}
catch ( Exception e )
{
throw new XmlParseException( e );
}
}
//endregion
//region SmartRandomShipCard - Private Methods Section
private void updateCardInfoAndSave() throws Exception
{
OutputStream outputStream = null;
XMLWriter writer = null;
try
{
SAXReader reader = new SAXReader();
Document document = reader.read( source );
document.getRootElement().element( "last-updated" ).setText( props.get( "last-updated" ).toString() );
document.getRootElement().element( "updater-user" ).setText( props.get( "updater-user" ).toString() );
document.getRootElement().element( "updater-host" ).setText( props.get( "updater-host" ).toString() );
for( XmlShipCard card : selectedCards )
{
card.increaseSelections();
card.updateLastUpdated();
Element ship = document.getRootElement().element( "ships" ).elementByID( card.getShipId() );
ship.element( "selections" ).setText( String.valueOf( card.getCurrentSelection() ) );
ship.element( "last-selected" ).setText( String.valueOf( card.getCurrentUpdate() ) );
}
OutputFormat format = OutputFormat.createPrettyPrint();
outputStream = new FileOutputStream( source );
writer = new XMLWriter( outputStream, format );
writer.write( document );
}
catch ( Exception e )
{
throw new XmlParseException( e );
}
finally
{
if( outputStream != null )
{
outputStream.close();
}
if( writer != null )
{
writer.close();
}
}
}
private void orderBy( CruiseShipsPage.SelectRandom by )
{
if( by.equals( CruiseShipsPage.SelectRandom.LAST_SELECTED ) )
{
Collections.sort( xmlShipCards, new Comparator<XmlShipCard>()
{
@Override
public int compare( final XmlShipCard o1, final XmlShipCard o2 )
{
if ( o1.getLastUpdated().equals( o2.getLastUpdated() ) ) return 0;
if ( o1.getLastUpdated().isBefore( o2.getLastUpdated() ) ) return 1;
return - 1;
}
} );
}
else if( by.equals( CruiseShipsPage.SelectRandom.LESS_TIMES_SELECTED ) )
{
Collections.sort( xmlShipCards, new Comparator<XmlShipCard>()
{
@Override
public int compare( final XmlShipCard o1, final XmlShipCard o2 )
{
if( o1.getSelections() == o2.getSelections() ) return 0;
if( o1.getSelections() > o2.getSelections() ) return 1;
return -1;
}
} );
}
else if( by.equals( CruiseShipsPage.SelectRandom.MOST_TIME_SELECTED ) )
{
Collections.sort( xmlShipCards, new Comparator<XmlShipCard>()
{
@Override
public int compare( final XmlShipCard o1, final XmlShipCard o2 )
{
if( o1.getSelections() == o2.getSelections() ) return 0;
if( o1.getSelections() < o2.getSelections() ) return 1;
return -1;
}
} );
}
else if( by.equals( CruiseShipsPage.SelectRandom.OLDER_SELECTED ) )
{
Collections.sort( xmlShipCards, new Comparator<XmlShipCard>()
{
@Override
public int compare( final XmlShipCard o1, final XmlShipCard o2 )
{
if( o1.getLastUpdated().equals( o2.getLastUpdated() ) ) return 0;
if( o1.getLastUpdated().isAfter( o2.getLastUpdated() ) ) return 1;
return -1;
}
} );
}
}
//endregion
}