/*
 * The Kuali Financial System, a comprehensive financial management system for higher education.
 *
 * Copyright 2005-2016 The Kuali Foundation
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.kuali.kfs.kns.lookup;

import org.kuali.kfs.kns.document.authorization.BusinessObjectRestrictions;
import org.kuali.kfs.kns.service.BusinessObjectDictionaryService;
import org.kuali.kfs.kns.web.struts.form.LookupForm;
import org.kuali.kfs.kns.web.ui.Column;
import org.kuali.kfs.kns.web.ui.Field;
import org.kuali.kfs.kns.web.ui.ResultRow;
import org.kuali.kfs.kns.web.ui.Row;
import org.kuali.kfs.krad.service.DataDictionaryService;
import org.kuali.rice.krad.bo.BusinessObject;

import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.Map;

public interface LookupableHelperService extends Serializable {

    /**
     * Initializes the lookup with a business object class.  This is set
     * via the LookupableHelperService's consumer, namely the Lookupable
     * implementation (or in cases of nesting a wrapping LookupableHelperService).
     * The Lookupable in turn receives this value from the UI via
     * LookupForm population.
     *
     * @param businessObjectClass
     */
    public void setBusinessObjectClass(Class businessObjectClass);

    /**
     * @return Returns the dataObjectClass this lookupable is representing
     */
    // NOTE: used in exactly one place in RuleBaseValuesLookupableHelperServiceImpl to conditionally initialize
    // an internal lookup helper service reference; this reference should in theory be a unique instance or prototype
    // so the check should not be necessary
    public Class getBusinessObjectClass();

    /**
     * Initializes the lookup with the given Map of parameters.
     *
     * @param parameters
     */
    public void setParameters(Map<String, String[]> parameters);

    /**
     * @return Returns the parameters passed to this lookup
     */
    public Map<String, String[]> getParameters();

    /**
     * @return String url for the location to return to after the lookup
     */
    public String getReturnLocation();

    /**
     * @return List of Column objects used to render the result table
     */
    public List<Column> getColumns();

    /**
     * Validates the values filled in as search criteria, also checks for required field values.
     *
     * @param fieldValues - Map of property/value pairs
     */
    public void validateSearchParameters(Map<String, String> fieldValues);

    /**
     * Performs a search and returns result list.
     *
     * @param fieldValues - Map of property/value pairs
     * @return List of business objects found by the search
     * @throws Exception
     */
    public List<? extends BusinessObject> getSearchResults(Map<String, String> fieldValues);

    /**
     * Similar to getSearchResults, but the number of returned rows is not bounded
     *
     * @param fieldValues
     * @return
     */
    public List<? extends BusinessObject> getSearchResultsUnbounded(Map<String, String> fieldValues);

    /**
     * Determines if there should be more search fields rendered based on already entered search criteria.
     *
     * @param fieldValues - Map of property/value pairs
     * @return boolean
     */
    public boolean checkForAdditionalFields(Map<String, String> fieldValues);

    /**
     * Builds the return value url.
     *
     * @param businessObject   - Instance of a business object containing the return values
     * @param fieldConversions - Map of conversions mapping bo names to caller field names.
     * @param lookupImpl       - Current lookup impl name
     * @param returnKeys       - Keys to return
     * @return String url called when selecting a row from the result set
     */
    public HtmlData getReturnUrl(BusinessObject businessObject, Map fieldConversions, String lookupImpl, List returnKeys, BusinessObjectRestrictions businessObjectRestrictions);

    /**
     * This method builds the return url
     *
     * @param businessObject
     * @param lookupForm
     * @param returnKeys
     * @return
     */
    public HtmlData getReturnUrl(BusinessObject businessObject, LookupForm lookupForm, List returnKeys, BusinessObjectRestrictions businessObjectRestrictions);

    /**
     * Builds string of action urls that can take place for a result row
     *
     * @param businessObject - Instance of a business object containing the return values
     * @param pkNames        - List of primary key names
     * @return String rendered in actions column of result set
     */
    public String getActionUrls(BusinessObject businessObject, List pkNames, BusinessObjectRestrictions businessObjectRestrictions);

    /**
     * This method is a template method that allows child classes to return their own custom action html data.
     *
     * @param businessObject
     * @param pkNames
     * @return
     */
    public List<HtmlData> getCustomActionUrls(BusinessObject businessObject, List pkNames);

    /**
     * Builds string an inquiry url for drill down on a result field
     *
     * @param businessObject - Instance of a business object containing the return values
     * @param propertyName   - Name of the property in the business object
     * @return String url called on selection of the result field
     */
    public HtmlData getInquiryUrl(BusinessObject businessObject, String propertyName);

    /**
     * Sets the requested fields conversions in the lookupable
     *
     * @param fieldConversions
     */
    public void setFieldConversions(Map fieldConversions);

    /**
     * Gets the readOnlyFieldsList attribute.
     *
     * @return Returns the readOnlyFieldsList.
     */
    public List<String> getReadOnlyFieldsList();

    /**
     * Sets the requested read only fields list in the lookupable
     *
     * @param readOnlyFieldsList
     */
    public void setReadOnlyFieldsList(List<String> readOnlyFieldsList);

    /**
     * This method is public because some unit tests depend on it.
     *
     * @return a List of the names of fields which are marked in data dictionary as return fields.
     */
    public List<String> getReturnKeys();

    public String getDocFormKey();

    public void setDocFormKey(String docFormKey);

    public String getDocNum();

    public void setDocNum(String docNum);

    /**
     * This method builds a maintenance url.
     *
     * @param businessObject
     * @param htmlData
     * @param pkNames
     * @return
     */
    public String getMaintenanceUrl(BusinessObject businessObject, HtmlData htmlData, List pkNames, BusinessObjectRestrictions businessObjectRestrictions);

    /**
     * Determines if underlying lookup bo has associated maintenance document that allows new or copy maintenance actions.
     *
     * @return true if bo has maint doc that allows new or copy actions
     */
    public boolean allowsMaintenanceNewOrCopyAction();

    /**
     * Determines if underlying lookup bo has associated document that allows new or copy maintenance actions.
     *
     * @return true if bo has doc that allows new or copy actions
     */
    public boolean allowsNewOrCopyAction(String documentTypeName);

    /**
     * Returns a list of Row objects to be used to generate the search query screen
     * <p>
     * Generally, setDataObjectClass needs to be called with a non-null value for proper operation
     *
     * @return
     */
    public List<Row> getRows();

    /**
     * This method returns the DataDictionaryService used to initialize this helper service and is used by Lookupable implementations to
     * retrieve the proper service.
     *
     * @return
     */
    public DataDictionaryService getDataDictionaryService();

    /**
     * This method returns the BusinessObjectDictionaryService used to initialize this helper service and is used by Lookupable implementations to
     * retrieve the proper service.
     *
     * @return
     */
    public BusinessObjectDictionaryService getBusinessObjectDictionaryService();

    public void setBackLocation(String backLocation);

    public String getBackLocation();

    /**
     * This method performs the lookup and returns a collection of BO items
     *
     * @param lookupForm
     * @param resultTable
     * @param bounded
     * @return the list of result BOs, possibly bounded
     */
    public Collection<? extends BusinessObject> performLookup(LookupForm lookupForm, Collection<ResultRow> resultTable, boolean bounded);

    /**
     * This method returns a list of the default columns used to sort the result set.  For multiple value lookups,
     * this method does not change when different columns are sorted.
     *
     * @return
     */
    public List<String> getDefaultSortColumns();

    /**
     * This method returns whether the previously executed getSearchResults used the primary key values to search, ignoring all non key values
     *
     * @return
     * @see LookupableHelperService#getPrimaryKeyFieldLabels()
     */
    public boolean isSearchUsingOnlyPrimaryKeyValues();

    /**
     * Returns a comma delimited list of primary key field labels, to be used on the UI to tell the user which fields were used to search
     *
     * @return
     * @see LookupableHelperService#isSearchUsingOnlyPrimaryKeyValues()
     */
    public String getPrimaryKeyFieldLabels();

    /**
     * Determines whether a given BusinessObject that's returned as one of the lookup's results is considered returnable, which means that for
     * single-value lookups, a "return value" link may be rendered, and for multiple value lookups, a checkbox is rendered.
     * <p>
     * Note that this can be part of an authorization mechanism, but not the complete authorization mechanism.  The component that invoked the lookup/
     * lookup caller (e.g. document, nesting lookup, etc.) needs to check that the object that was passed to it was returnable as well because there
     * are ways around this method (e.g. crafting a custom return URL).
     *
     * @param object an object from the search result set
     * @return
     */
    public boolean isResultReturnable(BusinessObject object);

    /**
     * This method allows for overriding the clear behavior
     */
    public void performClear(LookupForm lookupForm);

    public boolean shouldDisplayHeaderNonMaintActions();

    public boolean shouldDisplayLookupCriteria();

    /**
     * This method gets the supplemental lookup menu if any
     *
     * @return supplemental menu bar
     */
    public String getSupplementalMenuBar();

    /**
     * @return String displayed as title for the lookup
     */
    public String getTitle();

    /**
     * performs custom actions.  return true to reperform search
     *
     * @param ignoreErrors
     * @return boolean to reperform search
     */
    public boolean performCustomAction(boolean ignoreErrors);

    /**
     * get an extra field
     *
     * @return
     */
    public Field getExtraField();

    public void applyFieldAuthorizationsFromNestedLookups(Field field);

    /**
     * Performs conditional logic (based on current search values or other parameters) to
     * override field hidden, read-only, and required attributes previously set.
     */
    public void applyConditionalLogicForFieldDisplay();
}
