package OWL2generator;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.ListIterator;

/**
 *  <b><code>SharedUtils</code></b> class offers a collection of utility methods 
 *  for OWL/XML ontology generation within the framework. It doesn't directly
 *  belong to any specific class but functions as a helper.
 *  <code>SharedUtils</code> acts as a utility class, providing reusable
 *  functionalities for building the OWL ontology structure. It
 *  helps in creating declarations for classes, individuals, properties,
 *  and their relationships within the ontology based on text file
 *  configurations.
 *  <p>
 *  <b>Key Functionalities</b>:
 *  <p>
 *  Generates OWL code snippets for various ontology elements:
 *  <p>
 *  <ul>
 *  <li>Classes (<code>declareClass</code>, <code>declareSubClass</code>)
 *  <li>Individuals (<code>genIndividual</code>) with their declarations, class
 *  assertions, and annotations
 *  <li>Object properties (<code>genObjPropDecl</code>) with potential
 *  super-properties and annotations
 *  <li>Sub-object property relationships (<code>genSubObjProp</code>)
 *  <li>Inverse object properties (<code>genInverseObjProps</code>)
 *  <li>OWL class individual triplets (<code>genTriplet</code>)
 *  </ul>
 *  <p>
 *  Formats class names with a project-wide IRI prefix (<code>formatClassName</code>)
 *  <p>
 *  Generates annotation assertions (<code>genAnnotationAssertion</code>)
 *  <p>
 *  Defines constants like <code>IRI</code> (Internationalized Resource Identifier)
 *  <p>
 *  <b>Additional Notes</b>:
 *  <p>
 *  The class utilizes a constant IRI (Internationalized Resource Identifier)
 *  to serve as a prefix for all identifiers within the generated ontology.
 *  <p>
 *  A boolean flag <code>GENERATE_HEADER</code> controls whether comments are included in
 *  the generated XML for better human readability during development
 *  (currently disabled).
 *  <p>
 *  Some methods (like <code>genObjPropDomainAndRange</code>) are currently not used,
 *  suggesting potential future extensibility for associating domain and
 *  range OWL classes with object properties.
 *  <p>
 *  <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
 *  </ul>
 *  @version 1-001
 *  @since   2024/05/24
 *  @author  Edit Hlaszny (https://www.edithlaszny.eu/ edithlaszny@gmail.com)
 */

public class SharedUtils 
{
    /**
	 *  W3C-defined separator between IRI and unique variable name
	 */
    private final String  SEPARATOR = "#" ;

    SharedUtils()
    {
        ; 
        
    }   //  end of constructor()

    public String getCurrTime() 
    {
    	String format = "yyyy-MM-dd HH:mm:ss.SSS" ;
    	return new SimpleDateFormat(format).format(new Date()) ;
    	
    }   //  end of method getCurrTime()
    
    
    public String assertClassAnnotation(String class_IRI,
                                        String annotation_type_IRI,
                                        String language,
                                        String annotation
                                       )
    {
        return  "    <AnnotationAssertion>\n" +
                "        <AnnotationProperty abbreviatedIRI=\"" + annotation_type_IRI  + "\"/>\n" +
                "        <IRI>" + this.SEPARATOR + class_IRI + "</IRI>\n" +
                "        <Literal xml:lang=\"" + language + "\">" + annotation + "</Literal>\n" +
                "    </AnnotationAssertion>\n" ;
        
    }   //  end of method assertClassAnnotation()

    
    /**
     *  Declares OWL subclass according to OWL2 XML Syntax
     *  
     *  @param superClass Name of the OWL superclass
     *  @param subClass Name of the OWL subclass
     *  
     *  @return XML code snippet     
     */
    public String declareSubClass(String superClass, 
                                  String subClass
                                 ) 
    {
        /**
         *  compensating the Protege's displaying error
         */
        if (superClass.equals("owl:Thing")) 
        {
        	/*
        	System.out.println("    Superclass (" + superClass + ") is \"owl:Thing\" at Sociology" +
        	                   "  - NOT GENERATED...");
        	 */
            return "" ;
        }
        
        return "    <SubClassOf>\n" +
               "        <Class IRI=\"" + SEPARATOR + subClass   + "\"/>\n" +
               "        <Class IRI=\"" + SEPARATOR + superClass + "\"/>\n" +
               "    </SubClassOf>\n" ;
        
    }   //  end of method declareSubClass()
    
    
    /**
     *  Declares BFO subclass according to OWL2 XML Syntax
     *  
     *  @param superClass Name of the OWL superclass
     *  @param subClass Name of the OWL subclass
     *  
     *  @return XML code snippet     
     */
    public String declareBFOsubClass(String superClass, 
                                     String subClass
                                    ) 
    {
        /**
         *  compensating the Protege's displaying error
         */
        if (superClass.equals("owl:Thing")) 
        {
        	/*
        	System.out.println("    Superclass (" + superClass + ") is \"owl:Thing\" at BFO" +
        	                   "  - NOT GENERATED...");
        	 */
            return "" ;
        }
        
        return "    <SubClassOf>\n" +
               "        <Class IRI=\"" + SEPARATOR + subClass   + "\"/>\n" +
               "        <Class abbreviatedIRI=\"bfo:" + superClass + "\"/>\n" +
               "    </SubClassOf>\n" ;
        
    }   //  end of method declareBFOsubClass()
    
    
    
    public String declareClass(String class_IRI)
    {
        return  "    <Declaration>\n" +
                "        <Class IRI=\"" + SEPARATOR + class_IRI + "\"/>\n" +
                "    </Declaration>\n" ;

    }   //  end of method declareClass()
    
    public String addHdrAnnotation(String iri,
                                   String literal
                                  )
    {
        return "    <Annotation>\n" +
               "        <AnnotationProperty abbreviatedIRI=\"" + iri + "\"/>\n" +
               "        <Literal>" + literal + "</Literal>\n" +
               "    </Annotation>\n" ;
               
    }   //  end of addHdrAnnotation()
        
    public String declareIAOannotation(String abbreviated_IRI)
    {
        return  "    <Declaration>\n" +
                "        <AnnotationProperty abbreviatedIRI=\"" + abbreviated_IRI + "\"/>\n" +
                "    </Declaration>\n" ;

    }   //  end of method declareIAOannotation()
    
    public String addSKOSannotation(String skos_annotation)
    {
        return  "    <Declaration>\n" +
                "        <AnnotationProperty abbreviatedIRI=\"" + skos_annotation + "\"/>\n" +
                "    </Declaration>\n" ;
        
    }   //  end of method addIAOannotation()

    public String declareObjectproperty(String objectProperty)
    {
         return
         "    <Declaration>\n" +
         "        <ObjectProperty IRI=\"" + this.SEPARATOR + objectProperty + "\"/>\n" +
         "    </Declaration>\n" ;

    }   //  end of method declareObjectproperty()
    
    public String setSubObjectPropertyOf(String objectProperty,
                                         String superObjectProperty
                                        )
    {
        if (superObjectProperty.equals("owl:topObjectProperty") == false)
        {
            /**
             *  if the superObjectProperty is NOT the 'owl:topObjectProperty' than
             *  must be prefixed with the SEPARATOR
             */
            superObjectProperty = this.SEPARATOR + superObjectProperty ;
        }
        
        return
        "    <SubObjectPropertyOf>\n" +
        "        <ObjectProperty IRI=\"" + this.SEPARATOR + objectProperty + "\"/>\n" +
        "        <ObjectProperty abbreviatedIRI=\"" +  superObjectProperty + "\"/>\n" +
        "    </SubObjectPropertyOf>\n" ;

    }   //  end of method setSubObjectPropertyOf()
    
    public String annotateObjectProperty(String object_property_IRI,
                                         String annotation_type_IRI,
                                         String language           ,
                                         String annotation
                                        )
    {
        return
        "    <AnnotationAssertion>\n" +
        "        <AnnotationProperty abbreviatedIRI=\"" + annotation_type_IRI + "\"/>\n" +
        "        <IRI>" + this.SEPARATOR + object_property_IRI + "</IRI>\n" +
        "        <Literal xml:lang=\"" + language + "\">\"" + annotation + "\"\n" +
        "        </Literal>\n" +
        "    </AnnotationAssertion>\n" ;
            
    }   //  end of method annotateObjectProperty() 
    
    public String setInverseObjectProperties(String objProp_IRI_1,
                                             String objProp_IRI_2
                                            )
    {
        return
        "    <InverseObjectProperties>\n" + 
        "        <ObjectProperty IRI=\"" + this.SEPARATOR + objProp_IRI_1 + "\"/>\n" +
        "        <ObjectProperty IRI=\"" + this.SEPARATOR + objProp_IRI_2 + "\"/>\n" +
        "    </InverseObjectProperties>" ;
        
    }   //  end of method setInverseObjectProperties()

    public String declareIndividual(String namedIndividual)
    {
        return
        "    <Declaration>\n" +
        "        <NamedIndividual IRI=\"" + this.SEPARATOR + namedIndividual + "\"/>\n" +
        "    </Declaration>\n" ;

    }   // end of method declareIndividual()

    public String assertIndividual(String classIRI,
                                   String namedIndividual)
    {
        return
        "    <ClassAssertion>\n" +
        "        <Class IRI=\"" + this.SEPARATOR + classIRI + "\"/>\n" +
        "        <NamedIndividual IRI=\"" + this.SEPARATOR + namedIndividual + "\"/>\n" +
        "    </ClassAssertion>\n" ;

    }   // end of method assertIndividual()

    public String classAssertion(String namedIndividual,
                                 String annotation)
    {
        return 
        "    <AnnotationAssertion>\n" +
        "        <AnnotationProperty abbreviatedIRI=\"obo:IAO_0000115\"/>\n" +
        "        <IRI>" + this.SEPARATOR + namedIndividual + "</IRI>\n" +
        "        <Literal>" + annotation + "</Literal>\n" +
        "    </AnnotationAssertion>\n" ;

    }   // end of method classAssertion()

    public String assertObjectProperty(String objectProperty,
                                       String subjectIndividual,
                                       String objectIndividual)
    {
        // 2x if inverse obj prop does exist !
        
        return 
        "    <ObjectPropertyAssertion>\n" +
        "        <ObjectProperty  IRI=\"" + this.SEPARATOR + objectProperty + "\"/>\n" +     
        "        <NamedIndividual IRI=\"" + this.SEPARATOR + subjectIndividual + "\"/>\n" +  
        "        <NamedIndividual IRI=\"" + this.SEPARATOR + objectIndividual + "\"/>\n" +   
        "    </ObjectPropertyAssertion>\n" ;

    }   // end of method assertObjectProperty()

    public String declareDataProperty(String dataProperty)
    {
        return
        "    <Declaration>\n" +
        "        <DataProperty IRI=\"" + this.SEPARATOR + dataProperty + "\"/>\n" +
        "    </Declaration>\n" ;

    }   // end of method declareDataProperty()

    public String declareDataSubProperty(String dataProperty,
                                         String superDataProperty
                                        )
    {
        return
        "    <SubDataPropertyOf>\n" +
        "        <DataProperty IRI=\"" + this.SEPARATOR + dataProperty + "\"/>\n" +
        "        <DataProperty abbreviatedIRI=\"" + superDataProperty + "\"/>\n" +
        "    </SubDataPropertyOf>\n" ;

    }   // end of method declareDataSubProperty()

    public String annotateDataProperty(String dataProperty,
                                       String annotation,
                                       String annotationType,
                                       String language
                                      )
    {
        return
        "    <AnnotationAssertion>\n" +
        "        <AnnotationProperty abbreviatedIRI=\"" + annotationType + "\"/>\n" +
        "        <IRI>" + this.SEPARATOR + dataProperty + "</IRI>\n" +
        "        <Literal xml:lang=\"" + language + "\">" + annotation + "</Literal>\n" +
        "    </AnnotationAssertion>\n" ;

    }   // end of method annotateDataProperty()

    public String assertDataProperty(String dataProperty,
                                     String namedIndividual,
                                     String dataType,
                                     String dataValue
                                    )
    {   //  call it AFTER a triplet definition !

        return
        "    <DataPropertyAssertion>\n" +
        "        <DataProperty IRI=\"" + this.SEPARATOR + dataProperty + "\"/>\n" +
        "        <NamedIndividual IRI=\"" + this.SEPARATOR + namedIndividual + "\"/>\n" +
        "        <Literal datatypeIRI=\"" + dataType + "\">" + dataValue + "</Literal>\n" +
        "    </DataPropertyAssertion>\n" ;

    }   // end of method assertDataProperty()

    //  ------------------------- object property handling methods ------------------------
    
    public String declareObjectPropertyData(TypeOf_ObjectProperty op)
    {
        String OWLcommand = 
        	"\n    <!-- object property def >" + op.object_property_IRI + "<\n      -->\n" +
            "    <Declaration>\n" +
            "        <ObjectProperty IRI=\"#" + op.object_property_IRI + "\"/>\n" +
            "    </Declaration>\n" +

            "    <AnnotationAssertion>\n" +
            "        <AnnotationProperty abbreviatedIRI=\"skos:definition\"/>\n" +
            "        <IRI>#" + op.object_property_IRI + "</IRI>\n" +
            "        <Literal xml:lang=\"en\">\"" + op.annotation + "\"\n" +
            "        </Literal>\n" +
            "    </AnnotationAssertion>\n" +

            "    <InverseObjectProperties>\n" +
            "        <ObjectProperty IRI=\"#" + op.object_property_IRI + "\"/>\n" +
            "        <ObjectProperty IRI=\"#" + op.inverse_object_property_IRI + "\"/>\n" +
            "    </InverseObjectProperties>\n" ;

      	String supObjProp_IRI = op.super_object_property_IRI ; 
        	
     	//  # prefix is conditional
       	if (supObjProp_IRI.compareTo("owl:topObjectProperty") != 0)
       		supObjProp_IRI = "#" + supObjProp_IRI ;        		
        	
        OWLcommand +=
            "    <SubObjectPropertyOf>\n" +
            "        <ObjectProperty IRI=\"#" + op.object_property_IRI + "\"/>\n" +
            "        <ObjectProperty abbreviatedIRI=\"" + supObjProp_IRI + "\"/>\n" +
            "    </SubObjectPropertyOf>\n" ;

        if (op.opc.ch_functional        )
        {
            OWLcommand +=
                "    <FunctionalObjectProperty>\n" +
                "        <ObjectProperty IRI=\"#" + op.object_property_IRI + "\"/>\n" +
                "    </FunctionalObjectProperty>\n" ;
        }
        if (op.opc.ch_inverseFunctional )
        {
            OWLcommand +=
                "    <InverseFunctionalObjectProperty>\n" +
                "        <ObjectProperty IRI=\"#" + op.object_property_IRI + "\"/>\n" +
                "    </InverseFunctionalObjectProperty>\n" ;
        }
        if (op.opc.ch_symmetric         )
        {
            OWLcommand +=
                "    <SymmetricObjectProperty>\n" +
                "        <ObjectProperty IRI=\"#" + op.object_property_IRI + "\"/>\n" +
                "    </SymmetricObjectProperty>\n" ;
        }
        if (op.opc.ch_asymmetric        )
        {
            OWLcommand +=
                "    <AsymmetricObjectProperty>\n" +
                "        <ObjectProperty IRI=\"#" + op.object_property_IRI + "\"/>\n" +
                "    </AsymmetricObjectProperty>\n" ;
        }
        if (op.opc.ch_transitive        )
        {
            OWLcommand +=
                "    <TransitiveObjectProperty>\n" +
                "        <ObjectProperty IRI=\"#" + op.object_property_IRI + "\"/>\n" +
                "    </TransitiveObjectProperty>\n" ;
        }
        if (op.opc.ch_transitive        )
        {
            OWLcommand +=
                "    <ReflexiveObjectProperty>\n" +
                "        <ObjectProperty IRI=\"#" + op.object_property_IRI + "\"/>\n" +
                "    </ReflexiveObjectProperty>\n" ;
        }
        if (op.opc.ch_irReflexive       )
        {
            OWLcommand +=
                "    <IrreflexiveObjectProperty>\n" +
                "        <ObjectProperty IRI=\"#" + op.object_property_IRI + "\"/>\n" +
                "    </IrreflexiveObjectProperty>\n" ;
        }
        
        return OWLcommand ;

        /**  triplet defs

            <ObjectPropertyAssertion>
                <ObjectProperty IRI="#documentUsedAt"/>
                <NamedIndividual IRI="#backlog_ID00001"/>
                <NamedIndividual IRI="#subsequentStage_ID00001"/>
            </ObjectPropertyAssertion>
            <ObjectPropertyAssertion>
                <ObjectProperty IRI="#documentUsedAt"/>
                <NamedIndividual IRI="#baselinePlan_ID00001"/>
                <NamedIndividual IRI="#initiationStage_ID00001"/>
            </ObjectPropertyAssertion>
        **/

    }   //  end of method declareObjectPropertyData()


    //  ------------------------- data property handling methods --------------------------
    
    public String declareDataPropertyData(TypeOf_DataProperty dp)
    {
        String OWLcommand = 
        "\n    <!-- data property def >" + dp.data_property_IRI + "<\n      -->\n" +

        "    <Declaration>" + "\n" +
        "        <DataProperty IRI=\"#" +  dp.data_property_IRI + "\"/>" + "\n" +
        "    </Declaration>" + "\n" +
        
        "    <SubDataPropertyOf>" + "\n" +
        "        <DataProperty IRI=\"#" +  dp.data_property_IRI + "\"/>" + "\n" +
        "        <DataProperty abbreviatedIRI=\"" + dp.super_data_property_IRI + "\"/>" + "\n" +
        "    </SubDataPropertyOf>" + "\n" +
        
        "    <AnnotationAssertion>" + "\n" +
        "        <AnnotationProperty abbreviatedIRI=\"skos:definition\"/>" + "\n" +
        "        <IRI>#" + dp.data_property_IRI + "</IRI>" + "\n" +
        "        <Literal xml:lang=\"en\">\"" + dp.data_property_annotationtype + "\"</Literal>" + "\n" +
        "    </AnnotationAssertion>" + "\n" +
        
        "    <DataPropertyRange>" + "\n" +
        "        <DataProperty IRI=\"#" +  dp.data_property_IRI + "\"/>" + "\n" +
        "        <Datatype abbreviatedIRI=\"" + dp.data_property_type + "\"/>" + "\n" +
        "    </DataPropertyRange>" + "\n" ;

        return OWLcommand ;
        
    }   //  end of method declareDataPropertyData()
    
    public void dsplyFatalMsgAndExit(String msg, int exitCode)
    {
        System.err.println(msg) ;
        System.exit(exitCode);
    
    }   //  end of method dsplyFatalMsgAndExit()
    
}   //  end of class SharedUtils
