/*
* This file is part of gwap, an open platform for games with a purpose
*
* Copyright (C) 2013
* Project play4science
* Lehr- und Forschungseinheit für Programmier- und Modellierungssprachen
* Ludwig-Maximilians-Universität München
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gwap.game.memory;
import gwap.model.resource.ArtResource;
import gwap.tools.ArtResourceFrequency;
import gwap.tools.DBLimiter;
import gwap.tools.Timer;
import gwap.widget.TagCloudBean;
import gwap.wrapper.TagFrequency;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.Create;
import org.jboss.seam.annotations.Destroy;
import org.jboss.seam.annotations.In;
import org.jboss.seam.annotations.Logger;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.annotations.Synchronized;
import org.jboss.seam.faces.FacesMessages;
import org.jboss.seam.international.LocaleSelector;
import org.jboss.seam.log.Log;
@Name("resourceGridBean")
@Scope(ScopeType.PAGE)
@Synchronized(timeout=10000)
public class ResourceGridBean implements Serializable {
private static final long serialVersionUID = 1L;
private static final int numImages = 3;
private static final long MIN_TAGGINGS=5;
@Create public void init() { log.info("Creating"); }
@Destroy public void destroy() { log.info("Destroying"); }
@Logger private Log log;
@In private EntityManager entityManager;
@In(create=true) private DBLimiter dbLimiter;
@In(create=true) private ForceBean gwapGameMemoryForceBean;
@In private FacesMessages facesMessages;
@In private Player gwapGameMemoryPlayer;
@In private LocaleSelector localeSelector;
@In(create=true) private ReplayBean gwapGameMemoryReplayBean;
@In(create=true) private TagCloudBean tagCloudBean;
//@Out(required=false) private ArtResource resource;
private List<ArtResource> resources0=new ArrayList<ArtResource>();
private List<ArtResource> resources1;
private List<TagFrequency> goalTags;
private ArtResource goal;
private ArtResource selected;
private int resourceCount;
public int getResourceCount() {
return resourceCount;
}
public void setGoal(ArtResource goal) {
this.goal = goal;
if (goal!=null)
{
goalTags=tagCloudBean.getTagCloud(goal, 0L, 30);
log.info("Goal set: #0, #1 tags", goal, goalTags.size());
}
else
goalTags=null;
}
public ArtResource getGoal() {
return goal;
}
public List<TagFrequency> getGoalTags() {
return goalTags;
}
public void removeGoalTag(TagFrequency tag)
{
goalTags.remove(tag);
}
/*public ArtResource getResource()
{
resource=goal;
return resource;
}*/
public ArtResource getSelected() {
return selected;
}
public void setSelected(ArtResource selected) {
this.selected = selected;
}
private void updateResourcesFromPrevious()
{
log.info("Updating Resource Grid with previous round");
resources0=gwapGameMemoryReplayBean.updatePreviousRound(numImages*numImages, gwapGameMemoryForceBean.getForcedId());
if (resources0==null)
{
resources0=new ArrayList<ArtResource>();
return;
}
List<ArtResource> resourcesPlayed=gwapGameMemoryReplayBean.getResourcesPlayed();
if (resourcesPlayed!=null)
setGoal(resourcesPlayed.remove(0));
else
setGoal(resources0.get(new Random().nextInt(resources0.size())));
if (resources0.size()>numImages*numImages)
{
log.info("Round id has too many played resources: #0", gwapGameMemoryReplayBean.getReplayRoundId());
resources0=resources0.subList(0, numImages*numImages);
}
log.info("Added #0 resources", resources0.size());
}
@SuppressWarnings("unchecked")
public void updateResourceGridBean(boolean replay, boolean requireTagged) {
setGoal(null);
resources0=new ArrayList<ArtResource>();
if (replay || gwapGameMemoryForceBean.getForcedId()!=0)
{
updateResourcesFromPrevious();
}
if (goal==null)
{
log.info("Updating random base resource");
Timer t=new Timer();
Query query;
//Select base resource by number of tags
if (requireTagged)
{
log.info("Selecting with more than #0 taggings", MIN_TAGGINGS);
query = entityManager.createNamedQuery("artResource.atLeastTaggedResourceIdLimit");
query.setParameter("minTaggings", MIN_TAGGINGS);
}
else
{
log.info("Selecting least tagged resource", MIN_TAGGINGS);
query = entityManager.createNamedQuery("artResource.leastTaggedResourceIdLimit");
}
query.setParameter("language", localeSelector.getLanguage());
dbLimiter.PrepareLimitedQuery(query);
query.setMaxResults(100);
List<Long> resGoal=query.getResultList();
log.info("Found #0 resources.", resGoal.size());
log.info("artResource.(at)leastTaggedResourceId: Query time: #0", t.timePassed());
if (resGoal.size()>0)
{
//Randomly select from bottom 20%
/*int limit=Math.min(Math.max(resGoal.size()/5, 20), resGoal.size());
resGoal=resGoal.subList(0, limit);
Random rand=new Random();
setGoal(entityManager.find(ArtResource.class, resGoal.get(rand.nextInt(limit))));*/
setGoal(entityManager.find(ArtResource.class, resGoal.get(new Random().nextInt(resGoal.size()))));
}
else //If no suitable resource is found (ie there is no tagged resource), pick a random one
{
log.info("Selecting random resource");
t=new Timer();
Query query2 = entityManager.createNamedQuery("artResource.random");
query2.setMaxResults(1);
setGoal((ArtResource)query2.getSingleResult());
log.info("artResource.random: Query time: #0", t.timePassed());
}
resources0.add(goal);
log.info("Selected goal "+goal.getId());
}
if (resources0.size()<numImages*numImages)
{
log.info("Adding similar resources to resource grid");
// Get all resources
try {
Timer t=new Timer();
Query query;
if (requireTagged)
{
query = entityManager.createNamedQuery("artResource.bySimilarityIdAndNotIdListAtLeastTaggedLimit");
query.setParameter("minTaggings", MIN_TAGGINGS);
}
else
query = entityManager.createNamedQuery("artResource.bySimilarityIdAndNotIdListLimit");
query.setParameter("id", goal.getId());
query.setParameter("others", resources0);
query.setParameter("lang", localeSelector.getLanguage());
query.setMaxResults(numImages*numImages*4);
dbLimiter.PrepareLimitedQuery(query);
List<ArtResourceFrequency> resF=query.getResultList();
log.info("artResource.bySimilarityId Query time: #0", t.timePassed());
log.info("Found #0 similar resources", resF.size());
//Collections.sort(resF);
//artResourceFrequencyBean.normalizeAll(resF);
Collections.shuffle(resF);
List<ArtResource> res=new ArrayList<ArtResource>();
int i=0;
//int limit=Math.min(Math.max(resF.size()/10, numImages*numImages-resources0.size()), resF.size());
//Randomly select from all images
int limit=Math.min(numImages*numImages-resources0.size(), resF.size());
for (ArtResourceFrequency r : resF)
{
res.add(r.getResource());
if (++i>=limit)
break;
}
Collections.shuffle(res);
resources0.addAll(res);
//Take random images if not enough matching ones were found
if (resources0.size()<numImages*numImages)
{
log.info("Adding random resources");
t=new Timer();
Query query2 = entityManager.createNamedQuery("artResource.byNotIdListRandom");
query2.setParameter("others", resources0);
query2.setMaxResults(numImages*numImages-resources0.size());
log.info("artResource.byNotIdListRandom Query time: #0", t.timePassed());
res=query2.getResultList();
if (res.size()<numImages*numImages-resources0.size())
{
facesMessages.add("#{messages['general.noResource']}");
return;
}
resources0.addAll(res);
}
} catch(Exception e) {
log.info("Failed: #0", e.getMessage());
facesMessages.add("#{messages['general.noResource']}");
}
}
log.info("Done");
Collections.shuffle(resources0);
resources1=new ArrayList<ArtResource>(resources0);
Collections.shuffle(resources1);
resourceCount=resources0.size();
if (resourceCount!=numImages*numImages)
log.info("Wrong resourceCount: #0, expected #1. This shouldn't happen!", resourceCount, numImages*numImages);
else
{
log.info("Found #0 resources:", resourceCount);
for (ArtResource res : resources0)
{
log.info("#0", res.getId());
}
}
}
private void removeResource(List<ArtResource> l, ArtResource r)
{
int index=l.indexOf(r);
l.remove(index);
l.add(index, null);
}
public void removeGoalResource()
{
if (resourceCount<=1)
{
log.info("resourceCount<=1 shouldn't happen");
}
if (goal!=null)
{
//Remove current resource from list, replace with null value
removeResource(resources0, goal);
removeResource(resources1, goal);
setGoal(null);
resourceCount--;
}
}
public List<ArtResource> getResources() {
//Randomize order for different players
if (gwapGameMemoryPlayer.getId()==0)
return resources0;
else
return resources1;
}
public List<ArtResource> getValidResources() {
List<ArtResource> res=new ArrayList<ArtResource>();
for (ArtResource r : resources0)
{
if (r!=null)
res.add(r);
}
return res;
}
public boolean isGoal(ArtResource resource)
{
return goal!=null && resource==this.goal;
}
public boolean isNoGoal()
{
return goal==null;
}
public boolean isSelected(ArtResource resource)
{
return resource!=null && resource==this.selected;
}
}