LayerAdapter = require 'lib/surface/LayerAdapter'
SegmentedSprite = require 'lib/surface/SegmentedSprite'
Lank = require 'lib/surface/Lank'
ThangType = require 'models/ThangType'
SpriteBuilder = require 'lib/sprites/SpriteBuilder'
ogreMunchkinThangType = new ThangType(require 'test/app/fixtures/ogre-munchkin-m.thang.type')
ogreFangriderThangType = new ThangType(require 'test/app/fixtures/ogre-fangrider.thang.type')
treeThangType = new ThangType(require 'test/app/fixtures/tree1.thang.type')
scaleTestUtils = require './scale-testing-utils'

describe 'SegmentedSprite', ->
  segmentedSprite = null
  stage = null
  
  showMe = ->
    canvas = $('<canvas width="600" height="400"></canvas>').css('position', 'absolute').css('index', 1000).css('background', 'white')
    $('body').append(canvas)
    stage = new createjs.Stage(canvas[0]) # this is not a SpriteStage because some tests require adding MovieClips
    stage.addChild(segmentedSprite)
    scale = 3
    stage.scaleX = stage.scaleY = scale
    stage.regX = -300 / scale
    stage.regY = -200 / scale
    window.stage = stage
  
    ticks = 0
    listener = {
      handleEvent: ->
        return if ticks >= 100
        ticks += 1
        segmentedSprite.tick(arguments[0].delta)
        stage.update()
    }
    createjs.Ticker.addEventListener "tick", listener
    
  describe 'with Tree ThangType', ->
    beforeEach ->
      layer = new LayerAdapter({webGL:true, name:'Default'})
      layer.buildAutomatically = false
      layer.buildAsync = false
      treeThangType.markToRevert()
      treeThangType.set('spriteType', 'segmented')
      sprite = new Lank(treeThangType)
      layer.addLank(sprite)
      sheet = layer.renderNewSpriteSheet()
      prefix = layer.renderGroupingKey(treeThangType) + '.'
      window.segmentedSprite = segmentedSprite = new SegmentedSprite(sheet, treeThangType, prefix)

    it 'scales rendered containers to the size of the source container', ->
      # build a movie clip, put it on top of the segmented sprite and make sure
      # they both 'hit' at the same time.

      segmentedSprite.gotoAndStop('idle')
      builder = new SpriteBuilder(treeThangType)
      container = builder.buildContainerFromStore('Tree_4')
      container.scaleX = container.scaleY = 0.3
      container.regX = 59
      container.regY = 100
      showMe()
      stage.addChild(container)
      stage.update()
      hitRate = scaleTestUtils.hitTest(stage, new createjs.Rectangle(-15, -30, 35, 40))
      expect(hitRate).toBeGreaterThan(0.92)
      $('canvas').remove()

    it 'scales placeholder containers to the size of the source container', ->
      # build a movie clip, put it on top of the segmented sprite and make sure
      # they both 'hit' at the same time.

      segmentedSprite.usePlaceholders = true
      segmentedSprite.gotoAndStop('idle')
      builder = new SpriteBuilder(treeThangType)
      container = builder.buildContainerFromStore('Tree_4')
      container.scaleX = container.scaleY = 0.3
      container.regX = 59
      container.regY = 100
      showMe()
      stage.addChild(container)
      stage.update()
      hitRate = scaleTestUtils.hitTest(stage, new createjs.Rectangle(-15, -30, 35, 40))
      expect(hitRate).toBeGreaterThan(0.73)
      $('canvas').remove()

  describe 'with Ogre Munchkin ThangType', ->
    beforeEach ->
      layer = new LayerAdapter({webGL:true, name:'Default'})
      layer.buildAutomatically = false
      layer.buildAsync = false
      ogreMunchkinThangType.markToRevert()
      ogreMunchkinThangType.set('spriteType', 'segmented')
      actions = ogreMunchkinThangType.getActions()
      
      # couple extra actions for doing some tests
      actions.littledance = {animation:'enemy_small_move_side',framerate:1, frames:'0,6,2,6,2,8,0', name: 'littledance'}
      actions.onestep = {animation:'enemy_small_move_side', loops: false, name:'onestep'}
      actions.head = {container:'head', name:'head'}
      
      colorConfig = {team: {hue: 0, saturation: 1, lightness: 0.5}}
      sprite = new Lank(ogreMunchkinThangType, {colorConfig: colorConfig})
      layer.addLank(sprite)
      sheet = layer.renderNewSpriteSheet()
      prefix = layer.renderGroupingKey(ogreMunchkinThangType, null, colorConfig) + '.'
      window.segmentedSprite = segmentedSprite = new SegmentedSprite(sheet, ogreMunchkinThangType, prefix)
    
    afterEach ->
      ogreMunchkinThangType.revert()

    it 'has gotoAndPlay, gotoAndStop, currentAnimation, and paused like a MovieClip or Sprite', ->
      segmentedSprite.gotoAndPlay('move_fore')
      expect(segmentedSprite.baseMovieClip).toBeDefined()
      expect(segmentedSprite.paused).toBe(false)
      segmentedSprite.gotoAndStop('move_fore')
      expect(segmentedSprite.paused).toBe(true)
      expect(segmentedSprite.currentAnimation).toBe('move_fore')
  
    it 'has a tick function which moves the animation forward', ->
      segmentedSprite.gotoAndPlay('attack')
      segmentedSprite.tick(100) # one hundred milliseconds
      expect(segmentedSprite.baseMovieClip.currentFrame).toBe(segmentedSprite.framerate*100/1000)
      
    it 'will interpolate between frames of a custom frame set', ->
      segmentedSprite.gotoAndPlay('littledance')
      segmentedSprite.tick(1000)
      expect(segmentedSprite.baseMovieClip.currentFrame).toBe(6)
      segmentedSprite.tick(1000)
      expect(segmentedSprite.baseMovieClip.currentFrame).toBe(2)
      segmentedSprite.tick(500)
      expect(segmentedSprite.baseMovieClip.currentFrame).toBe(4)
      segmentedSprite.tick(500)
      expect(segmentedSprite.baseMovieClip.currentFrame).toBe(6)

    it 'emits animationend for animations where loops is false and there is no goesTo', (done) ->
      fired = false
      segmentedSprite.gotoAndPlay('onestep')
      segmentedSprite.on('animationend', -> fired = true)
      segmentedSprite.tick(1000)
      _.defer -> # because the event is deferred
        expect(fired).toBe(true)
        done()

    it 'scales rendered animations like a MovieClip', ->
      # build a movie clip, put it on top of the segmented sprite and make sure
      # they both 'hit' at the same time.

      segmentedSprite.gotoAndStop('idle')
      builder = new SpriteBuilder(ogreMunchkinThangType)
      movieClip = builder.buildMovieClip('enemy_small_move_side')
      movieClip.scaleX = movieClip.scaleY = 0.3
      movieClip.regX = 285
      movieClip.regY = 300
      movieClip.stop()
      showMe()
      stage.addChild(movieClip)
      
      stage.update()
      hitRate = scaleTestUtils.hitTest(stage, new createjs.Rectangle(-10, -30, 25, 35))
      expect(hitRate).toBeGreaterThan(0.91)
      expect(segmentedSprite.baseScaleX).toBe(0.3)
      expect(segmentedSprite.baseScaleY).toBe(0.3)
      $('canvas').remove()

    it 'scales placeholder animations like a MovieClip', ->
      segmentedSprite.usePlaceholders = true
      segmentedSprite.gotoAndStop('idle')
      builder = new SpriteBuilder(ogreMunchkinThangType)
      movieClip = builder.buildMovieClip('enemy_small_move_side')
      movieClip.scaleX = movieClip.scaleY = 0.3
      movieClip.regX = 285
      movieClip.regY = 300
      movieClip.stop()
      showMe()
      stage.addChild(movieClip)
      stage.update()
      hitRate = scaleTestUtils.hitTest(stage, new createjs.Rectangle(-10, -30, 25, 35))
      expect(hitRate).toBeGreaterThan(0.96)
      $('canvas').remove()
      
  describe 'with Ogre Fangrider ThangType', ->
    beforeEach ->
      layer = new LayerAdapter({webGL:true})
      layer.buildAutomatically = false
      layer.buildAsync = false
      ogreFangriderThangType.markToRevert()
      ogreFangriderThangType.set('spriteType', 'segmented')
      colorConfig = {team: {hue: 0, saturation: 1, lightness: 0.5}}
      sprite = new Lank(ogreFangriderThangType, {colorConfig: colorConfig})
      layer.addLank(sprite)
      sheet = layer.renderNewSpriteSheet()
      prefix = layer.renderGroupingKey(ogreFangriderThangType, null, colorConfig) + '.'
      window.segmentedSprite = segmentedSprite = new SegmentedSprite(sheet, ogreFangriderThangType, prefix)
  
    afterEach ->
      ogreFangriderThangType.revert()
  
    it 'synchronizes animations with child movie clips properly', ->
      segmentedSprite.gotoAndPlay('die')
      segmentedSprite.tick(100) # one hundred milliseconds
      expectedFrame = segmentedSprite.framerate*100/1000
      expect(segmentedSprite.currentFrame).toBe(expectedFrame)
      for movieClip in segmentedSprite.childMovieClips
        expect(movieClip.currentFrame).toBe(expectedFrame)

    it 'does not include shapes from the original animation', ->
      segmentedSprite.gotoAndPlay('attack')
      segmentedSprite.tick(230)
      for child in segmentedSprite.children
        expect(_.isString(child)).toBe(false)

    it 'maintains the right number of shapes', ->
      segmentedSprite.gotoAndPlay('idle')
      lengths = []
      for i in _.range(10)
        segmentedSprite.tick(10)
        expect(segmentedSprite.children.length).toBe(20)