#==============================================================================
# ** Multiple Simultaneous Animations
#-----------------------------------------------------------------------------------------------------------------------------------------
#  A sprite class with animation display processing added.
#  Made by Cuauhtemoc
#  Terms of use: Credit me
#  NOT compatible with Yanfly's Melody Engine.
#==============================================================================

class Sprite_Base < Sprite
  #--------------------------------------------------------------------------
  # * Class Variable
  #--------------------------------------------------------------------------
  @@animations = []
  @@_reference_count = {}
  #--------------------------------------------------------------------------
  # * Object Initialization
  #     viewport : viewport
  #--------------------------------------------------------------------------
  def initialize(viewport = nil)
    super(viewport)
    @animation = {}
    @use_sprite = true          # Sprite use flag
  end
  #--------------------------------------------------------------------------
  # * Dispose
  #--------------------------------------------------------------------------
  def dispose
    super
    dispose_everything
  end
  #--------------------------------------------------------------------------
  # * Frame Update
  #--------------------------------------------------------------------------
  def update
    super
    if @animation.size > 0
      @animation.each_value{ |animation|
        animation[16] -= 1
        update_animation(animation)
        }
    end
  end
  #--------------------------------------------------------------------------
  # * Determine if animation is being displayed
  #--------------------------------------------------------------------------
  def animation?
    return @animation.size > 0
  end
  #--------------------------------------------------------------------------
  # * Start Animation
  #--------------------------------------------------------------------------
  def start_animation(animation, mirror = false, loop = nil)
    animation_data = []    
    return if animation == nil
    if @animation.has_key?(animation.name)
      temp = @animation[animation.name]
      return if temp[15]
      @animation[animation.name][16] = temp[17]
      return
    end
    animation_data[0] = animation
    animation_data[1] = mirror
    animation_data[2] = animation.frame_max * 3 + 1 
    animation_data = load_animation_bitmap(animation_data)
    animation_sprites = []
    if animation.position != 3
      if @use_sprite
        for i in 0..15
          sprite = ::Sprite.new(viewport)
          sprite.visible = false
          animation_sprites.push(sprite)
        end
      end
    end
    animation_data[3] = animation_sprites
    if animation_data[0].position == 3
      if viewport == nil
        animation_data[4] = Graphics.width / 2
        animation_data[5] = Graphics.height / 2
      else
        animation_data[4] = viewport.rect.width / 2
        animation_data[5] = viewport.rect.height / 2
      end
    else
     animation_data[4] = x - ox + width / 2
     animation_data[5] = y - oy + height / 2
      if animation_data[0].position == 0
        animation_data[5] -= height / 2
      elsif animation_data[0].position == 2
        animation_data[5] += height / 2
      end
    end
    if loop != nil
      animation_data[15] = true if loop == animation.name
    end
    @animation[animation.name] = animation_data
  end
  #--------------------------------------------------------------------------
  # * Read (Load) Animation Graphics
  #--------------------------------------------------------------------------
  def load_animation_bitmap(animation_data)
    animation = animation_data[0]
    animation_data[6] = animation.animation1_name
    animation_data[7] = animation.animation1_hue
    animation_data[8] = animation.animation2_name
    animation_data[9] = animation.animation2_hue
    
    if animation_data[6].include?("Anim")
      animation_data[10] = true 
      animation_data[12] = Cache.animation(animation_data[6], animation_data[7]).dup
    else
      animation_data[10] = false
      animation_data[12] = Cache.animation(animation_data[6], animation_data[7])
    end
    
    if animation_data[8].include?("Anim")
      animation_data[11] = true 
      animation_data[13] = Cache.animation(animation_data[8], animation_data[9]).dup
    else
      animation_data[11] = false
      animation_data[13] = Cache.animation(animation_data[8], animation_data[9])
    end
    
    if animation_data[10] or animation_data[11]
      animation_data[16] = animation_data[0].frame_max * 2 + 1
      animation_data[17] = animation_data[0].frame_max * 2 + 1
      animation_data[14] = 2
    else
      animation_data[16]  = animation_data[0].frame_max * 3 + 1
      animation_data[17]  =  animation_data[0].frame_max * 3 + 1
      animation_data[14]  = 3
    end
     Graphics.frame_reset
     return animation_data
  end
  #--------------------------------------------------------------------------
  # * Dispose of Animation
  #--------------------------------------------------------------------------
  def dispose_animation(animation)
    if animation.is_a?(Array)
      name = animation[0].name
      if animation[12] != nil
        animation[12].dispose 
        Cache.free(animation[0].animation1_name) if !animation[10]
      end
      if animation[13] != nil
       animation[13].dispose 
       Cache.free(animation[0].animation2_name) if !animation[11]
      end
      if animation[3] != nil
        for sprite in animation[3]
          sprite.dispose
        end
        animation[3] = nil
        animation[0] = nil
      end
      animation[12] = nil
      animation[13] = nil
    elsif animation.is_a?(RPG::Animation)
      dispose_animation(@animation[animation.name])
      return
    end
    return name
  end
  #--------------------------------------------------------------------------
  # * Disposes of every animation stored in the animation hash
  #--------------------------------------------------------------------------
  def dispose_everything
    return if @animation == nil
      @animation.each_pair{ |key, animation|
      if animation[3] != nil
        for sprite in animation[3]
          sprite.dispose
        end
        animation[3] = nil
      end
      if animation[12] != nil
        animation[12].dispose
        Cache.free(animation[0].animation1_name) if !animation[10]
      end
      if animation[13] != nil
        animation[13].dispose
        Cache.free(animation[0].animation2_name) if !animation[11]
      end
      animation[0] = nil
      @animation[key] = nil
      }
      @animation.clear
      GC.start
      @animation = nil
    end
  #--------------------------------------------------------------------------
  # * Stops a looping animation from looping again
  #--------------------------------------------------------------------------
  def stop_loop(name)
    if @animation.has_key?(name)
      animation = @animation[name]
      animation[15] = false
      animation[17]  =  animation[0].frame_max * 2 + 1
      @animation[name] = animation
    end
  end
  #--------------------------------------------------------------------------
  # * Update Animation
  #--------------------------------------------------------------------------
  def update_animation(animation)
    if animation[15]
      if animation[16] > 0
        frame_index = animation[0].frame_max - (animation[16] + animation[14] - 1) / animation[14]
        animation_set_sprites(animation[0].frames[frame_index], animation)
        if animation[16] % animation[14] == 0
          for timing in animation[0].timings
            next unless timing.frame == frame_index
              animation_process_timing(timing, animation[14])
          end
        end
      elsif animation[16] <= 0
        animation[16] = animation[17]
      end
    elsif animation[16] > 0
      frame_index = animation[0].frame_max - (animation[16] + animation[14] - 1) / animation[14]
      animation_set_sprites(animation[0].frames[frame_index], animation)
      if animation[16] % animation[14] == 0
      for timing in animation[0].timings
        next unless timing.frame == frame_index
          animation_process_timing(timing, animation[14])
      end
      end
    else
      @animation.delete(dispose_animation(animation))
    end
  end
  #--------------------------------------------------------------------------
  # * Set Animation Sprite
  #     frame : Frame data (RPG::Animation::Frame)
  #--------------------------------------------------------------------------
  def animation_set_sprites(frame, animation)
    cell_data = frame.cell_data
    for i in 0..15
      sprite = animation[3][i]
      next if sprite == nil
      pattern = cell_data[i, 0]
      if pattern == nil or pattern == -1
        sprite.visible = false
        next
      end
      if pattern < 100
        sprite.bitmap = animation[12]
      else
        sprite.bitmap = animation[13]
      end
      sprite.visible = true
      
      if animation[10] and (sprite.bitmap == animation[12])
        anim_height = 240
        anim_width = animation[12].width / 5
      elsif animation[11] and (sprite.bitmap == animation[13])
        anim_height = 240
        anim_width = animation[13].width / 5
      else
        anim_height = 192
        anim_width = 192
      end
      
      sprite.src_rect.set(pattern % 5 * anim_width,
        pattern % 100 / 5 * anim_height, anim_width, anim_height)
      if animation[1]
        sprite.x = animation[4] - cell_data[i, 1]
        sprite.y = animation[5] + cell_data[i, 2]
        sprite.angle = (360 - cell_data[i, 4])
        sprite.mirror = (cell_data[i, 5] == 0)
      else
        sprite.x = animation[4] + cell_data[i, 1]
        sprite.y = animation[5] + cell_data[i, 2]
        sprite.angle = cell_data[i, 4]
        sprite.mirror = (cell_data[i, 5] == 1)
      end
      sprite.z = self.z + 300 + i
      sprite.ox = anim_width / 2
      sprite.oy = anim_height / 2
      sprite.zoom_x = cell_data[i, 3] / 100.0
      sprite.zoom_y = cell_data[i, 3] / 100.0
      sprite.opacity = cell_data[i, 6] * self.opacity / 255.0
      sprite.blend_type = cell_data[i, 7]
    end
  end
  #--------------------------------------------------------------------------
  # * SE and Flash Timing Processing
  #     timing : timing data (RPG::Animation::Timing)
  #--------------------------------------------------------------------------
  def animation_process_timing(timing, rate)
    timing.se.play
    case timing.flash_scope
    when 1
      self.flash(timing.flash_color, timing.flash_duration * rate)
    when 2
      if viewport != nil
        viewport.flash(timing.flash_color, timing.flash_duration * rate)
      end
    when 3
      self.flash(nil, timing.flash_duration * rate)
    end
  end
end
#--------------------------------------------------------------------------
# * Module: Cache addition
#     Adds a method for disposing bitmap resources
#--------------------------------------------------------------------------
module Cache
  #--------------------------------------------------------------------------
  # * Deletes a part of the stored hashed animation
  #--------------------------------------------------------------------------
  def self.free(filename)
    @cache.delete("Graphics/Animations/"+filename)
  end
end