<?php
#
# helictite_rdf.php - Helictite Journal RDF 1.1, presented in Turtle format
#
# Revision history
# Version  Date        Author          Changes
# 1.0      2023-05-29  Glenn Baddeley  Initial version, refers to schema_rdf.php & abstracts_rdf.php
# 1.1      2023-06-18  GB              Update property names, Add GenDataFiles
# 1.2      2023-06-27  GB              Add GenNewsItems, Change object name format for data files
# 1.3      2023-07-23  GB              Add generated date time, Update order of properties
# 1.4      2026-01-29  GB              Support 3 digit volume numbers, Add sVersionDate
# 1.5      2026-02-11  GB              In GenContents, change isnull() to is_null()
# 1.6      2026-03-06  GB              Get data from PEDATA files rather than include files 'XXXXXX_vars.php',
#
# Update sVersionDate below
#

# Change the default encoding of data sent from web server to browser from gzip to no encoding
header_remove( "Content-Encoding" );
header( "Content-Encoding: none");

# Change the default content type from text/html to text/turtle UTF-8
header_remove( "Content-Type" );
header( "Content-Type: text/turtle;charset=UTF-8");

# Include configuration constants and PEDATA functions
require 'helweb_config.php';
if( $cbDebugErrs ) { ini_set('display_errors', 1); error_reporting(E_ALL); }

# Current version of this PHP file
$sVersionDate = "1.6 of 2026-03-03";

# Generate the namespace triples 
echo "# Main RDF data for Helictite, Journal of Australasian Spelelogical Research
# Version $sVersionDate
# Generated " . date('Y-m-d H:i') . "
# RDF 1.1 Turtle format - https://www.w3.org/TR/turtle
@base <https://helictite.caves.org.au/> .   # For relative IRI links to web pages, images, PDF files, data files
# Helictite namespaces
@prefix : <https://helictite.caves.org.au/helictite_rdf.php#> .
@prefix hs: <https://helictite.caves.org.au/schema_rdf.php#> .
@prefix abst: <https://helictite.caves.org.au/abstracts_rdf.php#> .
# Dublin Core DCMI Metadata properties, defined at https://www.dublincore.org/specifications/dublin-core/dcmi-terms/
@prefix dc: <http://purl.org/dc/terms/> .   # Superset of http://purl.org/dc/elements/1.1/
# schema.org properties
@prefix so: <http://www.schema.org/> .

";

# Get arrays of data from PEDATA files

$aCache = [];  # Cache of PEDATA objects to allow reuse of files
$aIssues = $aObit = $aDFiles = $aNewsItem = [];  # PEDATA Set arrays
$aNoMeta = $aNoSect = [];  # PEDATA Meta data and Section data are not required
# Get data for issues
if( !GetPedata( 'issues', $aCache, $aIssues, $aNoMeta, $aNoSect ) )
  echo GetPedataError() . "\n" ;
# Get data for obituaries
if( !GetPedata( 'obit', $aCache, $aObit, $aNoMeta, $aNoSect ) )
  echo GetPedataError() . "\n" ;
# Get data for data files
if( !GetPedata( 'datafiles', $aCache, $aDFiles, $aNoMeta, $aNoSect ) )
  echo GetPedataError() . "\n" ;
# Get data for news items
if( !GetPedata( 'newsitem', $aCache, $aNewsItem, $aNoMeta, $aNoSect ) )
  echo GetPedataError() . "\n" ;
FreePedataCache( $aCache );  # Finished with cached PEDATA files, run destructor for the objects
if( GetPedataError() != '' )
  echo "Error: Not all data sets are accessible, see previous error messages\n";

# Generate strings and arrays for further processing

# - Issues object list
$sIssues = "";
foreach($aIssues as $sIssueId=>$r)
  $sIssues .= " :i_" . $sIssueId;
# - Obituaries object list
$sObits = "";
$aObitRefs = [];  # Array for easier look up
foreach($aObit as $r) {
  $sObitId = $r['fn'] . $r['gn'][0];  # eg. "JenningsJ"
  $sObits .= " :o_" . $sObitId;
  foreach($r['ci'] as $v)   # Content Id values, eg. "022.01.002"
    $aObitRefs[$v] = $sObitId;
}
# - Data Files object list
$sFiles = "";
$aDataFiles = [];  # Array for easier look up
foreach($aDFiles as $sDataFileId=>$r) {
  $iSeq = 1;
  foreach( $r['f'] as $sFName=>$aFDesc ) {
    $sFileEntId = $sDataFileId . '.' . strval($iSeq++);  # Unique identifier for each file. eg. "038.01.007.D1.1"
    $sFiles .= " :d_" . $sFileEntId;
    $iBracketPos = strpos($aFDesc, ')');  # eg. "(342 Kb) The description"
    $sFSize = substr($aFDesc, 1, $iBracketPos-1 );  # "342 Kb"
    $sFDesc = substr($aFDesc, $iBracketPos+2 );     # "The description"
    $aDataFiles[$sFileEntId] = [ 'fname' => $sFName, 'fsize' => $sFSize, 'fdesc' => $sFDesc ];
  }
}
# - News Item object list
$sNewsItems = "";
foreach($aNewsItem as $iNewsItemId=>$r)
  $sNewsItems .= " :n_$iNewsItemId";  # eg. "ni_20150530"

# Generate the first triple, for Helictite Journal

echo ":Helictite a hs:HelictiteJournal ;
 dc:title \"Helictite, Journal of Australasian Spelelogical Research\";
 dc:alternative \"Helictite, Journal of Australasian Cave Research (1962-1993)\";
 dc:identifier <http://issn.org/resource/ISSN/0017-9973>;
 dc:publisher \"Australian Speleological Federation Inc.\", <https://www.caves.org.au/>;
 so:countryOfOrigin \"Australia\";
 dc:created \"1962\";
 dc:language \"en-au\";
 so:url <index.html>;
 dc:accrualPeriodicity \"Quarterly, Biannual or Annual\";
 dc:description \"\"\"Helictite publishes refereed papers, reports, abstracts, reviews and news of the
scientific study of caves and their contents, including the history of caves and technical aspects of
cave study and exploration. The main geographic focus is Australasia.\"\"\";
 dc:coverage \"\"\"Australasia geographic region, including Australia, New Zealand, New Guinea,
Malay Archipelago, Pacific Ocean, Indian Ocean and Antarctica.\"\"\";
 dc:rights \"As of 2000, all rights of ownership and copyright of Helictite Journal are held by Australian Speleological Federation Inc.\";
 dc:license \"\"\"Information in the Helicitite RDF data collection may only be published, copied or distributed
with written permission from The Secretary, Australian Speleological Federation Inc.\"\"\";
 dc:accessRights \"Free public access to read all issues and data\";
 hs:hasIssues ($sIssues );
 hs:hasObituaries ($sObits );
 hs:hasDataFiles ($sFiles );
 hs:hasNewsItems ($sNewsItems ) .

";

# Generate all other triples

GenIssues();
GenContents();
GenObituaries();
GenDataFiles();
GenNewsItems();

# End of generated RDF data

######## Functions ########

function GenIssues() {
  global $aIssues;
  # PDF directory names, eg. 'pdf4' 'pdf5'
  $sPrintDir = substr(SISSUEPRINTPDFDIR, strpos(SISSUEPRINTPDFDIR,'pdf'), 4);
  $sScreenDir = substr(SISSUESCREENPDFDIR, strpos(SISSUESCREENPDFDIR,'pdf'), 4);
  # Cover images directory name, eg. 'covers'
  $sCoversDir = substr(SCOVERIMAGESDIR, strpos(SCOVERIMAGESDIR,'cov'));

  echo "# Issue objects

";

  # Generate triples for all issues
  foreach($aIssues as $sIssueId=>$r) {  # Issue Id in format 'vvv.ii'
    $iVolNum = intval(substr($sIssueId,0,3));

    # Title
    switch( $r['i'] ) {  # Issue number, or none, or supplement, or combined issues eg. "1 & 2"
      case 'none':
        $sIssue = '';
        break;
      case 'supplement':
        $sIssue = ', Supplement';
        break;
      default:
        $sIssue = ", Issue " . $r['i'];
    }
    $sTitle = "Helicite, Volume " . $r['v'] . $sIssue . ", " . $r['y'];

    # List of publication dates
    $sPubDates = '';
    $aPub = str_getcsv( $r['pd'] );
    foreach($aPub as $v)
      $sPubDates .= ', "' . trim($v) . '"';

    # List of editors
    $sEditors = '';
    $aEd = str_getcsv( $r['eds'] );
    foreach($aEd as $v)
      $sEditors .= ', "' . trim($v) . '"';

    # Comment
    $sComment = $r['c'] ?? '';
    if( strlen($sComment)>0 )
      $sComment = " so:comment \"$sComment.\";
";

    # Determine volume group number
    $sVolGrp = substr($sIssueId,0,2);  # First 2 digits of 'vvv' Volume number
    if( $sVolGrp[0] == '0' )   # Strip leading zero
      $sVolGrp = $sIssueId[1];

    # Image of front cover of issue
    # JPG file name depends on volume group number and volume range
    # Based on code in contents_func.php
    switch( $sVolGrp ) {
      case '0':  # Volume group 0 only has small image
        if( $iVolNum < 4 ) {  # Cover image is the same for all issues in volume 1 - 3
          $sRepCoverImage = $sCoversDir . "001.01D.jpg";
        } else {  # Volume 4 to 9 only have small image
          $sRepCoverImage = $sCoversDir . $sIssueId . "D.jpg";
        } 
        break;

      case '1':  # 1 and 2 only have small image
      case '2':
        $sRepCoverImage = $sCoversDir . $sIssueId . "D.jpg";
        break;

      default:   # 3 and later have larger image
        $sRepCoverImage = $sCoversDir . $sIssueId . "C.jpg";
    }

    # PDF file name prefix
    $sIssPdfPrefix = "$sIssueId.Issue";
    if( $sIssPdfPrefix[0] == '0' )  # Strip leading zero
      $sIssPdfPrefix = substr($sIssPdfPrefix,1);

    # Print quality PDF
    $sRepPrint = '';
    $sPps = $r['pps'] ?? '';
    if( strlen($sPps)>0 )
      $sRepPrint = " hs:printPdfSizeK $sPps;
 hs:printPdfUrl <$sPrintDir/$sIssPdfPrefix.Print.pdf>;
";

    # Screen quality PDF
    $sRepScreen = '';
    $sSps = $r['sps'] ?? '';
    if( strlen($sSps)>0 )
      $sRepScreen = " hs:screenPdfSizeK $sSps;
 hs:screenPdfUrl <$sScreenDir/$sIssPdfPrefix.Screen.pdf>;
";

    # List of Content Ids
    $sContIds = '';
    foreach($r['itemids'] as $v)
      $sContIds .= ' :c_' . $sIssueId . '.' . $v;

    # Generate triple for an issue
    echo ":i_" . $sIssueId . " a hs:Issue;
 dc:title \"$sTitle\";
 hs:volumeNumber \"" . $r['v'] . "\";
 hs:issueNumber \"" . $r['i'] . "\";
 hs:publicationYear \"" . $r['y'] . "\";
 hs:publicationDates " . substr($sPubDates,2) . ";
 hs:editor " . substr($sEditors,2) . ";
 so:pageStart " . $r['pf'] . ";
 so:pageEnd " . $r['pl'] . ";
 hs:numberOfPages " . $r['np'] . ";
";
    if( strlen($sComment)>0 ) echo $sComment;
    echo " so:url <contents" . $sVolGrp . ".php#$sIssueId>;
 so:image <$sRepCoverImage>;
";
    if( strlen($sRepPrint)>0 )  echo $sRepPrint;
    if( strlen($sRepScreen)>0 ) echo $sRepScreen;
    echo " hs:hasContents ($sContIds ) .

";

  }
}

###########################

function GenContents() {
  global $aDataFiles, $aObitRefs; 
  # PDF directory names, eg. 'pdf1' 'pdf2'
  $sPrintDir = substr(SARTICLEPRINTPDFDIR, strpos(SARTICLEPRINTPDFDIR,'pdf'), 4);
  $sScreenDir = substr(SARTICLESCREENPDFDIR, strpos(SARTICLESCREENPDFDIR,'pdf'), 4);
  $aSubEntLookup = [];

  echo "# Content objects

";

  # Get volume groups data
  $aVolGroup = []; $aNoCache = $aNoMetaData = $aNoSectData = null;
  if( !GetPedata( 'volgroup', $aNoCache, $aVolGroup, $aNoMetaData, $aNoSectData ) ) {
    echo GetPedataError() . "\n";
    return;
  }
  $iVolGroupLast = count($aVolGroup) - 1;
  if( $iVolGroupLast < 0 ) {
    echo "Error: Invalid VolGroupLast=$iVolGroupLast\n";
    return;
  }

  # Process all volume groups
  for( $iVolGrp = $iVolGroupLast ; $iVolGrp >= 0 ; $iVolGrp-- ) {

    # Get data for contents of the volume group
    $aContentsData = [];
    if( !GetPedata( 'contents*', $aNoCache, $aContentsData, $aNoMetaData, $aNoSectData, $iVolGrp ) ) {
      echo GetPedataError() . "\n";
      return;
    }

    # Generate triples for all contents in a volume group
    foreach($aContentsData as $sContId=>$r) {  # Helictite contents id is in format 'vvv.ii.ppp.x'

      # List of authors
      if( isset($r['authors']) ) {
        $sAuthors = '';
        $aAuth = str_getcsv( $r['authors'], ';' );
        foreach($aAuth as $v) $sAuthors .= ', "' . trim($v) . '"';
      }

      # Helictite reference
      if( isset($r['helref']) ) {
        $sHelRef = $r['helref'];
      } else {  # Reformat vvv.ii.ppp to v(i):p
        $aHelRef = str_getcsv( $sContId, '.' );
        switch( $aHelRef[1] ) {
          case '00': $sIssRep = ''; break;
          case '12': $sIssRep = '(1&2)'; break;
          case 'SU': $sIssRep = '(Supplement)'; break;
          default: $sIssRep = '(' . ltrim($aHelRef[1], '0') . ')';
        }
        $sHelRef = ltrim($aHelRef[0], '0') . $sIssRep  . ':' . ltrim($aHelRef[2], '0');
      }

      # List of includes
      if( isset($r['includes']) ) {
        $sIncludes = '';
        # Handle includes like "11 figures (1 map, 10 images), 26 refs
        $sInc = str_replace( ['(',')'], [',',''], $r['includes'] );
        $aInc = str_getcsv($sInc);
        foreach($aInc as $v)
          if( !is_null($v) )
            $sIncludes .= ', "' . trim($v) . '"';
      }

      # List of keywords
      if( isset($r['keywords']) ) {
        $sKeyWords = '';
        $aKey = str_getcsv( $r['keywords'] );
        foreach($aKey as $v)
          if( !is_null($v) )
            $sKeyWords .= ', "' . trim($v) . '"';
      }

      # Print quality PDF
      if( isset($r['pps']) )
        $sPrintPdf = " hs:printPdfSizeK " . $r['pps'] . ";
 hs:printPdfUrl <$sPrintDir/" . $r['pdfname'] . "2.pdf>;
";

      # Screen quality PDF
      if( isset($r['sps']) )
        $sScreenPdf = " hs:screenPdfSizeK " . $r['sps'] . ";
 hs:screenPdfUrl <$sScreenDir/" . $r['pdfname'] . ".pdf>;
";

      # Obituary
      $sRepObit = '';
      if( array_key_exists($sContId, $aObitRefs) )
        $sRepObit = " hs:hasObituary :o_" . $aObitRefs[$sContId] . ";
";

      # Sub entries
      if( isset($r['subents']) ) {
        $sIssueId = substr($sContId,0,7);  # Issue Id in format 'vvv.ii.'
        $sEnts = '';
        foreach($r['subents'] as $v) {
          $sEnts .= ' :c_' . $sIssueId . $v;
          $aSubEntLookup[ $sIssueId . $v ] = $sContId;  # Add to a lookup array
        }
      }

      # List of data files
      $sRepDataFiles = '';
      for( $iFIdx = 1 ; ; $iFIdx++ ) {
        $sDIdx = $sContId . '.D1.' . strval($iFIdx);  # Data file Id, eg.'035.01.015.D1.1'
        if( ! array_key_exists($sDIdx, $aDataFiles) ) break;
        $sRepDataFiles .= ' :d_' . $sDIdx;
      }

      # Generate triple for a contents entry
      echo ":c_$sContId a hs:Content;
 dc:title \"" . $r['title'] . "\";
";
      if( isset($r['authors']) )  echo " hs:author " . substr($sAuthors,2) . ";
";
      if( isset($r['yearpub']) )  echo " hs:publicationDate \"" . $r['yearpub'] . "\";
";
      echo " hs:helRef \"$sHelRef\";
";
      if( isset($r['includes']) ) echo " hs:includes " . substr($sIncludes,2) . ";
";
      if( isset($r['keywords']) ) echo " so:keywords " . substr($sKeyWords,2) . ";
";
      if( isset($r['pps']) )      echo $sPrintPdf;
      if( isset($r['sps']) )      echo $sScreenPdf;
      # Content is either subordinate content of another content, or is content of an issue 
      if( array_key_exists($sContId, $aSubEntLookup) ) {
        echo " hs:isInContent :c_" . $aSubEntLookup[$sContId] . ";
";
      } else {  
        echo " hs:isInIssue :i_" . substr($sContId,0,5) . ";
";
      }
      # Content has subordinate content items
      if( isset($r['subents']) )  echo " hs:hasSubContents ($sEnts );
";
      # The Abstract text and Abstractors are in separate Turtle document abstracts_rdf.php
      if( isset($r['abstract']) ) echo " hs:hasAbstract abst:a_$sContId;
";

      if( strlen($sRepDataFiles)>0 ) echo " hs:hasDataFiles ($sRepDataFiles );
";
      if( strlen($sRepObit)>0 )  echo $sRepObit;

      # End of triple
      echo " .

";

    }
  }
}

###########################

function GenObituaries() {
  global $aObit;

  echo "# Obituary objects

";

  # Generate triples for all obituaries
  foreach($aObit as $v) {
    # Lists of Helictite references and contents ids
    $sHelRefs = '';
    $sContIds = '';
    $aHelRefs = $v['hr'];
    $aContentsIds = $v['ci'];
    foreach($aHelRefs as $sIdx=>$t) {
      $sHelRefs .= ' "' . trim($t) . '"';
      $sContIds .= " :c_" . trim($aContentsIds[$sIdx]);
    }

    # Comment
    if( isset($v['c']) )
      $sComment = " so:comment \"" . $v['c'] . "\";
";

    # Generate triple for an obituary
    echo ":o_" . $v['fn'] . $v['gn'][0] . " a hs:Obituary;
 so:givenName \"" . $v['gn'] . "\";
 so:familyName \"" . $v['fn']. "\";
 hs:yearsLived \"" . $v['yl'] . "\";
 hs:yearPublished \"" . $v['yp'] . "\";
";
    if( isset($v['c']) ) echo $sComment;
    echo " hs:obitAuthor \"" . $v['a'] . "\";
";
    echo " hs:helRefs ($sHelRefs );
 hs:isInContents ($sContIds ) .

";
  }
}

###########################

function GenDataFiles() {
  global $aDataFiles;

  echo "# DataFile objects

";

  # Generate triples for all data files
  foreach($aDataFiles as $n=>$v) {
    # Generate triple for a data file
    echo ":d_" . $n . " a hs:DataFile;
 dc:description \"" . $v['fdesc'] . "\";
 hs:fileSize \"" . $v['fsize']. "\";
 so:url <data/" . $v['fname'] . ">;
 hs:isInContent c_" . substr($n,0,9) . " .

";
  }
}

###########################

function GenNewsItems() {
  global $aNewsItem;

  echo "# NewsItem objects

";

  # Generate triples for all news items
  foreach($aNewsItem as $iNewsItemId=>$v) {
    # Generate triple for a news item
    echo ":n_$iNewsItemId a hs:NewsItem;
 hs:displayDate \"" . $v['d'] . "\";
 so:author \"" . $v['a']. "\";
 dc:text \"\"\"" . $v['n'] . "\"\"\";
 hs:visibility \"" . ($v['v'] ? 'yes' : 'no') . "\" . 

";
  }
}