package com.usemodj.forum.struts.action;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
import org.apache.ibatis.session.SqlSession;
import org.apache.log4j.Logger;
import com.opensymphony.xwork2.Action;
import com.usemodj.forum.ForumsHierarchical;
import com.usemodj.forum.Location;
import com.usemodj.forum.domain.Forum;
import com.usemodj.forum.domain.Term;
import com.usemodj.forum.domain.Topic;
import com.usemodj.forum.service.ForumService;
import com.usemodj.forum.service.MetaService;
import com.usemodj.forum.service.TermTaxonomyService;
import com.usemodj.forum.service.TopicService;
import com.usemodj.struts.Constants;
import com.usemodj.struts.Paginate;
import com.usemodj.struts.Paginate.LinkType;
import com.usemodj.struts.action.BaseAction;
public class ForumAction<E> extends BaseAction {
/**
*
*/
private static final long serialVersionUID = 1806709020315378331L;
private static Logger logger = Logger.getLogger( ForumAction.class);
protected ForumService forumService = new ForumService();
protected TopicService topicService = new TopicService();
protected MetaService metaService = new MetaService();
private TermTaxonomyService termTaxonomyService = new TermTaxonomyService();
private Paginate paginate = new Paginate();
private Forum forum = null;
private List<Topic> stickyTopics = null;
private List<Forum> forums = null;
ForumsHierarchical fh = new ForumsHierarchical();
int page = 1;
//private String siteName;
String breadcrumbs;
private E topTags;
private String forumDropdown;
public String index() throws Exception{
return execute();
}
public String execute() throws Exception {
SqlSession sqlSession = null;
//logger.debug( "-- character Encoding: " + request.getCharacterEncoding());
try {
this.setLocation( Location.FRONT);
sqlSession = this.getForumSqlSessionFactory().openSession();
paginate.setLocation(Location.FRONT);
if( 0< getPage()) this.paginate.setPage( getPage());
topicService.getLatestTopics(sqlSession, paginate);
// logger.debug("----- ForumAction SUCCESS count: "+ paginate.getCount());
// logger.debug("----- Paginate page: "+ paginate.getPage() + " , perPage: "+ paginate.getPerPage());
//stickyTopics = (List<Topic>) paginate.getResults();
stickyTopics = topicService.getStickyTopics(sqlSession, -1);
Map<Long, Forum> forums = forumService.getForumsWithMetaMap(sqlSession);
int childOf =0;
int hierarchical = 1;
int depth = 0;
int cutBranch = 0;
Map<Long, Forum> forumsMap = this.fh.getForumsMap( forums, childOf, hierarchical, depth, cutBranch);
this.fh.getForumsLoopElements(forumsMap);
request.setAttribute("fh", this.fh);
//Top Tags
//getTagHeatMap(SqlSession sqlSession, int page, String contextPath)
this.topTags = (E)getTagHeatMap( sqlSession, 0, request.getContextPath());
} catch (Exception e) {
e.printStackTrace();
logger.error( "-- ForumAction.execute() Exception: "+ e.getMessage());
} finally {
if( null != sqlSession) sqlSession.close();
}
return Action.SUCCESS;
}
public String newTopic() throws Exception {
SqlSession sqlSession = null;
try {
this.setLocation( Location.FRONT);
sqlSession = this.getForumSqlSessionFactory().openSession();
Map<Long, Forum> forums = forumService.getForumsWithMetaMap(sqlSession);
int childOf =0;
int hierarchical = 1;
int depth = 0;
int cutBranch = 0;
Map<Long, Forum> forumsMap = this.fh.getForumsMap( forums, childOf, hierarchical, depth, cutBranch);
this.fh.getForumsLoopElements(forumsMap);
request.setAttribute("fh", this.fh);
// * $defaults = array( 'callback' => false, 'callback_args' => false, 'id' => 'forum_id', 'none' => false
// * , 'selected' => false, 'tab' => false, 'hierarchical' => 1, 'depth' => 0
// * , 'child_of' => 0, 'disable_categories' => 1, 'options_only' => false );
String id = "forum_id";
String none = null; // "-None-";
int selected = (null != this.forum)? this.forum.getForumId(): 0;
int tab = 0;
//int hierarchical = 1;
//int depth = 0;
//int childOf = 0;
int disableCategories = 1;
boolean optionsOnly = false;
this.forumDropdown = getForumDropdown( this.fh, id, none, selected, tab, hierarchical, depth
, childOf, disableCategories, optionsOnly);
this.fh.getForumsLoop().setLooping( false);
//Top Tags
//getTagHeatMap(SqlSession sqlSession, int page, String contextPath)
this.topTags = (E)getTagHeatMap( sqlSession, 0, request.getContextPath());
} catch (Exception e) {
e.printStackTrace();
logger.error( "-- ForumAction.execute() Exception: "+ e.getMessage());
} finally {
if( null != sqlSession) sqlSession.close();
}
return "newTopic";
}
public String forum() throws Exception {
SqlSession sqlSession = null;
try {
this.setLocation( Location.FORUM);
sqlSession = this.getForumSqlSessionFactory().openSession();
//site name
//this.siteName = metaService.getBBOption(sqlSession, "name");
//forum's bread crumb
String cssClass = "";
this.breadcrumbs = forumService.getForumBreadCrumb( sqlSession, request.getContextPath(), this.getForum().getForumId(), "»", cssClass, true);
// latest topics
paginate.setLocation(Location.FORUM);
paginate.setObjectId( this.getForum().getForumId());
paginate.setPage( this.getPage());
topicService.getLatestTopics(sqlSession, paginate);
//logger.debug("----- ForumAction FORUM count: "+ paginate.getCount());
//logger.debug("----- Paginate page: "+ paginate.getPage() + " , perPage: "+ paginate.getPerPage());
// sticky topics
stickyTopics = topicService.getStickyTopics(sqlSession, forum.getForumId());
Map<Long, Forum> forums = forumService.getForumsWithMetaMap(sqlSession);
int childOf = forum.getForumId();
int hierarchical = 1;
int depth = 0;
int cutBranch = 0;
Map<Long, Forum> forumsMap = fh.getForumsMap( forums, childOf, hierarchical, depth, cutBranch);
fh.getForumsLoopElements(forumsMap);
request.setAttribute("fh", fh);
if( this.forum.getForumId() > 0) {
this.forum = forumService.getForum( sqlSession, this.forum.getForumId());
//logger.debug(" --- forum forumName: " + forum.getForumName());
//logger.debug("--- forum forumDesc: " + forum.getForumDesc());
}
// TopTags
} catch (Exception e) {
// e.printStackTrace();
logger.error( "-- ForumAction.forum() Exception: "+ e.getMessage());
e.printStackTrace();
} finally {
sqlSession.close();
}
return "forum";
}
public String list() throws Exception {
//int forumId = forum.getForumId();
SqlSession sqlSession = null;
try {
sqlSession = this.getForumSqlSessionFactory().openSession();
forumService.getForums(sqlSession, paginate);
logger.debug(" ------ Paginate count: " + paginate.getCount() + ", page: "+ paginate.getPage());
} catch (Exception e) {
//e.printStackTrace();
logger.error( "------- ForumAction.list() Excteption: " + e.getMessage());
} finally {
sqlSession.close();
}
return Constants.LIST;
}
/**
* $defaults = array( 'callback' => false, 'callback_args' => false, 'id' => 'forum_id', 'none' => false
* , 'selected' => false, 'tab' => false, 'hierarchical' => 1, 'depth' => 0
* , 'child_of' => 0, 'disable_categories' => 1, 'options_only' => false );
*
* @param id
* @param none
* @param selected : int fourmId
* @param tab
* @param hierarchical
* @param depth
* @param childOf
* @param disableCategories
* @param optionsOnly
*/
public String getForumDropdown( ForumsHierarchical fh,String id, String none, int selected, int tab, int hierarchical, int depth,
int childOf, int disableCategories, boolean optionsOnly ){
//TODO: getForumDropdown
String tabIndex = "";
String ret ="";
String name = id;
id = id.replaceAll("_", "-");
if( !optionsOnly){
if( 0< tab) tabIndex = "tabindex='"+ tab +"'";
ret += "<select name='"+ id + "' id='" + id + "'"+ tabIndex + "> \n";
}
if(null != none) ret += "\n <option value='0'>"+ getText( none) + "</option>\n";
boolean noOptionSelected = true;
List<HashMap<String, Object>> options = new ArrayList<HashMap<String, Object>>();
while( fh.forumsLoopStep() > 0) {
String padLeft = fh.getForumsLoop().pad(" ", 0);
if( disableCategories > 0 && fh.isForumIsCategory()) {
HashMap<String, Object> option = new HashMap<String, Object>();
options.add( option);
option.put("value", 0);
option.put("display", padLeft + fh.getForum().getForumName() );
option.put("disabled", true);
option.put("selected", false);
continue;
}
boolean _selected = false;
if( selected == fh.getForum().getForumId()) {
_selected = true;
noOptionSelected = false;
}
HashMap<String, Object> option = new HashMap<String, Object>();
options.add( option);
option.put("value", fh.getForum().getForumId());
option.put("display", padLeft + fh.getForum().getForumName() );
option.put("disabled", false);
option.put("selected", _selected);
} //end while
if( 1 == options.size() && null != none) {
for( Map option : options){
if( (Boolean) option.get("disabled")) return "";
return "<input type='hidden' name='" + name + "' id='"+ id + "' value='" + option.get("value") + "' /><span>"
+ option.get("display") + "</span>";
}
}
for( Map option: options){
boolean optionSelected = (Boolean) option.get("selected");
boolean optionDisabled = (Boolean) option.get("disabled");
if( null == none && selected < 1 && noOptionSelected && !optionDisabled){
optionSelected = true;
noOptionSelected = false;
}
String optDisabled = optionDisabled ? " disabled='disabled' ": "";
String optSelected = optionSelected ? " selected='selected' ": "";
ret += "\n <option value='"+ option.get("value") + "' " + optDisabled + optSelected + ">"
+ option.get("display") + "</option>\n";
}
if( !optionsOnly)
ret += "</select>\n";
return ret;
}
public int getPageNumber( long rows){
return Paginate.getPageNumber(rows, Paginate.PER_PAGE);
}
public String getTopicPageLinks(Topic topic){
boolean showAll =false;
int endSize =3;
String before ="-";
String after = null;
return getTopicPageLinks(topic, showAll, endSize, before, after, request.getContextPath());
}
public String getTopicPageLinks(Topic topic, boolean showAll, int endSize, String before, String after, String contextPath){
String uri = contextPath + "/forum/topic?topic.topicId="+ topic.getTopicId();
uri += "&%_%"; // page=%#%"
//TODO: view, browseDeleted
String view = "all";
boolean showFirst = false;
boolean browseDeleted = true;
long total = topic.getTopicPosts() + Paginate.getTopicPagesAdd( topic, view, browseDeleted);
String prevText = getText("« Previous");
String nextText = getText("Next »");
String prevTitle = getText("Previous page");
String nextTitle = getText( "Next page");
String nTitle = getText("Page %d");
int perPage = Paginate.PER_PAGE;
String format = "page=%#%";
int midSize = 2;
int current =1;
String addFragment = "";
boolean dots = true;
boolean preNext = false;
LinkType type = LinkType.ARRAY;
List pageLinks = Paginate.getPaginateLinks(uri, current, total, midSize, endSize, perPage, format, type
, addFragment, dots, showAll, preNext, prevText, nextText, prevTitle, nextTitle, nTitle);
if( null != pageLinks && !pageLinks.isEmpty()) {
if( !showFirst) pageLinks.remove( 0);
}
String ret = "";
if( null != pageLinks){
if( null != before) ret += before;
ret += StringUtils.join( pageLinks, "");
if( null != after) ret += after;
}
return ret;
}
public <E> E getTagHeatMap(SqlSession sqlSession, int page, String contextPath) throws Exception{
int smallest = 8;
int largest = 22;
String unit = "pt";
int limit = 40;
LinkType format = LinkType.FLAT;
//LinkType format = LinkType.LIST;
List<Term> tags = getTopTags( sqlSession, limit);
Map<String, Long> counts = new HashMap<String, Long>();
Map<String, String> tagLinks = new HashMap<String, String>();
for( Term t: tags ){
counts.put(t.getName(), t.getTt().getCount());
tagLinks.put(t.getName(), getTagLink(t, page, contextPath));
}
long minCount = Collections.min( counts.values());
logger.debug("-- minCount: " + minCount);
int spread = (int) (Collections.max( counts.values()) - minCount);
if( 0 >= spread) spread = 1;
int fontSpread = largest - smallest;
if( 0 >= fontSpread) fontSpread = 1;
int fontStep = fontSpread / spread;
//do_action_ref_array( 'sort_tag_heat_map', array(&$counts) );
List<String> list = new ArrayList<String>();
for(Map.Entry<String, Long> e: counts.entrySet()){
String tag = e.getKey();
long count = e.getValue();
String tagLink = tagLinks.get(tag);
tag = tag.replace(" ", " ");
int fontSize = Math.round( (float)smallest +((count - minCount)* fontStep));
list.add("<a href='"+ tagLink + "' title='" + String.format("%d topics", count)
+ "' rel='"+ tag + "' style='font-size:"+ fontSize + unit+ ";' >"+ tag + "</a>" );
}
String ret = "";
switch( format){
case ARRAY:
return (E) list;
case LIST:
//ret = "<ul class='bb-tag-heat-map'>\n\t<li>";
//ret ="<ul id='tags-list' class='tags-list list:tag'>\n\t<li>";
ret = "<ul>\n\t<li>";
ret += StringUtils.join( list, "</li>\n\t<li>");
ret += "</li>\n</ul>\n";
break;
default:
ret = StringUtils.join( list, "\n");
break;
}
return (E) ret;
}
public String getTopicPages( String action){
return getTopicPages( action, "<div class='nav'>", "</div>");
}
public String getTopicPages(String action, String before, String after){
// String before = "<div class='nav'>";
// String after ="</div>";
//logger.debug("--- getTopicPages: page="+this.page + ", total="+ this.paginate.getCount() );
return getTopicPages(this.page, this.paginate.getCount(), action, before, after);
}
public String getTopicPages( int page, long total, String action, String before, String after ) {
String uri = request.getContextPath()+"/forum/" + action;
String queryString = request.getQueryString();
logger.debug("-- getTopicPages: request.getQueryString(): " + queryString);
String format = "page=%#%";
if( "null".equals(queryString) || StringUtils.isBlank( queryString)){
queryString = "%_%";
}else if( queryString.indexOf("page=") == -1){
queryString = queryString.replaceFirst("&+$", "");
queryString += "&%_%";
} else {
queryString = queryString.replaceAll("page=[0-9]*", "%_%");// %_% : replace by format (page=%#%)
//queryString = queryString.replace("page=", "");
}
uri += "?"+ queryString;
String prevText = getText("« Previous");
String nextText = getText("Next »");
String prevTitle = getText("Previous page");
String nextTitle = getText( "Next page");
String nTitle = getText("Page %d");
int perPage = Paginate.PER_PAGE;
int midSize = 1;
int endSize = 1;
LinkType type = LinkType.FLAT;
String addFragment ="";
boolean dots = false;
boolean showAll = false;
boolean preNext = true;
return before + Paginate.getPaginateLinks(uri, page, total, midSize, endSize, perPage, format, type,
addFragment, dots, showAll, preNext, prevText, nextText, prevTitle, nextTitle, nTitle) + after;
}
private String getTagLink(Term t, int page, String contextPath) {
String tag = t.getName();
page = (1< page)? page: 1;
String baseUri = "/forum/tag_topics";
String ret = getUri( baseUri, tag, page, contextPath);
return ret;
}
private String getUri(String baseUri, String tag, int page, String contextPath) {
String uri = contextPath + baseUri + "?tag="+tag;
if( 1< page) uri += "&page="+page;
return uri;
}
List<Term> getTopTags( SqlSession sqlSession, int number) throws Exception {
String taxonomy = "bb_topic_tag";
List<Term> terms = termTaxonomyService.getTerms( sqlSession, taxonomy, number);
return terms;
}
/* util */
/* Getter/Setter methods */
public Paginate getPaginate() {
return paginate;
}
public void setPaginate(Paginate page) {
this.paginate = page;
}
public Forum getForum() {
return forum;
}
public void setForum(Forum forum) {
this.forum = forum;
}
public List<Topic> getStickyTopics() {
return stickyTopics;
}
public void setStickyTopics(List<Topic> topics) {
this.stickyTopics = topics;
}
public List<Forum> getForums() {
return forums;
}
public void setForums(List<Forum> forums) {
this.forums = forums;
}
public ForumsHierarchical getFh() {
return fh;
}
public void setFh(ForumsHierarchical fh) {
this.fh = fh;
}
public int getPage() {
return page;
}
public void setPage(int page) {
this.page = page;
}
// public String getSiteName() {
// return siteName;
// }
//
// public void setSiteName(String siteName) {
// this.siteName = siteName;
// }
public String getBreadcrumbs() {
return breadcrumbs;
}
public void setBreadcrumbs(String breadcrumbs) {
this.breadcrumbs = breadcrumbs;
}
public <E> E getTopTags() {
return (E) topTags;
}
public void setTopTags( E topTags) {
this.topTags = topTags;
}
public String getForumDropdown() {
return forumDropdown;
}
public void setForumDropdown(String forumDropdown) {
this.forumDropdown = forumDropdown;
}
}