//===-- TypeValidator.h ------------------------------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#ifndef lldb_TypeValidator_h_
#define lldb_TypeValidator_h_

// C Includes

// C++ Includes
#include <functional>
#include <string>

// Other libraries and framework includes

// Project includes
#include "lldb/lldb-public.h"
#include "lldb/lldb-enumerations.h"
#include "lldb/lldb-private-enumerations.h"

namespace lldb_private {
    
class TypeValidatorImpl
{
public:
    class Flags
    {
    public:
        
        Flags () :
        m_flags (lldb::eTypeOptionCascade)
        {}
        
        Flags (const Flags& other) :
        m_flags (other.m_flags)
        {}
        
        Flags (uint32_t value) :
        m_flags (value)
        {}
        
        Flags&
        operator = (const Flags& rhs)
        {
            if (&rhs != this)
                m_flags = rhs.m_flags;
            
            return *this;
        }
        
        Flags&
        operator = (const uint32_t& rhs)
        {
            m_flags = rhs;
            return *this;
        }
        
        Flags&
        Clear()
        {
            m_flags = 0;
            return *this;
        }
        
        bool
        GetCascades () const
        {
            return (m_flags & lldb::eTypeOptionCascade) == lldb::eTypeOptionCascade;
        }
        
        Flags&
        SetCascades (bool value = true)
        {
            if (value)
                m_flags |= lldb::eTypeOptionCascade;
            else
                m_flags &= ~lldb::eTypeOptionCascade;
            return *this;
        }
        
        bool
        GetSkipPointers () const
        {
            return (m_flags & lldb::eTypeOptionSkipPointers) == lldb::eTypeOptionSkipPointers;
        }
        
        Flags&
        SetSkipPointers (bool value = true)
        {
            if (value)
                m_flags |= lldb::eTypeOptionSkipPointers;
            else
                m_flags &= ~lldb::eTypeOptionSkipPointers;
            return *this;
        }
        
        bool
        GetSkipReferences () const
        {
            return (m_flags & lldb::eTypeOptionSkipReferences) == lldb::eTypeOptionSkipReferences;
        }
        
        Flags&
        SetSkipReferences (bool value = true)
        {
            if (value)
                m_flags |= lldb::eTypeOptionSkipReferences;
            else
                m_flags &= ~lldb::eTypeOptionSkipReferences;
            return *this;
        }
        
        bool
        GetNonCacheable () const
        {
            return (m_flags & lldb::eTypeOptionNonCacheable) == lldb::eTypeOptionNonCacheable;
        }
        
        Flags&
        SetNonCacheable (bool value = true)
        {
            if (value)
                m_flags |= lldb::eTypeOptionNonCacheable;
            else
                m_flags &= ~lldb::eTypeOptionNonCacheable;
            return *this;
        }
        
        uint32_t
        GetValue ()
        {
            return m_flags;
        }
        
        void
        SetValue (uint32_t value)
        {
            m_flags = value;
        }
        
    private:
        uint32_t m_flags;
    };
    
    TypeValidatorImpl (const Flags& flags = Flags());
    
    typedef std::shared_ptr<TypeValidatorImpl> SharedPointer;
    
    virtual ~TypeValidatorImpl ();
    
    bool
    Cascades () const
    {
        return m_flags.GetCascades();
    }
    bool
    SkipsPointers () const
    {
        return m_flags.GetSkipPointers();
    }
    bool
    SkipsReferences () const
    {
        return m_flags.GetSkipReferences();
    }
    bool
    NonCacheable () const
    {
        return m_flags.GetNonCacheable();
    }
    
    void
    SetCascades (bool value)
    {
        m_flags.SetCascades(value);
    }
    
    void
    SetSkipsPointers (bool value)
    {
        m_flags.SetSkipPointers(value);
    }
    
    void
    SetSkipsReferences (bool value)
    {
        m_flags.SetSkipReferences(value);
    }
    
    void
    SetNonCacheable (bool value)
    {
        m_flags.SetNonCacheable(value);
    }
    
    uint32_t
    GetOptions ()
    {
        return m_flags.GetValue();
    }
    
    void
    SetOptions (uint32_t value)
    {
        m_flags.SetValue(value);
    }
    
    uint32_t&
    GetRevision ()
    {
        return m_my_revision;
    }
    
    enum class Type
    {
        eTypeUnknown,
        eTypeCXX
    };
    
    struct ValidationResult {
        TypeValidatorResult m_result;
        std::string m_message;
    };
    
    virtual Type
    GetType ()
    {
        return Type::eTypeUnknown;
    }
    
    // we are using a ValueObject* instead of a ValueObjectSP because we do not need to hold on to this for
    // extended periods of time and we trust the ValueObject to stay around for as long as it is required
    // for us to generate its value
    virtual ValidationResult
    FormatObject (ValueObject *valobj) const = 0;
    
    virtual std::string
    GetDescription() = 0;
    
    static ValidationResult
    Success ();
    
    static ValidationResult
    Failure (std::string message);
    
protected:
    Flags m_flags;
    uint32_t m_my_revision;
    
private:
    DISALLOW_COPY_AND_ASSIGN(TypeValidatorImpl);
};
    
class TypeValidatorImpl_CXX : public TypeValidatorImpl
{
public:
    typedef std::function<TypeValidatorImpl::ValidationResult(ValueObject* valobj)> ValidatorFunction;
    
    TypeValidatorImpl_CXX (ValidatorFunction f, std::string d, const TypeValidatorImpl::Flags& flags = Flags());
    
    typedef std::shared_ptr<TypeValidatorImpl_CXX> SharedPointer;
    
    ~TypeValidatorImpl_CXX() override;
    
    ValidatorFunction
    GetValidatorFunction () const
    {
        return m_validator_function;
    }
    
    void
    SetValidatorFunction (ValidatorFunction f)
    {
        m_validator_function = f;
    }
    
    TypeValidatorImpl::Type
    GetType() override
    {
        return TypeValidatorImpl::Type::eTypeCXX;
    }
    
    ValidationResult
    FormatObject(ValueObject *valobj) const override;
    
    std::string
    GetDescription() override;
    
protected:
    std::string m_description;
    ValidatorFunction m_validator_function;
    
private:
    DISALLOW_COPY_AND_ASSIGN(TypeValidatorImpl_CXX);
};

    
} // namespace lldb_private

#endif // lldb_TypeValidator_h_
