// Created on: 2007-07-06
// Created by: Pavel TELKOV
// Copyright (c) 2007-2014 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.

#ifndef _Message_Algorithm_HeaderFile
#define _Message_Algorithm_HeaderFile

#include <Standard.hxx>
#include <Standard_Type.hxx>

#include <Message_ExecStatus.hxx>
#include <Standard_Transient.hxx>
#include <NCollection_Array1.hxx>
#include <NCollection_HArray1.hxx>
#include <Message_Status.hxx>
#include <Standard_Integer.hxx>
#include <Standard_CString.hxx>
#include <Message_Gravity.hxx>
#include <TCollection_HAsciiString.hxx>
#include <TCollection_HExtendedString.hxx>
#include <NCollection_Sequence.hxx>
#include <NCollection_HSequence.hxx>
#include <Message_Msg.hxx>
#include <NCollection_Handle.hxx>

class Message_Messenger;
class TCollection_AsciiString;
class TCollection_HAsciiString;
class TCollection_ExtendedString;
class TCollection_HExtendedString;
class Message_Msg;
class TColStd_HPackedMapOfInteger;

//! Class Message_Algorithm is intended to be the base class for
//! classes implementing algorithms or any operations that need
//! to provide extended information on its execution to the
//! caller / user.
//!
//! It provides generic mechanism for management of the execution
//! status, collection and output of messages.
//!
//! The algorithm uses methods SetStatus() to set an execution status.
//! It is possible to associate a status with a number or a string
//! (second argument of SetStatus() methods) to indicate precisely
//! the item (object, element etc.) in the input data which caused
//! the problem.
//!
//! Each execution status generated by the algorithm has associated
//! text message that should be defined in the resource file loaded
//! with call to Message_MsgFile::LoadFile().
//!
//! The messages corresponding to the statuses generated during the
//! algorithm execution are output to Message_Messenger using
//! methods SendMessages(). If status have associated numbers
//! or strings, they are included in the message body in place of
//! "%s" placeholder which should be present in the message text.
//!
//! The name of the message text in the resource file is constructed
//! from name of the class and name of the status, separated by dot,
//! for instance:
//!
//! .TObj_CheckModel.Alarm2
//! Error: Some objects (%s) have references to dead object(s)
//!
//! If message for the status is not found with prefix of
//! the current class type, the same message is searched for the base
//! class(es) recursively.
//!
//! Message can be set explicitly for the status; in this case the
//! above procedure is not used and supplied message is used as is.
//!
//! The messages are output to the messenger, stored in the field;
//! though messenger can be changed, it is guaranteed to be non-null.
//! By default, Message::DefaultMessenger() is used.
class Message_Algorithm : public Standard_Transient
{

public:
  //! Empty constructor
  Standard_EXPORT Message_Algorithm();

  //! Sets status with no parameter
  Standard_EXPORT void SetStatus(const Message_Status& theStat);

  //! Sets status with integer parameter
  Standard_EXPORT void SetStatus(const Message_Status& theStat, const int theInt);

  //! Sets status with string parameter.
  //! If noRepetitions is True, the parameter will be added only
  //! if it has not been yet recorded for the same status flag
  void SetStatus(const Message_Status& theStat,
                 const char* const     theStr,
                 const bool            noRepetitions = true);

  //! Sets status with string parameter
  //! If noRepetitions is True, the parameter will be added only
  //! if it has not been yet recorded for the same status flag
  void SetStatus(const Message_Status&          theStat,
                 const TCollection_AsciiString& theStr,
                 const bool                     noRepetitions = true);

  //! Sets status with string parameter
  //! If noRepetitions is True, the parameter will be added only
  //! if it has not been yet recorded for the same status flag
  void SetStatus(const Message_Status&                        theStat,
                 const occ::handle<TCollection_HAsciiString>& theStr,
                 const bool                                   noRepetitions = true);

  //! Sets status with string parameter
  //! If noRepetitions is True, the parameter will be added only
  //! if it has not been yet recorded for the same status flag
  void SetStatus(const Message_Status&             theStat,
                 const TCollection_ExtendedString& theStr,
                 const bool                        noRepetitions = true);

  //! Sets status with string parameter
  //! If noRepetitions is True, the parameter will be added only
  //! if it has not been yet recorded for the same status flag
  Standard_EXPORT void SetStatus(const Message_Status&                           theStat,
                                 const occ::handle<TCollection_HExtendedString>& theStr,
                                 const bool noRepetitions = true);

  //! Sets status with preformatted message. This message will be
  //! used directly to report the status; automatic generation of
  //! status messages will be disabled for it.
  Standard_EXPORT void SetStatus(const Message_Status& theStat, const Message_Msg& theMsg);

  //! Returns copy of exec status of algorithm
  const Message_ExecStatus& GetStatus() const;

  //! Returns exec status of algorithm
  Message_ExecStatus& ChangeStatus();

  //! Clear exec status of algorithm
  Standard_EXPORT void ClearStatus();

  //! Sets messenger to algorithm
  Standard_EXPORT void SetMessenger(const occ::handle<Message_Messenger>& theMsgr);

  //! Returns messenger of algorithm.
  //! The returned handle is always non-null and can
  //! be used for sending messages.
  occ::handle<Message_Messenger> GetMessenger() const;

  //! Print messages for all status flags that have been set during
  //! algorithm execution, excluding statuses that are NOT set
  //! in theFilter.
  //!
  //! The messages are taken from resource file, names being
  //! constructed as {dynamic class type}.{status name},
  //! for instance, "Message_Algorithm.Fail5".
  //! If message is not found in resources for this class and all
  //! its base types, surrogate text is printed.
  //!
  //! For the statuses having number or string parameters,
  //! theMaxCount defines maximal number of numbers or strings to be
  //! included in the message
  //!
  //! Note that this method is virtual; this allows descendant
  //! classes to customize message output (e.g. by adding
  //! messages from other sub-algorithms)
  Standard_EXPORT virtual void SendStatusMessages(
    const Message_ExecStatus& theFilter,
    const Message_Gravity     theTraceLevel = Message_Warning,
    const int                 theMaxCount   = 20) const;

  //! Convenient variant of SendStatusMessages() with theFilter
  //! having defined all WARN, ALARM, and FAIL (but not DONE)
  //! status flags
  Standard_EXPORT void SendMessages(const Message_Gravity theTraceLevel = Message_Warning,
                                    const int             theMaxCount   = 20) const;

  //! Add statuses to this algorithm from other algorithm
  //! (including messages)
  Standard_EXPORT void AddStatus(const occ::handle<Message_Algorithm>& theOther);

  //! Add statuses to this algorithm from other algorithm, but
  //! only those items are moved that correspond to statuses
  //! set in theStatus
  Standard_EXPORT void AddStatus(const Message_ExecStatus&             theStatus,
                                 const occ::handle<Message_Algorithm>& theOther);

  //! Return the numbers associated with the indicated status;
  //! Null handle if no such status or no numbers associated with it
  Standard_EXPORT occ::handle<TColStd_HPackedMapOfInteger> GetMessageNumbers(
    const Message_Status& theStatus) const;

  //! Return the strings associated with the indicated status;
  //! Null handle if no such status or no strings associated with it
  Standard_EXPORT occ::handle<NCollection_HSequence<occ::handle<TCollection_HExtendedString>>>
                  GetMessageStrings(const Message_Status& theStatus) const;

  //! Prepares a string containing a list of integers contained
  //! in theError map, but not more than theMaxCount
  Standard_EXPORT static TCollection_ExtendedString PrepareReport(
    const occ::handle<TColStd_HPackedMapOfInteger>& theError,
    const int                                       theMaxCount);

  //! Prepares a string containing a list of names contained
  //! in theReportSeq sequence, but not more than theMaxCount
  Standard_EXPORT static TCollection_ExtendedString PrepareReport(
    const NCollection_Sequence<occ::handle<TCollection_HExtendedString>>& theReportSeq,
    const int                                                             theMaxCount);

  DEFINE_STANDARD_RTTIEXT(Message_Algorithm, Standard_Transient)

protected:
  Message_ExecStatus             myStatus;
  occ::handle<Message_Messenger> myMessenger;

private:
  occ::handle<NCollection_HArray1<occ::handle<Standard_Transient>>>       myReportIntegers;
  occ::handle<NCollection_HArray1<occ::handle<Standard_Transient>>>       myReportStrings;
  NCollection_Handle<NCollection_Array1<NCollection_Handle<Message_Msg>>> myReportMessages;
};

#include <Message_Algorithm.lxx>

#endif // _Message_Algorithm_HeaderFile
