/*
 * Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
 *
 * The contents of this file are subject to the CCM Public
 * License (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the
 * License at http://www.redhat.com/licenses/ccmpl.html.
 *
 * Software distributed under the License is distributed on an
 * "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
 * or implied. See the License for the specific language
 * governing rights and limitations under the License.
 *
 */
package com.arsdigita.search.ui;


import com.arsdigita.bebop.SimpleComponent;
import com.arsdigita.bebop.Page;
import com.arsdigita.bebop.PageState;
import com.arsdigita.bebop.parameters.IntegerParameter;

import com.arsdigita.kernel.Party;
import com.arsdigita.xml.Element;
import com.arsdigita.xml.XML;

import com.arsdigita.search.Search;
import com.arsdigita.search.QuerySpecification;
import com.arsdigita.search.Document;
import com.arsdigita.search.ResultSet;

import com.arsdigita.web.URL;
import com.arsdigita.web.ParameterMap;
import com.arsdigita.web.Web;

import java.util.Date;
import java.util.Iterator;

import org.apache.log4j.Logger;


public class ResultsPane extends SimpleComponent {
    
    private static final Logger s_log = Logger.getLogger(ResultsPane.class);

    public static final int PAGE_SIZE = 10;

    private int m_pageSize = PAGE_SIZE;

    private String m_engine;
    private QueryGenerator m_query;
    private IntegerParameter m_pageNumber;

    public ResultsPane(QueryGenerator query) {
        this(query, null);
    }

    public ResultsPane(QueryGenerator query,
                       String engine) {
        m_query = query;
        m_engine = engine;
        m_pageNumber = new IntegerParameter("page");
    }

    public void register(Page p) {
        super.register(p);
        
        p.addGlobalStateParam(m_pageNumber);
    }
    
    public void generateXML(PageState state,
                            Element parent) {
        if (!m_query.hasQuery(state)) {
            if (s_log.isDebugEnabled()) {
                s_log.debug("No query available, skipping XMl generation");
            }
            return;
        }

        QuerySpecification spec = m_query.getQuerySpecification(state);
        ResultSet resultSet = m_engine == null ? 
            Search.process(spec) :
            Search.process(spec, 
                           Search.DEFAULT_RESULT_CACHE, 
                           m_engine);

        if (s_log.isDebugEnabled()) {
            s_log.debug("Got result set " + resultSet.getClass() + 
                        " count: " + resultSet.getCount());
        }
        
        Integer page = (Integer)state.getValue(m_pageNumber);
        int pageNumber = (page == null ? 1 : page.intValue());
        long objectCount = resultSet.getCount();
        int pageCount = (int)Math.ceil((double)objectCount / (double)m_pageSize);
        
        if (pageNumber < 1) {
            pageNumber = 1;
        }

        if (pageNumber > pageCount) {
            pageNumber = (pageCount == 0 ? 1 : pageCount);
        }
        
        long begin = ((pageNumber-1) * m_pageSize);
        int count = (int)Math.min(m_pageSize, (objectCount - begin));
        long end = begin + count;

        Iterator results = resultSet.getDocuments(begin, count);
        
        Element content = Search.newElement("results");
        exportAttributes(content);

        if (s_log.isDebugEnabled()) {
            s_log.debug("Paginator stats\n  page number:" + pageNumber + 
                        "\n  page count: "+ pageCount + "\n  page size: " +
                        m_pageSize + "\n start " + begin + "\n  end: " +
                        end + "\n count: "+ objectCount);
        }
        
        content.addContent(generatePaginatorXML(state, 
                                                m_pageNumber.getName(),
                                                pageNumber, pageCount,
                                                m_pageSize, begin, end, 
                                                objectCount));
        content.addContent(generateDocumentsXML(state, results));
        
        parent.addContent(content);
        
        resultSet.close();
    }

    protected Element generatePaginatorXML(PageState state,
                                           String pageParam,
                                           int pageNumber,
                                           int pageCount,
                                           int pageSize,
                                           long begin,
                                           long end,
                                           long objectCount) {
        Element paginator = Search.newElement("paginator");
        URL url = Web.getContext().getRequestURL();
        
        ParameterMap map = new ParameterMap();
        Iterator current = url.getParameterMap().keySet().iterator();
        while (current.hasNext()) {
            String key = (String)current.next();
            if (key.equals(pageParam)) {
                continue;
            }
            map.setParameterValues(key, url.getParameterValues(key));
        }

        paginator.addAttribute("pageParam", m_pageNumber.getName());
        paginator.addAttribute("baseURL", URL.there(url.getPathInfo(), map)
                               .toString());
        paginator.addAttribute("pageNumber", XML.format(new Integer(pageNumber)));
        paginator.addAttribute("pageCount", XML.format(new Integer(pageCount)));
        paginator.addAttribute("pageSize", XML.format(new Integer(pageSize)));
        paginator.addAttribute("objectBegin", XML.format(new Long(begin+1)));
        paginator.addAttribute("objectEnd", XML.format(new Long(end)));
        paginator.addAttribute("objectCount", XML.format(new Long(objectCount)));
        return paginator;
    }

    protected Element generateDocumentsXML(PageState state,
                                           Iterator results) {
        Element documents = Search.newElement("documents");
        
        if (s_log.isDebugEnabled()) {
            s_log.debug("Outputting documents");
        }
        while (results.hasNext()) {
            Document doc = (Document)results.next();
            if (s_log.isDebugEnabled()) {
                s_log.debug("One doc " + doc.getOID() + " " + doc.getTitle());
            }
            documents.addContent(generateDocumentXML(state, doc));
        }
        
        return documents;
    }
    
    protected Element generateDocumentXML(PageState state,
                                          Document doc) {
        Element entry = Search.newElement("object");
        
        String summary = doc.getSummary();
        
        entry.addAttribute("oid", XML.format(doc.getOID()));
        entry.addAttribute("url", XML.format(doc.getURL()));
        entry.addAttribute("score", XML.format(doc.getScore()));
        entry.addAttribute("title", XML.format(doc.getTitle()));
        if (summary != null) {
            entry.addAttribute("summary", XML.format(summary));
        }
        
        entry.addAttribute("locale", XML.format(doc.getLocale()));
        
        Date creationDate = doc.getCreationDate();
        if (creationDate != null) {
            entry.addAttribute("creationDate", XML.format(creationDate.toString()));
        }
        Party creationParty = doc.getCreationParty();
        if (creationParty != null) {
            entry.addAttribute("creationParty", 
                               XML.format(creationParty.getDisplayName()));
        }
        
        Date lastModifiedDate = doc.getLastModifiedDate();
        if (lastModifiedDate != null) {
            entry.addAttribute("lastModifiedDate", 
                               XML.format(lastModifiedDate));
        }
        Party lastModifiedParty = doc.getLastModifiedParty();
        if (lastModifiedParty != null) {
            entry.addAttribute("lastModifiedParty", 
                               XML.format(lastModifiedParty.getDisplayName()));
        }
        
        return entry;
    }
    
    
}
