/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package paging.android.example.com.pagingsample

import android.app.Application
import androidx.lifecycle.AndroidViewModel
import androidx.paging.*
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map

/**
 * A simple [AndroidViewModel] that provides a [Flow]<[PagingData]> of delicious cheeses.
 */
class CheeseViewModel(app: Application) : AndroidViewModel(app) {
    private val dao = CheeseDb.get(app).cheeseDao()

    /**
     * We use the Kotlin [Flow] property available on [Pager]. Java developers should use the
     * RxJava or LiveData extension properties available in `PagingRx` and `PagingLiveData`.
     */
    val allCheeses = Pager(
            PagingConfig(
                    /**
                     * A good page size is a value that fills at least a few screens worth of content on a
                     * large device so the User is unlikely to see a null item.
                     * You can play with this constant to observe the paging behavior.
                     *
                     * It's possible to vary this with list device size, but often unnecessary, unless a
                     * user scrolling on a large device is expected to scroll through items more quickly
                     * than a small device, such as when the large device uses a grid layout of items.
                     */
                    pageSize = 60,

                    /**
                     * If placeholders are enabled, PagedList will report the full size but some items might
                     * be null in onBind method (PagedListAdapter triggers a rebind when data is loaded).
                     *
                     * If placeholders are disabled, onBind will never receive null but as more pages are
                     * loaded, the scrollbars will jitter as new pages are loaded. You should probably
                     * disable scrollbars if you disable placeholders.
                     */
                    enablePlaceholders = true,

                    /**
                     * Maximum number of items a PagedList should hold in memory at once.
                     *
                     * This number triggers the PagedList to start dropping distant pages as more are loaded.
                     */
                    maxSize = 200
            )
    ) {
        dao.allCheesesByName()
    }
            .flow
            .map { cheeses ->
                cheeses
                        .map { CheeseRow.Item(it) }
                        .insertSeparators { before, after ->
                            if (after == null) {
                                // At the end of the list
                                null
                            } else {
                                if (before?.cheese?.name?.length ?: 0 > 9) {
                                    CheeseRow.Header("HEADER after " + before!!.cheese.name)
                                } else {
                                    null
                                }
                            }
                        }
            }


    fun insert(text: CharSequence) = ioThread {
        dao.insert(Cheese(id = 0, name = text.toString()))
    }

    fun remove(cheese: Cheese) = ioThread {
        dao.delete(cheese)
    }
}

sealed class CheeseRow {
    abstract val id: Int

    data class Item(val cheese: Cheese) : CheeseRow() {
        override val id: Int
            get() = cheese.id
    }

    data class Header(val text: String) : CheeseRow() {
        override val id: Int
            get() = text.hashCode()
    }
}