package samples.webcenter.portlets.blog;

import java.io.IOException;

import javax.portlet.*;

import samples.webcenter.services.wiki.*;
import samples.webcenter.services.wiki.remote.*;
import samples.webcenter.beans.*;

public class BlogPortlet extends GenericPortlet {

	protected static String URL = "url";
	protected static String TYPE = "type"; // Personal = 0, Community = 1
	protected static String SCOPE = "scope"; // May be used as name for personal blogs, scope for community blogs
	protected static String SHOW = "show"; // Show all or only the specified entry
	protected static String ENTRY_ID = "entry_id"; // ID of the specified entry to show
	protected static String MAX_ENTRIES = "max_entries"; // Maximum number of entries to display
	protected static String TEMPLATE = "template"; // Name of template to use
	
	protected static String[] prefNames = {
		URL,
		TYPE,
		SCOPE,
		SHOW,
		ENTRY_ID,
		MAX_ENTRIES,
		TEMPLATE
	};
	
	public WikiServiceProxy getWikiServiceProxy(PortletRequest request, PortletResponse response) {

		java.security.Principal principal = request.getUserPrincipal();
		
		String username = principal != null ? principal.getName() : "anonymous";
		String passcode = "owCwIKi";
		String key = null;
		
		//PortletPreferences prefs = request.getPreferences();
		String url = (String) request.getPortletSession().getAttribute(URL);
		String wikiProxyUrl = url != null ? url + "/owc_wiki/services/WikiRemoteService" : null;
		
		WikiServiceProxy wikiProxy = null;
		
		try {
			wikiProxy = new WikiServiceProxy(wikiProxyUrl);
		} catch (Exception e) {
			request.setAttribute("error_type", "invalid_url");			
			request.getPortletSession().removeAttribute("wiki_key");
		}
		
		try {
			key = wikiProxy.login(username, passcode);
			request.getPortletSession().setAttribute("wiki_key", key);
			return wikiProxy;
		} catch (Exception e) {
			//e.printStackTrace();
			
			if (e.getMessage() != null) {
				if (e.getMessage().contains("404")) {
					request.setAttribute("error_type", "invalid_service");
				} else if (e.getMessage().toLowerCase().contains("connection refused")) {
					request.setAttribute("error_type", "invalid_url");			
				} else if (e.getMessage().toLowerCase().contains("no such user")) {
					request.setAttribute("error_type", "invalid_user");			
				} else {
					request.setAttribute("error_type", "other");
				}
			}
			request.getPortletSession().removeAttribute("wiki_key");
		}
		
		return null;
	}
	
	public void _doIt(RenderRequest request, RenderResponse response, boolean getBlogData)
		throws PortletException, IOException {

		response.setContentType("text/html");

        request.removeAttribute("error_type");
        
		// Make preferences available to JSPs
		PortletPreferences prefs = request.getPreferences();
		PortletSession session = request.getPortletSession();
		String name = null;
		String value = null;
		
		for (int i = 0; i < prefNames.length; i++) {
			name = prefNames[i];

			value = prefs.getValue(name, null);
			
			if (value == null) {
				value = (String) session.getAttribute(name);
			} else {
				session.setAttribute(name, value);
			}
			
			request.setAttribute("blog_" + name, value);
		}

        if (getBlogData == true) {
            WikiServiceProxy wikiProxy = this.getWikiServiceProxy(request, response);
            
            if (wikiProxy != null) {
				String key = (String) request.getPortletSession().getAttribute("wiki_key");
				
				String url = (String) session.getAttribute(URL);
				if (url != null) {
					String blogRssUrl = url + "/owc_wiki/blog/rss.jz";
					request.setAttribute("blog_rss_url", blogRssUrl);
				}
				
				String t = (String) session.getAttribute(TYPE);
				BlogType type = BlogType.all;
				try {
					type  = BlogType.fromString(t);
				} catch (Exception e) {
					//e.printStackTrace();
				}
				String show = (String) session.getAttribute(SHOW);
				show = show != null ? show : "all";
				String scope = (String) session.getAttribute(SCOPE);
				String entryId = (String) session.getAttribute(ENTRY_ID);
				String m = (String) session.getAttribute(MAX_ENTRIES);
				long max = 9999;
				try {
					max = Long.parseLong(m);
				} catch (Exception e) {
					//e.printStackTrace();
				}
				if (max <= 0) {
					max = 1;
					request.setAttribute("blog_max_entries", max);
				}

				try {
					String[] blogNames = wikiProxy.getListofBlogs(type, "", -1, 0, key);
					for (int i = 0; i < blogNames.length; i++) {
						blogNames[i] = blogNames[i].replaceAll(":", "");
					}
					request.setAttribute("blog_names", blogNames);
				} catch (Exception e) {
					//e.printStackTrace();
					request.removeAttribute("blog_names");
				}
				
				if ("all".equals(show)) {
					try {
						String[] blogEntryIds = wikiProxy.getAllBlogEntries(scope, key);
						request.setAttribute("blog_entryIds", blogEntryIds);
						String[] blogEntries = new String[blogEntryIds.length];
						for (int i = 0; i < blogEntryIds.length; i++) {
							blogEntries[i] = wikiProxy.getBlogEntry(blogEntryIds[i], key);
						}
						// TreeMap contains BlogEntry objects
						java.util.TreeMap<Long, BlogEntry> sortedEntries = this.sortBlogEntries(blogEntries, blogEntryIds);
						request.setAttribute("blog_entries", sortedEntries);
					
						java.util.Iterator<Long> keyIterator = sortedEntries.keySet().iterator();
						BlogEntry blogEntry = null;
						Long entryKey = null;
						int[] blogCommentSizes = new int[sortedEntries.size()];
						int i = 0;
						while (keyIterator.hasNext() && i < max) {
						    entryKey = keyIterator.next();
						    blogEntry = sortedEntries.get(entryKey);
						    String[] blogComments = wikiProxy.getAllBlogEntryComments(blogEntry.getId(), key);
						    blogCommentSizes[i] = blogComments.length;
						    i++;
						}
						request.setAttribute("blog_comment_sizes", blogCommentSizes);
					} catch (Exception e) {
						//e.printStackTrace();
						request.setAttribute("error_type", "invalid_blog");
					}

				} else if (entryId != null && !"".equals(entryId)) {
					try {
						String entry = wikiProxy.getBlogEntry(entryId, key);
						BlogEntry blogEntry = this.parseBlogEntry(entry, entryId);
						request.setAttribute("blog_entry", blogEntry);
						String[] blogComments = wikiProxy.getAllBlogEntryComments(entryId, key);	
						java.util.TreeMap<Long, BlogComment> sortedComments = this.sortBlogComments(blogComments);
						request.setAttribute("blog_comments", sortedComments);
					} catch (Exception e) {
						//e.printStackTrace();
						request.setAttribute("error_type", "invalid_blog_entry");
					}
			    }
            }
        }
        
		// Search results are in the session...
		request.setAttribute("search_results", request.getPortletSession().getAttribute("search_results"));
		request.getPortletSession().removeAttribute("search_results");
		
		request.setAttribute("blog_search_text", request.getPortletSession().getAttribute("blog_search_text"));
		request.getPortletSession().removeAttribute("blog_search_text");
		
		request.setAttribute("blog_create", request.getPortletSession().getAttribute("blog_create"));
		request.getPortletSession().removeAttribute("blog_create");

		request.setAttribute("blog_settings", request.getPortletSession().getAttribute("blog_settings"));
		request.getPortletSession().removeAttribute("blog_settings");
	}
	
	/* Returns the blog entries reverse ordered by date (latest entry is first) */
	public java.util.TreeMap<Long, BlogEntry> sortBlogEntries(String[] entries, String[] ids) {
		
		// Use the sorting feature of TreeMap
		java.util.TreeMap<Long, BlogEntry> map = new java.util.TreeMap<Long, BlogEntry>(java.util.Collections.reverseOrder());
		
		if (entries != null) {
			BlogEntry blogEntry = null;
			Long key;
			for (int i = 0; i < entries.length; i++) {
				blogEntry = this.parseBlogEntry(entries[i], ids[i]);
				if (blogEntry != null) {
					key = Long.valueOf(blogEntry.getDate().getTime());
					// Handle duplicate keys
					while (map.get(key) != null) {
						key = new Long(key.longValue() - 1);
					}
					map.put(key, blogEntry);
				}
			}
		}
		
		return map;
	}
	
	public BlogEntry parseBlogEntry(String entry, String id) {

		String strDateFormat = "MM/dd/yyyy HH:mm";
		java.text.SimpleDateFormat dfDate = new java.text.SimpleDateFormat(strDateFormat);
		BlogEntry blogEntry = null;

		String regex = "((0[1-9]|1[012]|[1-9])/(0[1-9]|[1-9]|[12][0-9]|3[01])/(19|20)\\d{2} (0[0-9]|1[0-9]|2[0-3])):([0-5][0-9])"; 
		java.util.regex.Pattern pattern = java.util.regex.Pattern.compile(regex); 
		String targetString = entry;
		java.util.regex.Matcher matcher = pattern.matcher(targetString); 

		int start = -1;
		int end = -1;
		while (matcher.find() && start == -1) {
			start = matcher.start();
			end = matcher.end();
		}
		
		String temp = entry;

		String author = temp.substring(0, temp.indexOf(": ")).trim();
		String title = temp.substring(temp.indexOf(": ") + 1, start - 2).trim();
		String dateTime = temp.substring(start, end);
		String content = temp.substring(end + 1);
		
		java.util.Date date = null;
		try {
			date = dfDate.parse(dateTime);
			blogEntry = new BlogEntry(id, author, title, date, content);
		} catch (Exception e) {
			e.printStackTrace();
		}

		return blogEntry;
	}

	/* Returns the blog comments ordered by date (latest entry is last) */
	public java.util.TreeMap<Long, BlogComment> sortBlogComments(String[] comments) {
		
		// Use the sorting feature of TreeMap
		java.util.TreeMap<Long, BlogComment> map = new java.util.TreeMap<Long, BlogComment>();
		
		if (comments != null) {

			BlogComment blogComment = null;
			Long key = null;
			
			for (int i = 0; i < comments.length; i++) {
				blogComment = this.parseBlogComment(comments[i]);
				if (blogComment != null) {
					key = Long.valueOf(blogComment.getDate().getTime());
					// Handle duplicate keys
					while (map.get(key) != null) {
						key = new Long(key.longValue() - 1);
					}
					map.put(key, blogComment);
				}
			}
		}
		
		return map;
	}

	public BlogComment parseBlogComment(String comment) {
		String strDateFormat = "MM/dd/yyyy HH:mm";
		java.text.SimpleDateFormat dfDate = new java.text.SimpleDateFormat(strDateFormat);
		BlogComment blogComment = null;
		
		int index = comment.indexOf(": ");
		String author = comment.substring(0, index);
		String remainder = comment.substring(index + 1);
		index = remainder.indexOf("[");
		String dateTime = remainder.substring(0, index);
		String content = remainder.substring(index + 1,  remainder.length() - 1);
		
		java.util.Date date = null;
		try {
			date = dfDate.parse(dateTime);
			blogComment = new BlogComment(author, date, content);
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		return blogComment;
	}
	
	public void doView(RenderRequest request, RenderResponse response)
		throws PortletException, IOException {
		
		this._doIt(request, response, true);
		PortletContext context = getPortletContext();
		PortletRequestDispatcher rd = context.getRequestDispatcher("/blog/blogView.jsp");
		rd.include(request, response);
	}
	
	public void doEdit(RenderRequest request, RenderResponse response)
		throws PortletException, java.io.IOException {

		this._doIt(request, response, true);
		PortletContext context = getPortletContext();
		PortletRequestDispatcher rd = context.getRequestDispatcher("/blog/blogEdit.jsp");
		rd.include(request, response);
	}

	public void doHelp(RenderRequest request, RenderResponse response)
		throws PortletException, java.io.IOException {

		this._doIt(request, response, true);
		PortletContext context = getPortletContext();
		PortletRequestDispatcher rd = context.getRequestDispatcher("/samples/webcenter/portlets/blog/help.jsp");
		rd.include(request, response);
	}
	
	public void processAction(ActionRequest request, ActionResponse response)
		throws PortletException, java.io.IOException {

		if (request.getPortletMode().equals(PortletMode.VIEW)) {

			this.parsePrefs(request, response);

			request.getPortletSession().setAttribute("blog_create", request.getParameter("blog_create"));

			String action = request.getParameter("blog_action");
			if (action != null) {
				if ("update".equals(action)) {
					this.updateBlogEntry(request, response);
				} else if ("create".equals(action)) {
					this.createBlogEntry(request, response);
				} else if ("delete".equals(action)) {
					this.deleteBlogEntry(request, response);					
				} else if ("comment".equals(action)) {
					this.addBlogComment(request, response);					
				} else if ("search".equals(action)) {
					this.searchBlog(request, response);					
				} else if ("create_blog".equals(action)) {
					this.createBlog(request, response);					
				} else if ("settings".equals(action)) {
					request.getPortletSession().setAttribute("blog_settings", "true");
				}
			}
		} else {
			if (request.getPortletMode().equals(PortletMode.EDIT)) {
				this.parsePrefs(request, response);
				response.setPortletMode(PortletMode.VIEW);
			}
		}
	}

	public void createBlog(PortletRequest request, PortletResponse response)
		throws PortletException, java.io.IOException {
	
		String scope = request.getParameter("blog_scope");
		String description = "";

		if (request.getUserPrincipal().getName().equals(scope)) {
			
			PortletPreferences prefs = request.getPreferences();
		
			WikiServiceProxy wikiProxy = this.getWikiServiceProxy(request, response);
			
			if (wikiProxy != null) {
				String key = (String) request.getPortletSession().getAttribute("wiki_key");
				try {
					wikiProxy.enablePersonalBlog(description, true, key);
					prefs.setValue(SCOPE, scope);
					request.getPortletSession().setAttribute(SCOPE, scope);
					prefs.store();
				} catch (Exception e) {
					//e.printStackTrace();
					request.setAttribute("error_type", "invalid_blog");
				}
			}
		} else {
			request.setAttribute("error_type", "invalid_blog");
		}
	}

	public void createBlogEntry(PortletRequest request, PortletResponse response)
		throws PortletException, java.io.IOException {

		String content = request.getParameter("blog_content");
		String title = request.getParameter("blog_title");

		PortletPreferences prefs = request.getPreferences();
		String scope = (String) request.getPortletSession().getAttribute(SCOPE);

 		WikiServiceProxy wikiProxy = this.getWikiServiceProxy(request, response);
		
		if (wikiProxy != null) {
			String key = (String) request.getPortletSession().getAttribute("wiki_key");
			try {
				wikiProxy.createBlogEntry(scope, title, content, key);
				
				Thread.sleep(1000);
				
				String[] entries = wikiProxy.getAllBlogEntries(scope, key);
				
				// First entry should be the most recently created
				String id = entries[0];
				
				// Set the newly created entry in the prefs
				prefs.setValue(ENTRY_ID, id);
				request.getPortletSession().setAttribute(ENTRY_ID, id);
				prefs.store();
			} catch (Exception e) {
				//e.printStackTrace();
				prefs.setValue(SHOW, "all");
				request.getPortletSession().setAttribute(SHOW, "all");
				prefs.setValue(ENTRY_ID, null);
				request.getPortletSession().removeAttribute(ENTRY_ID);
			}
		}

	}

	public void deleteBlogEntry(PortletRequest request, PortletResponse response)
		throws PortletException, java.io.IOException {

		PortletPreferences prefs = request.getPreferences();
		String scope = (String) request.getPortletSession().getAttribute(SCOPE);
		String id = (String) request.getPortletSession().getAttribute(ENTRY_ID);

 		WikiServiceProxy wikiProxy = this.getWikiServiceProxy(request, response);
		
		if (wikiProxy != null) {
			String key = (String) request.getPortletSession().getAttribute("wiki_key");
			try {
				wikiProxy.deleteBlogEntry(id, key);

				String[] entries = wikiProxy.getAllBlogEntries(scope, key);
				
				// First entry should be the most recent
				id = entries[0];
				
				// Set the first entry in the prefs
				prefs.setValue(ENTRY_ID, id);
				request.getPortletSession().setAttribute(ENTRY_ID, id);
				prefs.store();
			} catch (Exception e) {
				//e.printStackTrace();
				prefs.setValue(SHOW, "all");
				request.getPortletSession().setAttribute(SHOW, "all");
				prefs.setValue(ENTRY_ID, null);
				request.getPortletSession().removeAttribute(ENTRY_ID);
			}
		}
	}

	public void updateBlogEntry(PortletRequest request, PortletResponse response)
		throws PortletException, java.io.IOException {

		String content = request.getParameter("blog_content");
		String title = request.getParameter("blog_title");

		String id = (String) request.getPortletSession().getAttribute(ENTRY_ID);

 		WikiServiceProxy wikiProxy = this.getWikiServiceProxy(request, response);
		
		if (wikiProxy != null) {
			String key = (String) request.getPortletSession().getAttribute("wiki_key");
			try {
				wikiProxy.editBlogEntry(id, title, content, key);
			} catch (Exception e) {
				//e.printStackTrace();
			}
		}
	}
	
	public void addBlogComment(PortletRequest request, PortletResponse response)
		throws PortletException, java.io.IOException {
	
		/*
		 * These are submitted by the form but not currently used. 
		 * 
		String username = request.getParameter("blog_comment_username");
		String email = request.getParameter("blog_comment_email");
		String website = request.getParameter("blog_comment_website");
		*/
		String text = request.getParameter("blog_comment_text");
		text = (text == null || "null".equals(text)) ? "" : text;

		//PortletPreferences prefs = request.getPreferences();
		String id = (String) request.getPortletSession().getAttribute(ENTRY_ID);

 		WikiServiceProxy wikiProxy = this.getWikiServiceProxy(request, response);
		
		if (wikiProxy != null) {
			String key = (String) request.getPortletSession().getAttribute("wiki_key");
			try {
				wikiProxy.createBlogEntryComment(id, text, key);
			} catch (Exception e) {
				//e.printStackTrace();
			}
		}
	}

	public void searchBlog(PortletRequest request, PortletResponse response)
		throws PortletException, java.io.IOException {

		String text = request.getParameter("blog_search_text");
		request.getPortletSession().setAttribute("blog_search_text", text);
		
		WikiServiceProxy wikiProxy = this.getWikiServiceProxy(request, response);
		
		if (wikiProxy != null) {
			String key = (String) request.getPortletSession().getAttribute("wiki_key");
			try {
				SearchResult[] results = wikiProxy.search(text, SearchType.blog, 200, key);
				request.getPortletSession().setAttribute("search_results", results);
			} catch (Exception e) {
				//e.printStackTrace();
			}
		}
	}

	public void parsePrefs(PortletRequest request, PortletResponse response)
		throws PortletException, java.io.IOException {

		PortletPreferences prefs = request.getPreferences();
		String name = null;
		String value = null;
		
		PortletSession session = request.getPortletSession();
		
		for (int i = 0; i < prefNames.length; i++) {
			name = prefNames[i];
			value = request.getParameter("blog_" + name);
			if (value != null) {
				prefs.setValue(name, value);
				session.setAttribute(name, value);
			}
		}
		
		try {
			prefs.store();
		} catch (Exception e) {
			//e.printStackTrace();
		}
	}
}
