<commit_before>package x7c1.wheat.modern.observer

import java.lang.Math.{max, min}
import java.lang.System.currentTimeMillis
import java.util.{Timer, TimerTask}

import android.content.Context
import android.support.v7.widget.LinearLayoutManager
import android.view.View.OnTouchListener
import android.view.{MotionEvent, View}

object SkipDetector {
  def createListener[A <: ItemSkippedEvent, B <: SkipStoppedEvent](
    context: Context,
    positionFinder: SkipPositionFinder,
    skippedEventFactory: ItemSkippedEventFactory[A],
    skipDoneEventFactory: SkipStoppedEventFactory[B],
    onSkippedListener: OnItemSkippedListener[A],
    onSkipDoneListener: OnSkipStoppedListener[B]): OnTouchListener = {

    /*
    val detector = new GestureDetector(
      context,
      new GestureListener
    )
    */

    new OnTouchListener {

      val timer = new Timer()

      val maxInterval = 2000L
      val minInterval = 150L
      var interval = 500L
      val multiplier = 1.2

      var task: Option[TimerTask] = None
      var previous: Option[Long] = None

      private def createTimerTask = new TimerTask {
        override def run(): Unit = for {
          next <- positionFinder.findNext
          event <- skippedEventFactory createAt next
        } yield {
          onSkippedListener onSkipped event
        }
      }
      private def elapsed(msec: Long): Long = {
        ((currentTimeMillis() - msec) * multiplier).toLong
      }
      override def onTouch(v: View, event: MotionEvent): Boolean = {
        event.getAction match {
          case MotionEvent.ACTION_DOWN =>
            task foreach {_.cancel()}
            task = Some(createTimerTask)
            previous foreach { msec =>
              interval = min(
                maxInterval,
                max(minInterval, elapsed(msec))
              )
            }
            previous = Some(currentTimeMillis())
            task foreach { timer.schedule(_, interval, interval) }
            false
          case MotionEvent.ACTION_UP | MotionEvent.ACTION_CANCEL =>
            task foreach {_.cancel()}
            previous foreach { msec =>
              if (elapsed(msec) < interval) for {
                next <- positionFinder.findNext
                skipped <- skippedEventFactory createAt next
                done <- skipDoneEventFactory createAt next
              } yield {
                onSkippedListener onSkipped skipped
                onSkipDoneListener onSkipStopped done
              } else for {
                current <- positionFinder.findCurrent
                done <- skipDoneEventFactory createAt current
              } yield {
                onSkipDoneListener onSkipStopped done
              }
            }
            true
          case _ =>
            false
        }
      }
    }
  }
  /*
  private class GestureListener extends GestureDetector.OnGestureListener {
    override def onSingleTapUp(e: MotionEvent): Boolean = {
      Log error "[init]"

      true
    }
    override def onFling(
      e1: MotionEvent, e2: MotionEvent, velocityX: Float, velocityY: Float): Boolean = {

      Log error "[init]"
      true
    }
    override def onShowPress(e: MotionEvent): Unit = {
      Log error "[init]"
    }
    override def onLongPress(e: MotionEvent): Unit = {
      Log error "[init]"
    }
    override def onScroll(
      e1: MotionEvent, e2: MotionEvent, distanceX: Float, distanceY: Float): Boolean = {

      Log error "[init]"
      false
    }
    override def onDown(e: MotionEvent): Boolean = {
      Log error "[init]"
      false
    }
  }
  */
}

trait ItemSkippedEvent {
  require(nextPosition > -1, "must be non negative")
  def nextPosition: Int
}
trait SkipStoppedEvent {
  require(currentPosition > -1, "must be non negative")
  def currentPosition: Int
}
trait ItemSkippedEventFactory[A <: ItemSkippedEvent]{
  def createAt(nextPosition: Int): Option[A]
}
trait SkipStoppedEventFactory[A <: SkipStoppedEvent]{
  def createAt(donePosition: Int): Option[A]
}
trait OnItemSkippedListener[A <: ItemSkippedEvent] {
  def onSkipped(event: A): Unit
}
trait OnSkipStoppedListener[A <: SkipStoppedEvent]{
  def onSkipStopped(event: A): Unit
}

trait SkipPositionFinder {
  def findCurrent: Option[Int]
  def findNext: Option[Int]
}

object SkipPositionFinder {<commit_msg>remove useless comments<commit_after>package x7c1.wheat.modern.observer

import java.lang.Math.{max, min}
import java.lang.System.currentTimeMillis
import java.util.{Timer, TimerTask}

import android.content.Context
import android.support.v7.widget.LinearLayoutManager
import android.view.View.OnTouchListener
import android.view.{MotionEvent, View}

object SkipDetector {
  def createListener[A <: ItemSkippedEvent, B <: SkipStoppedEvent](
    context: Context,
    positionFinder: SkipPositionFinder,
    skippedEventFactory: ItemSkippedEventFactory[A],
    skipDoneEventFactory: SkipStoppedEventFactory[B],
    onSkippedListener: OnItemSkippedListener[A],
    onSkipDoneListener: OnSkipStoppedListener[B]): OnTouchListener = {

    new OnTouchListener {
      val timer = new Timer()

      val maxInterval = 2000L
      val minInterval = 150L
      var interval = 500L

      var task: Option[TimerTask] = None
      var previous: Option[Long] = None

      private def createTimerTask = new TimerTask {
        override def run(): Unit = for {
          next <- positionFinder.findNext
          event <- skippedEventFactory createAt next
        } yield {
          onSkippedListener onSkipped event
        }
      }
      private def elapsed(msec: Long): Long = {
        val multiplier = 1.2
        ((currentTimeMillis() - msec) * multiplier).toLong
      }
      override def onTouch(v: View, event: MotionEvent): Boolean = {
        event.getAction match {
          case MotionEvent.ACTION_DOWN =>
            task foreach {_.cancel()}
            task = Some(createTimerTask)
            previous foreach { msec =>
              interval = min(
                maxInterval,
                max(minInterval, elapsed(msec))
              )
            }
            previous = Some(currentTimeMillis())
            task foreach { timer.schedule(_, interval, interval) }
            false
          case MotionEvent.ACTION_UP | MotionEvent.ACTION_CANCEL =>
            task foreach {_.cancel()}
            previous foreach { msec =>
              if (elapsed(msec) < interval) for {
                next <- positionFinder.findNext
                skipped <- skippedEventFactory createAt next
                done <- skipDoneEventFactory createAt next
              } yield {
                onSkippedListener onSkipped skipped
                onSkipDoneListener onSkipStopped done
              } else for {
                current <- positionFinder.findCurrent
                done <- skipDoneEventFactory createAt current
              } yield {
                onSkipDoneListener onSkipStopped done
              }
            }
            true
          case _ =>
            false
        }
      }
    }
  }
}

trait ItemSkippedEvent {
  require(nextPosition > -1, "must be non negative")
  def nextPosition: Int
}
trait SkipStoppedEvent {
  require(currentPosition > -1, "must be non negative")
  def currentPosition: Int
}
trait ItemSkippedEventFactory[A <: ItemSkippedEvent]{
  def createAt(nextPosition: Int): Option[A]
}
trait SkipStoppedEventFactory[A <: SkipStoppedEvent]{
  def createAt(donePosition: Int): Option[A]
}
trait OnItemSkippedListener[A <: ItemSkippedEvent] {
  def onSkipped(event: A): Unit
}
trait OnSkipStoppedListener[A <: SkipStoppedEvent]{
  def onSkipStopped(event: A): Unit
}

trait SkipPositionFinder {
  def findCurrent: Option[Int]
  def findNext: Option[Int]
}

object SkipPositionFinder {
{'fraction_non_alphanumeric': 0.08425806451612904, 'fraction_numerical': 0.004903225806451613, 'mean_word_length': 2.3714658547194434, 'pattern_counts': {'":': 0, '<': 31, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6543144', 'n_tokens_mistral': 2194, 'n_tokens_neox': 2137, 'n_words': 540}