
package uk.ac.man.cs.lethe.internal.resolution.simplifications

import uk.ac.man.cs.lethe.internal.fol.datatypes._
import uk.ac.man.cs.lethe.internal.fol.unification._

import com.typesafe.scalalogging.Logger

abstract class SimplificationRule { 
  def simplify(clauses: Set[Clause]): Set[Clause] = { 
    clauses.map(simplify)
  }

  protected def simplify(clause: Clause): Clause = { null }
}

class CombinedSimplification(simplificationRules: Iterable[SimplificationRule]) extends SimplificationRule { 
  override def simplify(clauses: Set[Clause]) = { 
    var result = clauses
    simplificationRules.foreach { x => result = x.simplify(result) }
    result
  }
}

object TautologyDeletion extends SimplificationRule {
//  implicit val (logger, formatter, appender) = ZeroLoggerFactory.newLogger(this)

  val logger = Logger(TautologyDeletion.getClass)

  override def simplify(clauses: Set[Clause]) = { 
    clauses.filterNot(x => x.tautology && { logger.trace(x.toString + " is a tautology"); true})
  }
} 

object SubsumptionDeletion extends SimplificationRule {
//  implicit val (logger, formatter, appender) =
//  ZeroLoggerFactory.newLogger(this)

  val logger = Logger(SubsumptionDeletion.getClass)
 
  override def simplify(clauses: Set[Clause]) = { 
    var finished = false
    var result: Set[Clause] = clauses
    while(!finished) { 
      val f = result.find(x => result.exists(y => x!=y && Subsumer.subsumes(y, x) && 
					     { logger.trace(y.toString + " subsumes " + x.toString); true}))
      f match { 
	case Some(f: Clause) => result = result - f
	case None => finished = true 
      }
    }
    result
  }
}

object SubsumptionFactoring extends SimplificationRule { 
//  implicit val (logger, formatter, appender) =
//  ZeroLoggerFactory.newLogger(this)

  val logger = Logger(SubsumptionFactoring.getClass)

  override def simplify(clauses: Set[Clause]) = clauses.map(simplify)

  override def simplify(clause: Clause) = { 
    var finished = false
    var change = false
    var literals = clause.literals
    while(!finished) { 
      val f = literals.find(x => literals.exists(y => x!=y && Subsumer.subsumes(y, x)))
      f match { 
	case Some(f: Literal) => literals = literals - f; change=true
	case None => finished = true
      }
    }
    if(change)
      logger.trace(clause.toString + " is simplified to " + Clause(literals).toString)
    new Clause(literals)
  }
}

object IdentitySimplification extends SimplificationRule { 
//  implicit val (logger, formatter, appender) =
//  ZeroLoggerFactory.newLogger(this)

  val logger = Logger(IdentitySimplification.getClass)

  override def simplify(clauses: Set[Clause]) = clauses.map(simplify)

  override def simplify(clause: Clause) = { 
    var finished = false
    var change = false
    var literals = clause.literals
    while(!finished) { 
      val f = literals.find(x => x.predicate.isInstanceOf[IdentityPredicate] && 
			    literals.exists{ y =>  
			      val id1 = x.predicate.asInstanceOf[IdentityPredicate]
			      y match { 
				case Literal(p, IdentityPredicate(a, b)) =>  x.positive==p && id1.arg1==b && id1.arg2==a
				case _ => false
			      }
			    })
      f match { 
	case Some(f: Literal) => literals = literals - f; change = true
	case None => finished = true
      }
    }
    if(change)
      logger.trace(clause.toString + " is simplified to " + Clause(literals).toString)
    new Clause(literals)
  }

}
