package OWL2generator;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.*; 

/**
 *  The <b><code>WriteDisjointClassDefs</code></b> class processes
 *  a text file containing disjoint class definitions and generates
 *  corresponding OWL code snippets for inclusion in an
 *  OWL/XML ontology. This class contributes to the ontology
 *  generation process by defining disjointness relationships
 *  between classes within the ontology. These constraints
 *  ensure that specific classes are mutually exclusive.
 *  <p>
 *  <b>Key Functionalities:</b>
 *  <p>
 *  Reads Disjoint Class Definitions: Parses a text file
 *  structured with indentation levels to identify disjoint
 *  class groups.
 *  <p>
 *  Identifies Disjoint Class Groups: Analyzes indentation
 *  to group class names that belong to the same disjoint set.
 *  <p>
 *  Generates OWL Disjoint Class Axioms: Writes OWL code
 *  representing disjointness constraints, specifying that
 *  certain classes cannot have overlapping instances.
 *  <p>
 *  Handles File I/O: Manages file reading and writing operations.
 *  <p>
 *  <b>Additional Notes:</b>
 *  <p>
 *  The class relies on pre-defined file paths and utilizes
 *  comments within the code, suggesting potential improvements
 *  for user-configurable settings.
 *  <p>
 *  The code showcases functionalities for reading disjoint
 *  class definitions and generating OWL code. The actual
 *  implementation might handle additional logic for handling
 *  potential errors or complex indentation structures in the
 *  input file. *  
 *  <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/06/17
 *  @author  Edit Hlaszny (https://www.edithlaszny.eu/ edithlaszny@gmail.com)
 */

public class WriteDisjointClassDefs 
{
    private       int            countOfDCs     = 0 ;
	private       int            maxIndentation = 0 ;   
    private       OWL2_Generator OWL2G          = new OWL2_Generator() ;
	private       SharedUtils    shu            = null ; 
	private       FileWriter     writer         = null ;

	
	WriteDisjointClassDefs(String src,                //  disjunct class definitions
                           String dst,                //  result OWL file name 
                           String baseURI,            //  base URI
                           String sectionStartToken,  //  START_OF_DISJOINT_CLASS_SET 
                           String sectionEndToken,    //  START_OF_DISJOINT_CLASS_SET
                           String comment             //  "!" - 1st character of line 
                          )
    {	
	    this.shu = new SharedUtils(baseURI) ;
	    
        /**
         *  The disjoint class file definition input file structure 
         * 
         *  START_OF_DISJOINT_CLASS_SET
         *  	Process
         *  		Activity
         *  			P2standardProcess
         *  				ProjectStartingUP_process
         *  				ProjectClosing_process
         *                  . . .
         *  			Approving
         *  			Authorizing
         *  		StartUp
         *  		Workshop
         *  END_OF_DISJOINT_CLASS_SET
         */
		GetSectionsFromConfigFile gsfc = new GetSectionsFromConfigFile(src               ,
                                                                       sectionStartToken ,
                                                                       sectionEndToken   ,
                                                                       comment
                                                                      ) ;
		writeDisjointClasses(gsfc.getSections(), dst) ;

		/**
         *  Logging of the output volume
         */
        OWL2G.log(new StringBuilder()
                      .append("    declared " + this.countOfDCs + " disjoint class(es) ")
                      .append("in different groups\n")
                      .toString()
                 ) ; 
		
    }   //  end of constructor()

    private void writeDisjointClasses(List<List<String>> disjointClassSet, 
    		                          String             dst)            
    {
        ArrayList<ClassEntity> classList = new ArrayList<ClassEntity>();

    	try
        {   /**
             *  Append mode (set the 2nd parameter to false for overwrite)
             */
    	    this.writer = new FileWriter(new File(dst), true) ;
    	    
            for (int i = 0 ; i < disjointClassSet.size() ; i++)
            {
                List<String> section = disjointClassSet.get(i) ;

        	    for (int j = 0 ; j < section.size() ; j++)
        	    {
        	        String indentedClassName = section.get(j) ;
        	        
        	    	classList.add(new ClassEntity(countIndentation(indentedClassName), 
        	    			                      indentedClassName.trim()));
        	    }
        	    	
                /**
                 *  this method analyzes the indentation
                 */
        	    writeDisjunctClassSet(classList) ;
        	    	
            }   //  end of for-loop
        }
        catch (IOException e) 
        {
            e.printStackTrace() ;
        } 
        finally 
        {
            try 
            {
        	    this.writer.close() ;	            
            } 
            catch (IOException e) 
            {
                System.err.println("Error closing file: " + e.getMessage()) ;
            }
        }
        
	}   //  end of method writeDisjointClasses
		
    private int countIndentation(String line) 
    {
        int indentation = 0;
        
        for (char c : line.toCharArray()) 
        {
            if (c == '\t') 
            	indentation++ ;
            else
                break ;
        }
        
        if (this.maxIndentation < indentation)
        	this.maxIndentation = indentation ;
        
        return indentation ;
        
    }   //  end of method countIndentation

    private void writeDisjunctClassSet(ArrayList<ClassEntity> classList)  throws IOException
    {
    	/**
    	 *  Beginning from the deepest indentation
    	 */
    	for (int indentation  = this.maxIndentation ; 
    			 indentation >= 0 ;
    			 indentation--)    		
        {   //                 because of look-ahead: - 1              
    		for (int idx = 0 ; idx < classList.size() - 1 ; idx++)
    		{
    		    ClassEntity ce = classList.get(idx) ;
    	
    		    /**
    		     *  look-ahead condition
    		     */
    		    boolean thereIsMin2IdenticalCE = (indentation == classList.get(idx).level     && 
                                                  indentation == classList.get(idx + 1).level) ;
        		if (thereIsMin2IdenticalCE)
        		{
        			this.writer.write("    <DisjointClasses>\n");
            		    
            		int idxOfDJclasses  = idx ;
            		while (indentation == ce.level         && 
            		  	   idxOfDJclasses < classList.size())
            		{
            			/**
            			 *  current disjoint class name is written out
            			 */
            			this.writer.write("    " + this.shu.formatClassName(ce.name));
            			
            			this.countOfDCs++ ;
                		    
                		classList.remove(idxOfDJclasses) ;

                		/**
                		 *   Think about it: this checking IS NEEDED !
                		 */
                        if (idxOfDJclasses < classList.size())
                        {
                		    ce = classList.get(idxOfDJclasses) ;
                        }
            	    }
              		    	 
            		this.writer.write("    </DisjointClasses>\n");
    		    }
        		
    		}   //  end of inner loop

    		/** 
    		 *  The single classes belonging to this indentation should be removed
    		 */
    		for (int idx = 0 ; idx < classList.size() - 1 ; idx++)
    		{
    			ClassEntity ce = classList.get(idx) ;
    			if (ce.level == indentation)
    			{
    				classList.remove(idx) ;
    			}
    			
    		}   //  end of inner loop
    		
        }   //  end of outer loop

	    /**
	     *  The debris has already been removed, and what remains  
	     *  are the highest indented classes and the lonely ones
	     */
		ArrayList<ClassEntity> remained = new ArrayList<ClassEntity>() ;

	    /**
	     *  Collecting the highest indented classes
	     */
		classList.stream().filter(ce -> ce.level == 0)
                          .forEach(ce -> remained.add(ce));	        
		
		if (remained.size() > 1)
		{
			this.writer.write("    <DisjointClasses>\n");

			remained.forEach(ce -> {   try 
			                           {
				                           this.writer.write("        " + ce.name + "\n") ;
			                           }
	                                   catch (IOException e) 
		                               {
		                                   System.err.println("Error creating or writing to file: " + 
		                                                      e.getMessage()) ;
		                               }			
				                   }
			                ) ;
	        
	        this.writer.write("    </DisjointClasses>\n");
		}
    	
    }   //  end of method writeDisjunctClassSet()

    private class ClassEntity
    {
        public String name  ;
        public int    level ;
        
        ClassEntity(int    level, 
                    String name)
        {
            this.level = level ;
            this.name  = name ;
    
        }   //  end of constructor-1
        
    }   //  end of embedded class ClassEntity
    
}   //  end of class WriteDisjointClassDefs
