#include "stdafx.h"

#include "IndentedWriter.h"

#include "FindType.h"

bool FindType::get_ExactMatchOnly()
{
    return exactMatchOnly;
}

void FindType::set_ExactMatchOnly(bool value)
{
    exactMatchOnly = value;
}

bool FindType::get_RecurseTypes()
{
    return recurseTypes;
}

void FindType::set_RecurseTypes(bool value)
{
    recurseTypes = value;
}

bool FindType::get_MatchOnlyNamespace()
{
    return matchOnlyNamespace;
}

void FindType::set_MatchOnlyNamespace(bool value)
{
    matchOnlyNamespace = value;
}

bool FindType::get_WideSearch()
{
    return wideSearch;
}

void FindType::set_WideSearch(bool value)
{
    wideSearch = value;
}

bool FindType::get_VerbosePrint()
{
    return myVerboseWriter->Print;
}

void FindType::set_VerbosePrint(bool value)
{
    myVerboseWriter->Print = value;
}

bool FindType::get_ShowInterfaces()
{
    return (showOptions & 1) == 0 == false;
}

void FindType::set_ShowInterfaces(bool value)
{
    if (value)
    {
        showOptions |= 1;
    }
    else
    {
        showOptions &= -2;
    }
}

bool FindType::get_ShowFields()
{
    return (showOptions & 2) == 0 == false;
}

void FindType::set_ShowFields(bool value)
{
    if (value)
    {
        showOptions |= 2;
    }
    else
    {
        showOptions &= -3;
    }
}

bool FindType::get_ShowProperties()
{
    return (showOptions & 4) == 0 == false;
}

void FindType::set_ShowProperties(bool value)
{
    if (value)
    {
        showOptions |= 4;
    }
    else
    {
        showOptions &= -5;
    }
}

bool FindType::get_ShowEvents()
{
    return (showOptions & 8) == 0 == false;
}

void FindType::set_ShowEvents(bool value)
{
    if (value)
    {
        showOptions |= 8;
    }
    else
    {
        showOptions &= -9;
    }
}

bool FindType::get_ShowMethods()
{
    return (showOptions & 16) == 0 == false;
}

void FindType::set_ShowMethods(bool value)
{
    if (value)
    {
        showOptions |= 16;
    }
    else
    {
        showOptions &= -17;
    }
}

bool FindType::get_ShowModuleInfo()
{
    return (showOptions & 32) == 0 == false;
}

void FindType::set_ShowModuleInfo(bool value)
{
    if (value)
    {
        showOptions |= 32;
    }
    else
    {
        showOptions &= -33;
    }
}


void FindType::Search()
{
    if (myClassList->Count != 0)
    {
        for (int i = 0; i < myClassList->Count; i++)
        {
            Search(__try_cast<String*>(myClassList->Item[i]));
        }
    }
}

void FindType::Search(String* theSearchString)
{
    Assembly* testAssy = Assembly::Load(S"mscorlib.dll");
    myVerboseWriter->WriteLine(S"Searching System Libraries");
    String* dirFrameworks = Path::GetDirectoryName(testAssy->Location);
    ArrayList* l = new ArrayList();
    BuildDLLFileList(dirFrameworks, l);
    for (int j = 0; j < l->Count; j++)
    {
        Search(theSearchString, __try_cast<String*>(l->Item[j]));
    }
    myVerboseWriter->WriteLine(S"Searching the current directory...");
    l = new ArrayList();
    BuildDLLFileList(S".", l);
    for (int i = 0; i < l->Count; i++)
    {
        Search(theSearchString, __try_cast<String*>(l->Item[i]));
    }
    Object* dir[] = DirList->ToArray();
    for (int j2 = 0; j2 < (int)dir.Length; j2++)
    {
        myVerboseWriter->WriteLine(S"Searching directory  {0}...", {dir[j2]});
        l = new ArrayList();
        BuildDLLFileList(__try_cast<String*>(dir[j2]), l);
        for (int k = 0; k < l->Count; k++)
        {
            Search(theSearchString, __try_cast<String*>(l->Item[k]));
        }
    }
}

void FindType::Search(String* theSearchString, String* theModule)
{
    try
    {
        Assembly* a = Assembly::LoadFrom(theModule);
        Module* m[] = a->GetModules();
        theSearchString = theSearchString->ToUpper();
        for (int j = 0; j < (int)m.Length; j++)
        {
            myVerboseWriter->WriteLine(S"Searching Module {0}", {theModule});
            if (m != 0)
            {
                Type* types[] = m[j]->GetTypes();
                for (int i = 0; i < (int)types.Length; i++)
                {
                    Type* curType = types[i];
                    String* name = curType->FullName->ToUpper();
                    if (ExactMatchOnly)
                    {
                        if (name == theSearchString)
                        {
                            DumpType(curType);
                        }
                    }
                    else if (MatchOnlyNamespace)
                    {
                        if (curType->Namespace != '\0' && curType->Namespace->ToUpper() == theSearchString)
                        {
                            DumpType(curType);
                        }
                    }
                    else if (WideSearch)
                    {
                        if (curType->Namespace->ToUpper()->IndexOf(theSearchString) != -1)
                        {
                            DumpType(curType);
                        }
                    }
                    else if (name == theSearchString)
                    {
                        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;
        for (int i2 = 0; i2 < (int)loadedTypes.Length; i2++)
        {
            if (loadedTypes[i2] == 0)
            {
                exceptionCount++;
            }
        }
    }
    catch (FileNotFoundException* fnfe)
    {
        myVerboseWriter->WriteLine(fnfe->Message);
    }
    catch(...)
    {
    }
}

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* directory, ArrayList* list)
{
    try
    {
        if (Directory::Exists(directory))
        {
            String* e[] = Directory::GetFiles(directory, S"*.dll");
            for (int i = 0; i < (int)e.Length; i++)
            {
                list->Add(e[i]);
            }
        }
        else
        {
            myVerboseWriter->WriteLine(S"Directory [{0}] does not exist!", {directory});
        }
    }
    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* str2 = str;
    return str2;
}

void FindType::DumpType(Type* aType)
{
    Type* baseType = aType->BaseType;
    myWriter->WriteLine(S"{0,-10} {1}", {GetTypeDescription(aType), aType});
    if (ShowModuleInfo)
    {
        myWriter->WriteLine(S"{0,-10} {1}", {S"Module:", aType->Module->FullyQualifiedName});
    }
    DumpInterfaces(aType);
    DumpFields(aType);
    DumpProperties(aType);
    DumpEvents(aType);
    DumpMethods(aType);
    if (RecurseTypes)
    {
        myWriter->WriteLine();
    }
    if (RecurseTypes && baseType != 0)
    {
        myWriter->PushIndent();
        myVerboseWriter->PushIndent();
        DumpType(baseType);
        myWriter->PopIndent();
        myVerboseWriter->PopIndent();
    }
}

void FindType::DumpInterfaces(Type* aType)
{
    if (ShowInterfaces)
    {
        Type* info[] = aType->GetInterfaces();
        if ((int)info.Length != 0)
        {
            myWriter->WriteLine(S"{0} {1}", {S"# Interfaces:", __box((int)info.Length)});
            for (int i = 0; i < (int)info.Length; i++)
            {
                myWriter->PushIndent();
                myWriter->WriteLine(S"interface {0}", {info[i]->FullName});
                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 ((int)pInfo.Length != 0)
        {
            PropertyInfo* curInfo = 0;
            for (int i = 0; i < (int)pInfo.Length; i++)
            {
                curInfo = pInfo[i];
                if (curInfo->DeclaringType == aType)
                {
                    found = true;
                    String* flags = '\0';
                    if (curInfo->CanRead && curInfo->CanWrite)
                    {
                        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 ((int)eInfo.Length != 0)
        {
            for (int i = 0; i < (int)eInfo.Length; 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 ((int)info.Length != 0)
        {
            for (int i = 0; i < (int)info.Length; 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 ((int)mInfo.Length != 0)
        {
            for (int i = 0; i < (int)mInfo.Length; i++)
            {
                if (mInfo[i]->DeclaringType == aType && !mInfo[i]->IsSpecialName)
                {
                    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)");
        }
    }
}

FindType::FindType() : 
myVerboseWriter(new IndentedWriter()), 
myWriter(new IndentedWriter()), 
exactMatchOnly(false), 
recurseTypes(false), 
matchOnlyNamespace(false), 
wideSearch(false), 
showOptions(0), 
myClassList(new ArrayList()), 
DirList(new ArrayList())
{
}

