package ocelot.desktop.graphics

import ocelot.desktop.geometry.Size2D
import ocelot.desktop.ui.widget.modal.notification.NotificationType.NotificationType
import totoro.ocelot.brain.entity.tape.Tape.{Kind => TapeKind}
import totoro.ocelot.brain.util.Direction.{Direction, Down, East, North, South, Up, West}
import totoro.ocelot.brain.util.DyeColor
import totoro.ocelot.brain.util.ExtendedTier.ExtendedTier
import totoro.ocelot.brain.util.Tier.Tier

case class IconSource(path: String, animation: Option[IconSource.Animation] = None)

object IconSource {
  case class Animation(frames: Array[(Int, Float)], frameSize: Option[Size2D])

  object Animation {
    def apply(frames: (Int, Float)*) = new Animation(frames.toArray, None)
    def apply(size: Size2D)(frames: (Int, Float)*) = new Animation(frames.toArray, Some(size))
    def apply(size: Option[Size2D] = None)(frames: Array[(Int, Float)]) = new Animation(frames, size)
  }

  class IconScope(directory: String)(implicit parent: Option[IconScope]) {
    // this makes nested `IconScope` declarations use `this` as their parent scope.
    implicit def scope: Option[IconScope] = Some(this)

    private def prefix: String = parent match {
      case Some(parent) => s"${parent.prefix}/$directory"
      case None => directory
    }

    protected def get(name: String): IconSource = {
      get(name, None)
    }

    protected def get(name: String, animation: Animation): IconSource = {
      get(name, Some(animation))
    }

    protected def get(name: String, animation: Option[Animation]): IconSource = {
      IconSource(s"$prefix/$name", animation)
    }
  }

  private implicit val scope: Option[IconScope] = None

  val Empty: IconSource = IconSource("Empty")
  val EmptySlot: IconSource = IconSource("EmptySlot")
  val ShadowCorner: IconSource = IconSource("ShadowCorner")
  val ShadowBorder: IconSource = IconSource("ShadowBorder")
  val TabArrow: IconSource = IconSource("TabArrow")
  val BarSegment: IconSource = IconSource("BarSegment")
  val BackgroundPattern: IconSource = IconSource("BackgroundPattern")
  val Logo: IconSource = IconSource("Logo")

  val Knob: IconSource = IconSource("Knob")
  val KnobLimits: IconSource = IconSource("KnobLimits")
  val KnobCenter: IconSource = IconSource("KnobCenter")

  val Loading: IconSource = IconSource(
    "Loading",
    Some(
      Animation(Size2D(48, 32))(
        (0, 0.7f),
        (1, 0.7f),
        (2, 0.7f),
        (3, 0.7f),
        (4, 0.7f),
        (5, 0.7f),
        (6, 0.7f),
        (7, 0.7f),
        (8, 0.7f),
        (9, 0.7f),
        (10, 0.7f),
        (11, 0.7f),
        (12, 0.7f),
        (13, 0.7f),
      )
    ),
  )

  object Items extends IconScope("items") {
    val Cpu: Tier => IconSource = { tier =>
      get(s"CPU${tier.id}")
    }

    val Apu: Tier => IconSource = { tier =>
      get(s"APU${tier.id}", Animations.Apu)
    }

    val GraphicsCard: Tier => IconSource = { tier =>
      get(s"GraphicsCard${tier.id}")
    }

    val NetworkCard: IconSource = get("NetworkCard")

    val WirelessNetworkCard: Tier => IconSource = { tier =>
      get(s"WirelessNetworkCard${tier.id}")
    }

    val LinkedCard: IconSource = get("LinkedCard", Animations.LinkedCard)

    val InternetCard: IconSource = get("InternetCard", Animations.InternetCard)

    val RedstoneCard: Tier => IconSource = { tier =>
      get(s"RedstoneCard${tier.id}")
    }

    val DataCard: Tier => IconSource = { tier =>
      get(s"DataCard${tier.id}", Animations.DataCard)
    }

    val SoundCard: IconSource = get("SoundCard", Animations.DataCard)

    val SelfDestructingCard: IconSource =
      get("SelfDestructingCard", Animations.SelfDestructingCard)

    val OcelotCard: IconSource = get("OcelotCard", Animations.OcelotCard)

    val HardDiskDrive: Tier => IconSource = { tier =>
      get(s"HardDiskDrive${tier.id}")
    }

    val Eeprom: IconSource = get("EEPROM")

    val FloppyDisk: DyeColor => IconSource = { color =>
      get(s"FloppyDisk_${color.name}")
    }

    val Memory: ExtendedTier => IconSource = { tier =>
      get(s"Memory${tier.id}")
    }

    val Server: Tier => IconSource = { tier =>
      get(s"Server${tier.id}")
    }

    val ComponentBus: Tier => IconSource = { tier =>
      get(s"ComponentBus${tier.id}")
    }

    val Tape: TapeKind => IconSource = {
      case TapeKind.Golder => Tape(TapeKind.Gold)
      case TapeKind.NetherStarrer => Tape(TapeKind.NetherStar)
      case kind => get(s"Tape$kind")
    }

    val DiskDriveMountable: IconSource = get("DiskDriveMountable")

    // noinspection ScalaWeakerAccess
    object Animations {
      val Apu: Animation =
        Animation((0, 3f), (1, 3f), (2, 3f), (3, 3f), (4, 3f), (5, 3f), (4, 3f), (3, 3f), (2, 3f), (1, 3f), (0, 3f))

      val LinkedCard: Animation =
        Animation((0, 3f), (1, 3f), (2, 3f), (3, 3f), (4, 3f), (5, 3f))

      val InternetCard: Animation =
        Animation((0, 2f), (1, 7f), (0, 5f), (1, 4f), (0, 7f), (1, 2f), (0, 8f), (1, 9f), (0, 6f), (1, 4f))

      val DataCard: Animation = Animation((0, 4f), (1, 4f), (2, 4f), (3, 4f), (4, 4f), (5, 4f), (6, 4f), (7, 4f))

      val SelfDestructingCard: Animation = Animation((0, 4f), (1, 4f))

      val OcelotCard: Animation =
        Animation((0, 12f), (1, 4f), (2, 4f), (3, 4f), (4, 5f), (5, 6f), (0, 9f), (6, 4f), (7, 3f))
    }
  }

  object Icons extends IconScope("icons") {
    val Card: IconSource = get("Card")
    val Cpu: IconSource = get("CPU")
    val Hdd: IconSource = get("HDD")
    val Eeprom: IconSource = get("EEPROM")
    val Floppy: IconSource = get("Floppy")
    val Memory: IconSource = get("Memory")
    val Server: IconSource = get("Server")
    val ComponentBus: IconSource = get("ComponentBus")

    val Tier: Tier => IconSource = { tier =>
      get(s"Tier${tier.id}")
    }

    val SideNone: IconSource = get("SideNone")
    val SideAny: IconSource = get("SideAny")
    val SideUndefined: IconSource = get("SideUndefined")
    val Side: Direction => IconSource = {
      case Down => get("SideDown")
      case Up => get("SideUp")
      case North => get("SideNorth")
      case South => get("SideSouth")
      case West => get("SideWest")
      case East => get("SideEast")
      case _ => SideUndefined
    }

    val Notification: NotificationType => IconSource = { notificationType =>
      get(s"Notification$notificationType")
    }

    val NA: IconSource = get("NA")
    val SettingsKeymap: IconSource = get("SettingsKeymap")
    val SettingsSystem: IconSource = get("SettingsSystem")
    val SettingsSound: IconSource = get("SettingsSound")
    val SettingsUI: IconSource = get("SettingsUI")
    val Delete: IconSource = get("Delete")
    val Label: IconSource = get("Label")
    val Copy: IconSource = get("Copy")
    val Cut: IconSource = get("Cut")
    val Paste: IconSource = get("Paste")
    val AspectRatio: IconSource = get("AspectRatio")
    val Eject: IconSource = get("Eject")
    val Restart: IconSource = get("Restart")
    val Edit: IconSource = get("Edit")
    val Folder: IconSource = get("Folder")
    val FolderSlash: IconSource = get("FolderSlash")
    val Code: IconSource = get("Code")
    val File: IconSource = get("File")
    val Link: IconSource = get("Link")
    val LinkSlash: IconSource = get("LinkSlash")
    val Power: IconSource = get("Power")
    val Save: IconSource = get("Save")
    val SaveAs: IconSource = get("SaveAs")
    val Plus: IconSource = get("Plus")
    val Cross: IconSource = get("Cross")
    val Microchip: IconSource = get("Microchip")
    val Antenna: IconSource = get("Antenna")
    val Window: IconSource = get("Window")
    val Tiers: IconSource = get("Tiers")
    val LinesHorizontal: IconSource = get("LinesHorizontal")
    val ArrowRight: IconSource = get("ArrowRight")
    val Book: IconSource = get("Book")
    val Help: IconSource = get("Help")
    val Ocelot: IconSource = get("Ocelot")
    val Guitar: IconSource = get("Guitar")
    val Keyboard: IconSource = get("Keyboard")
    val KeyboardOff: IconSource = get("KeyboardOff")
    val ButtonRandomize: IconSource = get("ButtonRandomize")
    val ButtonClipboard: IconSource = get("ButtonClipboard")
    val ButtonCheck: IconSource = get("ButtonCheck")
    val Home: IconSource = get("Home")
    val Pin: IconSource = get("Pin")
    val Unpin: IconSource = get("Unpin")
    val Close: IconSource = get("Close")
    val Grid: IconSource = get("Grid")
    val GridOff: IconSource = get("GridOff")
    val LMB: IconSource = get("LMB")
    val RMB: IconSource = get("RMB")
    val DragLMB: IconSource = get("DragLMB")
    val DragRMB: IconSource = get("DragRMB")

    val Play: IconSource = get("Play")
    val Pause: IconSource = get("Pause")

    val WireArrowLeft: IconSource = get("WireArrowLeft")
    val WireArrowRight: IconSource = get("WireArrowRight")

    val WaveSine: IconSource = get("WaveSine")
    val WaveTriangle: IconSource = get("WaveTriangle")
    val WaveSawtooth: IconSource = get("WaveSawtooth")
    val WaveSquare: IconSource = get("WaveSquare")
    val WaveNoise: IconSource = get("WaveNoise")
    val WaveLFSR: IconSource = get("WaveLFSR")
  }

  object Nodes extends IconScope("nodes") {
    val NewNode: IconSource = get("NewNode")

    val Cable: IconSource = get("Cable")
    val Camera: IconSource = get("Camera")
    val Chest: IconSource = get("Chest")

    val HologramProjector: Tier => IconSource = { tier =>
      get(s"HologramProjector${tier.id}")
    }

    val IronNoteBlock: IconSource = get("IronNoteBlock")
    val NoteBlock: IconSource = get("NoteBlock")
    val OpenFMRadio: IconSource = get("OpenFMRadio")
    val Relay: IconSource = get("Relay")
    val TapeDrive: IconSource = get("TapeDrive")

    val Lamp: IconSource = get("Lamp")
    val LampFrame: IconSource = get("LampFrame")
    val LampGlow: IconSource = get("LampGlow")

    object Computer extends IconScope("computer") with PowerIconSource with DiskActivityIconSource {
      val Default: IconSource = get("Default")
    }

    object DiskDrive extends IconScope("disk-drive") with DiskActivityIconSource with FloppyDriveIconSource {
      val Default: IconSource = get("Default")
    }

    object Microcontroller extends IconScope("microcontroller") with PowerIconSource {
      val Default: IconSource = get("Default")
    }

    object OcelotBlock extends IconScope("ocelot-block") {
      val Default: IconSource = get(
        "Default",
        Some(Animation(Size2D(16, 16))((0, 30f), (1, 5f), (2, 2f), (0, 20f), (3, 3f), (4, 2f))),
      )

      val Rx: IconSource = get("Rx")
      val Tx: IconSource = get("Tx")
    }

    object Rack extends IconScope("rack") {
      val Empty: IconSource = get("Empty")
      val Default: IconSource = get("Default")

      val Server: Array[Server] = Array.tabulate(4)(new Server(_))
      val Drive: Array[Drive] = Array.tabulate(4)(new Drive(_))

      class Server(val slot: Int)
        extends IconScope(s"server/$slot")
          with PowerIconSource
          with DiskActivityIconSource
          with NetworkActivityIconSource {

        val Default: IconSource = get("Default")
      }

      class Drive(val slot: Int)
        extends IconScope(s"drive/$slot")
          with DiskActivityIconSource
          with FloppyDriveIconSource {

        val Default: IconSource = get("Default")
      }
    }

    object Raid extends IconScope("raid") {
      val Default: IconSource = get("Default")

      val Drive: Array[Drive] = Array.tabulate(3)(new Drive(_))

      class Drive(val slot: Int) extends IconScope(slot.toString) with DiskActivityIconSource {
        val Error: IconSource = get("Error")
      }
    }

    object Screen extends IconScope("screen") {
      val Standalone: IconSource = get("Standalone")
      val PowerOnOverlay: IconSource = get("PowerOnOverlay")

      val ColumnTop: IconSource = get("ColumnTop")
      val ColumnMiddle: IconSource = get("ColumnMiddle")
      val ColumnBottom: IconSource = get("ColumnBottom")

      val RowLeft: IconSource = get("RowLeft")
      val RowMiddle: IconSource = get("RowMiddle")
      val RowRight: IconSource = get("RowRight")

      val TopLeft: IconSource = get("TopLeft")
      val TopMiddle: IconSource = get("TopMiddle")
      val TopRight: IconSource = get("TopRight")

      val MiddleLeft: IconSource = get("MiddleLeft")
      val Middle: IconSource = get("Middle")
      val MiddleRight: IconSource = get("MiddleRight")

      val BottomLeft: IconSource = get("BottomLeft")
      val BottomMiddle: IconSource = get("BottomMiddle")
      val BottomRight: IconSource = get("BottomRight")
    }

    object Holidays extends IconScope("holidays") {
      val Christmas: IconSource = get("Christmas")
      val Valentines: IconSource = get("Valentines")
      val Halloween: IconSource = get("Halloween")
    }
  }

  trait PowerIconSource extends IconScope {
    val On: IconSource = get("On")
    val Error: IconSource = get("Error")
  }

  trait DiskActivityIconSource extends IconScope {
    val DiskActivity: IconSource = get("DiskActivity")
  }

  trait NetworkActivityIconSource extends IconScope {
    val NetworkActivity: IconSource = get("NetworkActivity")
  }

  trait FloppyDriveIconSource extends IconScope {
    val Floppy: IconSource = get("Floppy")
  }

  object Screen extends IconScope("screen") {
    val InnerCornerTL: IconSource = get("InnerCornerTL")
    val InnerCornerTR: IconSource = get("InnerCornerTR")
    val InnerCornerBL: IconSource = get("InnerCornerBL")
    val InnerCornerBR: IconSource = get("InnerCornerBR")

    val OuterCornerTL: IconSource = get("OuterCornerTL")
    val OuterCornerTR: IconSource = get("OuterCornerTR")
    val OuterCornerBL: IconSource = get("OuterCornerBL")
    val OuterCornerBR: IconSource = get("OuterCornerBR")

    val InnerBorderT: IconSource = get("InnerBorderT")
    val OuterBorderT: IconSource = get("OuterBorderT")

    val InnerBorderB: IconSource = get("InnerBorderB")
  }

  object Particles extends IconScope("particles") {
    val Note: IconSource = get("Note")
    val Smoke: IconSource = get("Smoke")
  }

  object Buttons extends IconScope("buttons") {
    val BottomDrawerOpen: IconSource = get("BottomDrawerOpen")
    val BottomDrawerClose: IconSource = get("BottomDrawerClose")

    val PowerOff: IconSource = get("PowerOff")
    val PowerOn: IconSource = get("PowerOn")

    val OpenFMRadioVolumeOff: Boolean => IconSource = { isUp =>
      get(s"OpenFMRadioVolume${if (isUp) "Up" else "Down"}Off")
    }

    val OpenFMRadioVolumeOn: Boolean => IconSource = { isUp =>
      get(s"OpenFMRadioVolume${if (isUp) "Up" else "Down"}On")
    }

    val OpenFMRadioRedstoneOff: IconSource = get("OpenFMRadioRedstoneOff")
    val OpenFMRadioRedstoneOn: IconSource = get("OpenFMRadioRedstoneOn")

    val OpenFMRadioCloseOff: IconSource = get("OpenFMRadioCloseOff")
    val OpenFMRadioCloseOn: IconSource = get("OpenFMRadioCloseOn")

    val OpenFMRadioStartOff: IconSource = get("OpenFMRadioStartOff")
    val OpenFMRadioStopOn: IconSource = get("OpenFMRadioStopOn")

    val RackRelayOff: IconSource = get("RackRelayOff")
    val RackRelayOn: IconSource = get("RackRelayOn")
  }

  object Window extends IconScope("window") {
    val CornerTL: IconSource = get("CornerTL")
    val CornerTR: IconSource = get("CornerTR")
    val CornerBL: IconSource = get("CornerBL")
    val CornerBR: IconSource = get("CornerBR")

    val BorderLight: IconSource = get("BorderLight")
    val BorderDark: IconSource = get("BorderDark")

    object Tape extends IconScope("tape") {
      abstract class TapeButtonIconSource private[Tape] (sprite: String) {
        val Released: IconSource = get(sprite)
        val Pressed: IconSource = get(s"${sprite}Pressed")
      }

      object Back extends TapeButtonIconSource("Back")
      object Play extends TapeButtonIconSource("Play")
      object Stop extends TapeButtonIconSource("Stop")
      object Forward extends TapeButtonIconSource("Forward")

      val Screen: IconSource = get("Screen")
    }

    object Case extends IconScope("case") {
      val Motherboard: IconSource = get("Motherboard")
    }

    object Rack extends IconScope("rack") {
      val Motherboard: IconSource = get("Motherboard")
      val Lines: IconSource = get("Lines")

      trait DirectionIconSource {
        protected def iconPrefix: String

        val DirectionIcon: Direction => IconSource = { direction =>
          get(s"$iconPrefix${direction.side.capitalize}")
        }
      }

      trait ConnectorIconSource {
        protected def iconPrefix: String

        val Connector: IconSource = get(s"${iconPrefix}Connector")
      }

      object Side extends DirectionIconSource with ConnectorIconSource {
        override protected def iconPrefix: String = "Side"
      }

      object Network extends DirectionIconSource with ConnectorIconSource {
        override protected def iconPrefix: String = "Network"
      }

      object Node extends DirectionIconSource {
        override protected def iconPrefix: String = "Node"
      }
    }

    object Raid extends IconScope("raid") {
      val Slots: IconSource = get("Slots")
    }

    val OpenFMRadio: IconSource = get("OpenFMRadio")
  }

  object Panel extends IconScope("panel") {
    val CornerTL: IconSource = get("CornerTL")
    val CornerTR: IconSource = get("CornerTR")
    val CornerBL: IconSource = get("CornerBL")
    val CornerBR: IconSource = get("CornerBR")

    val BorderT: IconSource = get("BorderT")
    val BorderB: IconSource = get("BorderB")
    val BorderL: IconSource = get("BorderL")
    val BorderR: IconSource = get("BorderR")

    val Fill: IconSource = get("Fill")
  }

  object LightPanel extends IconScope("light-panel") {
    val CornerTL: IconSource = get("CornerTL")
    val CornerTR: IconSource = get("CornerTR")
    val CornerBL: IconSource = get("CornerBL")
    val CornerBR: IconSource = get("CornerBR")

    val BorderT: IconSource = get("BorderT")
    val BorderB: IconSource = get("BorderB")
    val BorderL: IconSource = get("BorderL")
    val BorderR: IconSource = get("BorderR")

    val Fill: IconSource = get("Fill")
    val Vent: IconSource = get("Vent")

    val BookmarkLeft: IconSource = get("BookmarkLeft")
    val BookmarkRight: IconSource = get("BookmarkRight")
  }
}
