// Copyright 2020 Siemens Digital Industries Software
// ==================================================
// Copyright 2015.
// Siemens Product Lifecycle Management Software Inc.
// All Rights Reserved.
// ==================================================
// Copyright 2020 Siemens Digital Industries Software

#ifndef QRY_FINDERUTILS_HXX
#define QRY_FINDERUTILS_HXX

#include <vector>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <map>
#include <metaframework/BusinessObject.hxx>
#include <metaframework/BusinessObjectRef.hxx>
#include <tccore/aom_prop.h>
#include <qry/libqry_exports.h>


/**
*  @defgroup QRY Query
*  @ingroup TC
*/

namespace Teamcenter
{
    namespace QRY
    {
        class FinderUtils;
    }
}

/**
* This class provides Finder related utility methods.
*/
class QRY_API Teamcenter::QRY::FinderUtils
{
public:

    /**
    * A structure containing start and end values for a specific property.  The end value
    * is used for range comparisons if populated
    */
    struct PropertyGroupingValue
    {
        /**
        * ID used by client to identify the group
        */
        std::string propertyGroupID;
        /**
        * the start value for the property
        */
        std::string startValue;
        /**
        * The end value for the property used for range values if populated.
        */
        std::string endValue;
    };

    /**
    * A map containing a list of propertyGroupID for each BusinessObject. For multi-valued
    * properties, a single business object may be associated with multiple property group
    * IDs.
    */
    typedef std::map< BusinessObjectRef<Teamcenter::BusinessObject>, std::vector< std::string > > ObjectPropertyGroupingMap;;

    /**
    * A structure containing an internal property name and a list of ObjectPropertyGroup
    * objects.
    */
    struct ObjectsGroupedByProperty
    {
        /**
        * The internal name for the property.
        */
        std::string internalPropertyName;
        /**
        * Map of a business object and its associated grouping values.
        */
        ObjectPropertyGroupingMap groupedObjectsMap;
        /**
        * List of unmatched Business Objects.
        */
        std::vector< BusinessObjectRef<Teamcenter::BusinessObject> > unmatchedObjectList;
    };

    /**
    * A structure containing an internal property name, a list of PropertyGroupingValue
    * objects and a list of Business Objects.
    */
    struct ObjectPropertyGroupInput
    {
        /**
        * The internal name for the property
        */
        std::string internalPropertyName;
        /**
        * List of PropertyGroupingValue objects corresponding to the property.
        */
        std::vector< PropertyGroupingValue > propertyValues;
        /**
        * List of Business Objects to be grouped.
        */
        std::vector< BusinessObjectRef<Teamcenter::BusinessObject> > objectList;
    };


    /**
    Classifies Business Objects into groups.
    <br/>This allows users to send a list of ObjectPropertyGroupInput objects, each object containing an internal property name,
    a list of PropertyGroupingValue objects identifying groups and a list of Business Objects to be classified into the groups.
    @returns
    <ul>
    <li>#ITK_ok on success
    <li>#SOAQUERY_input_list_empty if the input list is empty,
    <li>#SOAQUERY_internal_property_empty if the internal Property name is empty,
    <li>#SOAQUERY_object_list_empty if the Business Object list is empty
    </ul>
    */
    static int groupObjectsByProperties(
                                         const std::vector< ObjectPropertyGroupInput >& objectPropertyGroupInputList, /**< (I) A list containing ObjectPropertyGroupInput objects that represents
                                                                                                                      property name and property value information to group a list of input Business Objects */
                                         std::vector< ObjectsGroupedByProperty>& groupedObjectsList                   /**< (O) List of ObjectPropertyGrouping objects */
                                       );

    
    
private:

    /**
    * Default Constructor
    */
    FinderUtils();

    /**
    * Copy Constructor
    */
    FinderUtils(const FinderUtils& obj);

    /**
    * Operator=
    */
    FinderUtils&  operator=(const FinderUtils&  other);

    /**
    * Destructor
    */
    ~FinderUtils();

    /**
    * Helper function to convert string to logical
    */
    static logical to_logical( std::string const& s );

    /**
    * Helper function for getting the property constant value for the passed Object type
     object_tag (I) tag of the Object
    * internalPropertyName (I) internal property name
    */
    static char* getReferencedObjectProperty( const tag_t &object_tag, std::string internalPropertyName );

    /**
    * Checks if the object is a User object
    * referencedObject (I) object tag 
    */
    static bool isUserObject( const tag_t referencedObject );

    /**
    * Checks if startValue for a PropertyGroupingValue exists or has string $NONE
    */
    static logical isStartValueEmptyOrNone( const FinderUtils::PropertyGroupingValue propertyValue );

    /**
    * Checks if endValue for a PropertyGroupingValue exists
    */
    static logical endValueExists( const FinderUtils::PropertyGroupingValue propertyValue );

    /**
    * Returns a list of PropertyGroupingValues that have $NONE as startValue
    */
    static std::vector< std::string > getGroupWithNoneInStartValues( const FinderUtils::ObjectPropertyGroupInput *objectPropertyGroupInput );

    /**
    * Performs grouping task on integer property
    */
    static void processIntegerProperty( BusinessObjectRef<Teamcenter::BusinessObject> &businessObject,
                                    FinderUtils::ObjectPropertyGroupInput &objectPropertyGroupInput,
                                    FinderUtils::ObjectPropertyGroupingMap &groupedObjectsMap,
                                    bool &foundGroup,
                                    const tag_t &tableRowBOTag,
                                    const char* tableRowPropertyName
                                   );

    /**
    * Performs grouping task on real property
    */
    static void processDoubleProperty( BusinessObjectRef<Teamcenter::BusinessObject> &businessObject,
                                   FinderUtils::ObjectPropertyGroupInput &objectPropertyGroupInput,
                                   FinderUtils::ObjectPropertyGroupingMap &groupedObjectsMap,
                                   bool &foundGroup,
                                   const tag_t &tableRowBOTag,
                                   const char* tableRowPropertyName
                                   );

    /**
    * Performs grouping task on logical property
    */
    static void processLogicalProperty( BusinessObjectRef<Teamcenter::BusinessObject> &businessObject,
                                    FinderUtils::ObjectPropertyGroupInput &objectPropertyGroupInput,
                                    FinderUtils::ObjectPropertyGroupingMap &groupedObjectsMap,
                                    bool &foundGroup,
                                    const tag_t &tableRowBOTag,
                                    const char* tableRowPropertyName
                                   );

    /**
    * Performs grouping task on date_t property
    */
    static void processDateProperty( BusinessObjectRef<Teamcenter::BusinessObject> &businessObject,
                                 FinderUtils::ObjectPropertyGroupInput &objectPropertyGroupInput,
                                 FinderUtils::ObjectPropertyGroupingMap &groupedObjectsMap,
                                 bool &foundGroup,
                                 const tag_t &tableRowBOTag,
                                 const char* tableRowPropertyName
                                 );

    /**
    * Performs grouping task on char property
    */
    static void processCharProperty( BusinessObjectRef<Teamcenter::BusinessObject> &businessObject,
                                 FinderUtils::ObjectPropertyGroupInput &objectPropertyGroupInput,
                                 FinderUtils::ObjectPropertyGroupingMap &groupedObjectsMap,
                                 bool &foundGroup,
                                 const tag_t &tableRowBOTag,
                                 const char* tableRowPropertyName
                                 );

    /**
    * Performs grouping task on string property
    */
        static void processStringProperty( BusinessObjectRef<Teamcenter::BusinessObject> &businessObject,
                                   FinderUtils::ObjectPropertyGroupInput &objectPropertyGroupInput,
                                   FinderUtils::ObjectPropertyGroupingMap &groupedObjectsMap,
                                   bool &foundGroup,
                                   const tag_t &tableRowBOTag,
                                   const char* tableRowPropertyName
                                   );

    /**
    * Performs grouping task on typed_reference/untyped_reference property
    */
    static void processReferenceProperty( BusinessObjectRef<Teamcenter::BusinessObject> &businessObject,
                                      FinderUtils::ObjectPropertyGroupInput &objectPropertyGroupInput,
                                      FinderUtils::ObjectPropertyGroupingMap &groupedObjectsMap,
                                      bool &isGroupFound
                                      );




    /**
    Helper method to switch based on property value type
    */
    static void processPropertyValuesForGrouping(PROP_value_type_t &propertyValueType,
                                             BusinessObjectRef<Teamcenter::BusinessObject> &businessObject,
                                             FinderUtils::ObjectPropertyGroupInput &objectPropertyGroupInput,
                                             FinderUtils::ObjectPropertyGroupingMap &groupedObjectsMap,
                                             bool &isGroupFound,
                                             const tag_t &tableRowBOTag,
                                             const char* tableRowPropertyName
                                             );

};

#include <qry/libqry_undef.h>
#endif
