package com.ustadmobile.core.db.dao

import androidx.paging.PagingSource
import com.ustadmobile.door.DoorDbType
import com.ustadmobile.door.EntityInsertionAdapter
import com.ustadmobile.door.PreparedStatementConfig
import com.ustadmobile.door.ext.prepareAndUseStatement
import com.ustadmobile.door.ext.prepareAndUseStatementAsync
import com.ustadmobile.door.flow.doorFlow
import com.ustadmobile.door.jdbc.PreparedStatement
import com.ustadmobile.door.jdbc.ext.executeQueryAsyncKmp
import com.ustadmobile.door.jdbc.ext.executeUpdateAsyncKmp
import com.ustadmobile.door.jdbc.ext.mapNextRow
import com.ustadmobile.door.jdbc.ext.mapRows
import com.ustadmobile.door.jdbc.ext.useResults
import com.ustadmobile.door.paging.DoorLimitOffsetPagingSource
import com.ustadmobile.door.room.RoomDatabase
import com.ustadmobile.lib.db.entities.ClazzLog
import kotlin.Boolean
import kotlin.IllegalArgumentException
import kotlin.Int
import kotlin.Long
import kotlin.String
import kotlin.collections.List
import kotlinx.coroutines.flow.Flow

public class ClazzLogDao_JdbcImpl(
  public val _db: RoomDatabase,
) : ClazzLogDao() {
  public val _insertAdapterClazzLog_upsert: EntityInsertionAdapter<ClazzLog> = object :
      EntityInsertionAdapter<ClazzLog>(_db) {
    override fun makeSql(returnsId: Boolean): String = when(dbType) {
      DoorDbType.SQLITE -> {
        "INSERT OR REPLACE INTO ClazzLog (clazzLogUid, clazzLogClazzUid, logDate, timeRecorded, clazzLogDone, cancellationNote, clazzLogCancelled, clazzLogNumPresent, clazzLogNumAbsent, clazzLogNumPartial, clazzLogScheduleUid, clazzLogStatusFlag, clazzLogMSQN, clazzLogLCSN, clazzLogLCB, clazzLogLastChangedTime) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
      }
      DoorDbType.POSTGRES ->  {
        "INSERT INTO ClazzLog (clazzLogUid, clazzLogClazzUid, logDate, timeRecorded, clazzLogDone, cancellationNote, clazzLogCancelled, clazzLogNumPresent, clazzLogNumAbsent, clazzLogNumPartial, clazzLogScheduleUid, clazzLogStatusFlag, clazzLogMSQN, clazzLogLCSN, clazzLogLCB, clazzLogLastChangedTime) VALUES(COALESCE(?,nextval('ClazzLog_clazzLogUid_seq')), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT (clazzLogUid) DO UPDATE SET clazzLogClazzUid = excluded.clazzLogClazzUid,logDate = excluded.logDate,timeRecorded = excluded.timeRecorded,clazzLogDone = excluded.clazzLogDone,cancellationNote = excluded.cancellationNote,clazzLogCancelled = excluded.clazzLogCancelled,clazzLogNumPresent = excluded.clazzLogNumPresent,clazzLogNumAbsent = excluded.clazzLogNumAbsent,clazzLogNumPartial = excluded.clazzLogNumPartial,clazzLogScheduleUid = excluded.clazzLogScheduleUid,clazzLogStatusFlag = excluded.clazzLogStatusFlag,clazzLogMSQN = excluded.clazzLogMSQN,clazzLogLCSN = excluded.clazzLogLCSN,clazzLogLCB = excluded.clazzLogLCB,clazzLogLastChangedTime = excluded.clazzLogLastChangedTime" + if(returnsId) { " RETURNING clazzLogUid" } else "" 
      }
      else -> {
        throw IllegalArgumentException("Unsupported db type")
      }
    }

    override fun bindPreparedStmtToEntity(stmt: PreparedStatement, entity: ClazzLog) {
      if(entity.clazzLogUid == 0L) {
        stmt.setObject(1, null)
      } else {
        stmt.setLong(1, entity.clazzLogUid)
      }
      stmt.setLong(2, entity.clazzLogClazzUid)
      stmt.setLong(3, entity.logDate)
      stmt.setLong(4, entity.timeRecorded)
      stmt.setBoolean(5, entity.clazzLogDone)
      stmt.setString(6, entity.cancellationNote)
      stmt.setBoolean(7, entity.clazzLogCancelled)
      stmt.setInt(8, entity.clazzLogNumPresent)
      stmt.setInt(9, entity.clazzLogNumAbsent)
      stmt.setInt(10, entity.clazzLogNumPartial)
      stmt.setLong(11, entity.clazzLogScheduleUid)
      stmt.setInt(12, entity.clazzLogStatusFlag)
      stmt.setLong(13, entity.clazzLogMSQN)
      stmt.setLong(14, entity.clazzLogLCSN)
      stmt.setInt(15, entity.clazzLogLCB)
      stmt.setLong(16, entity.clazzLogLastChangedTime)
    }
  }

  public val _insertAdapterClazzLog_abort: EntityInsertionAdapter<ClazzLog> = object :
      EntityInsertionAdapter<ClazzLog>(_db) {
    override fun makeSql(returnsId: Boolean): String = when(dbType) {
      DoorDbType.SQLITE -> {
        "INSERT INTO ClazzLog (clazzLogUid, clazzLogClazzUid, logDate, timeRecorded, clazzLogDone, cancellationNote, clazzLogCancelled, clazzLogNumPresent, clazzLogNumAbsent, clazzLogNumPartial, clazzLogScheduleUid, clazzLogStatusFlag, clazzLogMSQN, clazzLogLCSN, clazzLogLCB, clazzLogLastChangedTime) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
      }
      DoorDbType.POSTGRES ->  {
        "INSERT INTO ClazzLog (clazzLogUid, clazzLogClazzUid, logDate, timeRecorded, clazzLogDone, cancellationNote, clazzLogCancelled, clazzLogNumPresent, clazzLogNumAbsent, clazzLogNumPartial, clazzLogScheduleUid, clazzLogStatusFlag, clazzLogMSQN, clazzLogLCSN, clazzLogLCB, clazzLogLastChangedTime) VALUES(COALESCE(?,nextval('ClazzLog_clazzLogUid_seq')), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" + if(returnsId) { " RETURNING clazzLogUid" } else "" 
      }
      else -> {
        throw IllegalArgumentException("Unsupported db type")
      }
    }

    override fun bindPreparedStmtToEntity(stmt: PreparedStatement, entity: ClazzLog) {
      if(entity.clazzLogUid == 0L) {
        stmt.setObject(1, null)
      } else {
        stmt.setLong(1, entity.clazzLogUid)
      }
      stmt.setLong(2, entity.clazzLogClazzUid)
      stmt.setLong(3, entity.logDate)
      stmt.setLong(4, entity.timeRecorded)
      stmt.setBoolean(5, entity.clazzLogDone)
      stmt.setString(6, entity.cancellationNote)
      stmt.setBoolean(7, entity.clazzLogCancelled)
      stmt.setInt(8, entity.clazzLogNumPresent)
      stmt.setInt(9, entity.clazzLogNumAbsent)
      stmt.setInt(10, entity.clazzLogNumPartial)
      stmt.setLong(11, entity.clazzLogScheduleUid)
      stmt.setInt(12, entity.clazzLogStatusFlag)
      stmt.setLong(13, entity.clazzLogMSQN)
      stmt.setLong(14, entity.clazzLogLCSN)
      stmt.setInt(15, entity.clazzLogLCB)
      stmt.setLong(16, entity.clazzLogLastChangedTime)
    }
  }

  override fun replace(entity: ClazzLog): Long {
    val _retVal = _insertAdapterClazzLog_upsert.insertAndReturnId(entity)
    return _retVal
  }

  override suspend fun upsertListAsync(entityList: List<ClazzLog>) {
    _insertAdapterClazzLog_upsert.insertListAsync(entityList)
  }

  public override fun insert(entity: ClazzLog): Long {
    val _retVal = _insertAdapterClazzLog_abort.insertAndReturnId(entity)
    return _retVal
  }

  public override suspend fun insertAsync(entity: ClazzLog): Long {
    val _retVal = _insertAdapterClazzLog_abort.insertAndReturnIdAsync(entity)
    return _retVal
  }

  public override fun insertList(entityList: List<ClazzLog>) {
    _insertAdapterClazzLog_abort.insertList(entityList)
  }

  override suspend fun updateAsync(clazzLog: ClazzLog) {
    val _sql =
        "UPDATE ClazzLog SET clazzLogClazzUid = ?, logDate = ?, timeRecorded = ?, clazzLogDone = ?, cancellationNote = ?, clazzLogCancelled = ?, clazzLogNumPresent = ?, clazzLogNumAbsent = ?, clazzLogNumPartial = ?, clazzLogScheduleUid = ?, clazzLogStatusFlag = ?, clazzLogMSQN = ?, clazzLogLCSN = ?, clazzLogLCB = ?, clazzLogLastChangedTime = ? WHERE clazzLogUid = ?"
    _db.prepareAndUseStatementAsync(_sql) {
       _stmt ->
      _stmt.setLong(1, clazzLog.clazzLogClazzUid)
      _stmt.setLong(2, clazzLog.logDate)
      _stmt.setLong(3, clazzLog.timeRecorded)
      _stmt.setBoolean(4, clazzLog.clazzLogDone)
      _stmt.setString(5, clazzLog.cancellationNote)
      _stmt.setBoolean(6, clazzLog.clazzLogCancelled)
      _stmt.setInt(7, clazzLog.clazzLogNumPresent)
      _stmt.setInt(8, clazzLog.clazzLogNumAbsent)
      _stmt.setInt(9, clazzLog.clazzLogNumPartial)
      _stmt.setLong(10, clazzLog.clazzLogScheduleUid)
      _stmt.setInt(11, clazzLog.clazzLogStatusFlag)
      _stmt.setLong(12, clazzLog.clazzLogMSQN)
      _stmt.setLong(13, clazzLog.clazzLogLCSN)
      _stmt.setInt(14, clazzLog.clazzLogLCB)
      _stmt.setLong(15, clazzLog.clazzLogLastChangedTime)
      _stmt.setLong(16, clazzLog.clazzLogUid)
      _stmt.executeUpdateAsyncKmp()
    }
  }

  public override fun update(entity: ClazzLog) {
    val _sql =
        "UPDATE ClazzLog SET clazzLogClazzUid = ?, logDate = ?, timeRecorded = ?, clazzLogDone = ?, cancellationNote = ?, clazzLogCancelled = ?, clazzLogNumPresent = ?, clazzLogNumAbsent = ?, clazzLogNumPartial = ?, clazzLogScheduleUid = ?, clazzLogStatusFlag = ?, clazzLogMSQN = ?, clazzLogLCSN = ?, clazzLogLCB = ?, clazzLogLastChangedTime = ? WHERE clazzLogUid = ?"
    _db.prepareAndUseStatement(_sql) {
       _stmt ->
      _stmt.setLong(1, entity.clazzLogClazzUid)
      _stmt.setLong(2, entity.logDate)
      _stmt.setLong(3, entity.timeRecorded)
      _stmt.setBoolean(4, entity.clazzLogDone)
      _stmt.setString(5, entity.cancellationNote)
      _stmt.setBoolean(6, entity.clazzLogCancelled)
      _stmt.setInt(7, entity.clazzLogNumPresent)
      _stmt.setInt(8, entity.clazzLogNumAbsent)
      _stmt.setInt(9, entity.clazzLogNumPartial)
      _stmt.setLong(10, entity.clazzLogScheduleUid)
      _stmt.setInt(11, entity.clazzLogStatusFlag)
      _stmt.setLong(12, entity.clazzLogMSQN)
      _stmt.setLong(13, entity.clazzLogLCSN)
      _stmt.setInt(14, entity.clazzLogLCB)
      _stmt.setLong(15, entity.clazzLogLastChangedTime)
      _stmt.setLong(16, entity.clazzLogUid)
      _stmt.executeUpdate()
    }
  }

  override fun findByUid(uid: Long): ClazzLog? = _db.prepareAndUseStatement(PreparedStatementConfig(
    sql = "SELECT * FROM ClazzLog WHERE clazzLogUid = ?",
    readOnly = true,)
  ) { _stmt -> 
    _stmt.setLong(1,uid)
    _stmt.executeQuery().useResults{ _result -> 
      _result.mapNextRow(null) {
        val _tmp_clazzLogUid = _result.getLong("clazzLogUid")
        val _tmp_clazzLogClazzUid = _result.getLong("clazzLogClazzUid")
        val _tmp_logDate = _result.getLong("logDate")
        val _tmp_timeRecorded = _result.getLong("timeRecorded")
        val _tmp_clazzLogDone = _result.getBoolean("clazzLogDone")
        val _tmp_cancellationNote = _result.getString("cancellationNote")
        val _tmp_clazzLogCancelled = _result.getBoolean("clazzLogCancelled")
        val _tmp_clazzLogNumPresent = _result.getInt("clazzLogNumPresent")
        val _tmp_clazzLogNumAbsent = _result.getInt("clazzLogNumAbsent")
        val _tmp_clazzLogNumPartial = _result.getInt("clazzLogNumPartial")
        val _tmp_clazzLogScheduleUid = _result.getLong("clazzLogScheduleUid")
        val _tmp_clazzLogStatusFlag = _result.getInt("clazzLogStatusFlag")
        val _tmp_clazzLogMSQN = _result.getLong("clazzLogMSQN")
        val _tmp_clazzLogLCSN = _result.getLong("clazzLogLCSN")
        val _tmp_clazzLogLCB = _result.getInt("clazzLogLCB")
        val _tmp_clazzLogLastChangedTime = _result.getLong("clazzLogLastChangedTime")
        ClazzLog().apply {
          this.clazzLogUid = _tmp_clazzLogUid
          this.clazzLogClazzUid = _tmp_clazzLogClazzUid
          this.logDate = _tmp_logDate
          this.timeRecorded = _tmp_timeRecorded
          this.clazzLogDone = _tmp_clazzLogDone
          this.cancellationNote = _tmp_cancellationNote
          this.clazzLogCancelled = _tmp_clazzLogCancelled
          this.clazzLogNumPresent = _tmp_clazzLogNumPresent
          this.clazzLogNumAbsent = _tmp_clazzLogNumAbsent
          this.clazzLogNumPartial = _tmp_clazzLogNumPartial
          this.clazzLogScheduleUid = _tmp_clazzLogScheduleUid
          this.clazzLogStatusFlag = _tmp_clazzLogStatusFlag
          this.clazzLogMSQN = _tmp_clazzLogMSQN
          this.clazzLogLCSN = _tmp_clazzLogLCSN
          this.clazzLogLCB = _tmp_clazzLogLCB
          this.clazzLogLastChangedTime = _tmp_clazzLogLastChangedTime
        }
      }
    }
  }

  override suspend fun findByUidAsync(uid: Long): ClazzLog? =
      _db.prepareAndUseStatementAsync(PreparedStatementConfig(
    sql = "SELECT * FROM ClazzLog WHERE clazzLogUid = ?",
    readOnly = true,)
  ) { _stmt -> 
    _stmt.setLong(1,uid)
    _stmt.executeQueryAsyncKmp().useResults{ _result -> 
      _result.mapNextRow(null) {
        val _tmp_clazzLogUid = _result.getLong("clazzLogUid")
        val _tmp_clazzLogClazzUid = _result.getLong("clazzLogClazzUid")
        val _tmp_logDate = _result.getLong("logDate")
        val _tmp_timeRecorded = _result.getLong("timeRecorded")
        val _tmp_clazzLogDone = _result.getBoolean("clazzLogDone")
        val _tmp_cancellationNote = _result.getString("cancellationNote")
        val _tmp_clazzLogCancelled = _result.getBoolean("clazzLogCancelled")
        val _tmp_clazzLogNumPresent = _result.getInt("clazzLogNumPresent")
        val _tmp_clazzLogNumAbsent = _result.getInt("clazzLogNumAbsent")
        val _tmp_clazzLogNumPartial = _result.getInt("clazzLogNumPartial")
        val _tmp_clazzLogScheduleUid = _result.getLong("clazzLogScheduleUid")
        val _tmp_clazzLogStatusFlag = _result.getInt("clazzLogStatusFlag")
        val _tmp_clazzLogMSQN = _result.getLong("clazzLogMSQN")
        val _tmp_clazzLogLCSN = _result.getLong("clazzLogLCSN")
        val _tmp_clazzLogLCB = _result.getInt("clazzLogLCB")
        val _tmp_clazzLogLastChangedTime = _result.getLong("clazzLogLastChangedTime")
        ClazzLog().apply {
          this.clazzLogUid = _tmp_clazzLogUid
          this.clazzLogClazzUid = _tmp_clazzLogClazzUid
          this.logDate = _tmp_logDate
          this.timeRecorded = _tmp_timeRecorded
          this.clazzLogDone = _tmp_clazzLogDone
          this.cancellationNote = _tmp_cancellationNote
          this.clazzLogCancelled = _tmp_clazzLogCancelled
          this.clazzLogNumPresent = _tmp_clazzLogNumPresent
          this.clazzLogNumAbsent = _tmp_clazzLogNumAbsent
          this.clazzLogNumPartial = _tmp_clazzLogNumPartial
          this.clazzLogScheduleUid = _tmp_clazzLogScheduleUid
          this.clazzLogStatusFlag = _tmp_clazzLogStatusFlag
          this.clazzLogMSQN = _tmp_clazzLogMSQN
          this.clazzLogLCSN = _tmp_clazzLogLCSN
          this.clazzLogLCB = _tmp_clazzLogLCB
          this.clazzLogLastChangedTime = _tmp_clazzLogLastChangedTime
        }
      }
    }
  }

  override fun findByUidLive(uid: Long): Flow<ClazzLog?> = _db.doorFlow(arrayOf("ClazzLog")) {
    _db.prepareAndUseStatementAsync(PreparedStatementConfig(
      sql = "SELECT * FROM ClazzLog WHERE clazzLogUid = ?",
      readOnly = true,)
    ) { _stmt -> 
      _stmt.setLong(1,uid)
      _stmt.executeQueryAsyncKmp().useResults{ _result -> 
        _result.mapNextRow(null) {
          val _tmp_clazzLogUid = _result.getLong("clazzLogUid")
          val _tmp_clazzLogClazzUid = _result.getLong("clazzLogClazzUid")
          val _tmp_logDate = _result.getLong("logDate")
          val _tmp_timeRecorded = _result.getLong("timeRecorded")
          val _tmp_clazzLogDone = _result.getBoolean("clazzLogDone")
          val _tmp_cancellationNote = _result.getString("cancellationNote")
          val _tmp_clazzLogCancelled = _result.getBoolean("clazzLogCancelled")
          val _tmp_clazzLogNumPresent = _result.getInt("clazzLogNumPresent")
          val _tmp_clazzLogNumAbsent = _result.getInt("clazzLogNumAbsent")
          val _tmp_clazzLogNumPartial = _result.getInt("clazzLogNumPartial")
          val _tmp_clazzLogScheduleUid = _result.getLong("clazzLogScheduleUid")
          val _tmp_clazzLogStatusFlag = _result.getInt("clazzLogStatusFlag")
          val _tmp_clazzLogMSQN = _result.getLong("clazzLogMSQN")
          val _tmp_clazzLogLCSN = _result.getLong("clazzLogLCSN")
          val _tmp_clazzLogLCB = _result.getInt("clazzLogLCB")
          val _tmp_clazzLogLastChangedTime = _result.getLong("clazzLogLastChangedTime")
          ClazzLog().apply {
            this.clazzLogUid = _tmp_clazzLogUid
            this.clazzLogClazzUid = _tmp_clazzLogClazzUid
            this.logDate = _tmp_logDate
            this.timeRecorded = _tmp_timeRecorded
            this.clazzLogDone = _tmp_clazzLogDone
            this.cancellationNote = _tmp_cancellationNote
            this.clazzLogCancelled = _tmp_clazzLogCancelled
            this.clazzLogNumPresent = _tmp_clazzLogNumPresent
            this.clazzLogNumAbsent = _tmp_clazzLogNumAbsent
            this.clazzLogNumPartial = _tmp_clazzLogNumPartial
            this.clazzLogScheduleUid = _tmp_clazzLogScheduleUid
            this.clazzLogStatusFlag = _tmp_clazzLogStatusFlag
            this.clazzLogMSQN = _tmp_clazzLogMSQN
            this.clazzLogLCSN = _tmp_clazzLogLCSN
            this.clazzLogLCB = _tmp_clazzLogLCB
            this.clazzLogLastChangedTime = _tmp_clazzLogLastChangedTime
          }
        }
      }
    }
  }

  override fun findByClazzUidAsFactory(clazzUid: Long, excludeStatus: Int):
      PagingSource<Int, ClazzLog> = object : DoorLimitOffsetPagingSource<ClazzLog>(db = _db
  , tableNames = arrayOf("ClazzLog")
  ) {
    override suspend fun loadRows(_limit: Int, _offset: Int): List<ClazzLog> =
        _db.prepareAndUseStatementAsync(PreparedStatementConfig(
      sql = """
      |SELECT * FROM (
      |        SELECT ClazzLog.* 
      |          FROM ClazzLog 
      |         WHERE clazzLogClazzUid = ?
      |           AND clazzLog.clazzLogStatusFlag != ?
      |      ORDER BY ClazzLog.logDate DESC
      |    ) AS _PagingData LIMIT ? OFFSET ?
      """.trimMargin(),
      readOnly = true,)
    ) { _stmt -> 
      _stmt.setLong(1,clazzUid)
      _stmt.setInt(2,excludeStatus)
      _stmt.setInt(3,_limit)
      _stmt.setInt(4,_offset)
      _stmt.executeQueryAsyncKmp().useResults{ _result -> 
        _result.mapRows {
          val _tmp_clazzLogUid = _result.getLong("clazzLogUid")
          val _tmp_clazzLogClazzUid = _result.getLong("clazzLogClazzUid")
          val _tmp_logDate = _result.getLong("logDate")
          val _tmp_timeRecorded = _result.getLong("timeRecorded")
          val _tmp_clazzLogDone = _result.getBoolean("clazzLogDone")
          val _tmp_cancellationNote = _result.getString("cancellationNote")
          val _tmp_clazzLogCancelled = _result.getBoolean("clazzLogCancelled")
          val _tmp_clazzLogNumPresent = _result.getInt("clazzLogNumPresent")
          val _tmp_clazzLogNumAbsent = _result.getInt("clazzLogNumAbsent")
          val _tmp_clazzLogNumPartial = _result.getInt("clazzLogNumPartial")
          val _tmp_clazzLogScheduleUid = _result.getLong("clazzLogScheduleUid")
          val _tmp_clazzLogStatusFlag = _result.getInt("clazzLogStatusFlag")
          val _tmp_clazzLogMSQN = _result.getLong("clazzLogMSQN")
          val _tmp_clazzLogLCSN = _result.getLong("clazzLogLCSN")
          val _tmp_clazzLogLCB = _result.getInt("clazzLogLCB")
          val _tmp_clazzLogLastChangedTime = _result.getLong("clazzLogLastChangedTime")
          ClazzLog().apply {
            this.clazzLogUid = _tmp_clazzLogUid
            this.clazzLogClazzUid = _tmp_clazzLogClazzUid
            this.logDate = _tmp_logDate
            this.timeRecorded = _tmp_timeRecorded
            this.clazzLogDone = _tmp_clazzLogDone
            this.cancellationNote = _tmp_cancellationNote
            this.clazzLogCancelled = _tmp_clazzLogCancelled
            this.clazzLogNumPresent = _tmp_clazzLogNumPresent
            this.clazzLogNumAbsent = _tmp_clazzLogNumAbsent
            this.clazzLogNumPartial = _tmp_clazzLogNumPartial
            this.clazzLogScheduleUid = _tmp_clazzLogScheduleUid
            this.clazzLogStatusFlag = _tmp_clazzLogStatusFlag
            this.clazzLogMSQN = _tmp_clazzLogMSQN
            this.clazzLogLCSN = _tmp_clazzLogLCSN
            this.clazzLogLCB = _tmp_clazzLogLCB
            this.clazzLogLastChangedTime = _tmp_clazzLogLastChangedTime
          }
        }
      }
    }

    override suspend fun countRows(): Int = _db.prepareAndUseStatementAsync(PreparedStatementConfig(
      sql = """
      |SELECT COUNT(*) FROM (
      |        SELECT ClazzLog.* 
      |          FROM ClazzLog 
      |         WHERE clazzLogClazzUid = ?
      |           AND clazzLog.clazzLogStatusFlag != ?
      |      ORDER BY ClazzLog.logDate DESC
      |    ) AS _PagingCount
      """.trimMargin(),
      readOnly = true,)
    ) { _stmt -> 
      _stmt.setLong(1,clazzUid)
      _stmt.setInt(2,excludeStatus)
      _stmt.executeQueryAsyncKmp().useResults{ _result -> 
        _result.mapNextRow(0) {
          _result.getInt(1)
        }
      }
    }
  }

  override suspend fun findByClazzUidAsync(clazzUid: Long, excludeStatus: Int): List<ClazzLog> =
      _db.prepareAndUseStatementAsync(PreparedStatementConfig(
    sql = """
    |
    |        SELECT ClazzLog.* 
    |          FROM ClazzLog 
    |         WHERE ClazzLog.clazzLogClazzUid = ?
    |           AND clazzLog.clazzLogStatusFlag != ?
    |      ORDER BY ClazzLog.logDate ASC
    |    
    """.trimMargin(),
    readOnly = true,)
  ) { _stmt -> 
    _stmt.setLong(1,clazzUid)
    _stmt.setInt(2,excludeStatus)
    _stmt.executeQueryAsyncKmp().useResults{ _result -> 
      _result.mapRows {
        val _tmp_clazzLogUid = _result.getLong("clazzLogUid")
        val _tmp_clazzLogClazzUid = _result.getLong("clazzLogClazzUid")
        val _tmp_logDate = _result.getLong("logDate")
        val _tmp_timeRecorded = _result.getLong("timeRecorded")
        val _tmp_clazzLogDone = _result.getBoolean("clazzLogDone")
        val _tmp_cancellationNote = _result.getString("cancellationNote")
        val _tmp_clazzLogCancelled = _result.getBoolean("clazzLogCancelled")
        val _tmp_clazzLogNumPresent = _result.getInt("clazzLogNumPresent")
        val _tmp_clazzLogNumAbsent = _result.getInt("clazzLogNumAbsent")
        val _tmp_clazzLogNumPartial = _result.getInt("clazzLogNumPartial")
        val _tmp_clazzLogScheduleUid = _result.getLong("clazzLogScheduleUid")
        val _tmp_clazzLogStatusFlag = _result.getInt("clazzLogStatusFlag")
        val _tmp_clazzLogMSQN = _result.getLong("clazzLogMSQN")
        val _tmp_clazzLogLCSN = _result.getLong("clazzLogLCSN")
        val _tmp_clazzLogLCB = _result.getInt("clazzLogLCB")
        val _tmp_clazzLogLastChangedTime = _result.getLong("clazzLogLastChangedTime")
        ClazzLog().apply {
          this.clazzLogUid = _tmp_clazzLogUid
          this.clazzLogClazzUid = _tmp_clazzLogClazzUid
          this.logDate = _tmp_logDate
          this.timeRecorded = _tmp_timeRecorded
          this.clazzLogDone = _tmp_clazzLogDone
          this.cancellationNote = _tmp_cancellationNote
          this.clazzLogCancelled = _tmp_clazzLogCancelled
          this.clazzLogNumPresent = _tmp_clazzLogNumPresent
          this.clazzLogNumAbsent = _tmp_clazzLogNumAbsent
          this.clazzLogNumPartial = _tmp_clazzLogNumPartial
          this.clazzLogScheduleUid = _tmp_clazzLogScheduleUid
          this.clazzLogStatusFlag = _tmp_clazzLogStatusFlag
          this.clazzLogMSQN = _tmp_clazzLogMSQN
          this.clazzLogLCSN = _tmp_clazzLogLCSN
          this.clazzLogLCB = _tmp_clazzLogLCB
          this.clazzLogLastChangedTime = _tmp_clazzLogLastChangedTime
        }
      }
    }
  }

  override suspend fun findAllForClazzByClazzLogUid(clazzLogUid: Long, excludeStatus: Int):
      List<ClazzLog> = _db.prepareAndUseStatementAsync(PreparedStatementConfig(
    sql = """
    |
    |        SELECT ClazzLog.* 
    |          FROM ClazzLog 
    |         WHERE ClazzLog.clazzLogClazzUid = 
    |               (SELECT ClazzLogInner.clazzLogClazzUid
    |                  FROM ClazzLog ClazzLogInner
    |                 WHERE ClazzLogInner.clazzLogUid = ?)
    |           AND clazzLog.clazzLogStatusFlag != ?
    |      ORDER BY ClazzLog.logDate ASC
    |    
    """.trimMargin(),
    readOnly = true,)
  ) { _stmt -> 
    _stmt.setLong(1,clazzLogUid)
    _stmt.setInt(2,excludeStatus)
    _stmt.executeQueryAsyncKmp().useResults{ _result -> 
      _result.mapRows {
        val _tmp_clazzLogUid = _result.getLong("clazzLogUid")
        val _tmp_clazzLogClazzUid = _result.getLong("clazzLogClazzUid")
        val _tmp_logDate = _result.getLong("logDate")
        val _tmp_timeRecorded = _result.getLong("timeRecorded")
        val _tmp_clazzLogDone = _result.getBoolean("clazzLogDone")
        val _tmp_cancellationNote = _result.getString("cancellationNote")
        val _tmp_clazzLogCancelled = _result.getBoolean("clazzLogCancelled")
        val _tmp_clazzLogNumPresent = _result.getInt("clazzLogNumPresent")
        val _tmp_clazzLogNumAbsent = _result.getInt("clazzLogNumAbsent")
        val _tmp_clazzLogNumPartial = _result.getInt("clazzLogNumPartial")
        val _tmp_clazzLogScheduleUid = _result.getLong("clazzLogScheduleUid")
        val _tmp_clazzLogStatusFlag = _result.getInt("clazzLogStatusFlag")
        val _tmp_clazzLogMSQN = _result.getLong("clazzLogMSQN")
        val _tmp_clazzLogLCSN = _result.getLong("clazzLogLCSN")
        val _tmp_clazzLogLCB = _result.getInt("clazzLogLCB")
        val _tmp_clazzLogLastChangedTime = _result.getLong("clazzLogLastChangedTime")
        ClazzLog().apply {
          this.clazzLogUid = _tmp_clazzLogUid
          this.clazzLogClazzUid = _tmp_clazzLogClazzUid
          this.logDate = _tmp_logDate
          this.timeRecorded = _tmp_timeRecorded
          this.clazzLogDone = _tmp_clazzLogDone
          this.cancellationNote = _tmp_cancellationNote
          this.clazzLogCancelled = _tmp_clazzLogCancelled
          this.clazzLogNumPresent = _tmp_clazzLogNumPresent
          this.clazzLogNumAbsent = _tmp_clazzLogNumAbsent
          this.clazzLogNumPartial = _tmp_clazzLogNumPartial
          this.clazzLogScheduleUid = _tmp_clazzLogScheduleUid
          this.clazzLogStatusFlag = _tmp_clazzLogStatusFlag
          this.clazzLogMSQN = _tmp_clazzLogMSQN
          this.clazzLogLCSN = _tmp_clazzLogLCSN
          this.clazzLogLCB = _tmp_clazzLogLCB
          this.clazzLogLastChangedTime = _tmp_clazzLogLastChangedTime
        }
      }
    }
  }

  override suspend fun findByClazzUidWithinTimeRangeAsync(
    clazzUid: Long,
    fromTime: Long,
    toTime: Long,
    excludeStatusFilter: Int,
    limit: Int,
  ): List<ClazzLog> = _db.prepareAndUseStatementAsync(PreparedStatementConfig(
    sql = """
    |SELECT ClazzLog.* FROM ClazzLog 
    |        WHERE 
    |        ClazzLog.clazzLogClazzUid = ? 
    |        AND ClazzLog.logDate BETWEEN ? AND ?
    |        AND (? = 0 OR ((ClazzLog.clazzLogStatusFlag & ?) = 0))
    |        ORDER BY ClazzLog.logDate DESC
    |        LIMIT ?
    |    
    """.trimMargin(),
    readOnly = true,)
  ) { _stmt -> 
    _stmt.setLong(1,clazzUid)
    _stmt.setLong(2,fromTime)
    _stmt.setLong(3,toTime)
    _stmt.setInt(4,excludeStatusFilter)
    _stmt.setInt(5,excludeStatusFilter)
    _stmt.setInt(6,limit)
    _stmt.executeQueryAsyncKmp().useResults{ _result -> 
      _result.mapRows {
        val _tmp_clazzLogUid = _result.getLong("clazzLogUid")
        val _tmp_clazzLogClazzUid = _result.getLong("clazzLogClazzUid")
        val _tmp_logDate = _result.getLong("logDate")
        val _tmp_timeRecorded = _result.getLong("timeRecorded")
        val _tmp_clazzLogDone = _result.getBoolean("clazzLogDone")
        val _tmp_cancellationNote = _result.getString("cancellationNote")
        val _tmp_clazzLogCancelled = _result.getBoolean("clazzLogCancelled")
        val _tmp_clazzLogNumPresent = _result.getInt("clazzLogNumPresent")
        val _tmp_clazzLogNumAbsent = _result.getInt("clazzLogNumAbsent")
        val _tmp_clazzLogNumPartial = _result.getInt("clazzLogNumPartial")
        val _tmp_clazzLogScheduleUid = _result.getLong("clazzLogScheduleUid")
        val _tmp_clazzLogStatusFlag = _result.getInt("clazzLogStatusFlag")
        val _tmp_clazzLogMSQN = _result.getLong("clazzLogMSQN")
        val _tmp_clazzLogLCSN = _result.getLong("clazzLogLCSN")
        val _tmp_clazzLogLCB = _result.getInt("clazzLogLCB")
        val _tmp_clazzLogLastChangedTime = _result.getLong("clazzLogLastChangedTime")
        ClazzLog().apply {
          this.clazzLogUid = _tmp_clazzLogUid
          this.clazzLogClazzUid = _tmp_clazzLogClazzUid
          this.logDate = _tmp_logDate
          this.timeRecorded = _tmp_timeRecorded
          this.clazzLogDone = _tmp_clazzLogDone
          this.cancellationNote = _tmp_cancellationNote
          this.clazzLogCancelled = _tmp_clazzLogCancelled
          this.clazzLogNumPresent = _tmp_clazzLogNumPresent
          this.clazzLogNumAbsent = _tmp_clazzLogNumAbsent
          this.clazzLogNumPartial = _tmp_clazzLogNumPartial
          this.clazzLogScheduleUid = _tmp_clazzLogScheduleUid
          this.clazzLogStatusFlag = _tmp_clazzLogStatusFlag
          this.clazzLogMSQN = _tmp_clazzLogMSQN
          this.clazzLogLCSN = _tmp_clazzLogLCSN
          this.clazzLogLCB = _tmp_clazzLogLCB
          this.clazzLogLastChangedTime = _tmp_clazzLogLastChangedTime
        }
      }
    }
  }

  override fun findByClazzUidWithinTimeRange(
    clazzUid: Long,
    fromTime: Long,
    toTime: Long,
    excludeStatusFilter: Int,
    limit: Int,
  ): List<ClazzLog> = _db.prepareAndUseStatement(PreparedStatementConfig(
    sql = """
    |SELECT ClazzLog.* FROM ClazzLog 
    |        WHERE 
    |        ClazzLog.clazzLogClazzUid = ? 
    |        AND ClazzLog.logDate BETWEEN ? AND ?
    |        AND (? = 0 OR ((ClazzLog.clazzLogStatusFlag & ?) = 0))
    |        ORDER BY ClazzLog.logDate DESC
    |        LIMIT ?
    |    
    """.trimMargin(),
    readOnly = true,)
  ) { _stmt -> 
    _stmt.setLong(1,clazzUid)
    _stmt.setLong(2,fromTime)
    _stmt.setLong(3,toTime)
    _stmt.setInt(4,excludeStatusFilter)
    _stmt.setInt(5,excludeStatusFilter)
    _stmt.setInt(6,limit)
    _stmt.executeQuery().useResults{ _result -> 
      _result.mapRows {
        val _tmp_clazzLogUid = _result.getLong("clazzLogUid")
        val _tmp_clazzLogClazzUid = _result.getLong("clazzLogClazzUid")
        val _tmp_logDate = _result.getLong("logDate")
        val _tmp_timeRecorded = _result.getLong("timeRecorded")
        val _tmp_clazzLogDone = _result.getBoolean("clazzLogDone")
        val _tmp_cancellationNote = _result.getString("cancellationNote")
        val _tmp_clazzLogCancelled = _result.getBoolean("clazzLogCancelled")
        val _tmp_clazzLogNumPresent = _result.getInt("clazzLogNumPresent")
        val _tmp_clazzLogNumAbsent = _result.getInt("clazzLogNumAbsent")
        val _tmp_clazzLogNumPartial = _result.getInt("clazzLogNumPartial")
        val _tmp_clazzLogScheduleUid = _result.getLong("clazzLogScheduleUid")
        val _tmp_clazzLogStatusFlag = _result.getInt("clazzLogStatusFlag")
        val _tmp_clazzLogMSQN = _result.getLong("clazzLogMSQN")
        val _tmp_clazzLogLCSN = _result.getLong("clazzLogLCSN")
        val _tmp_clazzLogLCB = _result.getInt("clazzLogLCB")
        val _tmp_clazzLogLastChangedTime = _result.getLong("clazzLogLastChangedTime")
        ClazzLog().apply {
          this.clazzLogUid = _tmp_clazzLogUid
          this.clazzLogClazzUid = _tmp_clazzLogClazzUid
          this.logDate = _tmp_logDate
          this.timeRecorded = _tmp_timeRecorded
          this.clazzLogDone = _tmp_clazzLogDone
          this.cancellationNote = _tmp_cancellationNote
          this.clazzLogCancelled = _tmp_clazzLogCancelled
          this.clazzLogNumPresent = _tmp_clazzLogNumPresent
          this.clazzLogNumAbsent = _tmp_clazzLogNumAbsent
          this.clazzLogNumPartial = _tmp_clazzLogNumPartial
          this.clazzLogScheduleUid = _tmp_clazzLogScheduleUid
          this.clazzLogStatusFlag = _tmp_clazzLogStatusFlag
          this.clazzLogMSQN = _tmp_clazzLogMSQN
          this.clazzLogLCSN = _tmp_clazzLogLCSN
          this.clazzLogLCB = _tmp_clazzLogLCB
          this.clazzLogLastChangedTime = _tmp_clazzLogLastChangedTime
        }
      }
    }
  }

  override fun findByClazzUidWithinTimeRangeLive(
    clazzUid: Long,
    fromTime: Long,
    toTime: Long,
    statusFilter: Int,
  ): Flow<List<ClazzLog>> = _db.doorFlow(arrayOf("ClazzLog")) {
    _db.prepareAndUseStatementAsync(PreparedStatementConfig(
      sql = """
      |SELECT ClazzLog.* FROM ClazzLog 
      |        WHERE 
      |        ClazzLog.clazzLogClazzUid = ? 
      |        AND ClazzLog.logDate BETWEEN ? AND ?
      |        AND (? = 0 OR ClazzLog.clazzLogStatusFlag = ?)
      |        ORDER BY ClazzLog.logDate
      |    
      """.trimMargin(),
      readOnly = true,)
    ) { _stmt -> 
      _stmt.setLong(1,clazzUid)
      _stmt.setLong(2,fromTime)
      _stmt.setLong(3,toTime)
      _stmt.setInt(4,statusFilter)
      _stmt.setInt(5,statusFilter)
      _stmt.executeQueryAsyncKmp().useResults{ _result -> 
        _result.mapRows {
          val _tmp_clazzLogUid = _result.getLong("clazzLogUid")
          val _tmp_clazzLogClazzUid = _result.getLong("clazzLogClazzUid")
          val _tmp_logDate = _result.getLong("logDate")
          val _tmp_timeRecorded = _result.getLong("timeRecorded")
          val _tmp_clazzLogDone = _result.getBoolean("clazzLogDone")
          val _tmp_cancellationNote = _result.getString("cancellationNote")
          val _tmp_clazzLogCancelled = _result.getBoolean("clazzLogCancelled")
          val _tmp_clazzLogNumPresent = _result.getInt("clazzLogNumPresent")
          val _tmp_clazzLogNumAbsent = _result.getInt("clazzLogNumAbsent")
          val _tmp_clazzLogNumPartial = _result.getInt("clazzLogNumPartial")
          val _tmp_clazzLogScheduleUid = _result.getLong("clazzLogScheduleUid")
          val _tmp_clazzLogStatusFlag = _result.getInt("clazzLogStatusFlag")
          val _tmp_clazzLogMSQN = _result.getLong("clazzLogMSQN")
          val _tmp_clazzLogLCSN = _result.getLong("clazzLogLCSN")
          val _tmp_clazzLogLCB = _result.getInt("clazzLogLCB")
          val _tmp_clazzLogLastChangedTime = _result.getLong("clazzLogLastChangedTime")
          ClazzLog().apply {
            this.clazzLogUid = _tmp_clazzLogUid
            this.clazzLogClazzUid = _tmp_clazzLogClazzUid
            this.logDate = _tmp_logDate
            this.timeRecorded = _tmp_timeRecorded
            this.clazzLogDone = _tmp_clazzLogDone
            this.cancellationNote = _tmp_cancellationNote
            this.clazzLogCancelled = _tmp_clazzLogCancelled
            this.clazzLogNumPresent = _tmp_clazzLogNumPresent
            this.clazzLogNumAbsent = _tmp_clazzLogNumAbsent
            this.clazzLogNumPartial = _tmp_clazzLogNumPartial
            this.clazzLogScheduleUid = _tmp_clazzLogScheduleUid
            this.clazzLogStatusFlag = _tmp_clazzLogStatusFlag
            this.clazzLogMSQN = _tmp_clazzLogMSQN
            this.clazzLogLCSN = _tmp_clazzLogLCSN
            this.clazzLogLCB = _tmp_clazzLogLCB
            this.clazzLogLastChangedTime = _tmp_clazzLogLastChangedTime
          }
        }
      }
    }
  }

  override fun clazzHasScheduleLive(clazzUid: Long, excludeStatusFilter: Int): Flow<Boolean> =
      _db.doorFlow(arrayOf("ClazzLog")) {
    _db.prepareAndUseStatementAsync(PreparedStatementConfig(
      sql = """
      |
      |        SELECT EXISTS
      |               (SELECT ClazzLog.clazzLogUid 
      |                  FROM ClazzLog 
      |                 WHERE clazzLogClazzUid = ? 
      |                 AND (? = 0 
      |                      OR ((ClazzLog.clazzLogStatusFlag & ?) = 0))
      |               )
      |    
      """.trimMargin(),
      readOnly = true,)
    ) { _stmt -> 
      _stmt.setLong(1,clazzUid)
      _stmt.setInt(2,excludeStatusFilter)
      _stmt.setInt(3,excludeStatusFilter)
      _stmt.executeQueryAsyncKmp().useResults{ _result -> 
        _result.mapNextRow(false) {
          _result.getBoolean(1)
        }
      }
    }
  }

  override fun updateStatusByClazzLogUid(
    clazzLogUid: Long,
    newStatus: Int,
    timeChanged: Long,
  ) {
    _db.prepareAndUseStatement(PreparedStatementConfig(
      sql = """
      |UPDATE ClazzLog 
      |        SET clazzLogStatusFlag = ?,
      |        clazzLogLastChangedTime = ?
      |        WHERE clazzLogUid = ?
      """.trimMargin(),
      readOnly = false,)
    ) { _stmt -> 
      _stmt.setInt(1,newStatus)
      _stmt.setLong(2,timeChanged)
      _stmt.setLong(3,clazzLogUid)
      _stmt.executeUpdate()
    }
  }

  override suspend fun findMostRecentClazzLogToEditUid(clazzUid: Long): Long =
      _db.prepareAndUseStatementAsync(PreparedStatementConfig(
    sql = """
    |
    |        SELECT COALESCE(
    |               (SELECT ClazzLog.clazzLogUid
    |                  FROM ClazzLog
    |                 WHERE ClazzLog.clazzLogClazzUid = ?
    |                   AND (ClazzLog.clazzLogStatusFlag & 8) != 8
    |              ORDER BY ClazzLog.logDate DESC
    |                 LIMIT 1), 0)
    |
    |        
    |    
    """.trimMargin(),
    readOnly = true,)
  ) { _stmt -> 
    _stmt.setLong(1,clazzUid)
    _stmt.executeQueryAsyncKmp().useResults{ _result -> 
      _result.mapNextRow(0L) {
        _result.getLong(1)
      }
    }
  }
}
