package net.glowstone.entity;

import com.flowpowered.networking.Message;
import net.glowstone.entity.physics.BoundingBox;
import net.glowstone.net.message.play.entity.SpawnLightningStrikeMessage;
import net.glowstone.util.Position;
import org.bukkit.Location;
import org.bukkit.Sound;
import org.bukkit.entity.Damageable;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.LightningStrike;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.util.Vector;

import java.util.Arrays;
import java.util.List;
import java.util.Random;

/**
 * A GlowLightning strike is an entity produced during thunderstorms.
 */
public class GlowLightningStrike extends GlowWeather implements LightningStrike {

    /**
     * Whether the lightning strike is just for effect.
     */
    private boolean effect;

    /**
     * How long this lightning strike has to remain in the world.
     */
    private final int ticksToLive;

    private final Random random;

    public GlowLightningStrike(Location location, boolean effect, Random random) {
        super(location);
        this.effect = effect;
        this.ticksToLive = 30;
        this.random = random;
    }

    @Override
    public EntityType getType() {
        return EntityType.LIGHTNING;
    }

    @Override
    public boolean isEffect() {
        return effect;
    }

    @Override
    public void pulse() {
        super.pulse();
        if (getTicksLived() >= ticksToLive) {
            remove();
        }
        if (getTicksLived() == 1) {
            // Play Sound
            location.getWorld().playSound(location, Sound.AMBIENCE_THUNDER, 10000, 0.8F + random.nextFloat() * 0.2F);
            location.getWorld().playSound(location, Sound.EXPLODE, 2, 0.5F + random.nextFloat() * 0.2F);
            if (!effect) { // Deal damage to nearby entities if it's not just a visual effect
                for (Entity entity : getNearbyEntities(3, 6, 3)) {
                    if (entity instanceof Damageable) {
                        ((Damageable) entity).damage(5, this, EntityDamageEvent.DamageCause.LIGHTNING);
                    }
                    entity.setFireTicks(entity.getMaxFireTicks());
                }
            }
        }
    }

    @Override
    public List<Message> createSpawnMessage() {
        int x = Position.getIntX(location);
        int y = Position.getIntY(location);
        int z = Position.getIntZ(location);
        return Arrays.<Message>asList(new SpawnLightningStrikeMessage(id, x, y, z));
    }

    @Override
    public List<Message> createUpdateMessage() {
        return Arrays.asList();
    }

    @Override
    public List<Entity> getNearbyEntities(double x, double y, double z) {
        // This behavior is similar to CraftBukkit, where a call with args
        // (0, 0, 0) finds any entities whose bounding boxes intersect that of
        // this entity.

        final BoundingBox searchBox = BoundingBox.fromPositionAndSize(location.toVector(), new Vector(0, 0, 0));
        final Vector vec = new Vector(x, y, z);
        final Vector vec2 = new Vector(0, 0.5 * y, 0);
        searchBox.minCorner.subtract(vec).add(vec2);
        searchBox.maxCorner.add(vec).add(vec2);

        return world.getEntityManager().getEntitiesInside(searchBox, this);
    }
}

@@ -59,32 +59,67 @@
 orking.Message;%0A
+import net.glowstone.EventFactory;%0A
 import net.glows
@@ -307,21 +307,176 @@
 .bukkit.
-Sound
+Material;%0Aimport org.bukkit.Sound;%0Aimport org.bukkit.World;%0Aimport org.bukkit.block.Block;%0Aimport org.bukkit.block.BlockFace;%0Aimport org.bukkit.block.BlockState
 ;%0Aimport
@@ -618,16 +618,124 @@
 Strike;%0A
+import org.bukkit.event.block.BlockIgniteEvent;%0Aimport org.bukkit.event.block.BlockIgniteEvent.IgniteCause;%0A
 import o
@@ -1843,24 +1843,77 @@
 d() == 1) %7B%0A
+            final World world = location.getWorld();%0A
             
@@ -1938,35 +1938,21 @@
         
-location.getW
+w
 orld
-()
 .playSou
@@ -2042,35 +2042,21 @@
         
-location.getW
+w
 orld
-()
 .playSou
@@ -2113,32 +2113,33 @@
 loat() * 0.2F);%0A
+%0A
             if (
@@ -2156,39 +2156,8 @@
  // 
-Deal damage to nearby entities 
 if i
@@ -2184,16 +2184,604 @@
 l effect
+%0A                // set target block on fire if required%0A                Block block = world.getBlockAt(location);%0A                setBlockOnFire(block);%0A                for (int i = 0; i %3C 4; i++) %7B%0A                    int x = location.getBlockX() - 1 + random.nextInt(3);%0A                    int z = location.getBlockZ() - 1 + random.nextInt(3);%0A                    int y = location.getBlockY() - 1 + random.nextInt(3);%0A                    block = world.getBlockAt(x, y, z);%0A                    setBlockOnFire(block);%0A                %7D%0A%0A                // deal damage to nearby entities
 %0A       
@@ -4192,11 +4192,518 @@
 );%0A    %7D
+%0A%0A    private void setBlockOnFire(Block block) %7B%0A        if (block.isEmpty() && block.getRelative(BlockFace.DOWN).getType().isFlammable()) %7B%0A            BlockIgniteEvent igniteEvent = new BlockIgniteEvent(block, IgniteCause.LIGHTNING, this);%0A            EventFactory.callEvent(igniteEvent);%0A            if (!igniteEvent.isCancelled()) %7B%0A                final BlockState state = block.getState();%0A                state.setType(Material.FIRE);%0A                state.update(true);%0A            %7D%0A        %7D%0A    %7D
 %0A%7D%0A

Set a few blocks on fire where lightning strikes