// tree_ex.cpp

#include <stdlib.h>
#include <stdio.h>
#include <mimepp/mimepp.h>


// Recursively print information about nested entities (body parts).

void PrintEntity(int aLevel, const DwEntity& aEntity)
{
    int type = DwMime::kTypeText;
    int subtype = DwMime::kSubtypePlain;
    DwString contentTypeStr;
    if (aEntity.Headers().HasContentType()) {
        type = aEntity.Headers().ContentType().Type();
        subtype = aEntity.Headers().ContentType().Subtype();
        contentTypeStr += aEntity.Headers().ContentType().TypeStr();
        contentTypeStr += "/";
        contentTypeStr += aEntity.Headers().ContentType().SubtypeStr();
    }
    if (contentTypeStr == "") {
        contentTypeStr = "text/plain (implicit)";
    }
    if (type == DwMime::kTypeMultipart) {
        int i;
        printf(" ");
        for (i=0; i < aLevel-1; ++i) {
            printf("| ");
        }
        printf("\n");
        printf(" ");
        for (i=0; i < aLevel-2; ++i) {
            printf("| ");
        }
        for ( ; i < aLevel-1; ++i) {
            printf("+-");
        }
        printf("%s", contentTypeStr.c_str());
        int numBodyParts = aEntity.Body().NumBodyParts();
        if (numBodyParts == 1) {
            printf(" (1 body part)\n");
        }
        else {
            printf(" (%d body parts)\n", numBodyParts);
        }
        for (i=0; i < numBodyParts; ++i) {
            const DwBodyPart& part = aEntity.Body().BodyPartAt(i);
            PrintEntity(aLevel+1, part);
        }
    }
    else if (type == DwMime::kTypeMessage) {
        int i;
        printf(" ");
        for (i=0; i < aLevel-1; ++i) {
            printf("| ");
        }
        printf("\n");
        printf(" ");
        for (i=0; i < aLevel-2; ++i) {
            printf("| ");
        }
        for ( ; i < aLevel-1; ++i) {
            printf("+-");
        }
        printf("%s\n", contentTypeStr.c_str());
        const DwMessage* msg = aEntity.Body().Message();
        if (msg != 0) {
            PrintEntity(aLevel+1, *msg);
        }
    }
    else {
        DwString str;
        str = contentTypeStr;
        if (aEntity.Headers().HasContentDescription()) {
            str += " (";
            str += aEntity.Headers().ContentDescription().AsString();
            str += ")";
        }
        int i;
        printf(" ");
        for (i=0; i < aLevel-1; ++i) {
            printf("| ");
        }
        printf("\n");
        printf(" ");
        for (i=0; i < aLevel-2; ++i) {
            printf("| ");
        }
        for ( ; i < aLevel-1; ++i) {
            printf("+-");
        }
        printf("%s\n", str.c_str());
    }
}


int main(int argc, char **argv)
{
    if (argc < 2) {
        printf("Yikes! No input file!\n");
        return 1;
    }
    FILE* in = fopen(argv[1], "rb");
    if (in == NULL) {
        printf("Whoa! I can't open the file \"%s\".\n", argv[1]);
    }
    fseek(in, 0, SEEK_END);
    size_t fileLen = ftell(in);
    fseek(in, 0, SEEK_SET);
    DwString messageStr;
    messageStr.reserve(fileLen);
    char* buffer = (char*) malloc(8192);
    do {
        size_t count = fread(buffer, 1, 8192, in);
        messageStr.append(buffer, count);
    } while (! feof(in));
    free(buffer);
    fclose(in);
    DwMessage message(messageStr);
    message.Parse();
    PrintEntity(1, message);
    printf("\n");
    return 0;
}
