package page.tools.stats;

import java.util.Map;
import java.util.TreeSet;

import org.wikiwebserver.core.WareHouse;
import org.wikiwebserver.core.WikiMap;
import org.wikiwebserver.distribute.server.WorkerNodeManager;
import org.wikiwebserver.handler.http.interfaces.HTTPResponder;
import page.config.SiteTemplatedPage;
import org.wikiwebserver.util.comparator.DescendingEntryValueComparator;

import page.config.SiteMonitor;
import page.tools.entity.NodeData;

import static org.wikiwebserver.html.HTMLHelper.*;
import static org.wikiwebserver.html.HTMLHelper.ContainerType.*;

public class NodeList extends SiteTemplatedPage implements HTTPResponder {
    
    private static final int NODES_PER_PAGE = 10;
    
    public void generate() {
        
        setTitle("Nodes - WikiWebServer.org");
        addResourceRoot("/templates/default/list/");
        addCSSLink("list.css");   
        
        addJavascriptLink("/page/tools/html/ajax.js");
        
        append(h(1, "Nodes"));

        String query = "";
        int limit = NODES_PER_PAGE;
        int start = 0;
        if (getFormData() != null) {
            if (getFormData().getFirst("o") != null) {
                start = Integer.parseInt(getFormData().getFirst("o"));
            }
            if (getFormData().getFirst("q") != null) {
                query = getFormData().getFirst("q");
            }     
            if (getFormData().getFirst("limit") != null) {
                limit = Integer.parseInt(getFormData().getFirst("limit"));
            }               
        }

        append(form("Search: " + textfield("q", query, "onkeyup='cpov(this, 300);'")
                               + submitbutton("action", "Search")));

        append(div("list", nodeItems(start, limit, query)));
        append(cleardiv());
        
        String link = a("http://www.mydisk.co.uk/", "www.mydisk.co.uk");
        append(p("Please visit " + link + " to connect your computer to WikiWebServer."));

    }
    
    public void ajax() {
        append("$('#list').hide();");   
        String query = (String) getHandler().getRequest().getData();
        append(updateHTMLScript("list", nodeItems(0, NODES_PER_PAGE, query)));
        append("$('#list').fadeIn(500);");        
    }
    
    private String nodeItems(int start, int maxResults, String query) {
        
        query = query.toLowerCase();
        
        TreeSet<Map.Entry<String, Object>> sortedSet 
            = new TreeSet<Map.Entry<String, Object>>(
                    new DescendingEntryValueComparator<String, Object>());   
    
        Map<String, Object> dataStore = (WikiMap) SiteMonitor.getStatistic("NodeAccessTimes");
        if (dataStore == null) return p("No nodes found.");
        
        for (Map.Entry<String, Object> entry : dataStore.entrySet()) {
            sortedSet.add(entry);
        }
    
        int end = start + maxResults;
        StringBuilder bill = new StringBuilder();
        
        if (start > 0) {
            bill.append(p(a("?o=" + (start-maxResults) + "&q=" + query, "&lt;- Previous")));
        }
        
        int i = 0;        
        int numResults = 0;        
        
        // Add the example node
        String exampleNodeId = WorkerNodeManager.EXAMPLE_NODE.getNodeId();
        NodeData exampleNodeData = NodeData.getNodeDataById(exampleNodeId);   
        if (exampleNodeData != null) {
            if (start == 0 && exampleNodeData.getName().contains(query)) {
                bill.append(nodeItem(exampleNodeData));  
                i++;
                numResults++;
            }
        }        
        

        for (Map.Entry<String, Object> entry : sortedSet) {
            NodeData nodeData = NodeData.getNodeDataById(entry.getKey());
            if (nodeData != null && nodeData.getName() != null) {
                String nodeName = nodeData.getName().toLowerCase(); 
                if (nodeName.contains(query)) {
                    if (i++ < start) continue;                
                    if (i <= end) {
                        bill.append(nodeItem(nodeData));    
                    }
                    numResults++;                
                    // Optimisation (early exit)
                    if (numResults > maxResults) {
                        break;
                    }
                }
            }
            else {
            	// Remove this node, it can't be read
            	dataStore.remove(entry.getKey());
            }
        }
        
        bill.append(cleardiv());
        
        if (numResults > maxResults) {
            bill.append(p(a("?o=" + end + "&q=" + query, "Next -&gt;")));
        }
        
        if (numResults == 0) {
            bill.append(p("No nodes found."));
        } 
        else {
            bill.append(p("Total nodes: " + sortedSet.size()));      
        }           
        
        return bill.toString();
    }
    
    
    private String nodeItem(NodeData nodeData) {
        
        String name = nodeData.getName();
        String id = nodeData.getId();
        
        String profile = WareHouse.getUrlPathForClass(
                page.tools.stats.NodeInfo.class) + "?nodeID=" + id;
        
        String files = "/nodes/" + WareHouse.urlEncode(name) + "/";   
        
        return div(CLASS, "listitem", nodeImage(nodeData, "width='56' height='56' class='icon'") +
                    div(CLASS, "name", strong(name)) +
                    div(CLASS, "detailslink", a(profile, "Node details")) +
                    div(CLASS, "fileslink", a(files, "Files")));
    }

    @Override
    public String getCacheKey() {
        return String.valueOf(System.currentTimeMillis() / 1000);
    }    
    
    @Override
    public long getExpireTime() {
        return System.currentTimeMillis() + 1000;
    }
}

