/*!
 * \brief Parses the "EditionEntry"-element specified when constructing the object.
 *
 * Fetches the chapters() but does not parse them.
 *
 * Clears all previous parsing results.
 */
void MatroskaEditionEntry::parse(Diagnostics &diag)
{
    // clear previous values and status
    static const string context("parsing \"EditionEntry\"-element");
    clear();
    // iterate through children of "EditionEntry"-element
    EbmlElement *entryChild = m_editionEntryElement->firstChild();
    while (entryChild) {
        entryChild->parse(diag);
        switch (entryChild->id()) {
        case MatroskaIds::EditionUID:
            m_id = entryChild->readUInteger();
            break;
        case MatroskaIds::EditionFlagHidden:
            m_hidden = entryChild->readUInteger() == 1;
            break;
        case MatroskaIds::EditionFlagDefault:
            m_default = entryChild->readUInteger() == 1;
            break;
        case MatroskaIds::EditionFlagOrdered:
            m_ordered = entryChild->readUInteger() == 1;
            break;
        case MatroskaIds::ChapterAtom:
            m_chapters.emplace_back(make_unique<MatroskaChapter>(entryChild));
            break;
        default:
            diag.emplace_back(DiagLevel::Warning,
                "\"EditionEntry\"-element contains unknown child element \"" % entryChild->idToString() + "\" which will be ingored.", context);
        }
        entryChild = entryChild->nextSibling();
    }
}
/*!
 * \brief Parses field information from the specified EbmlElement.
 *
 * The specified atom should be a simple tag element. These elements
 * represents the fields of a MatroskaTag.
 *
 * \throws Throws std::ios_base::failure when an IO error occurs.
 * \throws Throws TagParser::Failure or a derived exception when a parsing
 *         error occurs.
 */
void MatroskaTagField::reparse(EbmlElement &simpleTagElement, Diagnostics &diag, bool parseNestedFields)
{
    string context("parsing Matroska tag field");
    simpleTagElement.parse(diag);
    bool tagDefaultFound = false;
    for (EbmlElement *child = simpleTagElement.firstChild(); child; child = child->nextSibling()) {
        try {
            child->parse(diag);
        } catch (const Failure &) {
            diag.emplace_back(DiagLevel::Critical, "Unable to parse children of \"SimpleTag\"-element.", context);
            break;
        }
        switch (child->id()) {
        case MatroskaIds::TagName:
            if (id().empty()) {
                setId(child->readString());
                context = "parsing Matroska tag field " + id();
            } else {
                diag.emplace_back(DiagLevel::Warning,
                    "\"SimpleTag\"-element contains multiple \"TagName\"-elements. Surplus TagName elements will be ignored.", context);
            }
            break;
        case MatroskaIds::TagString:
        case MatroskaIds::TagBinary:
            if (value().isEmpty()) {
                unique_ptr<char[]> buffer = make_unique<char[]>(child->dataSize());
                child->stream().seekg(static_cast<streamoff>(child->dataOffset()));
                child->stream().read(buffer.get(), static_cast<streamoff>(child->dataSize()));
                switch (child->id()) {
                case MatroskaIds::TagString:
                    value().assignData(move(buffer), child->dataSize(), TagDataType::Text, TagTextEncoding::Utf8);
                    break;
                case MatroskaIds::TagBinary:
                    value().assignData(move(buffer), child->dataSize(), TagDataType::Undefined);
                    break;
                }
            } else {
                diag.emplace_back(DiagLevel::Warning,
                    "\"SimpleTag\"-element contains multiple \"TagString\"/\"TagBinary\"-elements. Surplus \"TagName\"/\"TagBinary\"-elements will "
                    "be ignored.",
                    context);
            }
            break;
        case MatroskaIds::TagLanguage:
            if (value().language().empty() || value().language() == "und") {
                string lng = child->readString();
                if (lng != "und") {
                    value().setLanguage(lng);
                }
            } else {
                diag.emplace_back(DiagLevel::Warning,
                    "\"SimpleTag\"-element contains multiple \"TagLanguage\"-elements. Surplus \"TagLanguage\"-elements will be ignored.", context);
            }
            break;
        case MatroskaIds::TagDefault:
            if (!tagDefaultFound) {
                setDefault(child->readUInteger() > 0);
                tagDefaultFound = true;
            } else {
                diag.emplace_back(DiagLevel::Warning,
                    "\"SimpleTag\"-element contains multiple \"TagDefault\" elements. Surplus \"TagDefault\"-elements will be ignored.", context);
            }
            break;
        case MatroskaIds::SimpleTag:
            if (parseNestedFields) {
                nestedFields().emplace_back();
                nestedFields().back().reparse(*child, diag, true);
            } else {
                diag.emplace_back(DiagLevel::Warning,
                    "Nested fields are currently not supported. Nested tags can not be displayed and will be discarded when rewriting the file.",
                    context);
            }
            break;
        case EbmlIds::Crc32:
        case EbmlIds::Void:
            break;
        default:
            diag.emplace_back(DiagLevel::Warning,
                argsToString(
                    "\"SimpleTag\"-element contains unknown element ", child->idToString(), " at ", child->startOffset(), ". It will be ignored."),
                context);
        }
    }
}