lila/modules/study/src/main/ExplorerGame.scala

82 lines
2.8 KiB
Scala

package lila.study
import org.joda.time.DateTime
import scala.util.Try
import chess.format.pgn.{ Parser, Reader, ParsedPgn, Tag, TagType }
import lila.common.LightUser
import lila.game.{ Game, Namer }
import lila.round.JsonView.WithFlags
import lila.tree.Node.Comment
import lila.user.User
private final class ExplorerGame(
importer: lila.explorer.ExplorerImporter,
lightUser: LightUser.GetterSync,
baseUrl: String
) {
def quote(gameId: Game.ID): Fu[Option[Comment]] =
importer(gameId) map {
_ ?? { game =>
gameComment(game).some
}
}
def insert(userId: User.ID, study: Study, position: Position, gameId: Game.ID): Fu[Option[(Chapter, Path)]] =
importer(gameId) map {
_ ?? { game =>
position.node ?? { fromNode =>
val gameRoot = GameToRoot(game, none, false)
merge(fromNode, position.path, gameRoot, gameComment(game)) flatMap {
case (newNode, path) => position.chapter.addNode(newNode, path) map (_ -> path)
}
}
}
}
private def merge(fromNode: RootOrNode, fromPath: Path, game: Node.Root, comment: Comment): Option[(Node, Path)] = {
val gameNodes = game.mainline.dropWhile(_.fen != fromNode.fen) drop 1
val (path, foundGameNode) = gameNodes.foldLeft((Path.root, none[Node])) {
case ((path, None), gameNode) =>
val nextPath = path + gameNode
fromNode.children.nodeAt(nextPath) match {
case Some(child) => (nextPath, none)
case None => (path, gameNode.some)
}
case (found, _) => found
}
foundGameNode.map { nextGameNode =>
val commentedNode = nextGameNode setComment comment
commentedNode -> fromPath.+(path)
}
}
private def gameComment(game: Game) = Comment(
id = Comment.Id.make,
text = Comment.Text(s"${gameTitle(game)}, ${gameUrl(game)}"),
by = Comment.Author.Lichess
)
private def gameUrl(game: Game) = s"$baseUrl/${game.id}"
private def gameYear(pgn: Option[ParsedPgn], g: Game): Int = pgn.flatMap { p =>
p.tag(_.UTCDate) orElse p.tag(_.Date)
}.flatMap { pgnDate =>
Try(DateTime.parse(pgnDate, Tag.UTCDate.format)).toOption map (_.getYear)
} | g.createdAt.getYear
private def gameTitle(g: Game): String = {
val pgn = g.pgnImport.flatMap(pgnImport => Parser.full(pgnImport.pgn).toOption)
val white = pgn.flatMap(_.tag(_.White)) | Namer.playerText(g.whitePlayer)(lightUser)
val black = pgn.flatMap(_.tag(_.Black)) | Namer.playerText(g.blackPlayer)(lightUser)
val result = chess.Color.showResult(g.winnerColor)
val event: String = {
val raw = pgn.flatMap(_.tag(_.Event))
val year = gameYear(pgn, g).toString
raw.find(_ contains year) | raw.fold(year)(e => s"$e, $year")
}
s"$white - $black, $result, $event"
}
}