//===-- FormattersHelpers.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_FormattersHelpers_h_
#define lldb_FormattersHelpers_h_

// C Includes
// C++ Includes
// Other libraries and framework includes
// Project includes
#include "lldb/lldb-forward.h"
#include "lldb/lldb-enumerations.h"

#include "lldb/DataFormatters/TypeCategory.h"
#include "lldb/DataFormatters/TypeFormat.h"
#include "lldb/DataFormatters/TypeSummary.h"
#include "lldb/DataFormatters/TypeSynthetic.h"

namespace lldb_private {
    namespace formatters {
        void
        AddFormat (TypeCategoryImpl::SharedPointer category_sp,
                   lldb::Format format,
                   ConstString type_name,
                   TypeFormatImpl::Flags flags,
                   bool regex = false);
        
        void
        AddSummary(TypeCategoryImpl::SharedPointer category_sp,
                   lldb::TypeSummaryImplSP summary_sp,
                   ConstString type_name,
                   bool regex = false);

        void
        AddStringSummary(TypeCategoryImpl::SharedPointer category_sp,
                         const char* string,
                         ConstString type_name,
                         TypeSummaryImpl::Flags flags,
                         bool regex = false);
        
        void
        AddOneLineSummary (TypeCategoryImpl::SharedPointer category_sp,
                           ConstString type_name,
                           TypeSummaryImpl::Flags flags,
                           bool regex = false);

#ifndef LLDB_DISABLE_PYTHON
        void
        AddCXXSummary (TypeCategoryImpl::SharedPointer category_sp,
                       CXXFunctionSummaryFormat::Callback funct,
                       const char* description,
                       ConstString type_name,
                       TypeSummaryImpl::Flags flags,
                       bool regex = false);

        void
        AddCXXSynthetic  (TypeCategoryImpl::SharedPointer category_sp,
                          CXXSyntheticChildren::CreateFrontEndCallback generator,
                          const char* description,
                          ConstString type_name,
                          ScriptedSyntheticChildren::Flags flags,
                          bool regex = false);

        void
        AddFilter  (TypeCategoryImpl::SharedPointer category_sp,
                    std::vector<std::string> children,
                    const char* description,
                    ConstString type_name,
                    ScriptedSyntheticChildren::Flags flags,
                    bool regex = false);
#endif
        
        StackFrame*
        GetViableFrame (ExecutionContext exe_ctx);
        
        bool
        ExtractValueFromObjCExpression (ValueObject &valobj,
                                        const char* target_type,
                                        const char* selector,
                                        uint64_t &value);
        
        bool
        ExtractSummaryFromObjCExpression (ValueObject &valobj,
                                          const char* target_type,
                                          const char* selector,
                                          Stream &stream,
                                          lldb::LanguageType lang_type);
        
        lldb::ValueObjectSP
        CallSelectorOnObject (ValueObject &valobj,
                              const char* return_type,
                              const char* selector,
                              uint64_t index);
        
        lldb::ValueObjectSP
        CallSelectorOnObject (ValueObject &valobj,
                              const char* return_type,
                              const char* selector,
                              const char* key);
        
        size_t
        ExtractIndexFromString (const char* item_name);
        
        lldb::addr_t
        GetArrayAddressOrPointerValue (ValueObject& valobj);

        time_t
        GetOSXEpoch ();
        
        struct InferiorSizedWord {
            
            InferiorSizedWord(const InferiorSizedWord& word) : ptr_size(word.ptr_size)
            {
                if (ptr_size == 4)
                    thirty_two = word.thirty_two;
                else
                    sixty_four = word.sixty_four;
            }
            
            InferiorSizedWord
            operator = (const InferiorSizedWord& word)
            {
                ptr_size = word.ptr_size;
                if (ptr_size == 4)
                    thirty_two = word.thirty_two;
                else
                    sixty_four = word.sixty_four;
                return *this;
            }
            
            InferiorSizedWord(uint64_t val, Process& process) : ptr_size(process.GetAddressByteSize())
            {
                if (ptr_size == 4)
                    thirty_two = (uint32_t)val;
                else if (ptr_size == 8)
                    sixty_four = val;
                else
                    assert (false && "new pointer size is unknown");
            }
            
            bool
            IsNegative () const
            {
                if (ptr_size == 4)
                    return ((int32_t)thirty_two) < 0;
                else
                    return ((int64_t)sixty_four) < 0;
            }
            
            bool
            IsZero () const
            {
                if (ptr_size == 4)
                    return thirty_two == 0;
                else
                    return sixty_four == 0;
            }
            
            static InferiorSizedWord
            GetMaximum (Process& process)
            {
                if (process.GetAddressByteSize() == 4)
                    return InferiorSizedWord(UINT32_MAX,4);
                else
                    return InferiorSizedWord(UINT64_MAX,8);
            }
            
            InferiorSizedWord
            operator >> (int rhs) const
            {
                if (ptr_size == 4)
                    return InferiorSizedWord(thirty_two >> rhs,4);
                return InferiorSizedWord(sixty_four>>rhs,8);
            }
            
            InferiorSizedWord
            operator << (int rhs) const
            {
                if (ptr_size == 4)
                    return InferiorSizedWord(thirty_two << rhs,4);
                return InferiorSizedWord(sixty_four << rhs,8);
            }
            
            InferiorSizedWord
            operator & (const InferiorSizedWord& word) const
            {
                if (ptr_size != word.ptr_size)
                    return InferiorSizedWord(0,ptr_size);
                if (ptr_size == 4)
                    return InferiorSizedWord(thirty_two & word.thirty_two,4);
                return InferiorSizedWord(sixty_four & word.sixty_four,8);
            }
            
            InferiorSizedWord
            operator & (int x) const
            {
                if (ptr_size == 4)
                    return InferiorSizedWord(thirty_two & x,4);
                return InferiorSizedWord(sixty_four & x,8);
            }
            
            size_t
            GetBitSize () const
            {
                return ptr_size << 3;
            }
            
            size_t
            GetByteSize () const
            {
                return ptr_size;
            }
            
            uint64_t
            GetValue () const
            {
                if (ptr_size == 4)
                    return (uint64_t)thirty_two;
                return sixty_four;
            }
            
            InferiorSizedWord
            SignExtend () const
            {
                if (ptr_size == 4)
                    return InferiorSizedWord ((int32_t)thirty_two,4);
                return InferiorSizedWord((int64_t)sixty_four,8);
            }
            
            uint8_t*
            CopyToBuffer (uint8_t* buffer) const
            {
                if (ptr_size == 4)
                {
                    memcpy(buffer, &thirty_two, 4);
                    return buffer + 4;
                }
                else
                {
                    memcpy(buffer, &sixty_four, 8);
                    return buffer + 8;
                }
            }
            
            DataExtractor
            GetAsData (lldb::ByteOrder byte_order = lldb::eByteOrderInvalid) const
            {
                if (ptr_size == 4)
                    return DataExtractor(&thirty_two, 4, byte_order, 4);
                else
                    return DataExtractor(&sixty_four, 8, byte_order, 8);
            }
            
        private:
            
            InferiorSizedWord(uint64_t val, size_t psz) : ptr_size(psz)
            {
                if (ptr_size == 4)
                    thirty_two = (uint32_t)val;
                else
                    sixty_four = val;
            }
            
            size_t ptr_size;
            union {
                uint32_t thirty_two;
                uint64_t sixty_four;
            };
        };
    } // namespace formatters
} // namespace lldb_private

#endif	// lldb_FormattersHelpers_h_
