module Bioshogi
  module Board
    module UpdateMethods
      def place_on(soldier, options = {})
        options = {
          validate: false,
        }.merge(options)

        if options[:validate]
          assert_cell_blank(soldier.place)
        end

        surface[soldier.place] = soldier
      end

      def pick_up(place)
        soldier = safe_delete_on(place)
        unless soldier
          raise NotFoundOnBoard, "#{place}の位置には何もありません"
        end
        soldier
      end

      def safe_delete_on(place)
        surface.delete(place)
      end

      def all_clear
        surface.clear
      end

      # for DSL
      # 引数の種類がわかっているなら専用メソッドを使うべき
      def placement_from_any(v)
        case
        when PresetInfo.lookup(v)
          placement_from_preset(v)
        when BoardParser.accept?(v)
          placement_from_shape(v)
        when v.kind_of?(String) && !InputParser.scan(v).empty?
          placement_from_human(v)
        else
          raise ArgumentError, v.inspect
        end
      end

      # 手合割で設定
      def placement_from_preset(preset_key)
        placement_from_soldiers(Soldier.preset_soldiers(preset_key))
      end

      # 柿木盤を読み取って反映する
      # 毎回読み取るため遅い
      def placement_from_shape(str)
        placement_from_soldiers(BoardParser.parse(str).soldier_box)
      end

      # 詰将棋の配置の読み上げのような表記で盤に反映する
      # placement_from_human("△51玉 ▲59玉")
      def placement_from_human(str)
        soldiers = InputParser.scan(str).collect { |s| Soldier.from_str(s) }
        placement_from_soldiers(soldiers)
      end

      # まとめて追加で置く
      def placement_from_soldiers(soldiers)
        soldiers.each { |e| place_on(e) }
      end

      private

      def assert_cell_blank(place)
        if surface.has_key?(place)
          raise PieceAlredyExist, "空のはずの#{place}に駒があります\n#{self}"
        end
      end
    end
  end
end