package eu.dnetlib.enabling.inspector;

import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang.StringEscapeUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.xmldb.api.base.XMLDBException;

import edu.emory.mathcs.backport.java.util.Collections;
import eu.dnetlib.xml.database.XMLDatabase;

/**
 * test controller.
 *
 * @author marko
 *
 */
@Controller
public class ResourceTreeController extends AbstractInspectorController { // NOPMD
	/**
	 * base index.do path.
	 */
	private static final String INDEX_DO = "/inspector/index.do";

	/**
	 * logger.
	 */
	private static final Log log = LogFactory.getLog(ResourceTreeController.class); // NOPMD by marko on 11/24/08 5:02 PM

	/**
	 * xml database.
	 */
	@Resource(name = "existDatabase")
	private transient XMLDatabase xmlDatabase;

	/**
	 * debug.
	 */
	public ResourceTreeController() {
		super();
		log.info("ResourceTreeController created");
	}

	/**
	 * index.
	 *
	 * @return redirect url
	 */
	@RequestMapping("/inspector")
	String index() {
		return "redirect:inspector/index.do/db/list";
	}

	/**
	 * handles relative paths.
	 * @return redirect
	 */
	@RequestMapping("/inspector/")
	String indexSlash() {
		return "redirect:index.do/db/list";
	}


	/**
	 * index.
	 *
	 * @param model
	 *            model
	 * @param request
	 *            http request
	 * @throws XMLDBException
	 *             happens
	 */
	@RequestMapping("/inspector/index.do/**/list")
	void list(final Model model, final HttpServletRequest request) throws XMLDBException {
		final String path = request.getPathInfo().replace(INDEX_DO, "").replace("/list", "");

		log.debug("xml db: " + xmlDatabase);

		final Collection<String> children = xmlDatabase.listChildCollections(path);
		final Collection<String> files = xmlDatabase.list(path);

		model.addAttribute("path", path);
		model.addAttribute("pathComponents", extractPathComponents(path, ""));
		model.addAttribute("collections", children);
		model.addAttribute("files", files);
		model.addAttribute("title", "Title");
	}

	/**
	 * return a list of pairs (name, relative url bases) for each path component.
	 *
	 * @param path
	 *            slash separated path
	 * @param base
	 *            prepend this to all paths
	 * @return list of path components
	 */
	private List<Map<String, String>> extractPathComponents(final String path, final String base) {
		final String[] rawPathComponents = path.split("/");
		final List<Map<String, String>> pathComponents = new ArrayList<Map<String, String>>();
		for (String rawPathComponent : rawPathComponents) {
			final Map<String, String> pathElement = new HashMap<String, String>(); // NOPMD
			pathElement.put("name", rawPathComponent);

			pathComponents.add(pathElement);
		}
		Collections.reverse(pathComponents);
		final StringBuffer current = new StringBuffer(base); // NOPMD
		for (Map<String, String> pathComponent : pathComponents) {
			pathComponent.put("url", current.toString());
			current.append("../");
		}
		Collections.reverse(pathComponents);
		return pathComponents;
	}

	/**
	 * show a file.
	 *
	 * @param model
	 *            model
	 * @param request
	 *            request
	 * @return view name
	 * @throws XMLDBException
	 *             happens
	 */
	@RequestMapping("/inspector/index.do/**/show")
	String show(final Model model, final HttpServletRequest request) throws XMLDBException {

		final String path = request.getPathInfo().replace(INDEX_DO, "").replace("/show", "");
		log.info("index: " + path);

		final File fileHelper = new File(path);
		final String collection = fileHelper.getParent();
		final String fileName = fileHelper.getName();

		String file = xmlDatabase.read(fileName, collection);
		if (file == null)
			file = "no such file, click on edit to create";

		model.addAttribute("file", StringEscapeUtils.escapeHtml(file));
		model.addAttribute("pathComponents", extractPathComponents(collection, "../"));

		return "inspector/show";
	}

	/**
	 * Show raw profile.
	 *
	 * @param model mvc model
	 * @param request servlet request
	 * @return mvc view
	 * @throws XMLDBException could happen
	 */
	@RequestMapping("/inspector/index.do/**/raw")
	String raw(final Model model, final HttpServletRequest request) throws XMLDBException {

		final String path = request.getPathInfo().replace(INDEX_DO, "").replace("/show", "");
		log.info("index: " + path);

		final File fileHelper = new File(path);
		final String collection = fileHelper.getParent();
		final String fileName = fileHelper.getName();

		String file = xmlDatabase.read(fileName, collection);
		if (file == null)
			file = "no such file, click on edit to create";

		model.addAttribute("file", StringEscapeUtils.escapeHtml(file));

		return "inspector/raw";
	}

	/**
	 * show a file editor.
	 *
	 * @param model
	 *            model
	 * @param request
	 *            request
	 * @return view name
	 * @throws XMLDBException
	 *             happens
	 */
	@RequestMapping("/inspector/index.do/**/edit")
	String edit(final Model model, final HttpServletRequest request) throws XMLDBException {

		final String path = request.getPathInfo().replace(INDEX_DO, "").replace("/edit", "");

		final File fileHelper = new File(path);
		final String collection = fileHelper.getParent();
		final String fileName = fileHelper.getName();

		final String file = xmlDatabase.read(fileName, collection);
		if (file == null)
			model.addAttribute("creating", "true");

		model.addAttribute("file", StringEscapeUtils.escapeHtml(file));
		model.addAttribute("pathComponents", extractPathComponents(collection, "../"));

		return "inspector/edit";
	}

	/**
	 * update or create a file.
	 *
	 * @param model
	 *            model
	 * @param request
	 *            request
	 * @return view name
	 * @throws XMLDBException
	 *             happens
	 */
	@RequestMapping("/inspector/index.do/**/save")
	String save(final Model model, final HttpServletRequest request) throws XMLDBException {

		final String path = request.getPathInfo().replace(INDEX_DO, "").replace("/save", "");

		final File fileHelper = new File(path);
		final String collection = fileHelper.getParent();
		final String fileName = fileHelper.getName();

		log.info("saving: " + path);
		final String source = request.getParameter("source");

		if ("true".equals(request.getParameter("creating")))
			xmlDatabase.create(fileName, collection, source);
		else
			xmlDatabase.update(fileName, collection, source);

		return "redirect:show";
	}

	/**
	 * delete a file.
	 *
	 * @param model
	 *            model
	 * @param request
	 *            request
	 * @return view name
	 * @throws XMLDBException
	 *             happens
	 */
	@RequestMapping("/inspector/index.do/**/delete")
	String delete(final Model model, final HttpServletRequest request) throws XMLDBException {

		final String path = request.getPathInfo().replace(INDEX_DO, "").replace("/delete", "");

		final File fileHelper = new File(path);
		final String collection = fileHelper.getParent();
		final String fileName = fileHelper.getName();

		log.info("deleting: " + path);
		xmlDatabase.remove(fileName, collection);

		return "redirect:../list";
	}

	/**
	 * present a create form which will redirect to the edit form.
	 *
	 * @param model
	 *            model
	 * @param request
	 *            request
	 * @return view name
	 * @throws XMLDBException
	 *             happens
	 */
	@RequestMapping("/inspector/index.do/**/create")
	String create(final Model model, final HttpServletRequest request) throws XMLDBException {
		return "inspector/create";
	}

	/**
	 * sample controller.
	 *
	 * @param model
	 *            model
	 */
	@RequestMapping("/inspector/gadget.do")
	void gadget(final Model model) {
		log.info("GADGED CALLED");

		model.addAttribute("items", new String[] { "one", "two", "three" });
	}

}
