//
//  (C) Copyright 1994-2008 by Autodesk, Inc.  All rights reserved.
//
// Permission to use, copy, modify, and distribute this software in
// object code form for any purpose and without fee is hereby granted, 
// provided that the above copyright notice appears in all copies and 
// that both that copyright notice and the limited warranty and
// restricted rights notice below appear in all supporting 
// documentation.
//
// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. 
// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF
// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE.  AUTODESK, INC. 
// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE
// UNINTERRUPTED OR ERROR FREE.
//
// Use, duplication, or disclosure by the U.S. Government is subject to 
// restrictions set forth in FAR 52.227-19 (Commercial Computer
// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii)
// (Rights in Technical Data and Computer Software), as applicable.
//

// DESCRIPTION: This file contains the enums and definitions for
//              AmiStatus.
#ifndef AMISTATUS_H
#define AMISTATUS_H

#include "adesk.h"               // Adesk name space
#include "acadstrc.h"            // Acad::ErrorStatus
#include "attr.h"                // Attr name space
#include "mitstdstring.h"        // TSTDSTRING 

#include <string>
#ifdef DEBUG_WAS_ON_IN_MISTATUS
#define _DEBUG
#undef DEBUG_WAS_ON_IN_MISTATUS
#endif

#ifdef MCADAPIBUILD
    #define AMIAPI __declspec(dllexport)
#else
    #define AMIAPI __declspec(dllimport)
#endif

// Macro is used on all classes deriving from AmiBaseObject to declare
// virtual methods inherited from AcRxObject and also to declare a
// protected destructor forcing users to use "release" for management
// of object lifetime.
//
#define MCADAPI_DECLARE_MEMBERS(name) \
        protected:                    \
          virtual ~name() {}          \
        public:                       \
          ACRX_DECLARE_MEMBERS(name)

#define Designer_Assemblies ACRX_T(/*MSG0*/"Designer_Assemblies")

// MCAD API function identifier.
//
typedef long AmiFuncId;

// MCAD API app identifier.
//
typedef long AmiAppId;

class AmiStatus;

#define AMIFIRSTSTATUSCODEVAL 2001

namespace Ami
{
    // Enumeration of severities for AmiStatus (below)
    //
    enum Severity
    {
        kInfo       = 0x0,
        kWarning    = 0x1,
        kError      = 0x2,
        kSevere     = 0x3
    };

    // Enumeration of status codes for AmiStatus (below).
    // Using values in the range 2001-3000.
    //
    enum StatusCode
    {
        kOk              = 0,           // situation normal
        kNotApplicable   = AMIFIRSTSTATUSCODEVAL,   // op N/A to args
        kMakeMeProxy,                   // for dwgInFields()
        kInternalUnsupported,
        kInternalFailure,
        kInvalidArg,
        kNotCurrentDoc,
        kNoDocument,
        kDatabaseUnloaded,              // required database is unloaded
        kNoImpFunc,                     // no imp funct found
        kNoImplementation,              // op not supported yet
        kOutOfMemory,                   // out of memory
        kNullKey,                       // key not set
        kObjectNotEditable,             // obj can't be edited
        kNoKeySupported,
        kGKeyNotSupported,              // geom key create fail
        kKeyCreationFailure,
        kNotGeom,                       // obj is not geometry
        kSilhouette,                    // silhouette geom
        kTypeMapFailure,                // failure in type map
        kObjectNotFound,                // object not found
        kInvalidName,
        kNameAlreadyExists,

        // Components/Constraints
        //
        kNoConstraints ,
        kNoChildren,


        // Picking status
        //
        kUserTermination,               // user termination
        kUserEscape,                    // user-requested cancel
        kKeyWord,                        // user selected a keyword

        // Instantiable attributes
        //
        kNoClassRecord,
        kClassRecordAlreadyExists,
        kClassRecordInDb,
        kOutOfRange,                    // e.g. field index
        kReadError,                     // e.g. att read error

        kInvalidTypeForField,
        kInvalidTypeForSketchConstr,

        // Parameters
        //
        kObjectAlreadyExists,           // e.g. param object already exists
        kExprEvalFailure,
        kIllegalExpression,
        kCyclicDependency,

        // Feature descriptors.
        //
        kUnsupportedFeatType,
        kNoCombiner,
        kNoLocator,
        kNoTerminator,
            
        // Component Containment
        //
        kUnmatchedLeafObject,
        kNoContainingComp,
        kUnmatchedActiveContext,

        // Scene API
        //
        kNoScene,

        // More feature API.
        //
        kPartNotActive,
        kAmbiguousPartInfo,
        kNoPartInstance,
        kBaseFeatureAlreadyExists,      // attempted to create mutiple base features on a part.

        // Descriptors
        //
        kAttReadOnly,                   // attempted update of read-only attribute
        kAttTypeMismatch,               // type mis-match on attributes
        kAttValueNAV,                   // NAV: "Not A Value"
        kIllegalDescriptor,             // descriptor values inconsistent (wrt type)
        kAttMultiValued,                // multi-valued attribute in single-value context
        kAttSingleValued,               // single-valued attribute in multi-value context
        kAttNoAppend,                   // cannot append to attribute value (not allowed)

        // DwgMgr
        //
        kBaseView,                      // illegal op on base view (e.g. get parent)
        kNoCutlineContext,              // sectioning op requires context for cutline

        // Constraint Creation
        //
        kInvalidConstrType,             // invalid/unsupported constraint type
        kObjectErased,                  // key to erased data passed 
        kBadItemType,                   // argument geomtry type not supported for constraint type
        kGeomValidFailure,              // geometric validation failed

        kNoBaseOrdinate,                // no base ordinate defined on args 
        kNoConstrainableGeom,           // No sketch geometry passed in
        kNoCommonSketch,                // geometry from different sketches
        kNoCommonPart,                  // geometry from different parts
        kCoincidentGeom,                // keys point to same geometry
        kCoincidentBodies,              // keys reference same bodies

        kModelOverConstrained,          // constraint would make sketch over constrained
        kModelInconsistent,             // constr inconsistent with existing constrs
        kConstraintExists,              // constr already exists

        // Sketch Creation
        //
        kInvalidSketchType,             // invalid sketch type
        kMissingStartPoint,             // Sketch type requires a start point,none found
        kNoSketchFound,                 // no profile detected in geometry
        kMultipleSketches,              // Multiple of sketch type found
        kUnableToAddConstr,             // unable to add existing dimension
        kNonPlanarGeometry,             // geometry not planar to sketch plane

        // MDT system variables.
        //
        kVariableNotFound,              // named system variable not found
        kInvalidVariableType,           // wrong type specified for variable

        // Part-only files
        //
        kToolBody,                      // toolbody created instead of reg part/comp
        kLeafWithToolBodies,            // leaf compdef might have toolbodies
        kGroundedBasePart,              // grounded base part
        kGroundedBasePartIsMasterDef,   // both grounded base part and master def affected

        // new general Ami codes
        //
        kObjectIsProxy,
        kInvalidDesignMode,
        kComputeFailure,
        kExternalDef,
        kExternalAttachment,
        kLockConflict,
        kSubAssemblyRequired,
        kDelegationConflict,            // wants to delegate to conflicting imps
        kNoBrep,                        // object instance has no associated Brep
        kNonCurrentDb,                  // action available only in current database
        kNotAccessibleFromDb,           // Data not accessible from given database
        kUnspecified,                   // used for generic badness
        kInvalidModelState,             // operation not defined in current Designer state
        kUpdateFailure,                 // model update did not complete (as opposed to
                                        // to completing with compute errors)
        kNoColorOverride,               // object has no color override

        // Composite feature codes
        //
        kNoNestedComposites,
        kCompositeNotStarted,
        kDuplicateCompositeEditCallback,
        kFeatureNotInComposite,

        // other Ami codes, new in MDT5
        //
        kRequiresCompInDef,             // input must be a comp-in-def (use amiGetCompInDef())
        kFocusMismatch,                 // incompatibile w.r.t. amiRefocusKey()
        kDiscontinuousGeom,             // not tangent continuous in edge path sketch
        kSetStructModeEditEntityError,  // Failed to set structure entity edit mode.
        kForbidDetailView,              // Not permitted on detail view
        kFailResolveCompView,           // Failed to resolve component view
        kFailResolveFolder,             // Failed to resolve folder
        kForbidUnresolvedDefAnnoView,   // Not permitted for annotation view with unresolved view definition
        kForbidGhost,                   // Not permitted due to ghost
        kForbidAnnoSubView,             // Not permitted on annotation sub view
        kCopyCompSingleView,            // Cannot copy the single view of a component (Copy the component instead)
        kHostDbNotActive,               // Host database not active
        kForbidStandard,                // Not permitted on standard components
        kFailLockCompDefDb,             // Failed to lock component definition database
        kForbidFeature,                 // Not permitted on feature
        kFailLockViewDefDb,             // Failed to lock view definition database
        kEntityNotEditable,             // Entity cannot be edited
        kFailLockCompDb,                // Failed to lock component database
        kForbidExtFeature,              // Not permitted on external feature
        kForbidSingletonDef,            // Not allowed for definition with 1 permitted instance only
        kFailLockViewDb,                // Failed to lock view database
        kForbidShaftSideSectionView,    // Not permitted for SHAFT component Side or Section views
        kForbidDetailSubView,           // Not permitted on detail subviews
        kForbidPredefinedRefSet,        // Not permitted because predefined reference is set
        kFailGetNextCompDefName,                  // Failed to get next component definition name.
        kFailGetNextFolderDefName,                // Failed to get next folder definition name.
        kFailGetNextCompViewDefNameInvalidArg,    // Failed to get next component view definition name (invalid argument).
        kFailGetNextCompViewDefName,              // Failed to get next component view definition name.
        kFailHasCompDefInvalidArg,                // Failed to determine if component definition exists (invalid argument).
        kFailHasCompDef,                          // Failed to determine if component definition exists.
        kFailHasFolderDefInvalidArg,              // Failed to determine if folder definition exists (invalid argument).
        kFailHasFolderDef,                        // Failed to determine if folder definition exists.
        kFailHasCompViewDefInvalidArg,            // Failed to determine if component view definition exists (invalid argument).
        kFailHasCompViewDef,                      // Failed to determine if component view definition exists.
        kFailIsInActTgtInvalidArg,                // Failed to determine if entity is in active target (invalid argument).
        kFailIsInActTgt,                          // Failed to determine if entity is in active target.
        kFailIsFreeEntityInvalidArg,              // Failed to determine if entity is free entity (invalid argument).
        kFailIsFreeEntity,                        // Failed to determine if entity is free entity.
        kFailIsEntityAllowedInvalidArg,           // Failed to determine if entity is allowed in 2D structure (invalid argument).
        kFailIsStructEnabled,                     // Failed to determine if 2D structure is enabled.
        kFailViewIsGhost,                         // Failed to determine if component view is ghost view.
        kFailHasGhostViewsInvalidArg,             // Failed to determine if component has ghost views (invalid argument).
        kFailHasGhostViews,                       // Failed to determine if component has ghost views.
        kFailGetReferenceInvalidArg,              // Failed to determine if component is reference (invalid argument).
        kFailGetReference,                        // Failed to determine if component is reference.
        kFailSetReferenceInvalidArg,              // Failed to set component as reference (invalid argument).
        kFailSetReference,                        // Failed to set component as reference.
        kFailUpdateEntities,                      // Failed to update 2D structure with entity changes in model space.
        kForbidAnnoView,                          // Operation not permitted on annotation view.
        kForbidStandardPart,                      // Operation not permitted on standard part.
        kInvalidParentView,                       // Invalid parent view selected.
    };

    // Enumeration of Phantom State of Component Definition
    enum PhantomState
    {
      kNormalDef = 0,
      kPhantomDef = 1,
      kPhantomDefInCurrent = 2
    };
};


// The old error status symbols can still be used.
//
namespace Ami
{
    // Flat error status for MCAD API.
    // Some acdb and acme error mnemonics that are meaningful for the "Ami"
    // namespace are assigned numeric codes that match the acdb and acme codes
    // (e.g. Acad::eOk == AcMe::eOk == Ami::eOk)
    //
    // All error codes below 1000 are Acad codes.  All error codes between 999
    // and 2000 are AcMe codes.  All error codes between 3000 and 3999 are Attr
    // codes.
    //
    // NOTE: the error codes are hard-coded both here and in the include files
    // for Acad and AcMe.  The correspondence of error codes is not automatic.
    // Care must be taken when editing the enum's here and in the AcMe/Acad
    // files to make sure any codes below 2000 do in fact match (e.g. that
    // AcMe::eOk really is 0).
    //
    // Acad::ErrorStatus, AmdtAttr::Status and AcMe::Status can be assigned to 
    // Ami::Status without changing the meaning of any error codes.
    //
    enum FlatStatus
    {
        // codes shared with Acad::ErrorStatus
        //
        eOk                             = 0,
        eMakeMeProxy                    = 301,
        eInternalUnsupported            = 1001,
        eBad                            = kUnspecified,
        eInvalidArg                     = kInvalidArg,
        eDatabaseUnloaded               = kDatabaseUnloaded,
        eNoImpFunc                      = kNoImpFunc,
        eNoImplementation               = kNoImplementation,
        eOutOfMemory                    = kOutOfMemory,
        eNullKey                        = kNullKey,
        eObjectNotEditable              = kObjectNotEditable,
        eNoKeySupported                 = kNoKeySupported,
        eGKeyNotSupported               = kGKeyNotSupported,
        eKeyCreationFailure             = kKeyCreationFailure,
        eNotGeom                        = kNotGeom,
        eTypeMapFailure                 = kTypeMapFailure,
        eNotApplicable                  = kNotApplicable,

        eNoConstraints                  = kNoConstraints,
        eNoChildren                     = kNoChildren,
        eExternalComponentNotFound      = kObjectNotFound,

        eInvalidName                    = kInvalidName,
        eNameAlreadyExists              = kNameAlreadyExists,

        eUserTermination                = kUserTermination,
        eUserEscape                     = kUserEscape,

        eNoClassRecord                  = kNoClassRecord,
        eClassRecordAlreadyExists       = kClassRecordAlreadyExists,
        eClassRecordInDb                = kClassRecordInDb,
        eFieldIndexOutOfRange           = kOutOfRange,
        eInvalidFieldName               = kInvalidName,
        eInvalidFieldType               = kInvalidTypeForField,
        eAttributeReadError             = kReadError,

        eInvalidSketchConstrType        = kInvalidTypeForSketchConstr,

        eParamAlreadyExists             = kObjectAlreadyExists,
        eExprEvalFailure                = kExprEvalFailure,
        eIllegalExpression              = kIllegalExpression,
        eParamNotFound                  = kObjectNotFound,
        eCyclicDependency               = kCyclicDependency,

        eUnsupportedFeatType            = kUnsupportedFeatType,
        eNoCombiner                     = kNoCombiner,
        eNoLocator                      = kNoLocator,
        eNoTerminator                   = kNoTerminator,
            
        eUnmatchedLeafObject            = kUnmatchedLeafObject,
        eNoContainingComp               = kNoContainingComp,
        eUnmatchedActiveContext         = kUnmatchedActiveContext,

        eNoScene                        = kNoScene,

        ePartNotActive                  = kPartNotActive,
        eAmbiguousPartInfo              = kAmbiguousPartInfo,
        eNoPartInstance                 = kNoPartInstance,
        eBaseFeatureAlreadyExists       = kBaseFeatureAlreadyExists,

        eAttReadOnly                    = kAttReadOnly,
        eAttTypeMismatch                = kAttTypeMismatch,
        eAttValueNAV                    = kAttValueNAV,
        eIllegalDescriptor              = kIllegalDescriptor,
        eAttMultiValued                 = kAttMultiValued,
        eAttSingleValued                = kAttSingleValued,
        eAttNoAppend                    = kAttNoAppend,

        eBaseView                       = kBaseView,
        eNoCutlineContext               = kNoCutlineContext,

        eInvalidConstrType              = kInvalidConstrType,
        eArgErased                      = kObjectErased,
        eBadItemType                    = kBadItemType,
        eGeomValidFailure               = kGeomValidFailure,

        eNoBaseOrdinate                 = kNoBaseOrdinate,
        eNoConstrainableGeom            = kNoConstrainableGeom,
        eNoCommonSketch                 = kNoCommonSketch,
        eNoCommonPart                   = kNoCommonPart,
        eCoincidentGeom                 = kCoincidentGeom,

        eModelOverConstrained           = kModelOverConstrained,
        eModelInconsistent              = kModelInconsistent,
        eConstraintExists               = kConstraintExists,

        eInternalFailure                = kInternalFailure,

        eInvalidSketchType              = kInvalidSketchType,
        eMissingStartPoint              = kMissingStartPoint,
        eNoSketchFound                  = kNoSketchFound,
        eMultipleSketches               = kMultipleSketches,
        eUnableToAddConstr              = kUnableToAddConstr,
        eNonPlanarGeometry              = kNonPlanarGeometry,

        // MDT system variables.
        //
        eVariableNotFound               = kVariableNotFound,
        eInvalidVariableType            = kInvalidVariableType,

        // new general Ami codes
        //
        eObjectIsProxy                  = kObjectIsProxy,
        eInvalidDesignMode              = kInvalidDesignMode,
        eComputeFailure                 = kComputeFailure,
        eExternalDef                    = kExternalDef,
        eSubAssemblyRequired            = kSubAssemblyRequired,
        eDelegationConflict             = kDelegationConflict,
        eNoColorOverride                = kNoColorOverride,

        // Composite feature codes
        //
        eNoNestedComposites             = kNoNestedComposites,
        eCompositeNotStarted            = kCompositeNotStarted,
        eDuplicateCompositeEditCallback = kDuplicateCompositeEditCallback,
        eFeatureNotInComposite          = kFeatureNotInComposite,
        eSetStructModeEditEntityError   = kSetStructModeEditEntityError,
        eForbidDetailView               = kForbidDetailView,                 
        eFailResolveCompView            = kFailResolveCompView,           
        eFailResolveFolder              = kFailResolveFolder,               
        eForbidUnresolvedDefAnnoView    = kForbidUnresolvedDefAnnoView,   
        eForbidGhost                    = kForbidGhost,                   
        eForbidAnnoSubView              = kForbidAnnoSubView,             
        eCopyCompSingleView             = kCopyCompSingleView,
        eHostDbNotActive                = kHostDbNotActive,    
        eForbidStandard                 = kForbidStandard,     
        eFailLockCompDefDb              = kFailLockCompDefDb,           
        eForbidFeature                  = kForbidFeature,      
        eFailLockViewDefDb              = kFailLockViewDefDb,      
        eEntityNotEditable              = kEntityNotEditable,  
        eFailLockCompDb                 = kFailLockCompDb,     
        eForbidExtFeature               = kForbidExtFeature,   
        eForbidSingletonDef             = kForbidSingletonDef,
        eFailLockViewDb                 = kFailLockViewDb,
        eForbidShaftSideSectionView     = kForbidShaftSideSectionView,
        eForbidDetailSubView            = kForbidDetailSubView,
        eForbidPredefinedRefSet         = kForbidPredefinedRefSet,
        eFailGetNextCompDefName                   = kFailGetNextCompDefName,
        eFailGetNextFolderDefName                 = kFailGetNextFolderDefName,
        eFailGetNextCompViewDefNameInvalidArg     = kFailGetNextCompViewDefNameInvalidArg,
        eFailGetNextCompViewDefName               = kFailGetNextCompViewDefName,
        eFailHasCompDefInvalidArg                 = kFailHasCompDefInvalidArg,
        eFailHasCompDef                           = kFailHasCompDef,
        eFailHasFolderDefInvalidArg               = kFailHasFolderDefInvalidArg,
        eFailHasFolderDef                         = kFailHasFolderDef,
        eFailHasCompViewDefInvalidArg             = kFailHasCompViewDefInvalidArg,
        eFailHasCompViewDef                       = kFailHasCompViewDef,
        eFailIsInActTgtInvalidArg                 = kFailIsInActTgtInvalidArg,
        eFailIsInActTgt                           = kFailIsInActTgt,
        eFailIsFreeEntityInvalidArg               = kFailIsFreeEntityInvalidArg,
        eFailIsFreeEntity                         = kFailIsFreeEntity,
        eFailIsEntityAllowedInvalidArg            = kFailIsEntityAllowedInvalidArg,
        eFailIsStructEnabled                      = kFailIsStructEnabled,
        eFailViewIsGhost                          = kFailViewIsGhost,
        eFailHasGhostViewsInvalidArg              = kFailHasGhostViewsInvalidArg,
        eFailHasGhostViews                        = kFailHasGhostViews,
        eFailGetReferenceInvalidArg               = kFailGetReferenceInvalidArg,
        eFailGetReference                         = kFailGetReference,
        eFailSetReferenceInvalidArg               = kFailSetReferenceInvalidArg,
        eFailSetReference                         = kFailSetReference,
        eFailUpdateEntities                       = kFailUpdateEntities,
        eForbidAnnoView                           = kForbidAnnoView,
        eForbidStandardPart                       = kForbidStandardPart,
        eInvalidParentView                        = kInvalidParentView
    };

    typedef AmiStatus    Status;
};
// Convenience typedefs for namespace scoped enums.
//
typedef Ami::FlatStatus            AmiFlatStatus;


// CLASS AmiStatus
//
// All MCADAPI functions return AmiStatus objects.  The AmiStatus
// holds a simple status to convey the outcome of the function.
// This includes error codes, warning codes, and success codes.
//
//Query access:
//
//  success()   Return true if this is not an error status.
//
//  failure()   Returns true if this is an error status.
//
//  severity()  Returns the severity of the status.
//
//  symbol()    Returns an enum value which represents the
//              basic type of status.
//
//  argIndex()  Returns the position of the function argument
//              that gave rise to the status.  Numbering
//              begins with 0, and a negative number is returned
//              if no argument has been singled-out as the cause.
//
//  arrayIndex() When argIndex() indicates that an array input
//              argument is the cause of the status, and the
//              problem can be further pinpointed to a particular
//              element, then this function returns the index of
//              that element.  Numbering begins at 0, and a negative
//              number is returned if no element is singled-out.
//
//  attrKeyword() When argIndex() indicates that a descriptor input
//              argument is the cause of the status, and the problem
//              can be further isolated to a single attribute, then
//              this function returns the keyword for that attribute.
//              Note: the keyword is passed back as an 'int' and not
//              as an enum.  This is because there is no single enum
//              datatype for attributes of all descriptor types (the
//              enum values are distinct, however, so there is no loss
//              of information in using an 'int' here).
//
//  text()      Returns a string holding a short text description of
//              the status.
//
// operator ==
// operator !=  Comparison are possible between two AmiStatus objects,
//              between an AmiStatus and an enum symbol, etc.
//
// operator <   This comparison returns true if the LHS is less severe
//              than the RHS.  If both operands have severity kInfo,
//              then this comparison will still return true if the RHS
//              has a non-kOk symbol while the LHS is kOk.
//
//
// Edit access:
//
//  setSeverity()  Sets the severity to the given level.
//
//  setSymbol()    Sets the symbol to the given StatusCode value.
//
//  setArgIndex()  Sets the arg-index to the given value.
//
//  setArrayIndex() Sets the array-index to the given value.  This
//                 will overwrite the attribute-keyword if it is set.
//                 The attribute-keyword and array-index cannot be
//                 used together in the same AmiStatus instance.
//
//  setAttrKeyword() Sets the attribute-keyword to the given value.
//                 This will overwrite the array-index if it is set.
//                 The attribute-keyword and array-index cannot be
//                 used together in the same AmiStatus instance.
//
//  operator =     The assignment operator.
//
//  operator +=    This operator performs an assignment if and only
//                 if LHS<RHS holds.  It can be used to "accumulate"
//                 status values.
//
// Notes:
//      AmiStatus objects can be compared directly to Ami::FlatStatus
//      enum values.  The Ami::FlatStatus value will be promoted
//      to an AmiStatus before the comparison takes place, with the
//      severity of the promoted object set to kError.  There is ONE
//      exception:  Ami::eOk is promoted to AmiStatus(kOk, kInfo).
//
//      The same promotion rule is used when an AmiStatus variable is
//      assigned an Ami::FlatStatus value.
//
//      For example, the following equalities hold:
//
//          AmiStatus(Ami::kInvalidArg, Ami::kError)     == Ami::eInvalidArg
//          AmiStatus(Ami::kOk, Ami::kInfo)              == Ami::eOk
//          AmiStatus status; (status = Ami::eInvalidArg)== Ami::eInvalidArg
//
//      When an AmiStatus object is constructed or assigned a value using
//      an Ami::StatusCode, the same promotion rules apply -- the severity
//      is assumed to be kError except for kOk which has severity kInfo.
//      So, for example,
//          AmiStatus(Ami::kInvalidArg, Ami::kError)     == Ami::kInvalidArg
//          AmiStatus(Ami::kOk, Ami::kInfo)              == Ami::kOk
//
//      While Ami::StatusCode values often correspond to Ami::FlatStatus
//      values, there is no guarantee.  For example, the following equality
//      is not guaranteed to hold in future releases:
//                  Ami::eInvalidArg =?= Ami::kInvalidArg
//
class AMIAPI AmiStatus
{
public:
    AmiStatus();
    AmiStatus(Ami::StatusCode);
    AmiStatus(Ami::StatusCode, Ami::Severity);
    AmiStatus(Ami::StatusCode, Ami::Severity, int argIndex);
    AmiStatus(Ami::StatusCode, Ami::Severity, int argIndex, int attrKeyword);
    AmiStatus(Ami::FlatStatus);
    AmiStatus(Acad::ErrorStatus);
    AmiStatus(AmdtAttr::Status);
    AmiStatus(const AmiStatus&);
    AmiStatus(int);

    bool            success()       const;
    bool            failure()       const;

    Ami::Severity   severity()      const;
    Ami::StatusCode symbol()        const;
    int             argIndex()      const;
    int             arrayIndex()    const;
    int             attrKeyword()   const;
    TSTDSTRING     text()          const;

    bool operator==(const Ami::FlatStatus&)   const;
    bool operator!=(const Ami::FlatStatus&)   const;
    bool operator==(const AmiStatus&)         const;
    bool operator!=(const AmiStatus&)         const;
    bool operator==(const Acad::ErrorStatus&) const;
    bool operator!=(const Acad::ErrorStatus&) const;
    bool operator==(const AmdtAttr::Status&)      const;
    bool operator!=(const AmdtAttr::Status&)      const;
    bool operator==(const int&)               const;
    bool operator!=(const int&)               const;

    bool       operator< (const AmiStatus&)   const;
    AmiStatus& operator+=(const AmiStatus&);

    operator Ami::FlatStatus   ()   const;
    operator Acad::ErrorStatus ()   const;
    operator int               ()   const;
    operator AmdtAttr::Status  ()   const;

public:
    AmiStatus&      setSeverity(Ami::Severity);
    AmiStatus&      setSymbol(Ami::StatusCode);
    AmiStatus&      setArgIndex(int);
    AmiStatus&      setArrayIndex(int);
    AmiStatus&      setAttrKeyword(int);

private:
    Adesk::UInt32       mData;      // 32-bit encodement
};


bool AMIAPI operator==(const Ami::FlatStatus&, const AmiStatus&);
bool AMIAPI operator!=(const Ami::FlatStatus&, const AmiStatus&);



#define AMI_SEVERITY_BITS      0xC0000000       /*  2 bits */
#define AMI_SYMBOL_BITS        0x3FFE0000       /* 13 bits */

#define AMI_SEVERITY_SHIFT     30           /* 32-2           =30 */
#define AMI_SYMBOL_SHIFT       17           /* 32-2-13        =17 */


#define AMI_STATUS_ENCODEMENT(sev,sym)               \
                                                     \
        (((Adesk::UInt32)(sev) << AMI_SEVERITY_SHIFT)\
         |                                           \
         ((Adesk::UInt32)(sym) << AMI_SYMBOL_SHIFT))

#define AMI_SET_SEVERITY(bits, sev) \
        bits = (bits & ~AMI_SEVERITY_BITS) \
               | ((Adesk::UInt32)(sev) << AMI_SEVERITY_SHIFT)

#define AMI_SET_SYMBOL(bits, sym) \
        bits = (bits & ~AMI_SYMBOL_BITS) \
               | ((Adesk::UInt32)(sym) << AMI_SYMBOL_SHIFT)



inline AmiStatus::AmiStatus()
    : mData(0x0)                // kInfo,kOk
{
}
inline AmiStatus::AmiStatus(Ami::StatusCode sym, Ami::Severity sev)
    : mData(AMI_STATUS_ENCODEMENT(sev,sym))
{
}
inline AmiStatus::AmiStatus(Ami::StatusCode sym, Ami::Severity sev,
                            int argIndex)
    : mData(AMI_STATUS_ENCODEMENT(sev,sym))
{
    setArgIndex(argIndex);
}
inline AmiStatus::AmiStatus(Ami::StatusCode sym, Ami::Severity sev,
                            int argIndex, int attrKeyword)
    : mData(AMI_STATUS_ENCODEMENT(sev,sym))
{
    setArgIndex(argIndex);
    setAttrKeyword(attrKeyword);
}
inline AmiStatus::AmiStatus(const AmiStatus& x)
    : mData(x.mData)
{
}
inline AmiStatus::AmiStatus(Ami::FlatStatus oldSymbol)
    : mData(0x0)
{
    if (oldSymbol != Ami::eOk)
        mData = AMI_STATUS_ENCODEMENT(Ami::kError, oldSymbol);
}


__forceinline AmiStatus::operator Ami::FlatStatus ()  const
{
    return failure() ? (Ami::FlatStatus) symbol() : Ami::eOk;
}


inline bool AmiStatus::success()    const
{
    return (Adesk::Int32)mData >= 0;
}
inline bool AmiStatus::failure()    const
{
    return (Adesk::Int32)mData < 0;
}

inline AmiStatus& AmiStatus::setSeverity(Ami::Severity sev)
{
    AMI_SET_SEVERITY(mData, sev);
    return *this;
}
inline AmiStatus& AmiStatus::setSymbol(Ami::StatusCode c)
{
    AMI_SET_SYMBOL(mData, c);
    return *this;
}

inline bool AmiStatus::operator==(const AmiStatus& rhs)  const
{
    return  mData == rhs.mData;
}
inline bool AmiStatus::operator!=(const AmiStatus& rhs)  const
{
    return  mData != rhs.mData;
}

inline Ami::Severity  AmiStatus::severity()  const
{
    return (Ami::Severity)  ((mData & AMI_SEVERITY_BITS) >> AMI_SEVERITY_SHIFT);
}

inline Ami::StatusCode AmiStatus::symbol()  const
{
    return  (Ami::StatusCode)  ((mData & AMI_SYMBOL_BITS) >> AMI_SYMBOL_SHIFT);
}

inline bool AmiStatus::operator< (const AmiStatus& rhs)  const
{
    if (severity() < rhs.severity())
        return true;
    else if (severity()==Ami::kInfo
             && symbol()==Ami::kOk
             && rhs.symbol()!=Ami::kOk)
        return true;
    return false;
}

inline AmiStatus& AmiStatus::operator+=(const AmiStatus& rhs)
{
    if (*this < rhs)
    {
        setSeverity(rhs.severity());
        setSymbol(rhs.symbol());
    }
    return *this;
}


inline bool AmiStatus::operator==(const Ami::FlatStatus& rhs)  const
{
    return ((Ami::FlatStatus) *this) == rhs;
}
inline bool AmiStatus::operator!=(const Ami::FlatStatus& rhs)  const
{
    return ((Ami::FlatStatus) *this) != rhs;
}

inline bool operator==(const Ami::FlatStatus& lhs, const AmiStatus& rhs)
{
    return lhs == (Ami::FlatStatus)rhs;
}
inline bool operator!=(const Ami::FlatStatus& lhs, const AmiStatus& rhs)
{
    return lhs != (Ami::FlatStatus)rhs;
}


#endif  // AMISTATUS_H
