class PurifyChamberSet
  attr_accessor :facing
  attr_accessor :shadow

  def partialSum(x)
    return (x*x+x)/2 # pattern: 1 3 6 10 15 21 28 ...
  end

  def length
	  return @list.length
  end

  def initialize
    @list=[] 
    @facing=0
  end

  def facing=(value)
	  if value>=0 && value<@list.length  
	    @facing=value
	  end
  end

  def shadow=(value)
	  if value==nil || value.isShadow?
		  @shadow=value
	  end
  end

=begin
Main component is tempo
Boosted if center has advantage over facing Pokemon
Boosted based on number of best circles
=end
  def flow
	  ret=0
	  return 0 if !@shadow
	  for i in 0...@list.length
	    ret+=(PurifyChamberSet.isSuperEffective(@list[i],@list[(i+1)%@list.length])) ? 1 : 0
	  end
	  if @list[@facing]
		  ret+=PurifyChamberSet.isSuperEffective(@shadow,@list[@facing]) ? 1 : 0
	  end
	  return [ret+(@list.length/2),4].min
  end

  def shadowAffinity
    return 0 if @facing<0 || @facing>=@list.length || !@shadow
    return (PurifyChamberSet.isSuperEffective(@shadow,@list[@facing])) ? 2 : 1       
  end

  def affinity(i)
    return 0 if i<0 || i>=@list.length
    return (PurifyChamberSet.isSuperEffective(@list[i],@list[(i+1)%@list.length])) ? 2 : 1
  end

# Tempo refers to the type advantages of each Pokemon in a certain set in a
# clockwise direction. Tempo also depends on the number of Pokemon in the set
  def tempo
	  ret=0
	  for i in 0...@list.length
		  ret+=(PurifyChamberSet.isSuperEffective(@list[i],@list[(i+1)%@list.length])) ? 1 : 0
	  end
	  return partialSum(@list.length)+ret
  end

  def list
	  return @list.clone
  end

  def [](index)
	  return @list[index]
  end

  def insertAfter(index,value)
    return if self.length>=PurifyChamber::SETSIZE
    return if index<0 || index>=PurifyChamber::SETSIZE
    if !value || !value.isShadow?
      @list.insert(index+1,value)
      @list.compact!
      if @facing>index && value!=nil
        @facing+=1
      end
      @facing=[[@facing,@list.length-1].min,0].max
    end
  end

  def insertAt(index,value)
    return if index<0 || index>=PurifyChamber::SETSIZE
    if !value || !value.isShadow?
      @list[index]=value
      @list.compact!
      @facing=[[@facing,@list.length-1].min,0].max
    end 
  end

# Purify Chamber treats Normal/Normal matchup as super effective
  def self.typeAdvantage(p1,p2)
    if isConst?(p1,PBTypes,:NORMAL) && isConst?(p2,PBTypes,:NORMAL)
      return true
    end
    return PBTypes.isSuperEffective?(p1,p2)
  end

  def self.isSuperEffective(p1,p2)
    if typeAdvantage(p1.type1,p2.type1) || typeAdvantage(p1.type1,p2.type2)
      return true
    end
    return false
  end
end



class PurifyChamber # German: der Kryptorbis
  NUMSETS=9
  SETSIZE=4
  attr_accessor :currentSet # German: das Forum

  def self.maximumTempo() # Calculates the maximum possible tempo
    x=SETSIZE+1
    return ((x*x+x)/2)-1 
  end

  def initialize
    @sets=[]
    @currentSet=0
    NUMSETS.times {|i| 
       @sets[i]=PurifyChamberSet.new
    }
  end

  def currentSet=(value)
    if value>=0 && value<NUMSETS
      @currentSet=value
    end
  end

# Number of regular Pokemon in a set
  def setCount(set)
    return @sets[set].length
  end

  def setList(set)
    return [] if set<0 || set>=NUMSETS
    return @sets[set].list
  end

  def chamberFlow(chamber) # for speeding up purification. German: Fluidum
    return 0 if chamber<0 || chamber>=NUMSETS
    return @sets[chamber].flow
  end

  def getShadow(chamber)
    return nil if chamber<0 || chamber>=NUMSETS
    return @sets[chamber].shadow
  end

  def setShadow(chamber,value)# allow only "shadow" Pokemon
    return if chamber<0 || chamber>=NUMSETS
    @sets[chamber].shadow=value
  end

  def switch(set1,set2)
    return if set1<0 || set1>=NUMSETS
    return if set2<0 || set2>=NUMSETS
    s=@sets[set1]
    @sets[set1]=@sets[set2]
    @sets[set2]=s
  end

  def insertAfter(set,index,value)
    return if set<0 || set>=NUMSETS
    @sets[set].insertAfter(index,value)
  end

  def insertAt(set,index,value)
    return if set<0 || set>=NUMSETS
    @sets[set].insertAt(index,value)
  end

  def [](chamber,slot=nil)
    if slot==nil
      return @sets[chamber]
    end
    return nil if chamber<0 || chamber>=NUMSETS
    return nil if slot<0 || slot>=SETSIZE
    return @sets[chamber][slot]
  end

  def isPurifiableIgnoreRegular?(set)
    shadow=getShadow(set)
    return false if !shadow
    return false if shadow.heartgauge!=0
    # Define an exception for Lugia
    if isConst?(shadow.species,PBSpecies,:LUGIA)
      maxtempo=PurifyChamber.maximumTempo()
      for i in 0...NUMSETS
        return false if @sets[i].tempo!=maxtempo
      end
    end
    return true
  end

  def isPurifiable?(set)
    isPurifiableIgnoreRegular?(set) && setCount(set)>0
  end

  def update # called each step
    for set in 0...NUMSETS
      # If a shadow Pokemon and a regular Pokemon are on the same set
      count=setCount(set)
      if @sets[set].shadow
        if @sets[set].shadow.heartgauge>0
          flow=self.chamberFlow(set)
          @sets[set].shadow.adjustHeart(-flow)
          if isPurifiable?(set)
            Kernel.pbMessage(_INTL("Your {1} in the Purify Chamber is ready for purification!",@sets[set].shadow.name))
          end
        end
      end
    end
  end

  def debugAddShadow(set,species)
    species=getID(PBSpecies,species)
    pkmn=PokeBattle_Pokemon.new(species,1)
    pkmn.makeShadow
    setShadow(set,pkmn)
  end

  def debugAddNormal(set,species)
    species=getID(PBSpecies,species)
    pkmn=PokeBattle_Pokemon.new(species,1)
    insertAfter(set,setCount(set),pkmn)
  end

  def debugAdd(set,shadow,type1,type2=nil)
    species=getID(PBSpecies,species)
    pkmn=PseudoPokemon.new(shadow,type1,type2||type1)
    if pkmn.isShadow?
 	   self.setShadow(set,pkmn)
    else
 	   self.insertAfter(set,setCount(set),pkmn)
    end
  end
end



class PokemonGlobalMetadata
  attr_accessor :purifyChamber
  attr_accessor :seenPurifyChamber

  def purifyChamber
    if !@purifyChamber
      @purifyChamber=PurifyChamber.new()
    end
	  return @purifyChamber
  end
end



class PurifyChamberPC
  def shouldShow?
    return $PokemonGlobal.seenPurifyChamber
  end

  def name
    return _INTL("Purify Chamber")
  end

  def access
    Kernel.pbMessage(_INTL("\\se[accesspc]Accessed the Purify Chamber."))
    pbPurifyChamber()
  end
end



PokemonPCList.registerPC(PurifyChamberPC.new)

#####################
#
#  General purpose utilities
#

def pbDrawGauge(bitmap,rect,color,value,maxValue)
  return if !bitmap
  bitmap.fill_rect(rect.x,rect.y,rect.width,rect.height,Color.new(0,0,0))
  width=(maxValue<=0) ? 0 : (rect.width-4)*value/maxValue
  if rect.width>=4 && rect.height>=4
    bitmap.fill_rect(rect.x+2,rect.y+2,rect.width-4,rect.height-4,Color.new(248,248,248))
    bitmap.fill_rect(rect.x+2,rect.y+2,width,rect.height-4,color)
  end
end

def calcPoint(x,y,distance,angle) # angle in degrees
  angle -=(angle/360.0).floor*360 # normalize
  angle = (angle/360.0)*(2*Math::PI) # convert to radians
  angle = -angle % (2*Math::PI) # normalize radians
  point = [(Math.cos(angle) * distance), (Math.sin(angle) * distance)]
  point[0] += x
  point[1] += y
  return point
end


#####################


module PurifyChamberHelper
  def self.pbGetPokemon2(chamber,set,position)
    if position==0
      return chamber.getShadow(set)
    elsif position>0
      position-=1
      if position%2==0
        return chamber[set,position/2]
      else # In between two indices
        return nil
      end
    end
    return nil
  end

  def self.pbGetPokemon(chamber,position)
    if position==0
      return chamber.getShadow(chamber.currentSet)
    elsif position>0
      position-=1
      if position%2==0
        return chamber[chamber.currentSet,position/2]
      else # In between two indices
        return nil
      end
    end
    return nil
  end

  def self.adjustOnInsert(position)
    if position>0
 	    position-=1
 	    oldpos=position/2
 	    if position%2==0
        return position+1
 	    else
	      return ((oldpos+1)*2)+1
	    end
    end
    return position
  end

  def self.pbSetPokemon(chamber,position,value)
    if position==0
      chamber.setShadow(chamber.currentSet,value)
    elsif position>0
      position-=1
      if position%2==0
        chamber.insertAt(chamber.currentSet,position/2,value)
      else # In between two indices
        chamber.insertAfter(chamber.currentSet,position/2,value)
      end
    end
  end	
end



class PurifyChamberScreen
  def initialize(scene)
    @scene=scene
    @chamber=$PokemonGlobal.purifyChamber
#   for j in 0...PurifyChamber::NUMSETS
#     @chamber.debugAddShadow(j,rand(100)+1)
#     @chamber[j].shadow.heartgauge=0
#     for i in 0...PurifyChamber::SETSIZE
#       @chamber.debugAddNormal(j,rand(100)+1)
#     end
#   end
  end

  def pbPlace(pkmn,position)
    return false if !pkmn
    if pkmn.isEgg?
      @scene.pbDisplay(_INTL("Can't place an egg there."))
      return false
    end  
    if (position==0)
      if pkmn.isShadow?
        # Remove from storage and place in set
        oldpkmn=PurifyChamberHelper.pbGetPokemon(@chamber,position)
        if oldpkmn
          @scene.pbShift(position,pkmn)
        else
          @scene.pbPlace(position,pkmn)
	      end
	      PurifyChamberHelper.pbSetPokemon(@chamber,position,pkmn)
        @scene.pbRefresh()
      else
        @scene.pbDisplay(_INTL("Only a Shadow Pokémon can go there."))
        return false
      end
    elsif (position>=1)
      if !pkmn.isShadow?
        oldpkmn=PurifyChamberHelper.pbGetPokemon(@chamber,position)
        if oldpkmn
          @scene.pbShift(position,pkmn)
        else
          @scene.pbPlace(position,pkmn)
	      end
	      PurifyChamberHelper.pbSetPokemon(@chamber,position,pkmn)
        @scene.pbRefresh()
      else
        @scene.pbDisplay(_INTL("Can't place a Shadow Pokémon there."))
        return false
      end
    end
    return true
  end

  def pbPlacePokemon(pos,position)
    return false if !pos
    pkmn=$PokemonStorage[pos[0],pos[1]]
    if pbPlace(pkmn,position)
      $PokemonStorage.pbDelete(pos[0],pos[1])
      return true
    end
    return false
  end

  def pbOnPlace(pkmn)
    set=@chamber.currentSet
    if @chamber.setCount(set)==0 && @chamber.isPurifiableIgnoreRegular?(set)
      pkmn=@chamber.getShadow(set)
      @scene.pbDisplay(
         _INTL("This {1} is ready to open its heart. However, there must be at least one regular Pokémon in the set to perform a purification ceremony.",pkmn.name))
    end
  end

  def pbOpenSetDetail
    chamber=@chamber
    @scene.pbOpenSetDetail(chamber.currentSet)
    selected=nil
    heldpkmn=nil
    loop do
      # Commands
      # array[0]==0 - a position was chosen
      # array[0]==1 - a new set was chosen
      # array[0]==2 - choose Pokemon command
      cmd=@scene.pbSetScreen()
      if cmd[0]==0
        # Place Pokemon in the set
        curpkmn=PurifyChamberHelper.pbGetPokemon(@chamber,cmd[1])
        if curpkmn || heldpkmn
          commands=[_INTL("MOVE"),_INTL("SUMMARY"),
             _INTL("WITHDRAW")]
          if curpkmn && heldpkmn
            commands[0]=_INTL("EXCHANGE")
          elsif heldpkmn
            commands[0]=_INTL("PLACE")
          end
          cmdReplace=-1
          cmdRotate=-1
          if !heldpkmn && curpkmn && cmd[1]==0 &&
             @chamber[@chamber.currentSet].length>0
            commands[cmdRotate=commands.length]=_INTL("ROTATE")
          end
          if !heldpkmn && curpkmn
            commands[cmdReplace=commands.length]=_INTL("REPLACE")
          end
	        commands.push(_INTL("CANCEL"))
          choice=@scene.pbShowCommands(
             _INTL("What shall I do with this {1}?",
             heldpkmn ? heldpkmn.name : curpkmn.name),commands)
          if choice==0
            if heldpkmn
              if pbPlace(heldpkmn,cmd[1]) # calls place or shift as appropriate
                if !curpkmn
                  pbOnPlace(heldpkmn)
			            @scene.pbPositionHint(PurifyChamberHelper.adjustOnInsert(cmd[1]))
                  heldpkmn=nil # Pokemon was placed
                else
                  heldpkmn=curpkmn # Pokemon was shifted
                end
              end
            else
              @scene.pbMove(cmd[1])
              PurifyChamberHelper.pbSetPokemon(@chamber,cmd[1],nil)
              @scene.pbRefresh()
              heldpkmn=curpkmn
            end
          elsif choice==1
            @scene.pbSummary(cmd[1],heldpkmn)
          elsif choice==2
            if pbBoxesFull?
              @scene.pbDisplay("All boxes are full.")
            elsif heldpkmn
              @scene.pbWithdraw(cmd[1],heldpkmn)
              $PokemonStorage.pbStoreCaught(heldpkmn)
              heldpkmn=nil
              @scene.pbRefresh()
		        else
              # Store and delete Pokemon.
              @scene.pbWithdraw(cmd[1],heldpkmn)
              $PokemonStorage.pbStoreCaught(curpkmn)
              PurifyChamberHelper.pbSetPokemon(@chamber,cmd[1],nil)
              @scene.pbRefresh()
            end
          elsif cmdRotate>=0 && choice==cmdRotate
            count=@chamber[@chamber.currentSet].length
            nextPos=@chamber[@chamber.currentSet].facing
            if count>0
              @scene.pbRotate((nextPos+1)%count)
              @chamber[@chamber.currentSet].facing=(nextPos+1)%count
              @scene.pbRefresh()
            end
          elsif cmdReplace>=0 && choice==cmdReplace
            pos=@scene.pbChoosePokemon()
            if pos
              newpkmn=$PokemonStorage[pos[0],pos[1]]
              if newpkmn
                if (newpkmn.isShadow?)!=(curpkmn.isShadow?)
                  @scene.pbDisplay(_INTL("That Pokémon can't be placed there."))
                else
                  @scene.pbReplace(cmd,pos)
                  PurifyChamberHelper.pbSetPokemon(@chamber,cmd[1],newpkmn)
                  $PokemonStorage[pos[0],pos[1]]=curpkmn
    		          @scene.pbRefresh()
                  pbOnPlace(curpkmn)
                end
              end
            end
          end
        else  # No current Pokemon
          pos=@scene.pbChoosePokemon()
          if pbPlacePokemon(pos,cmd[1])
            curpkmn=PurifyChamberHelper.pbGetPokemon(@chamber,cmd[1])
            pbOnPlace(curpkmn)
		        @scene.pbPositionHint(PurifyChamberHelper.adjustOnInsert(cmd[1]))
          end
        end
      elsif cmd[0]==1 # Change the active set
        @scene.pbChangeSet(cmd[1])
        chamber.currentSet=cmd[1]
      elsif cmd[0]==2 # Choose a Pokemon
        pos=@scene.pbChoosePokemon()
        pkmn=pos ? $PokemonStorage[pos[0],pos[1]] : nil
        heldpkmn=pkmn if pkmn
      else # cancel
        if heldpkmn
          @scene.pbDisplay("You're holding a Pokémon!")
        else
          if !@scene.pbConfirm("Continue editing sets?")
            break
          end
        end
      end
    end
    if pbCheckPurify()
      @scene.pbDisplay(_INTL("There is a Pokemon that is ready to open its heart!\1"))
      @scene.pbCloseSetDetail()
      pbDoPurify()
      return false
    else
      @scene.pbCloseSetDetail()
      return true
    end
  end

  def pbDisplay(msg)
    @scene.pbDisplay(msg)
  end

  def pbConfirm(msg)
    @scene.pbConfirm(msg)
  end

  def pbRefresh
    @scene.pbRefresh
  end

  def pbCheckPurify
    purifiables=[]
    for set in 0...PurifyChamber::NUMSETS
      if @chamber.isPurifiable?(set) # if ready for purification
        purifiables.push(set)
      end
      return purifiables.length>0
    end
  end

  def pbDoPurify
    purifiables=[]
    for set in 0...PurifyChamber::NUMSETS
      if @chamber.isPurifiable?(set) # if ready for purification
        purifiables.push(set)
      end
    end
    for i in 0...purifiables.length
      set=purifiables[i]
      @chamber.currentSet=set
      @scene.pbOpenSet(set)
      @scene.pbPurify()
      pbPurify(@chamber[set].shadow,self)
      pbStorePokemon(@chamber[set].shadow)
      @chamber.setShadow(set,nil) # Remove shadow Pokemon from set
      if (i+1)!=purifiables.length
        @scene.pbDisplay(_INTL("There is another Pokemon that is ready to open its heart!"))  
        if !@scene.pbConfirm("Would you like to switch sets?")
          @scene.pbCloseSet()
          break
        end  
      end
      @scene.pbCloseSet()
    end
  end

  def pbStartPurify
    chamber=@chamber
    @scene.pbStart(chamber)
    if pbCheckPurify()
      pbDoPurify()
      @scene.pbEnd()
      return
    end
    alreadyopen=false
    @scene.pbOpenSet(chamber.currentSet)
    loop do
      set=@scene.pbChooseSet
      if set<0
        if !@scene.pbConfirm("Continue viewing holograms?")
          break
        end
      else
        chamber.currentSet=set
        cmd=@scene.pbShowCommands(
           _INTL("What do you want to do?"),[
           _INTL("EDIT"),_INTL("SWITCH"),_INTL("CANCEL")])
        if cmd==0 # edit
          if !pbOpenSetDetail()
            break
          end
        elsif cmd==1 # switch
          chamber.currentSet=set
          newSet=@scene.pbSwitch(set)
          chamber.switch(set,newSet)
          chamber.currentSet=newSet
          @scene.pbRefresh()
        end
      end
    end
    @scene.pbCloseSet()
    @scene.pbEnd()
  end
end


################################################


class Window_PurifyChamberSets < Window_DrawableCommand
  attr_accessor :switching

  def initialize(chamber,x,y,width,height,viewport=nil)
    @chamber=chamber
    @switching=-1
    super(x,y,width,height,viewport)
  end

  def itemCount
    return PurifyChamber::NUMSETS
  end

  def switching=(value)
    @switching=value; refresh
  end

  def drawItem(index,count,rect)
    textpos=[]
    rect=drawCursor(index,rect)
    if index==@switching
      textpos.push([_ISPRINTF("{1:d}",index+1),rect.x,
         rect.y,false,Color.new(248,0,0),self.shadowColor])
    else
      textpos.push([_ISPRINTF("{1:d}",index+1),rect.x,
         rect.y,false,self.baseColor,self.shadowColor])
    end
    if @chamber.setCount(index)>0
      pbDrawGauge(self.contents,Rect.new(rect.x+16,rect.y+6,48,8),
         Color.new(0,0,256),@chamber[index].tempo,PurifyChamber.maximumTempo())
    end
    if @chamber.getShadow(index)
      pbDrawGauge(self.contents,Rect.new(rect.x+16,rect.y+18,48,8),
         Color.new(192,0,256),@chamber.getShadow(index).heartgauge,
         PokeBattle_Pokemon::HEARTGAUGESIZE)
    end
    pbDrawTextPositions(self.contents,textpos)
  end
end



class DirectFlowDiagram
  def initialize(viewport=nil)
    @points=[]
    @angles=[]
    @viewport=viewport
    @strength=0
    @offset=0
    @x=306
    @y=138
    @distance=96
  end

# 0=none, 1=weak, 2=strong
  def setFlowStrength(strength)
    @strength=strength
  end

  def visible=(value)
    for point in @points
      point.visible=value
    end
  end

  def dispose
    for point in @points
      point.dispose
    end
  end

  def ensurePoint(j)
    if !@points[j] || @points[j].disposed?
      @points[j]=BitmapSprite.new(8,8,@viewport)
      @points[j].bitmap.fill_rect(0,0,8,8,Color.new(0,0,0))
    end
    @points[j].tone=(@strength==2) ? Tone.new(232,232,248) : 
       Tone.new(16,16,232)
    @points[j].visible=(@strength!=0)
  end

  def update
    for point in @points
      point.update
      point.visible=false
    end
    j=0
    i=0; while i<@distance
      o=(i+@offset)%@distance
      if o>=0 && o<@distance
        ensurePoint(j)
        pt=calcPoint(@x,@y,o,@angle)
        @points[j].x=pt[0]
        @points[j].y=pt[1]
        j+=1
      end
      i+=(@strength==2) ? 16 : 32
    end
    @offset+=(@strength==2) ? 3 : 2
    @offset%=@distance
  end

  def color=(value)
    for point in @points
      point.color=value
    end
  end

  def setAngle(angle1)
    @angle=angle1-(angle1/360).floor*360
  end
end



class FlowDiagram
  def initialize(viewport=nil)
    @points=[]
    @angles=[]
    @viewport=viewport
    @strength=0
    @offset=0
    @x=306
    @y=138
    @distance=96
  end

# 0=none, 1=weak, 2=strong
  def setFlowStrength(strength)
    @strength=strength
  end

  def visible=(value)
    for point in @points
      point.visible=value
    end
  end

  def dispose
    for point in @points
      point.dispose
    end
  end

  def ensurePoint(j)
    if !@points[j] || @points[j].disposed?
      @points[j]=BitmapSprite.new(8,8,@viewport)
      @points[j].bitmap.fill_rect(0,0,8,8,Color.new(0,0,0))
    end
    @points[j].tone=(@strength==2) ? Tone.new(232,232,248) : 
       Tone.new(16,16,232)
    @points[j].visible=(@strength!=0)
  end

  def withinRange(angle,startAngle,endAngle)
    if startAngle>endAngle
      return (angle>=startAngle || angle<=endAngle) &&
         (angle>=0 && angle<=360)
    else
      return (angle>=startAngle && angle<=endAngle)
    end
  end

  def update
    for point in @points
      point.update
      point.visible=false
    end
    j=0
    i=0; while i<360
      angle=(i+@offset)%360
      if withinRange(angle,@startAngle,@endAngle)
        ensurePoint(j)
        pt=calcPoint(@x,@y,@distance,angle)
        @points[j].x=pt[0]
        @points[j].y=pt[1]
        j+=1
      end
      i+=(@strength==2) ? 10 : 20
    end
    @offset-=(@strength==2) ? 3 : 2
    @offset%=(360*6)
  end

  def color=(value)
    for point in @points
     point.color=value
    end
  end

  def setRange(angle1,angle2)
    @startAngle=angle1-(angle1/360).floor*360
    @endAngle=angle2-(angle2/360).floor*360
    if @startAngle==@endAngle && angle1!=angle2
      @startAngle=0
      @endAngle=359.99
    end
  end
end



class PurifyChamberSetView < SpriteWrapper
  attr_reader :set
  attr_reader :cursor
  attr_reader :heldpkmn

  def initialize(chamber,set,viewport=nil)
    super(viewport)
    @set=set
    @heldpkmn=nil
    @cursor=-1
    @view=BitmapSprite.new(64,64,viewport)
    @view.bitmap.fill_rect(8,8,48,48,Color.new(255,255,255))
    @view.bitmap.fill_rect(10,10,44,44,Color.new(255,255,255,128))
    @info=BitmapSprite.new(Graphics.width-112,48,viewport)
    @flows=[]
    @directflow=DirectFlowDiagram.new(viewport)
    @directflow.setAngle(0)
    @directflow.setFlowStrength(1)
    @__sprites=[]
    @__sprites[0]=PokemonIconSprite.new(nil,viewport)
    for i in 0...PurifyChamber::SETSIZE*2
      @__sprites[i+1]=PokemonIconSprite.new(nil,viewport)
    end
    @__sprites[1+PurifyChamber::SETSIZE*2]=PokemonIconSprite.new(nil,viewport)
    @chamber=chamber
    refresh
  end

  def refreshFlows()
    for flow in @flows
      flow.setFlowStrength(0)
    end
    setcount=@chamber.setCount(@set)
    for i in 0...setcount
      if !@flows[i]
        @flows[i]=FlowDiagram.new(self.viewport)
      end
      angle=360-(i*360/setcount)
      angle+=90 # start at 12 not 3 o'clock
      endAngle=angle-(360/setcount)
      @flows[i].setRange(endAngle,angle)
      @flows[i].setFlowStrength(@chamber[@set].affinity(i))
    end
  end

  def moveCursor(button)
    points=[@chamber.setCount(@set)*2,1].max
    oldcursor=@cursor
    if @cursor==0 && points>0
      @cursor=1 if button==Input::UP
      @cursor=points*1/4+1 if button==Input::RIGHT
      @cursor=points*2/4+1 if button==Input::DOWN
      @cursor=points*3/4+1 if button==Input::LEFT
    elsif @cursor>0
      pos=@cursor-1
      if @chamber.setCount(@set)==PurifyChamber::SETSIZE
        points=[points/2,1].max
        pos/=2
      end	 
      seg=pos*8/points
      if seg==7 || seg==0
        pos-=1 if button==Input::LEFT
        pos+=1 if button==Input::RIGHT
        pos=nil if button==Input::DOWN
      elsif seg==1 || seg==2
        pos-=1 if button==Input::UP
        pos+=1 if button==Input::DOWN
        pos=nil if button==Input::LEFT
      elsif seg==3 || seg==4
        pos-=1 if button==Input::RIGHT
        pos+=1 if button==Input::LEFT
        pos=nil if button==Input::UP
      elsif seg==5 || seg==6
        pos-=1 if button==Input::DOWN
        pos+=1 if button==Input::UP
        pos=nil if button==Input::RIGHT
      end
      if pos!=nil
        pos-=(pos/points).floor*points # modulus
        pos*=2 if @chamber.setCount(@set)==PurifyChamber::SETSIZE
        @cursor=pos+1
      else
        @cursor=0
      end
    end
    if @cursor!=oldcursor
      refresh
    end
  end

  def checkCursor(index)
    if @cursor==index
      @view.x=@__sprites[index].x
      @view.y=@__sprites[index].y
      @view.visible=true
    end
  end

  def refresh
    pkmn=@chamber.getShadow(@set)
    @view.visible=false
    @info.bitmap.fill_rect(0,0,@info.bitmap.width,@info.bitmap.height,Color.new(0,248,0))
    pbSetSmallFont(@info.bitmap)
    textpos=[]
    if pkmn
	    if pkmn.type1==pkmn.type2
        textpos.push([_INTL("{1}  Lv{2}  {3}",pkmn.name,pkmn.level,PBTypes.getName(pkmn.type1)),2,0,0,
	         Color.new(248,248,248),Color.new(128,128,128)])
      else
        textpos.push([_INTL("{1}  Lv{2}  {3}/{4}",pkmn.name,pkmn.level,PBTypes.getName(pkmn.type1),
	         PBTypes.getName(pkmn.type2)),2,0,0,
	         Color.new(248,248,248),Color.new(128,128,128)])
      end
      textpos.push([_INTL("FLOW"),2+@info.bitmap.width/2,24,0,
	       Color.new(248,248,248),Color.new(128,128,128)])
		  # draw heart gauge
	    pbDrawGauge(@info.bitmap,Rect.new(@info.bitmap.width*3/4,8,@info.bitmap.width*1/4,8),
	       Color.new(192,0,256),pkmn.heartgauge,
         PokeBattle_Pokemon::HEARTGAUGESIZE)
	    # draw flow gauge
      pbDrawGauge(@info.bitmap,Rect.new(@info.bitmap.width*3/4,24+8,@info.bitmap.width*1/4,8),
	       Color.new(0,0,248),@chamber.chamberFlow(@set),6)
    end
    if @chamber.setCount(@set)>0
      textpos.push([_INTL("TEMPO"),2,24,0,
	       Color.new(248,248,248),Color.new(128,128,128)])
      # draw tempo gauge
      pbDrawGauge(@info.bitmap,Rect.new(@info.bitmap.width*1/4,24+8,@info.bitmap.width*1/4,8),
	       Color.new(0,0,248),@chamber[@set].tempo,
         PurifyChamber.maximumTempo())
    end
    pbDrawTextPositions(@info.bitmap,textpos)
    @info.x=Graphics.width-@info.bitmap.width
    @info.y=Graphics.height-@info.bitmap.height
    @__sprites[0].pokemon=pkmn
    @__sprites[0].x=280
    @__sprites[0].y=96
    @__sprites[0].z=2
    @directflow.setAngle(angle)
    @directflow.setFlowStrength(0)
    checkCursor(0)
    points=[@chamber.setCount(@set)*2,1].max
    setList=@chamber.setList(@set)
    refreshFlows()
    for i in 0...PurifyChamber::SETSIZE*2
      pkmn=(i%2==1 || i>=points) ? nil : setList[i/2]
      angle=360-(i*360/points)
      angle+=90 # start at 12 not 3 o'clock
      if pkmn && @chamber[@set].facing==i/2
        @directflow.setAngle(angle)
        @directflow.setFlowStrength(@chamber[@set].shadowAffinity)
      end
      point=calcPoint(280,96,96,angle)
      @__sprites[i+1].x=point[0]
      @__sprites[i+1].y=point[1]
      @__sprites[i+1].z=2
      @__sprites[i+1].pokemon=pkmn
      checkCursor(i+1)
    end
    @__sprites[1+PurifyChamber::SETSIZE*2].pokemon=@heldpkmn
    @__sprites[1+PurifyChamber::SETSIZE*2].visible=@view.visible
    @__sprites[1+PurifyChamber::SETSIZE*2].x=@view.x
    @__sprites[1+PurifyChamber::SETSIZE*2].y=@view.y-6
    @__sprites[1+PurifyChamber::SETSIZE*2].z=3
  end

  def getCurrent
    return PurifyChamberHelper.pbGetPokemon(@chamber,@cursor)
  end

  def cursor=(value)
    @cursor=value
    refresh
  end

  def heldpkmn=(value)
    @heldpkmn=value
    refresh
  end

  def set=(value)
    @set=value
    refresh
  end

  def visible=(value)
    super
    for sprite in @__sprites
      sprite.visible=value
    end
    for flow in @flows
      flow.visible=value
    end
    @directflow.visible=value
    @view.visible=value
    @info.visible=value
  end

  def color=(value)
    super
    for sprite in @__sprites
      sprite.color=pbSrcOver(sprite.color,value.clone)
    end
    for flow in @flows
      flow.color=value.clone
    end
    @directflow.color=value.clone
    @view.color=value.clone
    @info.color=value.clone
  end

  def update
    super
    for sprite in @__sprites
      sprite.update if sprite
    end
    for flow in @flows
      flow.update
    end
    @directflow.update
    @view.update
    @info.update
  end

  def dispose
    for sprite in @__sprites
      sprite.dispose if sprite
    end
    for flow in @flows
      flow.dispose
    end
    @directflow.dispose
    @view.dispose
    @info.dispose
    @__sprites.clear
    super
  end
end



def pbPurifyChamber()
   $PokemonGlobal.seenPurifyChamber=true
   pbFadeOutIn(99999){
      scene=PurifyChamberScene.new()
      screen=PurifyChamberScreen.new(scene)
      screen.pbStartPurify()
  }
end



class PurifyChamberScene
  def pbUpdate()
    pbUpdateSpriteHash(@sprites)
  end

  def pbRefresh()
    if @sprites["setview"]
      @sprites["setview"].refresh
      @sprites["setwindow"].refresh
    end
  end

  def pbStart(chamber)
    @chamber=chamber
  end

  def pbEnd()
  end

  def pbOpenSet(set)
    @sprites={}
    @viewport=Viewport.new(0,0,Graphics.width,Graphics.height)
    @viewport.z=99999
    @viewportmsg=Viewport.new(0,0,Graphics.width,Graphics.height)
    @viewportmsg.z=99999
    addBackgroundOrColoredPlane(@sprites,"bg","purifychamberbg",
       Color.new(0,0,0),@viewport)
    @sprites["setwindow"]=Window_PurifyChamberSets.new(
       @chamber,0,0,112,Graphics.height,@viewport)
    @sprites["setview"]=PurifyChamberSetView.new(@chamber,set,@viewport)
    @sprites["msgwindow"]=Window_AdvancedTextPokemon.new("")
    @sprites["msgwindow"].viewport=@viewportmsg
    @sprites["msgwindow"].visible=false
    @sprites["setwindow"].index=set
    pbDeactivateWindows(@sprites)
    pbFadeInAndShow(@sprites) { pbUpdate }
  end

  def pbCloseSet()
    pbFadeOutAndHide(@sprites) { pbUpdate }
    pbDisposeSpriteHash(@sprites)
    @viewport.dispose
    @viewportmsg.dispose
  end

  def pbOpenSetDetail(set)
    @sprites["setwindow"].index=set
    @sprites["setview"].set=set
    @sprites["setview"].cursor=0
  end

  def pbCloseSetDetail()
  end

  def pbPurify()
    pbRefresh
  end

  def pbMove(pos)
    @sprites["setview"].heldpkmn=@sprites["setview"].getCurrent()
    pbRefresh
  end

  def pbShift(pos,heldpoke)
    @sprites["setview"].heldpkmn=@sprites["setview"].getCurrent()
    pbRefresh
  end

  def pbPlace(pos,heldpoke)
    @sprites["setview"].heldpkmn=nil
    pbRefresh
  end

  def pbReplace(pos,storagePos)
    @sprites["setview"].heldpkmn=nil
    pbRefresh
  end

  def pbRotate(facing)
  end

  def pbWithdraw(pos,heldpoke)
    @sprites["setview"].heldpkmn=nil
    pbRefresh
  end

  def pbDisplay(msg)
    UIHelper.pbDisplay(@sprites["msgwindow"],msg,false) { pbUpdate }
  end

  def pbConfirm(msg)
    UIHelper.pbConfirm(@sprites["msgwindow"],msg) { pbUpdate }
  end

  def pbShowCommands(msg,commands)
    UIHelper.pbShowCommands(@sprites["msgwindow"],msg,commands) { pbUpdate }
  end

  def pbSetScreen()
    pbDeactivateWindows(@sprites){
       loop do
         Graphics.update; Input.update; pbUpdate
         btn=0
         btn=Input::DOWN if Input.repeat?(Input::DOWN)
         btn=Input::UP if Input.repeat?(Input::UP)
         btn=Input::RIGHT if Input.repeat?(Input::RIGHT)
         btn=Input::LEFT if Input.repeat?(Input::LEFT)
         if btn!=0
           pbPlayCursorSE()
           @sprites["setview"].moveCursor(btn)
         end
         if Input.repeat?(Input::L)
           nextset=(@sprites["setview"].set==0) ? PurifyChamber::NUMSETS-1 : @sprites["setview"].set-1
           pbPlayCursorSE()
           return [1,nextset]
         end
         if Input.repeat?(Input::R)
           nextset=(@sprites["setview"].set==PurifyChamber::NUMSETS-1) ? 0 : @sprites["setview"].set+1
           pbPlayCursorSE()
           return [1,nextset]
         end
         if Input.trigger?(Input::C) || Input.triggerex?(Input::LeftMouseKey)
           pbPlayDecisionSE()
           return [0,@sprites["setview"].cursor]
         end
         if Input.trigger?(Input::B) || Input.triggerex?(Input::RightMouseKey)
           pbPlayCancelSE()
           return [3,0]
         end
       end
    }
  end

  def pbChooseSet()
    pbActivateWindow(@sprites,"setwindow"){
       oldindex=@sprites["setwindow"].index
       loop do
         if oldindex!=@sprites["setwindow"].index
           oldindex=@sprites["setwindow"].index
           @sprites["setview"].set=oldindex
         end
         Graphics.update; Input.update; pbUpdate
         if Input.trigger?(Input::C) || Input.triggerex?(Input::LeftMouseKey)
           pbPlayDecisionSE()
           return @sprites["setwindow"].index
         end
         if Input.trigger?(Input::B) || Input.triggerex?(Input::RightMouseKey)
           pbPlayCancelSE()
           return -1
         end
       end
    }
  end

  def pbSwitch(set)
    @sprites["setwindow"].switching=set
    ret=pbChooseSet()
    @sprites["setwindow"].switching=-1
    return ret<0 ? set : ret
  end

  def pbSummary(pos,heldpkmn)
    if heldpkmn
      oldsprites=pbFadeOutAndHide(@sprites)
      scene=PokemonSummaryScene.new
      screen=PokemonSummary.new(scene)
      screen.pbStartScreen([heldpkmn],0)
      pbFadeInAndShow(@sprites,oldsprites)
      return
    end
    party=[]
    indexes=[]
    startindex=0
    set=@sprites["setview"].set
    for i in 0...@chamber.setCount(set)*2
      p=PurifyChamberHelper.pbGetPokemon2(@chamber,set,i)
      if p
        startindex=party.length if i==pos
        party.push(p)
        indexes.push(i)
      end
    end
    return if party.length==0
    oldsprites=pbFadeOutAndHide(@sprites)
    scene=PokemonSummaryScene.new
    screen=PokemonSummary.new(scene)
    selection=screen.pbStartScreen(party,startindex)
    @sprites["setview"].cursor=indexes[selection]
    pbFadeInAndShow(@sprites,oldsprites)
  end

  def pbPositionHint(pos)
    @sprites["setview"].cursor=pos
    pbRefresh
  end

  def pbChangeSet(set)
    @sprites["setview"].set=set
    @sprites["setwindow"].index=set
    @sprites["setwindow"].refresh
    pbRefresh
  end

  def pbChoosePokemon()
    visible=pbFadeOutAndHide(@sprites)
    scene=PokemonStorageScene.new()
    screen=PokemonStorageScreen.new(scene,$PokemonStorage)
    pos=screen.pbChoosePokemon()
    pbRefresh
    pbFadeInAndShow(@sprites,visible)
    return pos
  end
end
