package DBFOschemafy_V_3_001;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;

/**
 *  <b>Environment:</b> 
 *  <ul>
 *  <li>    IDE:              Eclipse IDE for Java Developers
 *  <li>    Version:          2021-12 (4.22.0)
 *  <li>    Build id:         20211202-1639
 *  <li>    HW Model Name:    iMac, MacOS Monterey, 12.5.1
 *  <li>    Processor Name:   Quad-Core Intel Core i5
 *  <li>    Processor Speed:  3.2 GHz
 *  <li>    Memory:           32 GB 1867 MHz DDR3
 *  <li>    Disk:             APPLE SSD SM0256G    
 *  <li>    Serial:           DGKRC080GG7V
 *  <li>    RDB:              MySQL Server (Version 8.0.30), 
 *  <li>    Workbench:        MySQL Workbench (Version 8.0.31 build 2235049 CE (64 bits) Community)
 *  <li>    JDBC connector:   mysql-connector-j-9.1.0.jar
 *  </ul>
 *  @version 1-001
 *  @since   2024/11/27
 *  @author  Edit Hlaszny PhD (https://www.edithlaszny.eu/) 
 */

public class WriteTriplets 
{
    private Connection  DBconnection       = null ;
    private int         countOfDatProps    = 0 ;
    private int         countOfDatPropRefs = 0 ;
    private DButils     dbu                = null ; 
    private FileWriter  fileWriter         = null ;
    private SharedUtils shu                = null ;
    private int         triplet_id         = 0 ;
    
    WriteTriplets(String      OWLresultFile,  //  result file name 
                  Connection  DBconnection    //  active DB connection
                 )
    {
        int  countOfTriplets = 0 ;
        this.DBconnection    = DBconnection ;
        this.dbu             = new DButils() ;
        this.shu             = new SharedUtils() ;
        
        /*
         *  Set each 'already_declared of OWL_OBJECT_PROPERTIES' and
         *      each 'already_declared of OWL_DATA_PROPERTIES' flags to false 
         */
        dbu.resetAllDBflags(DBconnection) ;
        
        ResultSet rs = dbu.establishResultSet(DBconnection, 
                       "SELECT triplet_id FROM TRIPLETS ORDER BY triplet_id ;") ;

        /*
         *   processing NOT BY predicate_IRI, but by this.triplet_id !
         */
        try 
        {
            this.fileWriter = new FileWriter(new File(OWLresultFile), true) ;

            /**
             *  The predicates (= Object Properties) can previously be generated
             */
            new WT_ProcessPredicates(OWLresultFile,  //  result file name 
                                     DBconnection    //  active DB connection
                                    ) ;
            while (rs.next()) 
            {
                this.triplet_id = rs.getInt("triplet_id") ;
                
                StringBuilder dataPropertyXMLcode = new StringBuilder().append("") ;  

                dataPropertyXMLcode.append(genSubjectDataPropArgs())
                                   .append(genObjectDataPropArgs()) ;

                this.fileWriter.write(dataPropertyXMLcode.toString()) ;
                
                this.fileWriter.write(produceTriplet()) ;
                
                countOfTriplets++ ;
            }
            
            this.fileWriter.flush() ;
            this.fileWriter.close() ;
            
            /**
             *  closing the result set
             */
            rs.close() ;
        }
        catch(SQLException SQLex)
        {
            System.out.println("Cannot select from the database") ;
            System.out.println("SQLException: " + SQLex.getMessage());
            System.out.println("SQLState: "     + SQLex.getSQLState());
            System.out.println("VendorError: "  + SQLex.getErrorCode());

            SQLex.printStackTrace();
        }
        catch(IOException IOex)
        {
            IOex.printStackTrace() ;
        }

        /**
         *  Logging of the output volume
         */
        new DBFOschemafyMain().log(new StringBuilder()
                              .append("    added     " + countOfTriplets    + " triplet(s)\n")
                              .append("    added     " + countOfDatProps    + " data properties(s)\n")
                              .append("    added     " + countOfDatPropRefs + " data property reference(s)\n")
                              .toString()
                                  ) ; 
        
    }   //  end of constructor()

    private String connectObjectAndDataProperties(String subjectIndividual,
                                                  String objectIndividual
                                                 )
    {
        StringBuilder result = new StringBuilder().append("") ;
        
        /**
         *  testing whether subject's data property does exist
         */
        String dataProperty = dbu.getSubjectDataProperty(this.DBconnection, this.triplet_id) ; 
        if (dataProperty.length() > 0)
        {    
            /**
             *  if subject's data property does exist, is must be generated
             */
            result.append(shu.assertDataProperty(dataProperty,
                              subjectIndividual,
                              dbu.getSubjectDataPropertyType(DBconnection, this.triplet_id),
                              dbu.getSubjectDataPropertyValue(DBconnection, this.triplet_id)
                                                ) ) ;
            countOfDatPropRefs++ ;
        }

        /**
         *  testing whether object's data property does exist
         */
        dataProperty = dbu.getObjectDataProperty(this.DBconnection, this.triplet_id) ; 
        if (dataProperty.length() > 0)
        {    
            /**
             *  if object's data property does exist, is must be generated
             */
            result.append(shu.assertDataProperty(dataProperty,
                              objectIndividual,
                              dbu.getObjectDataPropertyType(DBconnection, this.triplet_id),
                              dbu.getObjectDataPropertyValue(DBconnection, this.triplet_id)
                                                ) ) ;
            countOfDatPropRefs++ ;
        }
        
        return result.toString() ;
        
    }   //  end of method connectObjectAndDataProperties()
        
    private String genDataPropArgs(String dataProperty,
                                   String superDataProperty 
                                  )
    {
        StringBuilder result = new StringBuilder().append("") ;

        /**
         *  declare data property
         */
        result.append(this.shu.declareDataProperty(dataProperty)) ;  
        
        /**
         *  declare super data property
         */
        result.append(this.shu.declareDataSubProperty(dataProperty, superDataProperty)) ;
       
        if (dbu.isDataPropertyAnnotated(this.DBconnection, dataProperty))
        {
            String annotation         = dbu.getDataPropertyAnnotation        (this.DBconnection, dataProperty) ;
            String annotationType     = dbu.getDataPropertyAnnotationType    (this.DBconnection, dataProperty) ;
            String annotationLanguage = dbu.getDataPropertyAnnotationLanguage(this.DBconnection, dataProperty) ; 

            /**
             *  append data property annotations
             */
            result.append(this.shu.annotateDataProperty(dataProperty,
                                                        annotation,
                                                        annotationType,
                                                        annotationLanguage
                                                       )) ;
        }
       
        return result.toString() ;  
       
    }   //  end of genDataPropArgs()

    private String genSubjectDataPropArgs() 
    {
        StringBuilder result = new StringBuilder().append("") ;

        String dataProperty = dbu.getSubjectDataProperty(this.DBconnection, this.triplet_id) ; 
        if (dataProperty.length() > 0)
        {    
            /*
             *  Subject's Data Property is present: it must be connected.
             *  To avoid multiple data property declarations...
             */
            if (dbu.isDatapropertyUnprocessed(DBconnection, dataProperty))
            {
                this.countOfDatProps++ ;
  
                dbu.setDataPropertyProcessed(DBconnection, dataProperty) ;
                
                String superDataProperty = dbu.getSubjectSuperDataProperty(this.DBconnection, this.triplet_id) ;
                result.append(genDataPropArgs(dataProperty, superDataProperty)) ;
            }
        }
        
        return result.toString() ;  
        
    }   //  end of method genSubjectDataPropArgs() 
    
    private String genObjectDataPropArgs() 
    {
        StringBuilder result = new StringBuilder().append("") ;

        String dataProperty =  dbu.getObjectDataProperty(this.DBconnection, this.triplet_id) ; 
       
        if (dataProperty.length() > 0)
        {    
            /*
             *  Subject's Data Property is present: it must be connected.
             *  To avoid multiple data property declarations...
             */
            if (dbu.isDatapropertyUnprocessed(DBconnection, dataProperty))

            {
                this.countOfDatProps++ ;
                
                dbu.setDataPropertyProcessed(DBconnection, dataProperty) ;

                String superDataProperty = dbu.getObjectSuperDataProperty(this.DBconnection, this.triplet_id) ;
                result.append(genDataPropArgs(dataProperty, superDataProperty)) ;
            }
        }
        
        return result.toString() ;  
        
    }   //  end of genObjectDataPropArgs()

    private String produceTriplet()
    {
        String subjectClass         = this.dbu.getSubjectIRI(           this.DBconnection, this.triplet_id) ;
        String subjectIndividual    = this.dbu.produceSubjectIndividual(this.DBconnection, this.triplet_id) ;
        String objectClass          = this.dbu.getObjectIRI(            this.DBconnection, this.triplet_id) ;
        String objectIndividual     = this.dbu.produceObjectIndividual( this.DBconnection, this.triplet_id) ;
        String individualAnnotation = this.dbu.produceTripletAnnotation(this.DBconnection, this.triplet_id) ;
        String objectProperty       = this.dbu.getPredicateIRI(         this.DBconnection, this.triplet_id) ;
        
        StringBuilder result = new StringBuilder() ;
        
        result.append(shu.declareIndividual(subjectIndividual))
              .append(shu.assertIndividual(subjectClass, subjectIndividual))
              .append(shu.classAssertion(subjectIndividual, individualAnnotation))
              
              .append(shu.declareIndividual(objectIndividual))
              .append(shu.assertIndividual(objectClass, objectIndividual))
              .append(shu.classAssertion(objectIndividual, individualAnnotation))
              
              .append(shu.assertObjectProperty(objectProperty,
                                               subjectIndividual,
                                               objectIndividual)) ;
        /**
         *   Checking the subject/object data properties, and connects them to the individuals
         */
        result.append(connectObjectAndDataProperties(subjectIndividual, objectIndividual)) ;
        
        String inverseObjectProperty = dbu.getInversePredicate(this.DBconnection, this.triplet_id) ;
        
        /**  
         *  checking is there inverse object property
         */
        if (inverseObjectProperty.length() > 0)
        {
            result.append(shu.assertObjectProperty(inverseObjectProperty,
                                                   objectIndividual,
                                                   subjectIndividual)) ;
        }
        
        return result.toString() ;
        
    }   //  end of method produceTriplet()
   
}   //  end of class WriteOWLTrailer
 