package com.logicaldoc.gui.frontend.client.search;

import com.google.gwt.i18n.client.NumberFormat;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.logicaldoc.gui.common.client.CookiesManager;
import com.logicaldoc.gui.common.client.Session;
import com.logicaldoc.gui.common.client.beans.GUIDocument;
import com.logicaldoc.gui.common.client.beans.GUIFolder;
import com.logicaldoc.gui.common.client.beans.GUISearchOptions;
import com.logicaldoc.gui.common.client.i18n.I18N;
import com.logicaldoc.gui.common.client.log.Log;
import com.logicaldoc.gui.common.client.observer.DocumentController;
import com.logicaldoc.gui.common.client.observer.DocumentObserver;
import com.logicaldoc.gui.common.client.observer.FolderController;
import com.logicaldoc.gui.common.client.observer.FolderObserver;
import com.logicaldoc.gui.common.client.util.Util;
import com.logicaldoc.gui.common.client.widgets.preview.PreviewPopup;
import com.logicaldoc.gui.frontend.client.document.DocumentsPanel;
import com.logicaldoc.gui.frontend.client.document.grid.ContextMenu;
import com.logicaldoc.gui.frontend.client.document.grid.Cursor;
import com.logicaldoc.gui.frontend.client.document.grid.DocumentsGrid;
import com.logicaldoc.gui.frontend.client.document.grid.DocumentsTileGrid;
import com.logicaldoc.gui.frontend.client.services.FolderService;
import com.smartgwt.client.widgets.Canvas;
import com.smartgwt.client.widgets.events.DoubleClickEvent;
import com.smartgwt.client.widgets.events.DoubleClickHandler;
import com.smartgwt.client.widgets.form.fields.events.ChangedEvent;
import com.smartgwt.client.widgets.form.fields.events.ChangedHandler;
import com.smartgwt.client.widgets.grid.ListGridField;
import com.smartgwt.client.widgets.grid.events.CellContextClickEvent;
import com.smartgwt.client.widgets.grid.events.CellContextClickHandler;
import com.smartgwt.client.widgets.grid.events.SelectionChangedHandler;
import com.smartgwt.client.widgets.grid.events.SelectionEvent;
import com.smartgwt.client.widgets.layout.VLayout;
import com.smartgwt.client.widgets.menu.Menu;
import com.smartgwt.client.widgets.menu.MenuItem;
import com.smartgwt.client.widgets.menu.events.MenuItemClickEvent;

/**
 * This panel shows a list of search results in a tabular way.
 * 
 * @author Marco Meschieri - LogicalDOC
 * @since 6.0
 */
public class HitsListPanel extends VLayout implements SearchObserver, DocumentObserver, FolderObserver {

	protected DocumentsGrid grid = null;

	private Cursor cursor;

	private int visualizationMode = DocumentsGrid.MODE_LIST;

	public HitsListPanel() {
		if (CookiesManager.get(CookiesManager.COOKIE_HITSLIST_MODE) != null)
			visualizationMode = Integer.parseInt(CookiesManager.get(CookiesManager.COOKIE_HITSLIST_MODE).toString());
		Search.get().addObserver(this);
		DocumentController.get().addObserver(this);
		FolderController.get().addObserver(this);
		initialize();
	}

	void initialize() {
		if (grid != null)
			removeMember((Canvas) grid);

		ListGridField id = new ListGridField("id", 60);
		id.setHidden(true);

		if (visualizationMode == DocumentsGrid.MODE_LIST)
			grid = new SearchHitsGrid();
		else if (visualizationMode == DocumentsGrid.MODE_GALLERY)
			grid = new DocumentsTileGrid(null, null);

		grid.registerSelectionChangedHandler(new SelectionChangedHandler() {
			@Override
			public void onSelectionChanged(SelectionEvent event) {
				onHitSelected();
			}
		});

		grid.registerCellContextClickHandler(new CellContextClickHandler() {
			@Override
			public void onCellContextClick(CellContextClickEvent event) {
				GUIDocument doc = grid.getSelectedDocument();
				final String type = doc.getType();
				long id = doc.getFolder().getId();

				if (type == null || (!type.contains("folder") && Session.get().getCurrentDocument() != null
						&& Session.get().getCurrentDocument().getId() == id)) {
					showContextMenu(Session.get().getCurrentDocument().getFolder(), true);
				} else {
					/*
					 * We need to retrieve the folder from the server
					 */
					FolderService.Instance.get().getFolder(id, false, false, false, new AsyncCallback<GUIFolder>() {

						@Override
						public void onFailure(Throwable caught) {
							Log.serverError(caught);
						}

						@Override
						public void onSuccess(GUIFolder folder) {
							showContextMenu(folder, !type.contains("folder"));
						}
					});
				}
				event.cancel();
			}
		});

		grid.registerDoubleClickHandler(new DoubleClickHandler() {
			@Override
			public void onDoubleClick(DoubleClickEvent event) {
				if (Search.get().getOptions().getType() != GUISearchOptions.TYPE_FOLDERS) {
					final GUIDocument doc = grid.getSelectedDocument();

					FolderService.Instance.get().getFolder(doc.getFolder().getId(), false, false, false,
							new AsyncCallback<GUIFolder>() {

								@Override
								public void onFailure(Throwable caught) {
									Log.serverError(caught);
								}

								@Override
								public void onSuccess(GUIFolder folder) {
									if (folder.isDownload()
											&& "download".equals(Session.get().getInfo().getConfig("gui.doubleclick")))
										Window.open(Util.downloadURL(doc.getId()), "_blank", "");
									else {
										PreviewPopup iv = new PreviewPopup(doc);
										iv.show();
									}
								}
							});
				}
				event.cancel();
			}
		});

		if (cursor != null)
			removeMember(cursor);
		cursor = new Cursor();
		cursor.setMaxDisplayedRecords(Search.get().getOptions().getMaxHits());
		cursor.registerMaxChangedHandler(new ChangedHandler() {

			@Override
			public void onChanged(ChangedEvent event) {
				GUISearchOptions opt = Search.get().getOptions();
				opt.setMaxHits(cursor.getMaxDisplayedRecords());
				Search.get().search();
			}
		});

		setMembers(cursor, (Canvas) grid);

		onSearchArrived();
	}

	@Override
	public void onSearchArrived() {
		/**
		 * Update the cursor. Prepare a stack for 2 sections the Title with
		 * search time and the list of hits
		 */
		NumberFormat format = NumberFormat.getFormat("#.###");

		String stats = I18N.message("aboutresults", new String[] { "" + Search.get().getEstimatedHits(),
				format.format((double) Search.get().getTime() / (double) 1000) });
		stats += " (<b>" + format.format((double) Search.get().getTime() / (double) 1000) + "</b> "
				+ I18N.message("seconds").toLowerCase() + ")";
		cursor.setMessage(stats);

		GUISearchOptions options = Search.get().getOptions();
		if (options.getType() == GUISearchOptions.TYPE_FULLTEXT)
			grid.setCanExpandRows();
		GUIDocument[] result = Search.get().getLastResult();
		if (result != null)
			grid.setDocuments(result);
		
		if (Search.get().isHasMore())
			Log.warn(I18N.message("possiblemorehits"), I18N.message("possiblemorehitsdetail"));

		cursor.setMaxDisplayedRecords(options.getMaxHits());
	}

	@Override
	public void onOptionsChanged(GUISearchOptions newOptions) {
	}

	private void onHitSelected() {
		// Avoid server load in case of multiple selections
		if (grid.getSelectedCount() != 1)
			return;

		final GUIDocument hit = grid.getSelectedDocument();
		if (hit != null)
			if ("folder".equals(hit.getType()))
				SearchPanel.get().onSelectedFolderHit(hit.getId());
			else
				SearchPanel.get().onSelectedDocumentHit(hit.getId());
	}

	protected void showContextMenu(GUIFolder folder, final boolean document) {
		Menu contextMenu = new Menu();

		if (document) {
			contextMenu = new ContextMenu(Session.get().getCurrentFolder(), grid);

			if (com.logicaldoc.gui.common.client.Menu.enabled(com.logicaldoc.gui.common.client.Menu.DOCUMENTS)) {
				MenuItem openInFolder = new MenuItem();
				openInFolder.setTitle(I18N.message("openinfolder"));
				openInFolder.addClickHandler(new com.smartgwt.client.widgets.menu.events.ClickHandler() {
					public void onClick(MenuItemClickEvent event) {
						GUIDocument doc = grid.getSelectedDocument();
						DocumentsPanel.get().openInFolder(doc.getFolder().getId(), doc.getId());
					}
				});
				contextMenu.addItem(openInFolder);
			}

		} else {
			if (com.logicaldoc.gui.common.client.Menu.enabled(com.logicaldoc.gui.common.client.Menu.DOCUMENTS)) {
				MenuItem openInFolder = new MenuItem();
				openInFolder.setTitle(I18N.message("openinfolder"));
				openInFolder.addClickHandler(new com.smartgwt.client.widgets.menu.events.ClickHandler() {
					public void onClick(MenuItemClickEvent event) {
						GUIDocument doc = grid.getSelectedDocument();
						DocumentsPanel.get().openInFolder(doc.getFolder().getId(), null);
					}
				});
				contextMenu.addItem(openInFolder);
			}
		}

		contextMenu.showContextMenu();
	}

	public DocumentsGrid getList() {
		return grid;
	}

	@Override
	public void onFolderSelected(GUIFolder folder) {
		// Nothing to do
	}

	@Override
	public void onFolderDeleted(GUIFolder folder) {
		// Nothing to do
	}

	@Override
	public void onFolderCreated(GUIFolder folder) {
		// Nothing to do
	}

	@Override
	public void onFolderMoved(GUIFolder folder) {
		// Nothing to do
	}

	@Override
	public void onFolderChanged(GUIFolder folder) {
		GUIDocument doc = grid.getSelectedDocument();
		if (doc != null) {
			doc.setFileName(folder.getName());
			doc.getFolder().setName(folder.getName());
			doc.getFolder().setDescription(folder.getDescription());
			grid.updateDocument(doc);
		}
	}

	@Override
	public void onDocumentSelected(GUIDocument document) {
		// Nothing to do
	}

	@Override
	public void onDocumentsDeleted(GUIDocument[] documents) {
		// Nothing to do
	}

	@Override
	public void onDocumentMoved(GUIDocument document) {
		// Nothing to do
	}

	@Override
	public void onDocumentModified(GUIDocument document) {
		grid.updateDocument(document);
	}

	@Override
	public void onDocumentCheckedIn(GUIDocument document) {
		onDocumentModified(document);
	}

	@Override
	public void onDocumentCheckedOut(GUIDocument document) {
		onDocumentModified(document);
	}

	@Override
	public void onDocumentLocked(GUIDocument document) {
		onDocumentModified(document);

	}

	@Override
	public void onDocumentUnlocked(GUIDocument document) {
		onDocumentModified(document);
	}

	@Override
	public void onDocumentStored(GUIDocument document) {

	}

	@Override
	public void destroy() {
		DocumentController.get().removeObserver(this);
		FolderController.get().removeObserver(this);
		Search.get().removeObserver(this);
	}

	@Override
	protected void finalize() throws Throwable {
		destroy();
	}

	@Override
	protected void onUnload() {
		destroy();
		super.onUnload();
	}

	@Override
	protected void onDestroy() {
		destroy();
		super.onDestroy();
	}

	public int getVisualizationMode() {
		return visualizationMode;
	}

	public void setVisualizationMode(int visualizationMode) {
		this.visualizationMode = visualizationMode;
	}

	public DocumentsGrid getGrid() {
		return grid;
	}
}