package OWLpreprocessing ;

import java.io.* ;
import java.util.* ;
import java.util.regex.* ;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.sql.Connection;

import java.util.ListIterator;

public class OWL_RelationEvaluator 
{
    /**
     * Common file handling methods
     */
    private OWL_BufferedWriterUtils bwu        = new OWL_BufferedWriterUtils() ;

    private OWL_DButils   dbu   = new OWL_DButils() ;
	
    private final int         leadingZeroesInIndividualNameSuffix = 6 ;  //  e.g. actor_ID000012
    private       Connection  DBconnection                        = null ; 
	

	//  test method is the constructor yet ----------------------------------------------
    
    OWL_RelationEvaluator(Connection DBconnection ,
    		              String     DBname ,
    		              String     relationDefs_TXT ,
    		              String     n_ary_relations_SQL ,
    		              String     n_ary_participants_SQL ,
    		              String     n_ary_data_assertions_SQL
                         ) 
    {
    	this.DBconnection = DBconnection ;
    	
        writeSQLfileHdr(n_ary_relations_SQL,       "n-ary relations",       DBname) ; 
        writeSQLfileHdr(n_ary_participants_SQL,    "n-ary participants",    DBname) ;
        writeSQLfileHdr(n_ary_data_assertions_SQL, "n-ary data assertions", DBname) ;

    	ListIterator<TYPE_OF_RELATION> itr = evalRelationDefs(relationDefs_TXT).listIterator();            
        while (itr.hasNext())
        {
        	TYPE_OF_RELATION r = itr.next() ; 
        	
            System.out.println("\npredicate is >" + r.predicate + "<") ;
            
            ListIterator<RelationMemberData> sub_itr = r.subject.listIterator();
            while (sub_itr.hasNext())
            {
            	RelationMemberData s = sub_itr.next();
/*            	
            	System.out.println("    Subject is               >" + s.OWLclassName      + "<") ;
            	System.out.println("    S-data property name is  >" + s.dataPropertyName  + "<") ;
            	System.out.println("    S-data property value is >" + s.dataPropertyValue + "<\n") ;
 */            	
            }            
            
            ListIterator<RelationMemberData> obj_itr = r.object.listIterator();
            while (obj_itr.hasNext())
            {
            	RelationMemberData o = obj_itr.next();
/*            	
            	System.out.println("    Object  is               >" + o.OWLclassName      + "<") ;
            	System.out.println("    O-data property name is  >" + o.dataPropertyName  + "<") ;
            	System.out.println("    O-data property value is >" + o.dataPropertyValue + "<\n") ;
 */            	
            }            
            
        }

        System.out.println("individual is >" + generateIndividualName("Adoption") + "<") ;
        System.out.println("individual is >" + generateIndividualName("Adoption") + "<") ;
        System.out.println("individual is >" + generateIndividualName("Adoption") + "<") ;
       
        System.out.println("individual is >" + generateIndividualName("Anomie")   + "<") ;
        System.out.println("individual is >" + generateIndividualName("Anomie")   + "<") ;

    }   //  end of constructor
    
    // Main method to evaluate relation definitions
	
    public ArrayList<TYPE_OF_RELATION> evalRelationDefs(String inFileName) 
    {
        ArrayList<TYPE_OF_RELATION> relations = new ArrayList<>() ;
        
        try (BufferedReader reader = new BufferedReader(new FileReader(inFileName))) 
        {
            String line ;
            TYPE_OF_RELATION currentRelation = null ;
            
            while ((line = reader.readLine()) != null) 
            {
                line = line.trim() ;
                
                // Skip comments, empty lines, and lines with only spaces
                if (line.isEmpty() || line.startsWith("#")) 
                {
                    continue ;
                }
                
                // Check for PREDICATE line
                if (line.startsWith("PREDICATE")) 
                {
                    // Save previous relation if exists
                    if (currentRelation != null) 
                    {
                        relations.add(currentRelation) ;
                    }
                    
                    // Start new relation
                    currentRelation = new TYPE_OF_RELATION() ;
                    currentRelation.predicate = extractPredicate(line) ;
                    currentRelation.subject = new ArrayList<>() ;
                    currentRelation.object = new ArrayList<>() ;
                }
                // Check for SUBJECT line (including SUBJECT_0)
                else if (line.startsWith("SUBJECT")) {
                    if (currentRelation != null) {
                        RelationMemberData memberData = parseRelationMemberData(line);
                        if (memberData != null) {
                            currentRelation.subject.add(memberData);
                        }
                    }
                }
                // Check for OBJECT line (including OBJECT_0)
                else if (line.startsWith("OBJECT")) {
                    if (currentRelation != null) {
                        RelationMemberData memberData = parseRelationMemberData(line);
                        if (memberData != null) {
                            currentRelation.object.add(memberData);
                        }
                    }
                }            }
            
            // Don't forget the last relation
            if (currentRelation != null) 
            {
                relations.add(currentRelation) ;
            }
            
        } 
        catch (IOException e) 
        {
            System.err.println("Error reading file: " + e.getMessage()) ;
            e.printStackTrace() ;
        }
        
        return relations ;
        
    }   //  end of method evalRelationDefs() 
    
    // Extract predicate name from PREDICATE line
    
    private String extractPredicate(String line) 
    {
        // Pattern: PREDICATE = predicateName
        Pattern pattern = Pattern.compile("PREDICATE\\s*=\\s*(.+)") ;
        Matcher matcher = pattern.matcher(line) ;
        
        if (matcher.find()) 
        {
            return matcher.group(1).trim() ;
        }
        
        return "" ;
        
    }   //  end of method extractPredicate()
    
    // Parse SUBJECT or OBJECT line to extract member data
    
    private RelationMemberData parseRelationMemberData(String line) {
        // Pattern: SUBJECT/OBJECT (with optional _0 suffix) = OWLclassName [dataPropertyName] [dataPropertyValue]
        Pattern pattern = Pattern.compile("(SUBJECT|OBJECT)(_0)?\\s*=\\s*(\\S+)\\s*(\\S+)?\\s*(\\S+)?");
        Matcher matcher = pattern.matcher(line);
        
        if (matcher.find()) {
            RelationMemberData memberData = new RelationMemberData();
            memberData.OWLclassName = matcher.group(3).trim();
            
            // Check if data property name exists (group 4)
            if (matcher.group(4) != null && !matcher.group(4).trim().isEmpty()) {
                memberData.dataPropertyName = matcher.group(4).trim();
            }
            
            // Check if data property value exists (group 5)
            if (matcher.group(5) != null && !matcher.group(5).trim().isEmpty()) {
                memberData.dataPropertyValue = matcher.group(5).trim();
            }
            
            return memberData;
        }
        return null;
    }    
    // TYPE_OF_RELATION class as specified
    
    public static class TYPE_OF_RELATION 
    {
        String predicate ;
        ArrayList<RelationMemberData> subject ;
        ArrayList<RelationMemberData> object ;
        
        // Constructor
        public TYPE_OF_RELATION() 
        {
            subject = new ArrayList<>() ;
            object = new ArrayList<>() ;
        }
        
    }   //  end of class TYPE_OF_RELATION
    
    // RelationMemberData inner class as specified
    
    public static class RelationMemberData 
    {
        String OWLclassName ;
        String dataPropertyName ;
        String dataPropertyValue ;
        
    }   //  end of class RelationMemberData

    private String generateIndividualName(String class_IRI)
    {
    	int incremented_class_individual_count = dbu.getIncrementedIndividualCount(this.DBconnection, 
    			                                                                   class_IRI) ;
    	
    	if (incremented_class_individual_count == -1)
        {
        	System.err.println("Fatal error: DB could not be updated.") ;
        	System.exit(-1) ;
        }
    	
        String numberString = Integer.toString(incremented_class_individual_count);
        int    zerosToAdd   = this.leadingZeroesInIndividualNameSuffix - numberString.length();

        String zeros = Stream.generate(() -> "0").limit(zerosToAdd).collect(Collectors.joining());

        return cvtThe1stCharToLowercase(class_IRI + "_ID" + zeros + numberString) ;
    	
    }   //  end of method addLeadingZeros()
	
	private String cvtThe1stCharToLowercase(String s) 
	{
	    if (s == null || s.isEmpty()) 
	        return s;
	    
	    int firstCodePoint = s.codePointAt(0);
	    int lowerFirst     = Character.toLowerCase(firstCodePoint);
	    int firstLen       = Character.charCount(firstCodePoint);
	    if (firstCodePoint == lowerFirst) 
	        return s;

	    return new StringBuilder(s.length())
                                  .appendCodePoint(lowerFirst)
	                              .append(s.substring(firstLen))
	                              .toString();
	    
	}   //  end of method cvtThe1stCharToLowercase ()

    
    
    private void writeSQLfileHdr(String outFile,
                                 String description,
                                 String DBname
                                )
    {
        String  content = 
                "/*\n" +          
                "    Title:       " + outFile + "\n" +         
                "    Description: " + description + "\n" +         
                "    Format:      OWL/XML encoding" + "\n" +         
                "    Written by:  Java class " + this.getClass().getSimpleName() + "\n" +         
                "    Date:        " + bwu.getCurrTime() + "\n" +         
                " */ \n" +          
                "USE   " + DBname + " ; \n" +         
                "\n" +          
                "SET   TRANSACTION READ WRITE ; \n" +         
                "START TRANSACTION ; \n" ;         

        //                              create mode
        addSQLcontent(outFile, content, false) ;
        
    }   //  end of method writeSQLfileHdr()
    
    private void addSQLcontent(String SQLfile, String content, boolean appendMode)
    {
        try  
        {
            FileWriter fw = new FileWriter(new File(SQLfile), appendMode) ;

            fw.write(content) ;
            fw.flush() ;
            fw.close() ;
        }
        catch (IOException e) { e.printStackTrace() ; }
        
    }   //  end of method commitSQLfiles()
	
}   //  end of class OWL_RelationEvaluator
