/*
 * $Id: SearchDocumentsAction.java,v 1.75 2008/04/17 10:01:01 marbobo Exp $
 *
 * Copyright (c) Siemens AG 2008 
 *           (c) Universität Paderborn 2008 
 * Licensed under EUPL 1.1. 
 *
 * $Log: SearchDocumentsAction.java,v $
 * Revision 1.75  2008/04/17 10:01:01  marbobo
 * + Velocity-Templates angepasst
 *
 * Revision 1.74  2006/12/18 15:50:23  lawern
 * Korowas Änderungen überarbeitet.
 *
 * Revision 1.72  2006/09/29 21:10:07  marbobo
 * + Sucheoptimiert
 *
 * Revision 1.71  2006/09/21 13:08:27  marbobo
 * + Unnötige addAll-Methodenaufruf entfernt
 *
 * Revision 1.70  2006/04/29 18:39:49  marbobo
 * + Refactoriengs und eine Ausgaben vereinheitlicht
 *
 * Revision 1.69  2005/09/15 00:48:11  marbobo
 * + Sprachabhängiges Sortieren implementiert
 *
 * Revision 1.68  2005/09/07 22:06:57  marbobo
 * + Sortierung nach Herausgeber implementiert
 *
 * Revision 1.67  2005/09/05 22:45:19  marbobo
 * + Suche nach Metadaten-Attribute (Erstellungsdatum) für Dokumente implementiert
 *
 * Revision 1.66  2005/09/05 13:52:49  marbobo
 * + Refactoring (Methode umbenannt)
 *
 * Revision 1.65  2005/09/04 23:21:22  marbobo
 * +Suche nach Metadaten-Attribute (Erstellungsdatum) für Dokumente implementiert
 *
 * Revision 1.64  2005/08/14 18:14:02  marbobo
 * + Alternative-Sicht implementiert
 *
 * Revision 1.63  2005/05/02 15:24:51  marbobo
 * +Ergänzungen und Bugfixing bzgl. der Speicherung der Sortierungeinstellungen in der Session
 *
 * Revision 1.62  2005/04/22 07:39:05  korowa
 * Die Sortierungsart von Search bleibt über die ganze Sitzung erhalten
 *
 * Revision 1.61  2005/02/15 09:26:53  bigmac
 * Refactorings
 *
 * Revision 1.60  2005/02/14 01:28:49  marbobo
 * + Schnellsuche auf Unicode-Zeichen angepasst
 *
 * Revision 1.59  2005/01/24 18:46:49  marbobo
 * + Bugfix bei der Schnellsuche beseitigt
 *
 * Revision 1.58  2004/11/13 22:24:15  marbobo
 * + Registrierung der Suchanfrage für Gast-Benutzer gesperrt
 *
 * Revision 1.57  2004/11/09 20:14:58  marbobo
 * + Suche nach Herausgeber
 *
 * Revision 1.56  2004/10/06 12:33:39  marbobo
 * + Suche nach Globalen Dokument-Attributen korrigiert
 *
 * Revision 1.55  2004/10/05 17:59:51  marbobo
 * + Suche nach Globalen Dokument-Attributen überarbeitet
 *
 * Revision 1.54  2004/09/15 14:18:55  marbobo
 * + Volltextsuche korrigiert
 * + Suche über alle Felder
 *
 * Revision 1.53  2004/09/03 00:42:43  marbobo
 * + Kategorieauswahl über ein Explorer für die Suche eingebaut
 *
 * Revision 1.52  2004/08/25 17:59:05  marbobo
 * + Bugfix ( Benutzerquery erstellen )
 *
 * Revision 1.51  2004/08/20 15:43:12  jonyp
 * refactoring due to change of VKCSearchQuerySerializer to VKCUserRegSearchQuerySerializer
 *
 * Revision 1.50  2004/08/20 12:52:36  koppy
 * + handleREgisterQueryAction(...)
 *
 * Revision 1.49  2004/04/27 11:37:54  marbobo
 * + Suche nach "Dateinamen" hinzugefügt
 *
 * Revision 1.48  2004/04/26 21:59:27  marbobo
 * + Dokumentsicht erweitert (mit/ohne Details)
 *
 * Revision 1.47  2004/04/17 21:00:46  marbobo
 * + Suche im beliebigem Zeitraum
 *
 * Revision 1.46  2004/03/25 21:21:17  marbobo
 * kleiner Bugfix
 *
 * Revision 1.45  2004/03/25 14:39:04  marbobo
 * Handling der Ergebnisseiten angepasst
 *
 * Revision 1.44  2004/03/25 01:52:47  marbobo
 * Suche nach Bestimmten Dokumenttypen gefixt (nochmal)
 *
 * Revision 1.43  2004/03/24 19:07:15  marbobo
 * Suche nach Bestimmten Dokumenttypen gefixt
 *
 * Revision 1.42  2004/03/23 19:47:54  marbobo
 * SearchDocumentsAction und SearchDocumentsForm neu überarbeitet
 * und auf Request-Scope umgestellt
 *
 */
package vkc.search.action;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Vector;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.lucene.search.Hits;
import org.apache.lucene.search.Sort;
import org.apache.lucene.search.SortField;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;

import vkc.db.entities.VKCAddAttribute;
import vkc.db.entities.VKCCategory;
import vkc.db.entities.VKCSearchQuery;
import vkc.db.entities.VKCUser;
import vkc.db.serializer.VKCAddAttributeSerializer;
import vkc.db.serializer.VKCUserRegSearchQuerySerializer;
import vkc.search.Search;
import vkc.search.SearchResultEntry;
import vkc.search.form.SearchDocumentsForm;
import vkc.util.VKCStringUtils;
import vkc.view.WebShare;

/**
 * Action-Klasse zur Verarbeitung von Suchanfragen und
 * Darstellung von Suchergebnissen
 *
 * @author marbobo
 * @version $Revision: 1.75 $
 */
public final class SearchDocumentsAction extends Action {
	private ActionForward DEFAULT_FORWARD = new ActionForward("/templates/${template.name}/search/searchDocuments.jsp");
	private ActionForward DEFAULT_FORWARD_ANCHORRESULT = new ActionForward("/templates/${template.name}/search/searchDocuments.jsp?anchor=results");
    
	/**
     * Hier werden die entsprechenden Aktionen eingeleitet
     */
    public ActionForward execute( ActionMapping mapping, 
    							  ActionForm f, 
    							  HttpServletRequest request, 
    							  HttpServletResponse response ) 
    throws Exception {
		SearchDocumentsForm form = (SearchDocumentsForm) f;

        if (request.getParameter("action.change.page") != null) {
            return handleChangeCurrentPageAction(form, request);
        } else if (request.getParameter("action.change.category") != null) {
            return handleChangeCategoryAction(form, request);
        } else if (request.getParameter("action.register.query") != null) {
            return handleRegisterQueryAction(form, request);
        } else if (request.getParameter("action.show.document.details") != null) {
			return handleShowDocumentDetailsAction(form, request);
		} else if (request.getParameter("action.hide.document.details") != null) {
			return handleHideDocumentDetailsAction(form, request);
		} else if (request.getParameter("action.show.documents") != null) {
			return handleShowDocumentsAction(form, request);
		} else if (request.getParameter("action.hide.documents") != null) {
			return handleHideDocumentsAction(form, request);
		} else if (form.isSearchAction(request)) {
            form.setCurrentResultPageId(new Integer(1));
            
            return handleSearchDocumentsAction(form, request);
        } else {
			return handleInitializeAction(form, request);
		}
    }

    private ActionForward handleRegisterQueryAction(SearchDocumentsForm form, HttpServletRequest request) throws Exception {
        if (!form.getUser().isGuestUser()) {
            VKCSearchQuery query = new VKCSearchQuery();
            query.setQuery(form.getSearchQuery() + form.getSearchOptions());
            
            VKCUserRegSearchQuerySerializer.saveSearchQuery(query, form.getUser().getUserId());
            
            request.setAttribute(WebShare.INFO_KEY, "vkc.search.queryRegistered");
            
            return new ActionForward("/editMessenger.do?initialize=true", false);
        }
        
        return handleInitializeAction(form, request);
    }

    /**
     * Diese Methode ermöglicht das Suchen nach Dokumenten entsprechend
     * der gestellten Suchanfrage. Die Suchergebnisse werden anhand der
     * Einstellungen der Suchmaske sortiert und dargestellt.
     */
    private ActionForward handleSearchDocumentsAction(SearchDocumentsForm form, HttpServletRequest request) throws Exception {
        VKCUser user = form.getUser();

		Integer resultsPerPage = new Integer(form.getSelectedNumberOfResultsPerPage());
		String documentType = form.getSelectedSearchResultLimitation();
		Integer sortId = new Integer(form.getSelectedSortResults());
		Integer currentPageId = form.getCurrentResultPageId();
		Integer searchCategoryId = (Integer.parseInt(form.getSelectedCategoryId()) == VKCCategory.ROOT_CATEGORY_ID) 
									? null 
									: Integer.valueOf(form.getSelectedCategoryId());
		Date from = form.getFrom();
		Date until = form.getUntil();
		String searchQuery = "";
        Hits hits = null;
        Sort sort = null;
        int startIndex = resultsPerPage.intValue() * ((currentPageId.intValue() > 1) ? (currentPageId.intValue() - 1) : 0);
		int endIndex = startIndex + resultsPerPage.intValue();

        Long startTime = new Long(0);
        Long endTime = new Long(0);

        if (form.isQuickSearchAction(request)) {
            //Suchanfrage kommt von der Schnellsuche-Box
            searchQuery = VKCStringUtils.base64Decode(form.getSearchFromHereText());

            //ab einer bestimmten Kategorie suchen
            if (request.getParameter("searchFromHere") != null) {
                searchCategoryId = new Integer(request.getParameter("searchFromHere"));
                form.setSelectedCategoryId(request.getParameter("searchFromHere"));
            }

            form.setSearchInAnyField(searchQuery);
        } else {
            searchQuery = form.getSearchQuery();
        }

		form.setSearching(true);

		//Suchergebnisse entsprechend der Suchmaskeauswahl sortieren
		switch (sortId.intValue()) {
			case 0:	
				sort = new Sort(new SortField(null, SortField.SCORE, true));
				break;
			case 1: 
				sort = new Sort(new SortField(null, SortField.SCORE));
				break;
			case 2:
				sort = new Sort(new SortField("published", SortField.STRING));
				break;
			case 3:
				sort = new Sort(new SortField("published", SortField.STRING, true));
				break;
			case 4:
				sort = new Sort(new SortField("authorname_sort", form.getUser().getLanguage().getLocale()));
				break;
			case 5:
				sort = new Sort(new SortField("authorname_sort", form.getUser().getLanguage().getLocale(), true));
				break;
			case 6:
				sort = new Sort(new SortField("creationDate", SortField.STRING));
				break;
			case 7:
				sort = new Sort(new SortField("creationDate", SortField.STRING, true));
				break;
			case 8:
				sort = new Sort(new SortField("publishername_sort", form.getUser().getLanguage().getLocale()));
				break;
			case 9:
				sort = new Sort(new SortField("publishername_sort", form.getUser().getLanguage().getLocale(), true));
				break;
		}
		
		startTime = new Long(System.currentTimeMillis());
		hits = Search.search(searchQuery, from, until, documentType, user, searchCategoryId, null, null, sort);
		endTime = new Long(System.currentTimeMillis());
		
		int hitsSize = hits != null ? hits.length() : 0;
		form.setHitsCount(new Integer(hitsSize));
		form.setStartIndex(new Integer(startIndex));

		if (hitsSize < endIndex) {
			endIndex = hitsSize;
		}
		
		form.getResults().clear();
		
		if (hits != null) {
	        for (int i = startIndex; i < endIndex; i++) {
	            form.getResults().add(SearchResultEntry.toSearchResultEntry(hits.doc(i), hits.score(i)));
	        }
		}
		
		Search.searchFinished();
        
		form.setHitsFound(form.getResults().isEmpty() ? false : true);
		
        //Anzahl der Ergebnisseiten ermitteln
        Integer pageCount = new Integer(((form.getHitsCount().intValue() % resultsPerPage.intValue()) == 0)
                						? (form.getHitsCount().intValue() / resultsPerPage.intValue())
                                        : ((form.getHitsCount().intValue() / resultsPerPage.intValue()) + 1));

		form.setPageCount(pageCount);
		
        //Suchdauer ermitteln
        Double searchTime = new Double((endTime.longValue() - startTime.longValue()) / 1000.0);
        form.setSearchTime(searchTime);

    	//Einstellungen für die Sortierung in der Session speichern
        request.getSession().setAttribute("searchDocumentSortMode", sortId);

    	if (form.getResults().isEmpty()) {
			return DEFAULT_FORWARD;
        } else if (request.getParameter("action.show.document.details") != null ||
				   request.getParameter("action.hide.document.details") != null ||
				   request.getParameter("action.show.documents") != null ||
				   request.getParameter("action.hide.documents") != null){
			return new ActionForward("/templates/${template.name}/search/searchDocuments.jsp?anchor=doc" + form.getSelectedId());
        } else {
			return DEFAULT_FORWARD_ANCHORRESULT;
        }
    }

    /**
     * Diese Methode wird beim ersten Aufruf von der Suche ausgeführt.
     * Es werden die Standardwerte der Suchmaske gesetzt.
     */
    private ActionForward handleInitializeAction(SearchDocumentsForm form, HttpServletRequest request) throws Exception {
		form.setSearchInAnyField("");
		form.setSearchInFullText("");
		form.setSearchForCreationDateFrom("");
		form.setSearchForCreationDateUntil("");
		form.setSearchForDynaAttributeNames("");
		form.setSearchForDynaAttributeValues("");
		form.setSearchForFilename("");
		form.setSearchForTitle("");
		form.setSearchForKeywords("");
		form.setSearchForDescription("");
		form.setSearchForAuthor("");
		form.setSearchForPublisher("");
		form.setSearchFromHereText("");
		form.setSelectedDocClassId("-1");
		form.setSelectedDocStatusId("-1");
		form.setValidFrom("");
		form.setValidUntil("");
		form.setSelectedNumberOfResultsPerPage("5");
		form.setSelectedSearchResultLimitation("*");
		form.setSelectedCategoryId(String.valueOf(VKCCategory.ROOT_CATEGORY_ID));
		form.setCurrentResultPageId(new Integer(1));
		form.setHitsCount(new Integer(0));
		form.setPageCount(new Integer(1));
		form.setSearchTime(new Double(0));
		form.setHitsFound(false);
		form.setSearching(false);
		form.setResults(new ArrayList());
		
		//Nachsehen ob in der Session Einstellungen für die Sortierung existiert
		if (request.getSession().getAttribute("searchDocumentSortMode") == null) {
			//Wenn nicht werden die Einstellungen aus dem User-Objekt geholt
        	if (form.getUser() != null && form.getUser().getSearchDocumentSortMode() != null) {
            	request.getSession().setAttribute("searchDocumentSortMode", form.getUser().getSearchDocumentSortMode());
        	    form.setSelectedSortResults(form.getUser().getSearchDocumentSortMode().toString());
        	} else {
            	form.setSelectedSortResults("1");
        	}
		} else {
        	form.setSelectedSortResults(((Integer)request.getSession().getAttribute("searchDocumentSortMode")).toString());
		}
		
		HashMap	addDocAttributes = new HashMap();
		Vector addDocAttr = VKCAddAttributeSerializer.getAllAddDocAttributes();
        
		for (int i = 0; i < addDocAttr.size(); i++) {
			VKCAddAttribute addAttribute = (VKCAddAttribute)addDocAttr.get(i);
			addDocAttributes.put("adddocattrId_" + addAttribute.getAttrId(), "");
		}

		form.setAddDocAttributes(addDocAttributes);

        return DEFAULT_FORWARD;
    }

    /**
     * Diese Methode ändert die aktuelle Ergebnisseite auf die
     * gewählte Seite
     */
    private ActionForward handleChangeCurrentPageAction(SearchDocumentsForm form, HttpServletRequest request) throws Exception {
        return handleSearchDocumentsAction(form, request);
    }

    private ActionForward handleChangeCategoryAction(SearchDocumentsForm form, HttpServletRequest request) throws Exception {
        return DEFAULT_FORWARD;
    }

    private ActionForward handleHideDocumentDetailsAction(SearchDocumentsForm form, HttpServletRequest request) throws Exception {
		List ids = new ArrayList(Arrays.asList(form.getShowDocumentDetails()));
		ids.remove( form.getSelectedId() );
		form.setShowDocumentDetails((Integer[])ids.toArray(new Integer[0]));

		return handleSearchDocumentsAction(form, request);
	}

	private ActionForward handleShowDocumentDetailsAction(SearchDocumentsForm form, HttpServletRequest request) throws Exception {
		List ids = new ArrayList(Arrays.asList(form.getShowDocumentDetails()));
		ids.add(form.getSelectedId());
		form.setShowDocumentDetails((Integer[])ids.toArray(new Integer[0]));

		return handleSearchDocumentsAction(form, request);
	}

	private ActionForward handleHideDocumentsAction(SearchDocumentsForm form, HttpServletRequest request) throws Exception {
		List ids = new ArrayList(Arrays.asList(form.getShowDocuments()));
		ids.remove(form.getSelectedId());
		form.setShowDocuments((Integer[])ids.toArray(new Integer[0]));
		
		return handleSearchDocumentsAction(form, request);
	}

	private ActionForward handleShowDocumentsAction(SearchDocumentsForm form, HttpServletRequest request) throws Exception {
		List ids = new ArrayList(Arrays.asList(form.getShowDocuments()));
		ids.add(form.getSelectedId());
		form.setShowDocuments((Integer[])ids.toArray(new Integer[0]));

		return handleSearchDocumentsAction(form, request);
	}
}