####################################################################################################
#
# Invoking X3D model self-test:
#
#   $ python XmpMetadataEmbedded.py
#
# Python package x3d.py package is available on PyPI for import.
#   This approach simplifies Python X3D deployment and use.
#   https://pypi.org/project/x3d
#
# Installation:
#       pip install x3d
# or
#       python -m pip install x3d
#
# Developer options for loading x3d package in other Python programs:
#
#    from x3d import *  # preferred approach, terser source that avoids x3d.* class prefixes
#
# or
#    import x3d         # traditional way to subclass x3d package, all classes require x3d.* prefix,
#                       # but python source is very verbose, for example x3d.Material x3d.Shape etc.
#                       # X3dToPython.xslt stylesheet insertPackagePrefix=true supports this option.
#
# Project home page:    # X3D Python Scene Access Interface Library (X3DPSAIL)
#                       # https://www.web3d.org/x3d/stylesheets/python/python.html
# Conversion generator: # https://www.web3d.org/x3d/stylesheets/X3dToPython.xslt
#
####################################################################################################

from x3d import *

newModel=X3D(profile='Immersive',version='4.0',
  head=head(
    children=[
    Comment('of note is that name values for these document meta terms are defined by Dublin Core'),
    meta(content='XmpMetadataEmbedded.x3d',name='title'),
    meta(content='Simple XMP sidecar example: Hello XMP metadata!',name='description'),
    meta(content='29 April 2021',name='created'),
    meta(content='15 July 2025',name='modified'),
    meta(content='Don Brutzman, Vince Marchetti, Jakub Flotynski, Dick Puk',name='creator'),
    meta(content='Source model assumes default containerField=value for X3D4 Metadata nodes, specification resolution needed',name='warning'),
    meta(content='Summary presentation XmpMetadataSupportX3D.pptx',name='reference'),
    meta(content='XmpMetadataSidecar.xml',name='reference'),
    meta(content='XmpMetadataSidecar.rdf',name='reference'),
    meta(content='XmpMetadataSidecar.ttl',name='reference'),
    meta(content='Protege https://protege.stanford.edu',name='generator'),
    meta(content='XmpMetadataEmbeddedX3dComparison.png',name='Image'),
    meta(content='https://www.web3d.org/specifications/X3Dv4/ISO-IEC19775-1v4-IS/Part01/components/core.html#MetadataSet',name='reference'),
    Comment('Wikipedia example RDF XML plus Protege conversion to Turtle .ttl'),
    meta(content='XmpMetadataExampleWikipedia.xml',name='reference'),
    meta(content='XmpMetadataExampleWikipedia.ttl',name='reference'),
    meta(content='https://wwwimages2.adobe.com/content/dam/acom/en/devnet/xmp/pdfs/XMP%20SDK%20Release%20cc-2016-08/XMPSpecificationPart1.pdf',name='reference'),
    meta(content='Once pattern OK, write conversion stylesheets XmpToX3dMetadata.xslt and X3dMetadataToXmp.xslt',name='TODO'),
    meta(content='X3D support for xml:lang attribute not provided in X3D XML Schema, instead use MetadataString as best practice.',name='info'),
    meta(content='Wikipedia XMP https://en.wikipedia.org/wiki/Extensible_Metadata_Platform',name='reference'),
    meta(content='Wikipedia Metadata https://en.wikipedia.org/wiki/Metadata',name='reference'),
    meta(content='https://en.wikipedia.org/wiki/Sidecar',name='reference'),
    meta(content='https://experienceleague.adobe.com/docs/experience-manager-64/assets/administer/xmp.html',name='reference'),
    meta(content='https://en.wikipedia.org/wiki/Ontology_for_Media_Resources',name='reference'),
    meta(content='https://en.wikipedia.org/wiki/Multimedia_Web_Ontology_Language',name='reference'),
    meta(content='W3C Ontology for Media Resources 1.0 https://www.w3.org/TR/mediaont-10',name='reference'),
    meta(content='ISO XMP ISO 16684-1:2019Part 1: Data model, serialization and core properties https://www.iso.org/standard/75163.html',name='reference'),
    meta(content='ISO XMP 16684-2:2014 Part 2: Description of XMP schemas using RELAX NG https://www.iso.org/standard/57422.html',name='reference'),
    meta(content='Adobe XMP https://www.adobe.com/devnet/xmp.html',name='reference'),
    meta(content='Adobe XMP https://www.adobe.com/products/xmp.html',name='reference'),
    meta(content='ExifTool XMP Tags https://exiftool.org/TagNames/XMP.html',name='reference'),
    meta(content='https://www.web3d.org/x3d/content/examples/X3dForWebAuthors/Chapter15Metadata/XmpMetadataEmbedded.x3d',name='identifier'),
    meta(content='https://www.web3d.org/x3d/content/examples/license.html',name='license'),
    meta(content='X3D-Edit 4.0, https://www.web3d.org/x3d/tools/X3D-Edit',name='generator')]),
  Scene=Scene(
    children=[
    Comment('Design considerations:'),
    Comment('a. avoid containerField=\'metadata\' and containerField=\'value\' wherever possible, note X3D4 XML schema revision is needed'),
    Comment('b. literal XMP values wherever possible, lossless'),
    Comment('c. avoid nested quotes/apostrophes by using MetadataString name/value pairs'),
    Comment('d. map XMP parent elements to MetadataSet, otherwise have typed Metadata* values wherever possible'),
    Comment('e. push shared properties as high as possible in MetadataSet hierarchy, since they apply to all children'),
    Comment('f. assumptions: unquoted MFString values equal a single SFString array element, default Metadata* node containerField=\'value\''),
    Comment('g. MetadataSet nodes contain other Metadata* nodes as the /value/ field, thus producing tree-like structured metadata information'),
    WorldInfo(title='XmpMetadataEmbedded.x3d'),
    Background(skyColor=[(0,0.439216,0.760784)]),
    Comment('Sample (partial) XMP sidecar file XmpMetadataSidecar.xml generated manually by Vince Marchetti as part of the STEP Geometry Services Pilot Project'),
    MetadataSet(name='rdf:RDF',reference='TODO refer to XMP ISO specification document',
      value=[
      MetadataSet(name='namespaces',
        value=[
        MetadataString(name='xmlns:rdf',value=['http://www.w3.org/1999/02/22-rdf-syntax-ns#']),
        MetadataString(name='xmlns:dc',value=['http://purl.org/dc/elements/1.1/']),
        MetadataString(name='xmlns:xmp',value=['http://ns.adobe.com/xap/1.0/'])]),
      MetadataSet(name='rdf:Description',
        value=[
        MetadataString(name='rdf:about',value=['https://kshell.com/sgs/example_uri_0001/']),
        MetadataSet(name='dc:description',
          value=[
          MetadataSet(name='rdf:Alt',
            value=[
            MetadataString(name='rdf:li',value=['VRML visualization'],
# discouraging direct use of xml:lang='en' as an attribute, since that is legal XML but invalid X3D

              metadata=MetadataString(name='xml:lang',reference='prefer using MetadataString to indicate xml:lang values',value=['en']))])]),
        MetadataString(name='dc:format',value=['model/x3d-vrml']),
        MetadataString(name='dc:rights',reference='https://www.dublincore.org/specifications/dublin-core/dcmi-terms/terms/rights/',value=["open source"]),
        MetadataSet(name='dc:title',
          value=[
          MetadataSet(name='rdf:Alt',
            value=[
            MetadataString(name='rdf:li',reference="xml:lang='en'",value=['l-bracket_20120725.134815'],
              metadata=MetadataString(name='xml:lang',value=['en'])),
            MetadataString(name='rdf:li',reference="xml:lang='gr'",value=['aristsirra-bracket_20120725.134815'],
              metadata=MetadataString(name='xml:lang',reference='prefer using MetadataString to indicate xml:lang values',value=['en']))]),
          MetadataSet(name='dc:creator',
            value=[
            MetadataSet(name='rdf:Seq',
              value=[
              MetadataString(name='rdf:li',value=['vmarchetti@kshell.com'])])]),
          MetadataString(name='xmp:CreateDate',value=['10 February 2021'])])])]),
    Viewpoint(description='View scene source to see metadata examples',position=(0,0,9)),
    Anchor(description='Load scene index page',parameter=["target=_blank"],url=["XmpMetadataEmbeddedIndex.html","https://www.web3d.org/x3d/content/examples/X3dForWebAuthors/Chapter15Metadata/XmpMetadataEmbeddedIndex.html"],
      children=[
      Shape(
        geometry=Text(string=["View scene source","to see","XmpMetadataEmbedded","example"],
          fontStyle=FontStyle(justify=["MIDDLE","MIDDLE"])),
        appearance=Appearance(
          material=Material(diffuseColor=(1,0.992157,0.039216))))])])
)

### X3D model conversion complete ###

####################################################################################################
# Self-test diagnostics
####################################################################################################

print('Self-test diagnostics for XmpMetadataEmbedded.py:')
if        metaDiagnostics(newModel): # built-in utility method in X3D class
    print(metaDiagnostics(newModel)) # display meta info, hint, warning, error, TODO values in this model
# print('check newModel.XML() serialization...')
newModelXML= newModel.XML() # test export method XML() for exceptions during export
newModel.XMLvalidate()
# print(newModelXML) # diagnostic

try:
#   print('check newModel.VRML() serialization...')
    newModelVRML=newModel.VRML() # test export method VRML() for exceptions during export
    # print(prependLineNumbers(newModelVRML)) # debug
    print("Python-to-VRML export of VRML output successful", flush=True)
except Exception as err: # usually BaseException
    # https://stackoverflow.com/questions/18176602/how-to-get-the-name-of-an-exception-that-was-caught-in-python
    print("*** Python-to-VRML export of VRML output failed:", type(err).__name__, err)
    if newModelVRML: # may have failed to generate
        print(prependLineNumbers(newModelVRML, err.lineno))

try:
#   print('check newModel.JSON() serialization...')
    newModelJSON=newModel.JSON() # test export method JSON() for exceptions during export
#   print(prependLineNumbers(newModelJSON)) # debug
    print("Python-to-JSON export of JSON output successful (under development)")
except Exception as err: # usually SyntaxError
    print("*** Python-to-JSON export of JSON output failed:", type(err).__name__, err)
    if newModelJSON: # may have failed to generate
        print(prependLineNumbers(newModelJSON,err.lineno))

print("python XmpMetadataEmbedded.py load and self-test diagnostics complete.")
