/*
 * Inscoper NBO Example: Object Accessors
 * ======================================
 * This example demonstrates how to read and write NBO attributes and children,
 * covering XSD primitives, optional values, complex children, and repeated
 * elements.
 *
 * 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/AnnotationRef.h>
#include <NBO/NBO/CMOS.h>
#include <NBO/NBO/Denomination_Type.h>
#include <NBO/NBO/Reagent.h>
#include <NBO/Shared/Exception/InscoperNBOException.h>

#include <iostream>
#include <memory>
#include <vector>

using namespace Inscoper;

int main() {
    // Step 1: XSD primitives map to standard C++ types
    NBO::CMOS camera;
    camera.setPixelWidth(6.5f);            // xsd:float  -> float
    camera.setPixelWellCapacity(30000);    // xsd:long   -> long long
    camera.setManufacturer("Hamamatsu");   // xsd:string -> std::string

    std::cout << camera.getPixelWidth() << " " << camera.getPixelWellCapacity() << " "
              << camera.getManufacturer() << std::endl;

    // Step 2: Optional values expose has / get / set / reset
    // Reading an unset optional value throws InscoperNBOException rather than
    // returning a placeholder, so the absence of a value is never silently ignored.
    std::cout << std::boolalpha << camera.hasArrayWidth() << std::endl;   // false

    try {
        camera.getArrayWidth();
    } catch (const NBO::InscoperNBOException &error) {
        std::cout << "ArrayWidth is not set: " << error.what() << std::endl;
    }

    camera.setArrayWidth(2048);
    std::cout << camera.hasArrayWidth() << " " << camera.getArrayWidth() << std::endl;

    camera.resetArrayWidth();                                            // back to unset
    std::cout << camera.hasArrayWidth() << std::endl;

    // Step 3: Complex children are shared pointers, assigned through their own accessor
    NBO::Denomination_TypePtr name = std::make_shared<NBO::Denomination_Type>();
    name->set("ORCA-Fusion BT");
    camera.setName(name);
    std::cout << camera.getName()->get() << std::endl;

    // Step 4: Repeated elements are vectors, assigned in bulk or one by one
    NBO::Reagent reagent;

    std::vector<NBO::AnnotationRefPtr> annotationRefs;
    annotationRefs.push_back(std::make_shared<NBO::AnnotationRef>());
    annotationRefs.push_back(std::make_shared<NBO::AnnotationRef>());
    reagent.setAnnotationRef_List(annotationRefs);
    std::cout << reagent.getAnnotationRef_List().size() << std::endl;

    reagent.addToAnnotationRef_List(std::make_shared<NBO::AnnotationRef>());
    std::cout << reagent.getAnnotationRef_List().size() << std::endl;

    reagent.clearAnnotationRef_List();
    std::cout << reagent.getAnnotationRef_List().size() << std::endl;

    return 0;
}
// --8<-- [end:main_logic]
