package page.tools.stats;

import java.io.*;
import java.text.SimpleDateFormat;
import java.util.*;

import org.wikiwebserver.core.WareHouse;
import org.wikiwebserver.handler.http.interfaces.*;
import page.config.SiteTemplatedPage;
import org.wikiwebserver.util.comparator.FileModifiedComparator;


import static org.wikiwebserver.html.HTMLHelper.*;

public class ChangeView extends SiteTemplatedPage implements HTTPResponder {

    private static final long CACHE_TIME = 6 * 60 * 60 * 1000; // 6 Hours
    private static final String resourcePath = "/templates/default/changes/";
    
    private List<File> getAllFiles() {
        
        ArrayList<File> list = new ArrayList<File>();
        populate(new File("org/"), list);
        populate(new File("page/"), list);
        //populate(new File("image/"), list);        
        //populate(new WikiFile("templates/"), list);     
        //populate(new WikiFile("gallery/"), list);  
        //populate(new File("user/"), list);
        Collections.sort(list, new FileModifiedComparator());      
        
        return list;
    }
    
    public String getCacheKey() {
        return String.valueOf(System.currentTimeMillis() / CACHE_TIME);
    }
    
    public void generate() {
        
        addResourceRoot(resourcePath);
        setTitle("Changes - WikiWebServer.org");
        setDescription("Recent changes made to WikiWebServer");
        addCSSLink("changes.css");
        
        String rss = getServiceAddress() + getUrl() + "?type=rss";
        
        appendToHead("<link href='" + rss + "' title='Recent changes'" +
        		     " type='application/rss+xml' rel='alternate' />"); 
           
        append("<h1>Recent changes</h1>");
        
        append(a(rss, image("rssicon.gif", "RSS Feed of changes", "class='rssIcon'"),
                    "title='RSS feed of recent changes'"));            
        append(p("Recent changes made to WikiWebServer"));
        append(getHTMLChanges(getAllFiles())); 
        
        append(p("Changes observed on " + WareHouse.formatStandardDate(System.currentTimeMillis())));
        
    }
    
    private String getHTMLChanges(List<File> list) {
        
        String[] timeLabels = getTimeLables();
        long[] timePoints = getTimePoints();        
        StringBuilder body = new StringBuilder();
        int i = 0;
        for (File file : list) {
            String name = file.getName();
            String path = WareHouse.getUrlPathForFile(file);
            long modified = file.lastModified();
            while (modified < timePoints[i]) {
                if (modified > timePoints[i+1]) {
                    body.append(h(2, timeLabels[i]));
                    i++;
                    break;
                } 
                i++;
            }

            body.append(getFileDetailElement(name, path, file, resourcePath));
        }
        return body.toString();
    }   
    
    private String[] getTimeLables() {
        Calendar cal = getDayStart();
        String[] timeLabels = new String[11];
        timeLabels[0] = "Today";
        timeLabels[1] = "Yesterday";
        cal.add(Calendar.DATE, -2);
        SimpleDateFormat df = new SimpleDateFormat("EEEE d MMM");
        for (int i=2; i<7; i++) {
            timeLabels[i] = df.format(cal.getTimeInMillis());
            cal.add(Calendar.DATE, -1);
        }
        timeLabels[7] = "1 week ago";
        timeLabels[8] = "2 weeks ago";
        timeLabels[9] = "3 weeks ago";
        timeLabels[10] = "Over 4 weeks ago";
        
        return timeLabels;
    }
    
    private Calendar getDayStart() {
        GregorianCalendar cal = new GregorianCalendar();
        cal.setTime(new Date());
        cal.setTimeZone(TimeZone.getTimeZone("GMT"));
        cal.set(Calendar.HOUR_OF_DAY, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MILLISECOND, 0);
        return cal;
    }
    
    private long[] getTimePoints() {
        
        long[] timePoints = new long[12];
        timePoints[0] = Long.MAX_VALUE;
        Calendar cal = getDayStart();
        for (int i=1; i<8; i++) {
            timePoints[i] = cal.getTimeInMillis();
            cal.add(Calendar.DATE, -1);
        }
        for (int i=8; i<11; i++) {
            timePoints[i] = cal.getTimeInMillis();
            cal.add(Calendar.DATE, -7);
        }   
        timePoints[11] = 0;
        
        return timePoints;
    }  
    
    private static String getFileDetailElement(String name, String href, File file, String iconRoot) {
        StringBuffer buffer = new StringBuffer();
        boolean editable = isEditable(file);
        String icon = WareHouse.getIconForFile(file, iconRoot);
        String openTip = "Open " + href;
        String editTip = editable ? "Edit " + name : "Binary file";
        String editPath = WareHouse.SOURCE_EDITOR_URL + "?path=" + href;
        buffer.append("<div class='fileNodeDetail'>");
        
        buffer.append("<div class='fileDateDetail'>");
        buffer.append(WareHouse.formatStandardDate(file.lastModified()));
        buffer.append("</div>");        
        
        buffer.append("<div class='fileSizeDetail'>");
        buffer.append(WareHouse.formatNumber(file.length()));
        buffer.append("</div>");        
        
        buffer.append("<a title='" + openTip + "' href='" + href + "'>");
        buffer.append("<img border='0' src='" +  icon + "' width='16' height='16' alt='" + openTip + "' class='fileIcon'/>");
        buffer.append("</a>");
        
        buffer.append(" <a title='" + openTip + "' href='" + href + "'>");
        buffer.append(name);
        buffer.append("</a>");
        
        if (editable) {
            buffer.append(" [<a title='" + editTip + "' href='" + editPath + "'>");
            buffer.append("Edit</a>]"); 
        }
        
        buffer.append("</div>");
        return buffer.toString();
    }     
    
    private void populate(File dir, ArrayList<File> list) {
        File[] files = dir.listFiles();
        if (files == null) return;
        
        for (File file : files) {
            try {
                if (file.isDirectory()) {
                    populate(file, list);
                }
                else if (isVisible(file)) {
                    list.add(file);
                }
            } catch (SecurityException ex) {
                // Thrown by org.wikiwebserver.core.SecurityMan
            }
        }
    }
    
    private static boolean isEditable(File file) {
        String name = file.getName();
        String contentType = WareHouse.getContentType(file);
        
        if (name.startsWith(".")) return true;
        if (contentType != null && contentType.startsWith("text/")) {
            return true;
        }
        return false;
    }  
    
    private static boolean isVisible(File file) {
        String name = file.getName();
        if (name.startsWith(".")) return false;
        if (name.endsWith(".class")) return false;
        
        String contentType = WareHouse.getContentType(file);
        if (contentType != null && contentType.equals("application/wikiwebserver")) {
            return false;
        }
        return true;
    }     
}
