package ocelot.desktop.inventory.item

import ocelot.desktop.graphics.IconSource
import ocelot.desktop.inventory.item.HddItem.Hdd
import ocelot.desktop.inventory.traits.{ComponentItem, DiskItem, PersistableItem}
import ocelot.desktop.inventory.{Item, ItemFactory, ItemRecoverer}
import ocelot.desktop.ui.widget.tooltip.ItemTooltip
import totoro.ocelot.brain.entity.fs.{Label, ReadWriteLabel}
import totoro.ocelot.brain.entity.traits.{Disk, Entity, Environment}
import totoro.ocelot.brain.entity.{HDDManaged, HDDUnmanaged}
import totoro.ocelot.brain.util.Tier.Tier

class HddItem(var hdd: Hdd) extends Item with ComponentItem with PersistableItem with DiskItem {
  // constructors for deserialization as required by [[ComponentItem]]
  def this(hdd: HDDManaged) = {
    this(Hdd.Managed(hdd))
  }

  def this(hdd: HDDUnmanaged) = {
    this(Hdd.Unmanaged(hdd))
  }

  override def entity: Entity with Disk = hdd.hdd

  override def diskKind: String = "HDD"

  private def fsLabel: Label = hdd match {
    case Hdd.Managed(hdd) => hdd.fileSystem.label
    case Hdd.Unmanaged(hdd) => hdd.label
  }

  def diskLabel: Option[String] = fsLabel.labelOption

  override def diskLabel_=(label: Option[String]): Unit = fsLabel.setLabel(label.orNull)

  override def isLabelWriteable: Boolean = fsLabel.isInstanceOf[ReadWriteLabel]

  override def setManaged(managed: Boolean): Unit = {
    val label = this.diskLabel

    reinserting {
      hdd =
        if (managed) Hdd(new HDDManaged(tier.get))
        else Hdd(new HDDUnmanaged(tier.get))
    }

    diskLabel = label
  }

  override def fillTooltip(tooltip: ItemTooltip): Unit = {
    super.fillTooltip(tooltip)

    diskLabel.foreach(addDiskLabelTooltip(tooltip, _))

    hdd match {
      case Hdd.Managed(hdd) => addSourcePathTooltip(tooltip, hdd)
      case Hdd.Unmanaged(_) => // unmanaged HDDs don't need any special entries
    }

    addManagedTooltip(tooltip, hdd.hdd)
  }

  override def factory: HddItem.Factory = hdd match {
    case Hdd.Managed(hdd) => new HddItem.Factory(true, hdd.tier)
    case Hdd.Unmanaged(hdd) => new HddItem.Factory(false, hdd.tier)
  }
}

object HddItem {
  class Factory(managed: Boolean, _tier: Tier) extends ItemFactory {
    override type I = HddItem

    override def itemClass: Class[I] = classOf

    override def name: String = s"Hard Disk Drive (${_tier.label})"

    override def tier: Option[Tier] = Some(_tier)

    override def icon: IconSource = IconSource.Items.HardDiskDrive(_tier)

    override def build(): HddItem = new HddItem(
      if (managed) Hdd(new HDDManaged(_tier)) else Hdd(new HDDUnmanaged(_tier))
    )

    override def recoverers: Iterable[ItemRecoverer[_, _]] = Seq(
      ItemRecoverer((hdd: HDDManaged) => new HddItem(Hdd(hdd))),
      ItemRecoverer((hdd: HDDUnmanaged) => new HddItem(Hdd(hdd))),
    )
  }

  sealed trait Hdd {
    def hdd: Disk with Entity
  }

  object Hdd {
    case class Managed(hdd: HDDManaged) extends Hdd

    case class Unmanaged(hdd: HDDUnmanaged) extends Hdd

    def apply(hdd: HDDManaged): Hdd.Managed = Hdd.Managed(hdd)
    def apply(hdd: HDDUnmanaged): Hdd.Unmanaged = Hdd.Unmanaged(hdd)
  }
}
