package uk.ac.man.cs.lethe.internal.applications.statistics2

import java.io.{ File, FileOutputStream, PrintWriter }

import scala.collection.mutable.HashMap
import scala.io.Source



import uk.ac.man.cs.lethe.internal.tools.MultiSet
import uk.ac.man.cs.lethe.internal.tools.statistics.IncrementalValuesCount


object Statistics { 

  val codec = io.Codec("ISO-8859-15")

  var runs = 0

  val notCompleted = MultiSet[String]()
  var notCompletedOverall: Int = 0

  var ontologies = Set[String]()

  var tooSmall = Set[String]()

  var definerOccurrencesOverall: Int = 0

  var individualInputValues = new HashMap[String, HashMap[String, IncrementalValuesCount]]()
  var inputValues = new HashMap[String, IncrementalValuesCount]()
 
  var individualDurations = new HashMap[String, IncrementalValuesCount]()
  var durations = new IncrementalValuesCount()

  var individualResultValues = new HashMap[String, HashMap[String, IncrementalValuesCount]]()
  var resultValues = new HashMap[String, IncrementalValuesCount]()

  def main(args: Array[String]) = { 
    val folder = new File(args(0))

    folder.listFiles.foreach{ file => { 
      if(file.getName.startsWith("results.")){ 
	parse(file)
      }
    } }

    println(tooSmall.size+" ontologies where too small")
    println((ontologies.size-tooSmall.size-notCompleted.keySet.size)
	    +" ontologies always completed uniform interpolation within time.")

    val neverCompleted = notCompleted.toSeq.filter(_._2==360).size
    println(neverCompleted + " ontologies never completed uniform interpolation within time.")

//    ((ontologies -- tooSmall) -- notCompleted.keySet).foreach{ ont => println(ont + ": 0 not completed.") }
//    notCompleted.toSeq.sortBy(_._2).foreach{ pair => println(pair._1+": "+pair._2+" not completed.") }

    println()
    println("Overall "+notCompletedOverall+" runs were not completed.")
    println("That is "+(notCompletedOverall.toDouble/runs*100)+"% timeouts")

    println((definerOccurrencesOverall.toDouble/runs*100)+"% of ontologies contained definers")

    writeData(individualDurations, "duration.dat")

    println(" Values for input ontologies: ")
    inputValues.keySet.foreach{ key => 
      println("Input "+key+": "+inputValues(key).toString)
    }

    individualResultValues.keySet.foreach{ key =>
      writeData(individualResultValues(key), key+".dat")
    }

  
    println("Duration all ontologies: "+durations)
    resultValues.keySet.foreach{ key => 
      println("Result "+key+": "+resultValues(key).toString)
    }
  }

  def writeData(map: HashMap[String, IncrementalValuesCount], filename: String) = { 
    val file = new File(filename)
    
    val pr1 = new PrintWriter(new FileOutputStream(file, true))//, "UTF-16BE")
    val out = new PrintWriter(pr1, true)

    try{ 

      map.toSeq.sortBy(_._2.mean).foreach{ pair =>
	out.println(pair._2.mean+" "+pair._2.variance)
      }
    } finally { 
      out.close()
    }
  }


  def parse(file: File) = { 
    
    var currentOntology: String = ""
    var started: Boolean = false
    var finished: Boolean = false

    Source.fromFile(file)(codec).getLines.foreach{ _ match { 
      case reParsingOntology(ontology) => { 
	if(started && !finished){ 
	  notifyNotCompleted(currentOntology)
	}

	currentOntology = ontology
	ontologies += currentOntology

	started = false
	finished = false

	runs += 1
      }

      case reTooSmall() => 
	tooSmall += currentOntology

      case reInputValue(key, number) => { 
	started = true

	addValue(inputValues, key, number.toDouble)
	addValue(individualInputValues, key, currentOntology, number.toDouble)

      }


      case reDuration(number) => { 
	val durationSeconds = number.toDouble/1000.0
	addValue(individualDurations, currentOntology, durationSeconds)
	durations.addValue(durationSeconds)
      }


      case reResultValue(key, number) => { 
	addValue(resultValues, key, number.toDouble)
	addValue(individualResultValues, key, currentOntology, number.toDouble)

	if(key=="Definers" && number!="0")
	  definerOccurrencesOverall += 1

	finished = true
      }
      
      case _ => ;
    }}
  }
			 
  def addValue(map: HashMap[String, HashMap[String, IncrementalValuesCount]],
	       key1: String,
	       key2: String,
	       value: Double): Unit = { 
    if(!map.contains(key1))
      map.put(key1, new HashMap[String, IncrementalValuesCount]())

    addValue(map(key1), key2, value)
  }

  def addValue(map: HashMap[String, IncrementalValuesCount], 
	       key: String, 
	       value: Double): Unit = { 

    if(!map.contains(key))
      map.put(key, new IncrementalValuesCount())

    map(key).addValue(value)
  }

 
  def notifyNotCompleted(ontology: String) = { 
    notCompleted.add(ontology)
    notCompletedOverall += 1
  }

  val reParsingOntology = """Parsing (.+)\.\.\.""".r


  val reTooSmall = """Signature too small.""".r

  
  val reInputValue = """Input (.+): (\d+)""".r


  val reDuration = """Duration: (\d+)""".r


  val reResultValue = """Result (.+): ([\d.]+)""".r

}
