#include "stdafx.h"

#include "IndentedWriter.h"

#include "FindType.h"

bool FindType::get_VerbosePrint()
{
    return myVerboseWriter->Print;
}

void FindType::set_VerbosePrint(bool Value)
{
    myVerboseWriter->Print = Value;
}

bool FindType::get_ExactMatchOnly()
{
    return exactMatchOnlyField;
}

void FindType::set_ExactMatchOnly(bool Value)
{
    exactMatchOnlyField = Value;
}

bool FindType::get_RecurseTypes()
{
    return recurseTypesField;
}

void FindType::set_RecurseTypes(bool Value)
{
    recurseTypesField = Value;
}

bool FindType::get_MatchOnlyNamespace()
{
    return matchOnlyNamespaceField;
}

void FindType::set_MatchOnlyNamespace(bool Value)
{
    matchOnlyNamespaceField = Value;
}

bool FindType::get_WideSearch()
{
    return wideSearchField;
}

void FindType::set_WideSearch(bool Value)
{
    wideSearchField = Value;
}

bool FindType::get_ShowInterfaces()
{
    return (showOptions & SHOW_INTERFACES) == 0 == false;
}

void FindType::set_ShowInterfaces(bool Value)
{
    if (Value)
    {
        showOptions |= SHOW_INTERFACES;
    }
    else
    {
        showOptions &= ~SHOW_INTERFACES;
    }
}

bool FindType::get_ShowMethods()
{
    return (showOptions & SHOW_METHODS) == 0 == false;
}

void FindType::set_ShowMethods(bool Value)
{
    if (Value)
    {
        showOptions |= SHOW_METHODS;
    }
    else
    {
        showOptions &= ~SHOW_METHODS;
    }
}

bool FindType::get_ShowFields()
{
    return (showOptions & SHOW_FIELDS) == 0 == false;
}

void FindType::set_ShowFields(bool Value)
{
    if (Value)
    {
        showOptions |= SHOW_FIELDS;
    }
    else
    {
        showOptions &= ~SHOW_FIELDS;
    }
}

bool FindType::get_ShowProperties()
{
    return (showOptions & SHOW_PROPERTIES) == 0 == false;
}

void FindType::set_ShowProperties(bool Value)
{
    if (Value)
    {
        showOptions |= SHOW_PROPERTIES;
    }
    else
    {
        showOptions &= ~SHOW_PROPERTIES;
    }
}

bool FindType::get_ShowEvents()
{
    return (showOptions & SHOW_EVENTS) == 0 == false;
}

void FindType::set_ShowEvents(bool Value)
{
    if (Value)
    {
        showOptions |= SHOW_EVENTS;
    }
    else
    {
        showOptions &= ~SHOW_EVENTS;
    }
}

bool FindType::get_ShowModuleInfo()
{
    return (showOptions & SHOW_MODULE_INFO) == 0 == false;
}

void FindType::set_ShowModuleInfo(bool Value)
{
    if (Value)
    {
        showOptions |= SHOW_MODULE_INFO;
    }
    else
    {
        showOptions &= ~SHOW_MODULE_INFO;
    }
}


FindType::FindType()
{
    SHOW_INTERFACES = 1;
    SHOW_FIELDS = 2;
    SHOW_PROPERTIES = 4;
    SHOW_EVENTS = 8;
    SHOW_METHODS = 16;
    SHOW_MODULE_INFO = 32;
    myVerboseWriter = new IndentedWriter();
    myWriter = new IndentedWriter();
    exactMatchOnlyField = false;
    recurseTypesField = false;
    matchOnlyNamespaceField = false;
    wideSearchField = false;
    showOptions = 0;
    myClassList = new ArrayList();
    DirList = new ArrayList();
}

void FindType::Search()
{
    if (myClassList->Count != 0)
    {
        int _Vb_t_i4_0 = myClassList->Count - 1;
        for (int i = 0; i <= _Vb_t_i4_0; i++)
        {
            Search(StringType::FromObject(myClassList->Item[i]));
        }
    }
}

void FindType::Search(String* theSearchString)
{
    String* dirFrameworks = Path::GetDirectoryName(Assembly::Load(S"mscorlib.dll")->Location);
    myVerboseWriter->WriteLine(S"Searching System Libraries");
    ArrayList* l = new ArrayList();
    BuildDLLFileList(dirFrameworks, l);
    int _Vb_t_i4_0 = l->Count - 1;
    for (int j = 0; j <= _Vb_t_i4_0; j++)
    {
        Search(theSearchString, StringType::FromObject(l->Item[j]));
    }
    myVerboseWriter->WriteLine(S"Searching the current directory...");
    l = new ArrayList();
    BuildDLLFileList(S".", l);
    int _Vb_t_i4_1 = l->Count - 1;
    for (int j = 0; j <= _Vb_t_i4_1; j++)
    {
        Search(theSearchString, StringType::FromObject(l->Item[j]));
    }
    Object* dir[] = DirList->ToArray();
    int _Vb_t_i4_2 = dir->Length - 1;
    for (int i = 0; i <= _Vb_t_i4_2; i++)
    {
        myVerboseWriter->WriteLine(S"Searching directory  {0}...", {RuntimeHelpers::GetObjectValue(dir[i])});
        l = new ArrayList();
        BuildDLLFileList(StringType::FromObject(dir[i]), l);
        int _Vb_t_i4_3 = l->Count - 1;
        for (int j = 0; j <= _Vb_t_i4_3; j++)
        {
            Search(theSearchString, StringType::FromObject(l->Item[j]));
        }
    }
}

void FindType::Search(String* theSearchString, String* theModule)
{
    try
    {
        Assembly* a = Assembly::LoadFrom(theModule);
        Module* m[] = a->GetModules();
        theSearchString = theSearchString->ToUpper();
        int _Vb_t_i4_0 = m->Length - 1;
        for (int j = 0; j <= _Vb_t_i4_0; j++)
        {
            myVerboseWriter->WriteLine(S"Searching Module {0}", {theModule});
            if (m != 0)
            {
                Type* types[] = m[j]->GetTypes();
                int _Vb_t_i4_1 = types->Length - 1;
                for (int i = 0; i <= _Vb_t_i4_1; i++)
                {
                    Type* curType = types[i];
                    String* name = curType->FullName->ToUpper();
                    if (ExactMatchOnly)
                    {
                        if (StringType::StrCmp(name, theSearchString, false) == 0)
                        {
                            DumpType(curType);
                        }
                    }
                    else if (MatchOnlyNamespace)
                    {
                        if (curType->Namespace != '\0' && StringType::StrCmp(curType->Namespace->ToUpper(), theSearchString, false) == 0)
                        {
                            DumpType(curType);
                        }
                    }
                    else if (WideSearch)
                    {
                        if (curType->Namespace->ToUpper()->IndexOf(theSearchString) != -1)
                        {
                            DumpType(curType);
                        }
                    }
                    else if (StringType::StrCmp(name, theSearchString, false) == 0)
                    {
                        int oldOptions = showOptions;
                        if (showOptions == 0)
                        {
                            ShowAll();
                        }
                        DumpType(curType);
                        showOptions = oldOptions;
                    }
                    else if (name->IndexOf(theSearchString) != -1)
                    {
                        DumpType(curType);
                    }
                }
            }
        }
    }
    catch (ReflectionTypeLoadException* rcle)
    {
        Type* loadedTypes[] = rcle->Types;
        Exception* exceptions[] = rcle->LoaderExceptions;
        int exceptionCount = 0;
        int _Vb_t_i4_2 = loadedTypes->Length - 1;
        for (int i2 = 0; i2 <= _Vb_t_i4_2; i2++)
        {
            if (loadedTypes[i2] == 0)
            {
                exceptionCount++;
            }
        }
    }
    catch (FileNotFoundException* fnfe)
    {
        myVerboseWriter->WriteLine(fnfe->Message);
    }
    catch (Exception* e)
    {
    }
}

void FindType::ShowAll()
{
    ShowInterfaces = true;
    ShowMethods = true;
    ShowFields = true;
    ShowProperties = true;
    ShowEvents = true;
    ShowModuleInfo = true;
}

void FindType::DirAdd(String* dir)
{
    DirList->Add(dir);
}

void FindType::ClassAdd(String* newClass)
{
    myClassList->Add(newClass);
}

void FindType::BuildDLLFileList(String* dirName, ArrayList* list)
{
    try
    {
        if (Directory::Exists(dirName))
        {
            String* e[] = Directory::GetFiles(dirName, S"*.dll");
            int _Vb_t_i4_0 = e->Length - 1;
            for (int i = 0; i <= _Vb_t_i4_0; i++)
            {
                list->Add(e[i]);
            }
        }
        else
        {
            myVerboseWriter->WriteLine(S"Directory [{0}] does not exist!", {dirName});
        }
    }
    catch (Exception* Ex)
    {
        if (Ex->GetType() != __typeof(InvalidOperationException))
        {
        }
    }
}

String* FindType::GetTypeDescription(Type* aType)
{
    String* str = '\0';
    if (aType->IsClass)
    {
        str = S"class";
    }
    if (aType->IsInterface)
    {
        str = S"interface";
    }
    if (aType->IsValueType)
    {
        str = S"struct";
    }
    if (aType->IsArray)
    {
        str = S"array";
    }
    String* GetTypeDescription = str;
    return GetTypeDescription;
}

void FindType::DumpType(Type* aType)
{
    Type* baseType = aType->BaseType;
    Object* _Vb_t_array_0[] = {GetTypeDescription(aType), aType};
    myWriter->WriteLine(S"{0,-10} {1}", _Vb_t_array_0);
    if (ShowModuleInfo)
    {
        _Vb_t_array_0 = {S"Module:", aType->Module->FullyQualifiedName};
        myWriter->WriteLine(S"{0,-10} {1}", _Vb_t_array_0);
    }
    DumpInterfaces(aType);
    DumpFields(aType);
    DumpProperties(aType);
    DumpEvents(aType);
    DumpMethods(aType);
    if (RecurseTypes)
    {
        myWriter->WriteLine();
    }
    if ((RecurseTypes & baseType == 0 == false) != 0)
    {
        myWriter->PushIndent();
        myVerboseWriter->PushIndent();
        DumpType(baseType);
        myWriter->PopIndent();
        myVerboseWriter->PopIndent();
    }
}

void FindType::DumpInterfaces(Type* aType)
{
    if (ShowInterfaces)
    {
        Type* info[] = aType->GetInterfaces();
        if (info->Length != 0)
        {
            Object* _Vb_t_array_0[] = {S"# Interfaces:", __box(info->Length)};
            myWriter->WriteLine(S"{0} {1}", _Vb_t_array_0);
            int _Vb_t_i4_0 = info->Length - 1;
            for (int i = 0; i <= _Vb_t_i4_0; i++)
            {
                myWriter->PushIndent();
                _Vb_t_array_0 = {info[i]->FullName};
                myWriter->WriteLine(S"interface {0}", _Vb_t_array_0);
                if (ShowMethods)
                {
                    myWriter->PushIndent();
                    DumpType(info[i]);
                    myWriter->PopIndent();
                }
                myWriter->PopIndent();
            }
        }
    }
}

void FindType::DumpProperties(Type* aType)
{
    if (ShowProperties)
    {
        PropertyInfo* pInfo[] = aType->GetProperties();
        myWriter->WriteLine(S"Properties");
        bool found = false;
        if (pInfo->Length != 0)
        {
            PropertyInfo* curInfo = 0;
            int _Vb_t_i4_0 = pInfo->Length - 1;
            for (int i = 0; i <= _Vb_t_i4_0; i++)
            {
                curInfo = pInfo[i];
                if (curInfo->DeclaringType == aType)
                {
                    found = true;
                    String* flags = '\0';
                    if ((curInfo->CanRead & curInfo->CanWrite) != 0)
                    {
                        flags = S"get; set;";
                    }
                    else if (curInfo->CanRead)
                    {
                        flags = S"get";
                    }
                    else if (curInfo->CanWrite)
                    {
                        flags = S"set";
                    }
                    myWriter->WriteLine(S"  {0,-10} \'{1}\' ", {curInfo, flags});
                }
            }
        }
        if (!found)
        {
            myWriter->WriteLine(S"  (none)");
        }
    }
}

void FindType::DumpEvents(Type* aType)
{
    if (ShowEvents)
    {
        EventInfo* eInfo[] = aType->GetEvents();
        myWriter->WriteLine(S"Events:");
        bool found = false;
        if (eInfo->Length != 0)
        {
            int _Vb_t_i4_0 = eInfo->Length - 1;
            for (int i = 0; i <= _Vb_t_i4_0; i++)
            {
                if (eInfo[i]->DeclaringType == aType)
                {
                    found = true;
                    myWriter->WriteLine(S"  {0}", {eInfo[i]});
                }
            }
        }
        if (!found)
        {
            myWriter->WriteLine(S"  (none)");
        }
    }
}

void FindType::DumpFields(Type* aType)
{
    if (ShowFields)
    {
        FieldInfo* info[] = aType->GetFields();
        myWriter->WriteLine(S"Fields:");
        bool found = false;
        if (info->Length != 0)
        {
            int _Vb_t_i4_0 = info->Length - 1;
            for (int i = 0; i <= _Vb_t_i4_0; i++)
            {
                if (info[i]->DeclaringType == aType)
                {
                    myWriter->WriteLine(S"  {0}", {info[i]});
                    found = true;
                }
            }
        }
        if (!found)
        {
            myWriter->WriteLine(S"  (none)");
        }
    }
}

void FindType::DumpMethods(Type* aType)
{
    if (ShowMethods)
    {
        MethodInfo* mInfo[] = aType->GetMethods();
        myWriter->WriteLine(S"Methods");
        bool found = false;
        if (mInfo->Length != 0)
        {
            int _Vb_t_i4_0 = mInfo->Length - 1;
            for (int i = 0; i <= _Vb_t_i4_0; i++)
            {
                if ((mInfo[i]->DeclaringType == aType & mInfo[i]->IsSpecialName == false) != 0)
                {
                    found = true;
                    StringBuilder* modifiers = new StringBuilder();
                    if (mInfo[i]->IsStatic)
                    {
                        modifiers->Append(S"static ");
                    }
                    if (mInfo[i]->IsPublic)
                    {
                        modifiers->Append(S"public ");
                    }
                    if (mInfo[i]->IsFamily)
                    {
                        modifiers->Append(S"protected ");
                    }
                    if (mInfo[i]->IsAssembly)
                    {
                        modifiers->Append(S"internal ");
                    }
                    if (mInfo[i]->IsPrivate)
                    {
                        modifiers->Append(S"private ");
                    }
                    myWriter->WriteLine(S"  {0} {1}", {modifiers, mInfo[i]});
                }
            }
        }
        if (!found)
        {
            myWriter->WriteLine(S"  (none)");
        }
    }
}

