package edu.byu.support

import android.content.Context
import android.graphics.Canvas
import android.graphics.drawable.ColorDrawable
import android.support.v7.widget.RecyclerView
import android.support.v7.widget.helper.ItemTouchHelper
import edu.byu.support.adapter.ByuRecyclerAdapter
import edu.byu.support.utils.getColorFromRes
import edu.byu.support.utils.getDrawableFromRes

/**
 * Created by geogor37 on 5/29/18
 */
// We pass in 0 for the first argument of the parent constructor so that the viewHolders will not be draggable
abstract class ByuSwipeOnlyCallback<T>(protected val adapter: ByuRecyclerAdapter<*>, val context: Context, swipeDirs: Int): ItemTouchHelper.SimpleCallback(0, swipeDirs) {
	companion object {
		const val LEFT = ItemTouchHelper.LEFT
		const val RIGHT = ItemTouchHelper.RIGHT
		const val LEFT_AND_RIGHT = ItemTouchHelper.LEFT.or(ItemTouchHelper.RIGHT)
		const val NEITHER_DIRECTION = 0
	}

	@Suppress("UNCHECKED_CAST")
	// When deleting the swiped item, it's possible for onChildDraw to be called after the item is already deleted, which causes the below line of code to
	// throw an ArrayIndexOutOfBoundsException. When this happens we return null to stop drawing the background since the item is being deleted anyway.
	private fun getSwipedItem(viewHolder: RecyclerView.ViewHolder) = try {
		adapter.list[viewHolder.adapterPosition] as? T
	} catch (e: ArrayIndexOutOfBoundsException) {
		null
	}

	// This function should return either LEFT, RIGHT, LEFT_AND_RIGHT, or NEITHER_DIRECTION depending on whether viewHolder should be swipeable or not
	abstract fun getSwipeFlags(viewHolder: RecyclerView.ViewHolder): Int

	override fun getMovementFlags(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder) = makeMovementFlags(0, getSwipeFlags(viewHolder))

	override fun onMove(recyclerView: RecyclerView?, viewHolder: RecyclerView.ViewHolder?, target: RecyclerView.ViewHolder?) = false

	override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
		getSwipedItem(viewHolder)?.let { onSwiped(it, direction) }
	}

	// This function executes whatever action is supposed to occur when the user swipes viewHolder
	abstract fun onSwiped(swipedItem: T, direction: Int)

	// If the values returned from these first two functions are non-null then we will use them even if the other functions return something else, so make sure these return null
	// if you want to display different background colors or icons depending on the swipe direction.
	open fun getColorForBothDirections(swipedItem: T): Int? = null

	open fun getIconResForBothDirections(swipedItem: T): Int? = null

	open fun getColorForSwipeLeft(swipedItem: T): Int? = getColorForBothDirections(swipedItem)

	open fun getIconResForSwipeLeft(swipedItem: T): Int? = getIconResForBothDirections(swipedItem)

	open fun getColorForSwipeRight(swipedItem: T): Int? = getColorForBothDirections(swipedItem)

	open fun getIconResForSwipeRight(swipedItem: T): Int? = getIconResForBothDirections(swipedItem)

	override fun onChildDraw(c: Canvas?, recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, dX: Float, dY: Float, actionState: Int, isCurrentlyActive: Boolean) {
		val swipeLeft = dX < 0
		val swipedItem = getSwipedItem(viewHolder)
		val backgroundColor = swipedItem?.let { if (swipeLeft) getColorForSwipeLeft(it) else getColorForSwipeRight(it) }
		val iconResource = swipedItem?.let { if (swipeLeft) getIconResForSwipeLeft(it) else getIconResForSwipeRight(it) }

		val cell = viewHolder.itemView
		if (backgroundColor != null) {
			val background = ColorDrawable()
			background.color = context.getColorFromRes(backgroundColor)
			background.setBounds(cell.left, cell.top, cell.right, cell.bottom)
			background.draw(c)
		}

		if (iconResource != null) {
			val cellHeight = cell.height
			context.getDrawableFromRes(iconResource)?.let { icon ->
				// Center the icon vertically in the cell and set the margin equal to the space left between the top of the cell and the top of the icon.
				val margin = (cellHeight - icon.intrinsicHeight) / 2
				val top = cell.top + margin
				val bottom = top + icon.intrinsicHeight
				// Place the icon on either the left or the right, depending on which way the user is swiping.
				val left = if (swipeLeft) cell.right - margin - icon.intrinsicWidth else cell.left + margin
				val right = if (swipeLeft) cell.right - margin else cell.left + margin + icon.intrinsicWidth
				icon.setBounds(left, top, right, bottom)
				icon.draw(c)
			}
		}
		super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive)
	}
}