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

#include "lldb/DataFormatters/TypeCategory.h"
#include "lldb/Target/Language.h"

// C Includes
// C++ Includes
// Other libraries and framework includes
// Project includes

using namespace lldb;
using namespace lldb_private;

TypeCategoryImpl::TypeCategoryImpl(IFormatChangeListener *clist, ConstString name,
                                   std::initializer_list<lldb::LanguageType> langs)
    : m_format_cont("format", "regex-format", clist),
      m_summary_cont("summary", "regex-summary", clist),
      m_filter_cont("filter", "regex-filter", clist),
#ifndef LLDB_DISABLE_PYTHON
      m_synth_cont("synth", "regex-synth", clist),
#endif
      m_validator_cont("validator", "regex-validator", clist),
      m_enabled(false),
      m_change_listener(clist),
      m_mutex(),
      m_name(name),
      m_languages()
{
    for (const lldb::LanguageType lang : langs)
        AddLanguage(lang);
}

static bool
IsApplicable(lldb::LanguageType category_lang,
             lldb::LanguageType valobj_lang)
{
    switch (category_lang)
    {
            // these are not languages that LLDB would ordinarily deal with
            // only allow an exact equality here, since we really don't know
            // any better
        case eLanguageTypeAda83:
        case eLanguageTypeCobol74:
        case eLanguageTypeCobol85:
        case eLanguageTypeFortran77:
        case eLanguageTypeFortran90:
        case eLanguageTypePascal83:
        case eLanguageTypeModula2:
        case eLanguageTypeJava:
        case eLanguageTypeAda95:
        case eLanguageTypeFortran95:
        case eLanguageTypePLI:
        case eLanguageTypeUPC:
        case eLanguageTypeD:
        case eLanguageTypePython:
            return category_lang == valobj_lang;
            
            // the C family, we consider it as one
        case eLanguageTypeC89:
        case eLanguageTypeC:
        case eLanguageTypeC99:
            return valobj_lang == eLanguageTypeC89 ||
            valobj_lang == eLanguageTypeC ||
            valobj_lang == eLanguageTypeC99;
            
            // ObjC knows about C and itself
        case eLanguageTypeObjC:
            return valobj_lang == eLanguageTypeC89 ||
            valobj_lang == eLanguageTypeC ||
            valobj_lang == eLanguageTypeC99 ||
            valobj_lang == eLanguageTypeObjC;
            
            // C++ knows about C and C++
        case eLanguageTypeC_plus_plus:
            return valobj_lang == eLanguageTypeC89 ||
            valobj_lang == eLanguageTypeC ||
            valobj_lang == eLanguageTypeC99 ||
            valobj_lang == eLanguageTypeC_plus_plus;
            
            // ObjC++ knows about C,C++,ObjC and ObjC++
        case eLanguageTypeObjC_plus_plus:
            return valobj_lang == eLanguageTypeC89 ||
            valobj_lang == eLanguageTypeC ||
            valobj_lang == eLanguageTypeC99 ||
            valobj_lang == eLanguageTypeC_plus_plus ||
            valobj_lang == eLanguageTypeObjC;
            
        default:
        case eLanguageTypeUnknown:
            return true;
    }
}

bool
TypeCategoryImpl::IsApplicable (ValueObject& valobj)
{
    lldb::LanguageType valobj_lang = valobj.GetObjectRuntimeLanguage();
    for (size_t idx = 0;
         idx < GetNumLanguages();
         idx++)
    {
        const lldb::LanguageType category_lang = GetLanguageAtIndex(idx);
        if (::IsApplicable(category_lang,valobj_lang))
            return true;
    }
    return false;
}

size_t
TypeCategoryImpl::GetNumLanguages ()
{
    if (m_languages.empty())
        return 1;
    return m_languages.size();
}

lldb::LanguageType
TypeCategoryImpl::GetLanguageAtIndex (size_t idx)
{
    if (m_languages.empty())
        return lldb::eLanguageTypeUnknown;
    return m_languages[idx];
}

void
TypeCategoryImpl::AddLanguage (lldb::LanguageType lang)
{
    m_languages.push_back(lang);
}

bool
TypeCategoryImpl::HasLanguage (lldb::LanguageType lang)
{
    const auto iter = std::find(m_languages.begin(), m_languages.end(), lang),
               end = m_languages.end();
    return (iter != end);
}

bool
TypeCategoryImpl::Get (ValueObject& valobj,
                       const FormattersMatchVector& candidates,
                       lldb::TypeFormatImplSP& entry,
                       uint32_t* reason)
{
    if (!IsEnabled() || !IsApplicable(valobj))
        return false;
    if (GetTypeFormatsContainer()->Get(candidates, entry, reason))
        return true;
    bool regex = GetRegexTypeFormatsContainer()->Get(candidates, entry, reason);
    if (regex && reason)
        *reason |= lldb_private::eFormatterChoiceCriterionRegularExpressionSummary;
    return regex;
}

bool
TypeCategoryImpl::Get (ValueObject& valobj,
                       const FormattersMatchVector& candidates,
                       lldb::TypeSummaryImplSP& entry,
                       uint32_t* reason)
{
    if (!IsEnabled() || !IsApplicable(valobj))
        return false;
    if (GetTypeSummariesContainer()->Get(candidates, entry, reason))
        return true;
    bool regex = GetRegexTypeSummariesContainer()->Get(candidates, entry, reason);
    if (regex && reason)
        *reason |= lldb_private::eFormatterChoiceCriterionRegularExpressionSummary;
    return regex;
}

bool
TypeCategoryImpl::Get (ValueObject& valobj,
                       const FormattersMatchVector& candidates,
                       lldb::SyntheticChildrenSP& entry,
                       uint32_t* reason)
{
    if (!IsEnabled() || !IsApplicable(valobj))
        return false;
    TypeFilterImpl::SharedPointer filter_sp;
    uint32_t reason_filter = 0;
    bool regex_filter = false;
    // first find both Filter and Synth, and then check which is most recent
    
    if (!GetTypeFiltersContainer()->Get(candidates, filter_sp, &reason_filter))
        regex_filter = GetRegexTypeFiltersContainer()->Get (candidates, filter_sp, &reason_filter);
    
#ifndef LLDB_DISABLE_PYTHON
    bool regex_synth = false;
    uint32_t reason_synth = 0;
    bool pick_synth = false;
    ScriptedSyntheticChildren::SharedPointer synth;
    if (!GetTypeSyntheticsContainer()->Get(candidates, synth, &reason_synth))
        regex_synth = GetRegexTypeSyntheticsContainer()->Get (candidates, synth, &reason_synth);
    if (!filter_sp.get() && !synth.get())
        return false;
    else if (!filter_sp.get() && synth.get())
        pick_synth = true;
    
    else if (filter_sp.get() && !synth.get())
        pick_synth = false;
    
    else /*if (filter_sp.get() && synth.get())*/
    {
        if (filter_sp->GetRevision() > synth->GetRevision())
            pick_synth = false;
        else
            pick_synth = true;
    }
    if (pick_synth)
    {
        if (regex_synth && reason)
            *reason |= lldb_private::eFormatterChoiceCriterionRegularExpressionFilter;
        entry = synth;
        return true;
    }
    else
    {
        if (regex_filter && reason)
            *reason |= lldb_private::eFormatterChoiceCriterionRegularExpressionFilter;
        entry = filter_sp;
        return true;
    }
    
#else
    if (filter_sp)
    {
        entry = filter_sp;
        return true;
    }
#endif
    
    return false;
}

bool
TypeCategoryImpl::Get (ValueObject& valobj,
                       const FormattersMatchVector& candidates,
                       lldb::TypeValidatorImplSP& entry,
                       uint32_t* reason)
{
    if (!IsEnabled())
        return false;
    if (GetTypeValidatorsContainer()->Get(candidates, entry, reason))
        return true;
    bool regex = GetRegexTypeValidatorsContainer()->Get(candidates, entry, reason);
    if (regex && reason)
        *reason |= lldb_private::eFormatterChoiceCriterionRegularExpressionSummary;
    return regex;
}

void
TypeCategoryImpl::Clear (FormatCategoryItems items)
{
    if ( (items & eFormatCategoryItemValue)  == eFormatCategoryItemValue )
        GetTypeFormatsContainer()->Clear();
    if ( (items & eFormatCategoryItemRegexValue) == eFormatCategoryItemRegexValue )
        GetRegexTypeFormatsContainer()->Clear();

    if ( (items & eFormatCategoryItemSummary) == eFormatCategoryItemSummary )
        GetTypeSummariesContainer()->Clear();
    if ( (items & eFormatCategoryItemRegexSummary) == eFormatCategoryItemRegexSummary )
        GetRegexTypeSummariesContainer()->Clear();

    if ( (items & eFormatCategoryItemFilter)  == eFormatCategoryItemFilter )
        GetTypeFiltersContainer()->Clear();
    if ( (items & eFormatCategoryItemRegexFilter) == eFormatCategoryItemRegexFilter )
        GetRegexTypeFiltersContainer()->Clear();

#ifndef LLDB_DISABLE_PYTHON
    if ( (items & eFormatCategoryItemSynth)  == eFormatCategoryItemSynth )
        GetTypeSyntheticsContainer()->Clear();
    if ( (items & eFormatCategoryItemRegexSynth) == eFormatCategoryItemRegexSynth )
        GetRegexTypeSyntheticsContainer()->Clear();
#endif
    
    if ( (items & eFormatCategoryItemValidator)  == eFormatCategoryItemValidator )
        GetTypeValidatorsContainer()->Clear();
    if ( (items & eFormatCategoryItemRegexValidator) == eFormatCategoryItemRegexValidator )
        GetRegexTypeValidatorsContainer()->Clear();
}

bool
TypeCategoryImpl::Delete (ConstString name,
                          FormatCategoryItems items)
{
    bool success = false;
    
    if ( (items & eFormatCategoryItemValue)  == eFormatCategoryItemValue )
        success = GetTypeFormatsContainer()->Delete(name) || success;
    if ( (items & eFormatCategoryItemRegexValue) == eFormatCategoryItemRegexValue )
        success = GetRegexTypeFormatsContainer()->Delete(name) || success;

    if ( (items & eFormatCategoryItemSummary) == eFormatCategoryItemSummary )
        success = GetTypeSummariesContainer()->Delete(name) || success;
    if ( (items & eFormatCategoryItemRegexSummary) == eFormatCategoryItemRegexSummary )
        success = GetRegexTypeSummariesContainer()->Delete(name) || success;

    if ( (items & eFormatCategoryItemFilter)  == eFormatCategoryItemFilter )
        success = GetTypeFiltersContainer()->Delete(name) || success;
    if ( (items & eFormatCategoryItemRegexFilter) == eFormatCategoryItemRegexFilter )
        success = GetRegexTypeFiltersContainer()->Delete(name) || success;

#ifndef LLDB_DISABLE_PYTHON
    if ( (items & eFormatCategoryItemSynth)  == eFormatCategoryItemSynth )
        success = GetTypeSyntheticsContainer()->Delete(name) || success;
    if ( (items & eFormatCategoryItemRegexSynth) == eFormatCategoryItemRegexSynth )
        success = GetRegexTypeSyntheticsContainer()->Delete(name) || success;
#endif
    
    if ( (items & eFormatCategoryItemValidator)  == eFormatCategoryItemValidator )
        success = GetTypeValidatorsContainer()->Delete(name) || success;
    if ( (items & eFormatCategoryItemRegexValidator) == eFormatCategoryItemRegexValidator )
        success = GetRegexTypeValidatorsContainer()->Delete(name) || success;
    
    return success;
}

uint32_t
TypeCategoryImpl::GetCount (FormatCategoryItems items)
{
    uint32_t count = 0;

    if ( (items & eFormatCategoryItemValue) == eFormatCategoryItemValue )
        count += GetTypeFormatsContainer()->GetCount();
    if ( (items & eFormatCategoryItemRegexValue) == eFormatCategoryItemRegexValue )
        count += GetRegexTypeFormatsContainer()->GetCount();
    
    if ( (items & eFormatCategoryItemSummary) == eFormatCategoryItemSummary )
        count += GetTypeSummariesContainer()->GetCount();
    if ( (items & eFormatCategoryItemRegexSummary) == eFormatCategoryItemRegexSummary )
        count += GetRegexTypeSummariesContainer()->GetCount();

    if ( (items & eFormatCategoryItemFilter)  == eFormatCategoryItemFilter )
        count += GetTypeFiltersContainer()->GetCount();
    if ( (items & eFormatCategoryItemRegexFilter) == eFormatCategoryItemRegexFilter )
        count += GetRegexTypeFiltersContainer()->GetCount();

#ifndef LLDB_DISABLE_PYTHON
    if ( (items & eFormatCategoryItemSynth)  == eFormatCategoryItemSynth )
        count += GetTypeSyntheticsContainer()->GetCount();
    if ( (items & eFormatCategoryItemRegexSynth) == eFormatCategoryItemRegexSynth )
        count += GetRegexTypeSyntheticsContainer()->GetCount();
#endif
    
    if ( (items & eFormatCategoryItemValidator)  == eFormatCategoryItemValidator )
        count += GetTypeValidatorsContainer()->GetCount();
    if ( (items & eFormatCategoryItemRegexValidator) == eFormatCategoryItemRegexValidator )
        count += GetRegexTypeValidatorsContainer()->GetCount();
    
    return count;
}

bool
TypeCategoryImpl::AnyMatches(ConstString type_name,
                             FormatCategoryItems items,
                             bool only_enabled,
                             const char** matching_category,
                             FormatCategoryItems* matching_type)
{
    if (!IsEnabled() && only_enabled)
        return false;
    
    lldb::TypeFormatImplSP format_sp;
    lldb::TypeSummaryImplSP summary_sp;
    TypeFilterImpl::SharedPointer filter_sp;
#ifndef LLDB_DISABLE_PYTHON
    ScriptedSyntheticChildren::SharedPointer synth_sp;
#endif
    TypeValidatorImpl::SharedPointer validator_sp;
    
    if ( (items & eFormatCategoryItemValue) == eFormatCategoryItemValue )
    {
        if (GetTypeFormatsContainer()->Get(type_name, format_sp))
        {
            if (matching_category)
                *matching_category = m_name.GetCString();
            if (matching_type)
                *matching_type = eFormatCategoryItemValue;
            return true;
        }
    }
    if ( (items & eFormatCategoryItemRegexValue) == eFormatCategoryItemRegexValue )
    {
        if (GetRegexTypeFormatsContainer()->Get(type_name, format_sp))
        {
            if (matching_category)
                *matching_category = m_name.GetCString();
            if (matching_type)
                *matching_type = eFormatCategoryItemRegexValue;
            return true;
        }
    }
    
    if ( (items & eFormatCategoryItemSummary) == eFormatCategoryItemSummary )
    {
        if (GetTypeSummariesContainer()->Get(type_name, summary_sp))
        {
            if (matching_category)
                *matching_category = m_name.GetCString();
            if (matching_type)
                *matching_type = eFormatCategoryItemSummary;
            return true;
        }
    }
    if ( (items & eFormatCategoryItemRegexSummary) == eFormatCategoryItemRegexSummary )
    {
        if (GetRegexTypeSummariesContainer()->Get(type_name, summary_sp))
        {
            if (matching_category)
                *matching_category = m_name.GetCString();
            if (matching_type)
                *matching_type = eFormatCategoryItemRegexSummary;
            return true;
        }
    }
    
    if ( (items & eFormatCategoryItemFilter)  == eFormatCategoryItemFilter )
    {
        if (GetTypeFiltersContainer()->Get(type_name, filter_sp))
        {
            if (matching_category)
                *matching_category = m_name.GetCString();
            if (matching_type)
                *matching_type = eFormatCategoryItemFilter;
            return true;
        }
    }
    if ( (items & eFormatCategoryItemRegexFilter) == eFormatCategoryItemRegexFilter )
    {
        if (GetRegexTypeFiltersContainer()->Get(type_name, filter_sp))
        {
            if (matching_category)
                *matching_category = m_name.GetCString();
            if (matching_type)
                *matching_type = eFormatCategoryItemRegexFilter;
            return true;
        }
    }
    
#ifndef LLDB_DISABLE_PYTHON
    if ( (items & eFormatCategoryItemSynth)  == eFormatCategoryItemSynth )
    {
        if (GetTypeSyntheticsContainer()->Get(type_name, synth_sp))
        {
            if (matching_category)
                *matching_category = m_name.GetCString();
            if (matching_type)
                *matching_type = eFormatCategoryItemSynth;
            return true;
        }
    }
    if ( (items & eFormatCategoryItemRegexSynth) == eFormatCategoryItemRegexSynth )
    {
        if (GetRegexTypeSyntheticsContainer()->Get(type_name, synth_sp))
        {
            if (matching_category)
                *matching_category = m_name.GetCString();
            if (matching_type)
                *matching_type = eFormatCategoryItemRegexSynth;
            return true;
        }
    }
#endif
    
    if ( (items & eFormatCategoryItemValidator)  == eFormatCategoryItemValidator )
    {
        if (GetTypeValidatorsContainer()->Get(type_name, validator_sp))
        {
            if (matching_category)
                *matching_category = m_name.GetCString();
            if (matching_type)
                *matching_type = eFormatCategoryItemValidator;
            return true;
        }
    }
    if ( (items & eFormatCategoryItemRegexValidator) == eFormatCategoryItemRegexValidator )
    {
        if (GetRegexTypeValidatorsContainer()->Get(type_name, validator_sp))
        {
            if (matching_category)
                *matching_category = m_name.GetCString();
            if (matching_type)
                *matching_type = eFormatCategoryItemRegexValidator;
            return true;
        }
    }
    
    return false;
}

TypeCategoryImpl::FormatContainer::MapValueType
TypeCategoryImpl::GetFormatForType (lldb::TypeNameSpecifierImplSP type_sp)
{
    FormatContainer::MapValueType retval;
    
    if (type_sp)
    {
        if (type_sp->IsRegex())
            GetRegexTypeFormatsContainer()->GetExact(ConstString(type_sp->GetName()),retval);
        else
            GetTypeFormatsContainer()->GetExact(ConstString(type_sp->GetName()),retval);
    }
    
    return retval;
}

TypeCategoryImpl::SummaryContainer::MapValueType
TypeCategoryImpl::GetSummaryForType (lldb::TypeNameSpecifierImplSP type_sp)
{
    SummaryContainer::MapValueType retval;
    
    if (type_sp)
    {
        if (type_sp->IsRegex())
            GetRegexTypeSummariesContainer()->GetExact(ConstString(type_sp->GetName()),retval);
        else
            GetTypeSummariesContainer()->GetExact(ConstString(type_sp->GetName()),retval);
    }
    
    return retval;
}

TypeCategoryImpl::FilterContainer::MapValueType
TypeCategoryImpl::GetFilterForType (lldb::TypeNameSpecifierImplSP type_sp)
{
    FilterContainer::MapValueType retval;
    
    if (type_sp)
    {
        if (type_sp->IsRegex())
            GetRegexTypeFiltersContainer()->GetExact(ConstString(type_sp->GetName()),retval);
        else
            GetTypeFiltersContainer()->GetExact(ConstString(type_sp->GetName()),retval);
    }
    
    return retval;
}

#ifndef LLDB_DISABLE_PYTHON
TypeCategoryImpl::SynthContainer::MapValueType
TypeCategoryImpl::GetSyntheticForType (lldb::TypeNameSpecifierImplSP type_sp)
{
    SynthContainer::MapValueType retval;
    
    if (type_sp)
    {
        if (type_sp->IsRegex())
            GetRegexTypeSyntheticsContainer()->GetExact(ConstString(type_sp->GetName()),retval);
        else
            GetTypeSyntheticsContainer()->GetExact(ConstString(type_sp->GetName()),retval);
    }
    
    return retval;
}
#endif

TypeCategoryImpl::ValidatorContainer::MapValueType
TypeCategoryImpl::GetValidatorForType (lldb::TypeNameSpecifierImplSP type_sp)
{
    ValidatorContainer::MapValueType retval;
    
    if (type_sp)
    {
        if (type_sp->IsRegex())
            GetRegexTypeValidatorsContainer()->GetExact(ConstString(type_sp->GetName()),retval);
        else
            GetTypeValidatorsContainer()->GetExact(ConstString(type_sp->GetName()),retval);
    }
    
    return retval;
}

lldb::TypeNameSpecifierImplSP
TypeCategoryImpl::GetTypeNameSpecifierForSummaryAtIndex (size_t index)
{
    if (index < GetTypeSummariesContainer()->GetCount())
        return GetTypeSummariesContainer()->GetTypeNameSpecifierAtIndex(index);
    else
        return GetRegexTypeSummariesContainer()->GetTypeNameSpecifierAtIndex(index-GetTypeSummariesContainer()->GetCount());
}

TypeCategoryImpl::FormatContainer::MapValueType
TypeCategoryImpl::GetFormatAtIndex (size_t index)
{
    if (index < GetTypeFormatsContainer()->GetCount())
        return GetTypeFormatsContainer()->GetAtIndex(index);
    else
        return GetRegexTypeFormatsContainer()->GetAtIndex(index-GetTypeFormatsContainer()->GetCount());
}

TypeCategoryImpl::SummaryContainer::MapValueType
TypeCategoryImpl::GetSummaryAtIndex (size_t index)
{
    if (index < GetTypeSummariesContainer()->GetCount())
        return GetTypeSummariesContainer()->GetAtIndex(index);
    else
        return GetRegexTypeSummariesContainer()->GetAtIndex(index-GetTypeSummariesContainer()->GetCount());
}

TypeCategoryImpl::FilterContainer::MapValueType
TypeCategoryImpl::GetFilterAtIndex (size_t index)
{
    if (index < GetTypeFiltersContainer()->GetCount())
        return GetTypeFiltersContainer()->GetAtIndex(index);
    else
        return GetRegexTypeFiltersContainer()->GetAtIndex(index-GetTypeFiltersContainer()->GetCount());
}

lldb::TypeNameSpecifierImplSP
TypeCategoryImpl::GetTypeNameSpecifierForFormatAtIndex (size_t index)
{
    if (index < GetTypeFormatsContainer()->GetCount())
        return GetTypeFormatsContainer()->GetTypeNameSpecifierAtIndex(index);
    else
        return GetRegexTypeFormatsContainer()->GetTypeNameSpecifierAtIndex(index-GetTypeFormatsContainer()->GetCount());
}

lldb::TypeNameSpecifierImplSP
TypeCategoryImpl::GetTypeNameSpecifierForFilterAtIndex (size_t index)
{
    if (index < GetTypeFiltersContainer()->GetCount())
        return GetTypeFiltersContainer()->GetTypeNameSpecifierAtIndex(index);
    else
        return GetRegexTypeFiltersContainer()->GetTypeNameSpecifierAtIndex(index-GetTypeFiltersContainer()->GetCount());
}

#ifndef LLDB_DISABLE_PYTHON
TypeCategoryImpl::SynthContainer::MapValueType
TypeCategoryImpl::GetSyntheticAtIndex (size_t index)
{
    if (index < GetTypeSyntheticsContainer()->GetCount())
        return GetTypeSyntheticsContainer()->GetAtIndex(index);
    else
        return GetRegexTypeSyntheticsContainer()->GetAtIndex(index-GetTypeSyntheticsContainer()->GetCount());
}

lldb::TypeNameSpecifierImplSP
TypeCategoryImpl::GetTypeNameSpecifierForSyntheticAtIndex (size_t index)
{
    if (index < GetTypeSyntheticsContainer()->GetCount())
        return GetTypeSyntheticsContainer()->GetTypeNameSpecifierAtIndex(index);
    else
        return GetRegexTypeSyntheticsContainer()->GetTypeNameSpecifierAtIndex(index - GetTypeSyntheticsContainer()->GetCount());
}
#endif

TypeCategoryImpl::ValidatorContainer::MapValueType
TypeCategoryImpl::GetValidatorAtIndex (size_t index)
{
    if (index < GetTypeValidatorsContainer()->GetCount())
        return GetTypeValidatorsContainer()->GetAtIndex(index);
    else
        return GetRegexTypeValidatorsContainer()->GetAtIndex(index-GetTypeValidatorsContainer()->GetCount());
}

lldb::TypeNameSpecifierImplSP
TypeCategoryImpl::GetTypeNameSpecifierForValidatorAtIndex (size_t index)
{
    if (index < GetTypeValidatorsContainer()->GetCount())
        return GetTypeValidatorsContainer()->GetTypeNameSpecifierAtIndex(index);
    else
        return GetRegexTypeValidatorsContainer()->GetTypeNameSpecifierAtIndex(index - GetTypeValidatorsContainer()->GetCount());
}

void
TypeCategoryImpl::Enable (bool value, uint32_t position)
{
    std::lock_guard<std::recursive_mutex> guard(m_mutex);
    if ( (m_enabled = value) )
        m_enabled_position = position;
    if (m_change_listener)
        m_change_listener->Changed();
}

std::string
TypeCategoryImpl::GetDescription ()
{
    StreamString stream;
    stream.Printf("%s (%s",
                  GetName(),
                  (IsEnabled() ? "enabled" : "disabled"));
    StreamString lang_stream;
    lang_stream.Printf(", applicable for language(s): ");
    bool print_lang = false;
    for (size_t idx = 0;
         idx < GetNumLanguages();
         idx++)
    {
        const lldb::LanguageType lang = GetLanguageAtIndex(idx);
        if (lang != lldb::eLanguageTypeUnknown)
            print_lang = true;
        lang_stream.Printf("%s%s",
                           Language::GetNameForLanguageType(lang),
                           idx+1<GetNumLanguages() ? ", " : "");
    }
    if (print_lang)
        stream.Printf("%s",lang_stream.GetData());
    stream.PutChar(')');
    return stream.GetData();
}
