/*
 * Inscoper NBO Example: Choice Elements
 * =====================================
 * This example demonstrates how to populate and inspect XSD choice elements,
 * where a single position in the document may hold one of several alternatives.
 *
 * Prerequisites:
 * -------------
 * 1. Installation: the include directory of the release must be on the include
 *    paths, and the application must link against the NBO library.
 */

// --8<-- [start:main_logic]
#include <NBO/NBO/BinData.h>
#include <NBO/NBO/NonNegativeLong_Type.h>
#include <NBO/NBO/OME.h>
#include <NBO/NBO/Pixels.h>
#include <NBO/NBO/Project.h>
#include <NBO/NBO/ProjectID_Type.h>
#include <NBO/NBO/UniversallyUniqueIdentifier_Type.h>

#include <iostream>
#include <memory>
#include <vector>

using namespace Inscoper;

int main() {
    std::cout << std::boolalpha;

    // Step 1: A choice of repeated alternatives
    // Pixels may carry BinData, TiffData, NGFFData, or MetadataOnly children. The
    // choice object is filled first, then assigned to its parent.
    NBO::Pixels_ChoicePtr pixelsChoice = std::make_shared<NBO::Pixels_Choice>();
    std::cout << pixelsChoice->containsBinData() << " " << pixelsChoice->containsTiffData()
              << std::endl;

    std::vector<NBO::BinDataPtr> binDataList;
    for (const std::string &compression : {"zlib", "bzip2"}) {
        NBO::BinDataPtr binData = std::make_shared<NBO::BinData>();
        binData->setCompression(compression);
        binData->setBigEndian(true);
        NBO::NonNegativeLong_TypePtr length = std::make_shared<NBO::NonNegativeLong_Type>();
        length->set(12);
        binData->setLength(length);
        binDataList.push_back(binData);
    }

    pixelsChoice->addBinData(binDataList);
    std::cout << pixelsChoice->containsBinData() << " " << pixelsChoice->containsTiffData()
              << std::endl;

    NBO::Pixels pixels;
    pixels.setpixels_choice(pixelsChoice);

    // Pixels declares required attributes of its own, which a validated export would
    // demand. Only the choice matters here, so export without validation; see the
    // Describe an Acquired Image example for a complete, valid Pixels element.
    std::cout << pixels.toXmlString(false) << std::endl;

    // Step 2: A choice of exclusive alternatives
    // OME holds either a BinaryOnly reference or a full metadata document. Setting
    // one alternative clears the other. In C++ the choice is a std::variant, and the
    // generated is / set helpers replace the need for a visitor.
    NBO::OME_ChoicePtr omeChoice = std::make_shared<NBO::OME_Choice>();
    std::cout << omeChoice->isBinaryOnly() << " " << omeChoice->isOME_Choice_1() << std::endl;

    NBO::OME_Choice::InlineBinaryOnlyPtr binaryOnly =
        std::make_shared<NBO::OME_Choice::InlineBinaryOnly>();
    NBO::UniversallyUniqueIdentifier_TypePtr uuid =
        std::make_shared<NBO::UniversallyUniqueIdentifier_Type>();
    uuid->set("urn:uuid:3e450fae-b8f2-4d35-aa54-702168b2487f");
    binaryOnly->setUUID(uuid);
    binaryOnly->setMetadataFile("metadata.ome.xml");
    omeChoice->setBinaryOnly(binaryOnly);
    std::cout << omeChoice->isBinaryOnly() << " " << omeChoice->isOME_Choice_1() << std::endl;

    NBO::OME_Choice::InlineOME_Choice_1Ptr fullDocument =
        std::make_shared<NBO::OME_Choice::InlineOME_Choice_1>();
    NBO::ProjectPtr project = std::make_shared<NBO::Project>();
    NBO::ProjectID_TypePtr projectId = std::make_shared<NBO::ProjectID_Type>();
    projectId->set("Project:1");
    project->setID(projectId);
    project->setName("Mitosis screen");
    fullDocument->addToProject_List(project);
    omeChoice->setOME_Choice_1(fullDocument);
    std::cout << omeChoice->isBinaryOnly() << " " << omeChoice->isOME_Choice_1() << std::endl;

    NBO::OME ome;
    ome.setome_choice(omeChoice);
    std::cout << ome.toXmlString() << std::endl;

    return 0;
}
// --8<-- [end:main_logic]
