package org.sakaiproject.delegatedaccess.tool.pages;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.wicket.AttributeModifier;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.markup.html.AjaxLink;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.ChoiceRenderer;
import org.apache.wicket.markup.html.form.DropDownChoice;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.Radio;
import org.apache.wicket.markup.html.form.RadioGroup;
import org.apache.wicket.markup.html.form.TextField;
import org.apache.wicket.markup.html.link.Link;
import org.apache.wicket.markup.html.navigation.paging.PagingNavigator;
import org.apache.wicket.markup.repeater.DefaultItemReuseStrategy;
import org.apache.wicket.markup.repeater.Item;
import org.apache.wicket.markup.repeater.data.DataView;
import org.apache.wicket.markup.repeater.data.IDataProvider;
import org.apache.wicket.model.AbstractReadOnlyModel;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.model.PropertyModel;
import org.apache.wicket.model.ResourceModel;
import org.apache.wicket.model.StringResourceModel;
import org.sakaiproject.site.api.Site;
import org.sakaiproject.user.api.User;
import org.sakaiproject.delegatedaccess.model.ListOptionSerialized;
import org.sakaiproject.delegatedaccess.model.NodeModel;
import org.sakaiproject.delegatedaccess.model.SelectOption;
import org.sakaiproject.delegatedaccess.model.SiteSearchResult;
import org.sakaiproject.delegatedaccess.util.DelegatedAccessConstants;
import org.sakaiproject.delegatedaccess.util.SiteSearchResultComparator;
/**
*
* This page sorts and searches a user's access sites
*
* @author Bryan Holladay (holladay@longsight.com)
*
*/
public class UserPageSiteSearch extends BasePage {
private int orderBy = DelegatedAccessConstants.SEARCH_COMPARE_DEFAULT;
private boolean orderAsc = true;
private SiteSearchResultDataProvider provider;
private String search = "";
private String instructorField = "";
private String selectedInstructorOption = DelegatedAccessConstants.ADVANCED_SEARCH_INSTRUCTOR_TYPE_INSTRUCTOR;
private SelectOption termField;;
private List<SelectOption> termOptions;
private boolean statistics = false;
private boolean currentStatisticsFlag = false;
private Map<String, String> toolsMap;
public UserPageSiteSearch(final String search, final Map<String, String> advancedFields, final boolean statistics, final boolean currentStatisticsFlag){
this.search = search;
this.statistics = statistics;
this.currentStatisticsFlag = currentStatisticsFlag;
if(statistics){
disableLink(shoppingStatsLink);
}
List<ListOptionSerialized> blankRestrictedTools = projectLogic.getEntireToolsList();
toolsMap = new HashMap<String, String>();
for(ListOptionSerialized option : blankRestrictedTools){
toolsMap.put(option.getId(), option.getName());
}
//Setup Statistics Links:
Link<Void> currentLink = new Link<Void>("currentLink") {
private static final long serialVersionUID = 1L;
public void onClick() {
setResponsePage(new UserPageSiteSearch("", null, true, true));
}
@Override
public boolean isVisible() {
return statistics;
}
};
currentLink.add(new Label("currentLinkLabel",new ResourceModel("link.current")).setRenderBodyOnly(true));
currentLink.add(new AttributeModifier("title", true, new ResourceModel("link.current.tooltip")));
add(currentLink);
if(currentStatisticsFlag){
disableLink(currentLink);
}
Link<Void> allLink = new Link<Void>("allLink") {
private static final long serialVersionUID = 1L;
public void onClick() {
setResponsePage(new UserPageSiteSearch("", null, true, false));
}
@Override
public boolean isVisible() {
return statistics;
}
};
allLink.add(new Label("allLinkLabel",new ResourceModel("link.all")).setRenderBodyOnly(true));
allLink.add(new AttributeModifier("title", true, new ResourceModel("link.all.tooltip")));
add(allLink);
if(!currentStatisticsFlag){
disableLink(allLink);
}
termOptions = new ArrayList<SelectOption>();
for(String[] entry : sakaiProxy.getTerms()){
termOptions.add(new SelectOption(entry[1], entry[0]));
}
if(advancedFields != null){
for(Entry<String, String> entry : advancedFields.entrySet()){
if(DelegatedAccessConstants.ADVANCED_SEARCH_INSTRUCTOR.equals(entry.getKey())){
instructorField = entry.getValue();
selectedInstructorOption = advancedFields.get(DelegatedAccessConstants.ADVANCED_SEARCH_INSTRUCTOR_TYPE);
}
if(DelegatedAccessConstants.ADVANCED_SEARCH_TERM.equals(entry.getKey())){
for(SelectOption option : termOptions){
if(entry.getValue().equals(option.getValue())){
termField = option;
break;
}
}
}
}
}
//Create Search Form:
final PropertyModel<String> searchModel = new PropertyModel<String>(this, "search");
final PropertyModel<String> instructorFieldModel = new PropertyModel<String>(this, "instructorField");
final PropertyModel<SelectOption> termFieldModel = new PropertyModel<SelectOption>(this, "termField");
final IModel<String> searchStringModel = new IModel<String>() {
public void detach() {
}
public void setObject(String arg0) {
}
public String getObject() {
String searchString = "";
if(searchModel.getObject() != null){
searchString += new StringResourceModel("siteIdTitleField", null).getString() + " " + searchModel.getObject();
}
if(instructorFieldModel.getObject() != null && !"".equals(instructorFieldModel.getObject())){
if(!"".equals(searchString))
searchString += ", ";
String userType = new StringResourceModel("instructor", null).getString();
if(DelegatedAccessConstants.ADVANCED_SEARCH_INSTRUCTOR_TYPE_MEMBER.equals(selectedInstructorOption)){
userType = new StringResourceModel("member", null).getString();
}
searchString += userType + " " + instructorFieldModel.getObject();
}
if(termFieldModel.getObject() != null && !"".equals(termFieldModel.getObject())){
if(!"".equals(searchString))
searchString += ", ";
searchString += new StringResourceModel("termField", null).getString() + " " + termFieldModel.getObject().getLabel();
}
return searchString;
}
};
Form<?> form = new Form("form"){
@Override
protected void onSubmit() {
super.onSubmit();
if(provider != null){
provider.detachManually();
}
}
};
form.add(new TextField<String>("search", searchModel));
AbstractReadOnlyModel<String> instructorFieldLabelModel = new AbstractReadOnlyModel<String>() {
@Override
public String getObject() {
if(isShoppingPeriodTool()){
return new StringResourceModel("instructor", null).getObject() + ":";
}else{
return new StringResourceModel("user", null).getObject() + ":";
}
}
};
form.add(new Label("instructorFieldLabel", instructorFieldLabelModel));
form.add(new TextField<String>("instructorField", instructorFieldModel));
//Instructor Options:
RadioGroup group = new RadioGroup("instructorOptionsGroup", new PropertyModel<String>(this, "selectedInstructorOption")){
@Override
public boolean isVisible() {
//only show if its not shopping period
return !isShoppingPeriodTool();
}
};
group.add(new Radio("instructorOption", Model.of(DelegatedAccessConstants.ADVANCED_SEARCH_INSTRUCTOR_TYPE_INSTRUCTOR)));
group.add(new Radio("memberOption", Model.of(DelegatedAccessConstants.ADVANCED_SEARCH_INSTRUCTOR_TYPE_MEMBER)));
form.add(group);
ChoiceRenderer choiceRenderer = new ChoiceRenderer("label", "value");
DropDownChoice termFieldDropDown = new DropDownChoice("termField", termFieldModel, termOptions, choiceRenderer);
//keeps the null option (choose one) after a user selects an option
termFieldDropDown.setNullValid(true);
form.add(termFieldDropDown);
add(form);
//show user's search (if not null)
add(new Label("searchResultsTitle", new StringResourceModel("searchResultsTitle", null)){
@Override
public boolean isVisible() {
return (searchModel.getObject() != null && !"".equals(searchModel.getObject()))
|| (instructorFieldModel.getObject() != null && !"".equals(instructorFieldModel.getObject()))
|| (termFieldModel.getObject() != null && !"".equals(termFieldModel.getObject()));
}
});
add(new Label("searchString",searchStringModel){
@Override
public boolean isVisible() {
return (searchModel.getObject() != null && !"".equals(searchModel.getObject()))
|| (instructorFieldModel.getObject() != null && !"".equals(instructorFieldModel.getObject()))
|| (termFieldModel.getObject() != null && !"".equals(termFieldModel.getObject()));
}
});
//search result table:
//Headers
Link<Void> siteTitleSort = new Link<Void>("siteTitleSortLink"){
private static final long serialVersionUID = 1L;
public void onClick() {
changeOrder(DelegatedAccessConstants.SEARCH_COMPARE_SITE_TITLE);
}
@Override
public boolean isVisible() {
return provider.size() > 0;
}
};
add(siteTitleSort);
Link<Void> siteIdSort = new Link<Void>("siteIdSortLink"){
private static final long serialVersionUID = 1L;
public void onClick() {
changeOrder(DelegatedAccessConstants.SEARCH_COMPARE_SITE_ID);
}
@Override
public boolean isVisible() {
return provider.size() > 0;
}
};
add(siteIdSort);
Link<Void> termSort = new Link<Void>("termSortLink"){
private static final long serialVersionUID = 1L;
public void onClick() {
changeOrder(DelegatedAccessConstants.SEARCH_COMPARE_TERM);
}
@Override
public boolean isVisible() {
return provider.size() > 0;
}
};
add(termSort);
Link<Void> instructorSort = new Link<Void>("instructorSortLink"){
private static final long serialVersionUID = 1L;
public void onClick() {
changeOrder(DelegatedAccessConstants.SEARCH_COMPARE_INSTRUCTOR);
}
@Override
public boolean isVisible() {
return provider.size() > 0;
}
};
AbstractReadOnlyModel<String> instructorSortLabel = new AbstractReadOnlyModel<String>() {
@Override
public String getObject() {
if(DelegatedAccessConstants.ADVANCED_SEARCH_INSTRUCTOR_TYPE_MEMBER.equals(selectedInstructorOption)){
return new StringResourceModel("member", null).getObject();
}else{
return new StringResourceModel("instructor", null).getObject();
}
}
};
instructorSort.add(new Label("instructorSortLinkLabel", instructorSortLabel));
add(instructorSort);
Link<Void> accessSort = new Link<Void>("accessSortLink"){
private static final long serialVersionUID = 1L;
public void onClick() {
changeOrder(DelegatedAccessConstants.SEARCH_COMPARE_ACCESS);
}
};
add(accessSort);
Link<Void> startDateSort = new Link<Void>("startDateSortLink"){
private static final long serialVersionUID = 1L;
public void onClick() {
changeOrder(DelegatedAccessConstants.SEARCH_COMPARE_START_DATE);
}
@Override
public boolean isVisible() {
//this helps with the wicket:enlosure
return statistics;
}
};
add(startDateSort);
Link<Void> endDateSort = new Link<Void>("endDateSortLink"){
private static final long serialVersionUID = 1L;
public void onClick() {
changeOrder(DelegatedAccessConstants.SEARCH_COMPARE_END_DATE);
}
};
add(endDateSort);
Link<Void> accessModifiedBySort = new Link<Void>("accessModifiedBySortLink"){
private static final long serialVersionUID = 1L;
public void onClick() {
changeOrder(DelegatedAccessConstants.SEARCH_COMPARE_ACCESS_MODIFIED_BY);
}
@Override
public boolean isVisible() {
//this helps hide all the extra columns with the wicket:enclosure in the html
return !isShoppingPeriodTool();
}
};
add(accessModifiedBySort);
Link<Void> accessModifiedOnSort = new Link<Void>("accessModifiedOnSortLink"){
private static final long serialVersionUID = 1L;
public void onClick() {
changeOrder(DelegatedAccessConstants.SEARCH_COMPARE_ACCESS_MODIFIED);
}
};
add(accessModifiedOnSort);
//Data:
provider = new SiteSearchResultDataProvider();
final DataView<SiteSearchResult> dataView = new DataView<SiteSearchResult>("searchResult", provider) {
@Override
public void populateItem(final Item item) {
final SiteSearchResult siteSearchResult = (SiteSearchResult) item.getModelObject();
AjaxLink<Void> siteTitleLink = new AjaxLink("siteTitleLink"){
private static final long serialVersionUID = 1L;
public void onClick(AjaxRequestTarget target) {
if(siteSearchResult.getSiteUrl() != null){
//redirect the user to the site
target.appendJavascript("window.open('" + siteSearchResult.getSiteUrl() + "')");
}
}
};
siteTitleLink.add(new Label("siteTitle", siteSearchResult.getSiteTitle()));
item.add(siteTitleLink);
final String siteId = siteSearchResult.getSiteId();
item.add(new Label("siteId", siteId));
item.add(new Label("term", siteSearchResult.getSiteTerm()));
item.add(new Label("instructor", new AbstractReadOnlyModel<String>(){
@Override
public String getObject(){
return siteSearchResult.getInstructorsString();
}
}));
item.add(new Link<Void>("instructorLookupLink"){
private static final long serialVersionUID = 1L;
public void onClick() {
boolean foundInstructors = false;
for(User user : sakaiProxy.getInstructorsForSite(siteId)){
siteSearchResult.addInstructor(user);
foundInstructors = true;
}
if(!foundInstructors){
siteSearchResult.setHasInstructor(false);
}
}
@Override
public boolean isVisible() {
return (instructorField == null || "".equals(instructorField))
&& siteSearchResult.isHasInstructor() && siteSearchResult.getInstructors().size() == 0;
}
});
String access = isShoppingPeriodTool() ? siteSearchResult.getAccessRoleString() :siteSearchResult.getAccessString();
item.add(new Label("access", access));
item.add(new Label("startDate", siteSearchResult.getShoppingPeriodStartDateStr()){
@Override
public boolean isVisible() {
//this helps hide all the extra columns with the wicket:enclosure in the html
return statistics;
}
});
item.add(new Label("endDate", siteSearchResult.getShoppingPeriodEndDateStr()));
item.add(new Label("showAuthTools", siteSearchResult.getAuthToolsString(toolsMap)));
item.add(new Label("showPublicTools", siteSearchResult.getPublicToolsString(toolsMap)));
item.add(new Label("accessModifiedBy", siteSearchResult.getModifiedBySortName()){
@Override
public boolean isVisible() {
//this helps hide all the extra columns with the wicket:enclosure in the html
return !isShoppingPeriodTool();
}
});
item.add(new Label("accessModified", siteSearchResult.getModifiedStr()));
}
@Override
public boolean isVisible() {
return provider.size() > 0;
}
};
dataView.setItemReuseStrategy(new DefaultItemReuseStrategy());
dataView.setItemsPerPage(DelegatedAccessConstants.SEARCH_RESULTS_PAGE_SIZE);
add(dataView);
//Navigation
//add a pager to our table, only visible if we have more than SEARCH_RESULTS_PAGE_SIZE items
add(new PagingNavigator("navigatorTop", dataView) {
@Override
public boolean isVisible() {
if(provider.size() > DelegatedAccessConstants.SEARCH_RESULTS_PAGE_SIZE) {
return true;
}
return false;
}
@Override
public void onBeforeRender() {
super.onBeforeRender();
//clear the feedback panel messages
clearFeedback(feedbackPanel);
}
});
add(new PagingNavigator("navigatorBottom", dataView) {
@Override
public boolean isVisible() {
if(provider.size() > DelegatedAccessConstants.SEARCH_RESULTS_PAGE_SIZE) {
return true;
}
return false;
}
@Override
public void onBeforeRender() {
super.onBeforeRender();
//clear the feedback panel messages
clearFeedback(feedbackPanel);
}
});
}
/**
* changes order by desc or asc
*
* @param sortByColumn
*/
private void changeOrder(int sortByColumn){
if(sortByColumn == orderBy){
orderAsc = !orderAsc;
}else{
orderBy = sortByColumn;
}
}
/**
* A data provider for the search results table. This calls the search functions in Sakai
*
*/
private class SiteSearchResultDataProvider implements IDataProvider<SiteSearchResult>{
private static final long serialVersionUID = 1L;
private boolean lastOrderAsc = true;
private int lastOrderBy = DelegatedAccessConstants.SEARCH_COMPARE_DEFAULT;
private List<SiteSearchResult> list;
public void detach() {
}
public void detachManually(){
this.list = null;
}
public Iterator<? extends SiteSearchResult> iterator(int first, int count) {
return getData().subList(first, first + count).iterator();
}
public IModel<SiteSearchResult> model(final SiteSearchResult object) {
return new AbstractReadOnlyModel<SiteSearchResult>() {
private static final long serialVersionUID = 1L;
@Override
public SiteSearchResult getObject() {
return object;
}
};
}
public int size() {
return getData().size();
}
private List<SiteSearchResult> getData(){
if(list == null){
Map<String, String> advancedOptions = new HashMap<String,String>();
if(termField != null && !"".equals(termField)){
advancedOptions.put(DelegatedAccessConstants.ADVANCED_SEARCH_TERM, termField.getValue());
}
if(instructorField != null && !"".equals(instructorField)){
advancedOptions.put(DelegatedAccessConstants.ADVANCED_SEARCH_INSTRUCTOR, instructorField);
advancedOptions.put(DelegatedAccessConstants.ADVANCED_SEARCH_INSTRUCTOR_TYPE, selectedInstructorOption);
}
if(search == null){
search = "";
}
if(!"".equals(search) || (advancedOptions != null && !advancedOptions.isEmpty())){
list = projectLogic.searchUserSites(getSearch(), advancedOptions.isEmpty() ? null : advancedOptions, (isShoppingPeriodTool() || statistics), isShoppingPeriodTool() || (statistics && currentStatisticsFlag));
// if(currentStatisticsFlag){
// //need to filter out the results and find only current shopping period results:
// for (Iterator iterator = list.iterator(); iterator
// .hasNext();) {
// SiteSearchResult result = (SiteSearchResult) iterator.next();
// Map<String, String> nodes = projectLogic.getNodesBySiteRef(new String[]{result.getSiteReference()}, DelegatedAccessConstants.SHOPPING_PERIOD_HIERARCHY_ID);
// if(nodes == null || !nodes.containsKey(result.getSiteReference())){
// //this site doesn't exist in the current shopping period hierarchy, so remove it
// iterator.remove();
// }
// }
//
// }
}else {
list = new ArrayList<SiteSearchResult>();
}
sortList();
}else if(lastOrderAsc != orderAsc || lastOrderBy != orderBy){
sortList();
}
return list;
}
private void sortList(){
Collections.sort(list, new SiteSearchResultComparator(orderBy));
if(!orderAsc){
Collections.reverse(list);
}
this.lastOrderAsc = orderAsc;
this.lastOrderBy = orderBy;
}
}
public String getSearch() {
return search;
}
public void setSearch(String search) {
this.search = search;
}
public boolean isStatistics() {
return statistics;
}
public void setStatistics(boolean statistics) {
this.statistics = statistics;
}
}