package uk.ac.man.cs.lethe.internal.application.benchmarks

import uk.ac.man.cs.lethe.internal.dl.owlapi.ModuleExtractor
import uk.ac.man.cs.lethe.internal.dl.filters.OWLOntologyFilters
import uk.ac.man.cs.lethe.internal.dl.owlapi.{OWLApiConverter, OWLApiInterface, OWLReasonerFacade}

import java.io.File
import java.util.Date
import org.semanticweb.owlapi.model.OWLAxiom
import org.semanticweb.owlapi.model.parameters.Imports

import scala.concurrent._
import scala.collection.JavaConverters._
import scala.concurrent.duration._
import scala.util.Random
import uk.ac.man.cs.lethe.internal.dl.datatypes.Ontology
import uk.ac.man.cs.lethe.internal.dl.forgetting.DirectALCForgetter


object ABoxForgettingExperimenter {

  implicit val exec = new CustomExecutionContext()

  def main(args: Array[String]): Unit = { 
    print("Loading ontology...")
    val owlOntology = OWLApiInterface.getOWLOntology(new File(args(0)))
    val timeout = args(1).toInt
    val repetitions = args(2).toInt
    OWLOntologyFilters.restrictToALCH(owlOntology)

    // extract module for abox signature
    val owlAboxSig = owlOntology.getABoxAxioms(Imports.EXCLUDED).iterator.asScala.flatMap(_.getSignature().iterator.asScala.toSet)
    val backgroundModule = ModuleExtractor.getModule(owlOntology, owlAboxSig.toSet)

    if(!OWLReasonerFacade.isConsistent(owlOntology))
       return 

    val backgroundOntology = Ontology.buildFrom(backgroundModule.flatMap(OWLApiConverter.convert))
    val aboxOntology = Ontology.buildFrom(owlOntology.getABoxAxioms(Imports.EXCLUDED).iterator.asScala.toSet.flatMap(
      (a: OWLAxiom) => OWLApiConverter.convert(a)))

    println("ABox size: "+aboxOntology.size)
    println("Abox signature size: "+aboxOntology.abox.atomicConcepts.size)
    
    var completeSignature = backgroundOntology.atomicConcepts ++ aboxOntology.atomicConcepts


    for(i <- 1 to repetitions) { 
      var signature = Set[String]()

      println("Experiment "+i)
      
      completeSignature.foreach{ s => if(Random.nextBoolean) signature += s }
    

      println("signature size: "+signature.size)

      val startTime = new Date().getTime

      val futureResult = future[Ontology]{ 
	DirectALCForgetter.forget(aboxOntology, 
				  signature,
				  backgroundOntology)
      }
      
      try { 
	val result = Await.result(futureResult, timeout seconds)
	val duration = new Date().getTime-startTime
	
	println("Output statements: "+result.statements.size)
	println("Output avg axiom size: "+(result.size.toDouble/result.statements.size))
	if(result.statements.size>0)
	  println("Output max statement size: "+result.statements.map(_.size).max)
	println("Output signature: "+result.atomicConcepts.size)
	println("Duration: "+(duration.toDouble/1000)+"sec.")
      } catch { 
	case _: TimeoutException => 
	  println("Timeout.")
	exec.lastThread.getOrElse(throw new RuntimeException("Not started")).stop()
      }
      println()
      println()

    }
  }

}
