/*
 * Copyright PMEase (c) 2005-2008,
 * Date: Feb 24, 2008
 * Time: 4:29:05 PM
 * All rights reserved.
 * 
 * Revision: $$Id: ArtifactPanel.java 1645 2008-11-05 03:45:52Z robin $$ 
 */
package com.pmease.quickbuild.plugin.artifact;

import java.io.File;
import java.io.FileFilter;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.commons.lang.Validate;
import org.apache.wicket.AttributeModifier;
import org.apache.wicket.Component;
import org.apache.wicket.markup.ComponentTag;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.panel.Fragment;
import org.apache.wicket.markup.html.panel.Panel;

import com.pmease.quickbuild.ArtifactFile;
import com.pmease.quickbuild.Context;
import com.pmease.quickbuild.security.ConfigurationPermission;
import com.pmease.quickbuild.security.SecurityHelper;
import com.pmease.quickbuild.util.DateUtils;
import com.pmease.quickbuild.util.FileUtils;
import com.pmease.quickbuild.util.StringUtils;
import com.pmease.quickbuild.web.behavior.ConfirmBehavior;
import com.pmease.quickbuild.web.component.InternalImage;
import com.pmease.quickbuild.web.component.treetable.TreeDataProvider;
import com.pmease.quickbuild.web.component.treetable.TreeState;
import com.pmease.quickbuild.web.component.treetable.TreeTable;
import com.pmease.quickbuild.web.component.treetable.TreeTableColumn;

@SuppressWarnings("serial")
public class ArtifactPanel extends Panel {

	private Set<ArtifactFile> expandedPaths = new HashSet<ArtifactFile>();
	
	public ArtifactPanel(String panelId) {
		super(panelId);

		add(new TreeTable("treeTable", new TreeDataProvider() {
			
			public List<Serializable> getChildNodeKeys(Serializable nodeKey) {
				List<Serializable> childNodeKeys = new ArrayList<Serializable>();
				File parent = (File) nodeKey;
				if (parent.isDirectory()) {
					File[] folders = parent.listFiles(new FileFilter() {

						public boolean accept(File pathname) {
							return pathname.isDirectory();
						}
						
					});
					if (folders != null) {
						Arrays.sort(folders, new Comparator<File>() {

							public int compare(File file1, File file2) {
								return file1.getName().compareTo(file2.getName());
							}
							
						});
						for (File each: folders)
							childNodeKeys.add(new ArtifactFile(each));
					}
					List<ArtifactFile> files = new ArrayList<ArtifactFile>();
					File[] children = parent.listFiles(new FileFilter() {

						public boolean accept(File pathname) {
							return pathname.isFile();
						}
						
					});
					if (children != null) {
						for (File each: children) 
							files.add(new ArtifactFile(each));
					} 
					
					Collections.sort(files, new Comparator<File>() {

						public int compare(File file1, File file2) {
							return file1.getName().compareTo(file2.getName());
						}
						
					});
					for (ArtifactFile each: files)
						childNodeKeys.add(each);
				}
				return childNodeKeys;
			}

			public Serializable getParentNodeKey(Serializable nodeKey) {
				File parent = ((ArtifactFile) nodeKey).getParentFile();
				return parent.equals(Context.getBuild().getArtifactsDir())? null: parent;
			}

			public List<Serializable> getRootNodeKeys() {
				return getChildNodeKeys(Context.getBuild().getArtifactsDir());
			}

			public boolean isExpandable(Serializable nodeKey) {
				return ((ArtifactFile)nodeKey).isDirectory();
			}
			
		}, new TreeState() {

			public boolean isExpanded(Serializable nodeKey) {
				return expandedPaths.contains(nodeKey);
			}

			public void setExpanded(Serializable nodeKey, boolean expanded) {
				if (expanded)
					expandedPaths.add((ArtifactFile) nodeKey);
				else 
					expandedPaths.remove(nodeKey);
			}
			
		}, new TreeTableColumn() {

			public Component newCell(String id, Serializable nodeKey) {
				Fragment fragment = new Fragment(id, "nodeFrag", ArtifactPanel.this);
				final ArtifactFile file = (ArtifactFile) nodeKey;
				if (file.isDirectory()) {
					if (expandedPaths.contains(file.getAbsolutePath()))
						fragment.add(new InternalImage("icon", "/images/folder-open.gif"));
					else
						fragment.add(new InternalImage("icon", "/images/folder.gif"));
				} else {
					fragment.add(new InternalImage("icon", "/images/file.gif"));
				}
				WebMarkupContainer link = new WebMarkupContainer("link") {

					@Override
					protected void onComponentTag(ComponentTag tag) {
						super.onComponentTag(tag);
						String relativePath = FileUtils.getRelativePath(file.getAbsolutePath(), 
								Context.getBuild().getPublishDir().getAbsolutePath()).substring(1);
						Validate.isTrue(StringUtils.isNotBlank(relativePath));
						if (file.isDirectory()) {
							if (Context.getConfiguration().findArtifactStorage().getBatchSupport() != null 
									&& SecurityHelper.hasPermission(Context.getConfiguration(), ConfigurationPermission.BATCH_DOWNLOAD_ARTIFACTS.name())) {
								tag.put("href", Context.getConfiguration().findArtifactStorage().getBatchSupport().getUrl(
										Context.getBuild(), relativePath, "**")); 
								tag.put("title", "Download all files recursively under this directory");
							} else {
								tag.put("href", "javascript:void(0);");
								tag.put("class", "not-link");
							}
						} else {
							tag.put("href", Context.getConfiguration().findArtifactStorage().getUrl(Context.getBuild(), relativePath));
							tag.put("title", "Download this file");
						}
					}
					
				};
				if (file.isDirectory()
						&& Context.getConfiguration().findArtifactStorage().getBatchSupport() != null
						&& SecurityHelper.hasPermission(Context.getConfiguration(), ConfigurationPermission.BATCH_DOWNLOAD_ARTIFACTS.name())) {
					link.add(new ConfirmBehavior("This will download all files recursively under this directory, and " +
							"may take a considerable time if there are many files. Do you really want to continue?"));
				}

				link.add(new Label("name", file.getName()));
				fragment.add(link);
				return fragment;
			}

			public Component newHeader(String id) {
				return newTreeHeader(id);
			}
			
		}, new TreeTableColumn[]{
				new TreeTableColumn() {

					public Component newCell(String id, Serializable nodeKey) {
						File file = (File) nodeKey;
						if (file.isFile())
							return new Label(id, FileUtils.byteCountToDisplaySize(file.length()));
						else
							return new Label(id, " ");
					}

					public Component newHeader(String id) {
						Label header = new Label(id, "Size");
						header.add(new AttributeModifier("style", "font-weight:bold;"));
						return header;
					}
					
				}, 
				new TreeTableColumn() {

					public Component newCell(String id, Serializable nodeKey) {
						return new Label(id, DateUtils.formatDateTime(
								new Date(((File)nodeKey).lastModified())));
					}

					public Component newHeader(String id) {
						Label header = new Label(id, "Last Modified");
						header.add(new AttributeModifier("style", "font-weight:bold;"));
						return header;
					}
					
				}
		}, false));

	}

	protected Component newTreeHeader(String id) {
		Label header = new Label(id, "Name");
		header.add(new AttributeModifier("class", "bold"));
		return header;
	}

}
