package page.plugin;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
import java.util.TreeSet;

import org.wikiwebserver.core.WareHouse;
import org.wikiwebserver.core.WikiMap;
import org.wikiwebserver.handler.http.HTTPException;
import org.wikiwebserver.handler.http.HTTPHandler;
import org.wikiwebserver.handler.http.interfaces.HTTPResponder;
import org.wikiwebserver.html.TemplatedPage;
import org.wikiwebserver.html.plugin.Plugin;

import page.config.SiteTemplatedPage;
import org.wikiwebserver.util.comparator.EntryValueComparator;

import static org.wikiwebserver.html.HTMLHelper.*;

import page.config.SiteMonitor;
import page.misc.CommentView;
import page.tools.entity.Comment;
import page.tools.entity.User;

public class ClassComments extends SiteTemplatedPage implements Plugin, HTTPResponder {
    
    public static final String pluginID = "Comments";

    private String className = this.getClass().getName();
    
    public String getActivationButton(TemplatedPage page) {
        className = page.getClass().getName();
        String url = WareHouse.getUrlPathForClass(this.getClass());
        String f = "togglePlugin('" + pluginID + "', '" + className + "', '" + url + "');";
        String label = this.getNumComments() + " Comments";
        return a("#comments", label, "onclick=\"" + f + "\"");
    }
    
    public String getComponent() {
        return div(pluginID, "style='display: none'", ajaxLoadingBar());
    }
    
    public void init(HTTPHandler conn) throws HTTPException {
        super.init(conn);
        if (getFormData() != null) {
            String className = getFormData().getFirst("className");
            if (className != null) {
                this.className = className;
            }           
        }
    }
    
    
    public void ajax() {
        String data = (String) getPostedData();
        if (data != null) {  
            this.className = data;
            append(updateHTMLScript(pluginID, formatedComments()));
        }
    }
    
    public void generate() throws HTTPException {
        
        Comment selected = null;
        if (getFormData() != null) {
            
            // Update comment
            new CommentView().process(getHandler());  
            
            String action = getFormData().getFirst("action");
            if (action != null) {
                String commentID = getFormData().getFirst("commentID");
                if (commentID != null) {
                    selected = Comment.getCommentById(commentID);
                }                 
                if (action.contains("Comment")) {  
                    String comments = getFormData().getFirst("comments");                    
                    comments = WareHouse.unescapeHTMLEntities(comments);
                    if (comments != null && comments.length() > 0) {
                        if (selected == null) addComment(comments);
                        else {
                            selected.setText(comments, getHandler());
                            selected = null;
                        }
                    }
                }
                if (action.contains("Delete")) { 
                    removeComment(commentID);
                }
                if (action.equalsIgnoreCase("update") || action.equalsIgnoreCase("delete")) {
                    String url = getServiceAddress() + getUrl() + "?className=" + className;
                    throw new HTTPException(303, "POST-Redirect-GET Pattern", url);
                }
            }
        }
        
        setTitle("Comments - WikiWebServer.org");
        
        if (!getClass().getName().equals(className)) {
            append(p(a(WareHouse.getUrlPathForClass(className), "Return to previous page")));
        }        
        append(formatedComments(getComments(), selected)); 
    }      
 
    
    private String formatedComments() {
        return formatedComments(getComments(), null);
    }
    
    private String formatedComments(Collection<Comment> comments, Comment selected) {
        
        StringBuilder bill = new StringBuilder();
        
        CommentView view = new CommentView();

        bill.append(a(null, null, "name='comments'") +
                    h(1, "Comments") +
                    h(3, "Comments posted about: " + className));
        
        String url = WareHouse.getUrlPathForClass(getClass().getName()) + "?className=" + this.className;
        
        for (Comment comment : comments) {
            if (comment.equals(selected)) {
                bill.append(h(2, "Edit comment"));
                bill.append(view.editComment(comment, this, url));
            } else {
                bill.append(view.showComment(comment, this, url));
            }
        }
        if (comments.size() == 0) {
            bill.append(p("No comments have been posted"));
        }
        
        if (selected == null) {
            bill.append(h(2, "Add comment"));
            bill.append(view.editComment(null, this, url));
        }
        
        return bill.toString();
        
        
    }
    
    private int getNumComments() {
        return getData(className).size();
    }
    
    private Collection<Comment> getComments() {

        
        // Sort comments by value (date)
        TreeSet<Map.Entry<String, Object>> sortedSet 
            = new TreeSet<Map.Entry<String, Object>>(new EntryValueComparator<String, Object>());

        for (Map.Entry<String, Object> entry : getData(className).entrySet()) {
            sortedSet.add(entry);
        }
    
        Collection<Comment> comments = new ArrayList<Comment>();
        Collection<String> idsForRemoval = new ArrayList<String>();
                
        // Populate list of comments
        for (Map.Entry<String, Object> entry : sortedSet) {
            Comment comment = Comment.getCommentById(entry.getKey());
            if (comment == null) idsForRemoval.add(entry.getKey());
            else comments.add(comment);
        }
        
        // Remove deleted items
        for (String commentID : idsForRemoval) {
            getData(className).remove(commentID);
        }
        
        return comments;
    }
    
    private void addComment(String text) {
        User author = getUser();

        Comment comment = new Comment(text, getHandler());
        
        author.addComment(comment, getRequest());
        Long time = new Long(System.currentTimeMillis());
        getData(className).put(comment.getId(), time);
        SiteMonitor.logComment(comment);
    }
    
    private void removeComment(String commentId) {
        getData(className).remove(commentId);
    }
       
    private WikiMap getData(String className) {
        WikiMap map = WareHouse.getWikiMap("Comments", className);
        if (map == null) map = WareHouse.initWikiMap("Comments", className);
        return map;        
    }    
    
    @Override
    public String getCacheKey() {
        WikiMap data = getData(className);
        if (data == null) return "EMPTY";
        String key = cacheKeyBasedOnFormData();
        return String.valueOf(data.getLastModifiedTime()) + key;

    }
}
