package de.frajul.endlessroll.main.game;

import de.frajul.endlessroll.data.Vector;
import de.frajul.endlessroll.entities.DestroyEffect;
import de.frajul.endlessroll.entities.Goal;
import de.frajul.endlessroll.entities.Obstacle;
import de.frajul.endlessroll.entities.collectables.Energy;
import de.frajul.endlessroll.entities.collectables.Star;
import de.frajul.endlessroll.entities.collision.CollisionDetector;
import de.frajul.endlessroll.entities.particles.ParticleSource;
import de.frajul.endlessroll.entities.particles.ParticleSystem;
import de.frajul.endlessroll.entities.shapes.PlayerShape;
import de.frajul.endlessroll.entities.textures.TexturePack;
import de.frajul.endlessroll.entities.tools.Bomb;
import de.frajul.endlessroll.entities.tools.Magnet;
import de.frajul.endlessroll.entities.tools.Stasis;
import de.frajul.endlessroll.entities.tools.Tool;
import de.frajul.endlessroll.entities.tools.ToolType;
import de.frajul.endlessroll.levels.Level;
import de.frajul.endlessroll.levels.ObstacleData;
import de.frajul.endlessroll.levels.worlds.World;
import de.frajul.endlessroll.main.GameActivity;
import de.frajul.endlessroll.main.GameLog;
import de.frajul.endlessroll.main.physics.Physics;

/**
 * Created by Julian on 27.11.2015.
 */
public class GameScene extends Scene {

    private GameActivity gameActivity;
    private World currentWorld;
    private CollisionDetector collisionDetector;
    private Goal goal;
    private float goalX;

    public GameScene(GameActivity gameActivity, TexturePack texturePack, ParticleSystem particleSystem) throws Exception {
        super(gameActivity, texturePack, particleSystem);
        this.gameActivity = gameActivity;
        collisionDetector = new CollisionDetector();

        goal = new Goal(textures.goal);
    }

    public void loadLevel(Level level, World world, PlayerShape playerShape) throws Exception {
        this.currentWorld = world;
        super.reset();
        background.changeTextures(world.getBackgroundTextures());
        terrain.loadData(world, level.getTerrainEdge(), level.getTerrainTiles());
        ceiling.loadData(world, level.getCeilingEdge(), level.getCeilingTiles());
        uncategorizedEntities.add(goal);
        player.init(playerShape, terrain.getEdge(), level.getStartSpeed(), level.getEndSpeed(),
                particleSystem);
        uncategorizedEntities.add(player);
        collectables.init(level, textures);
        for (ObstacleData data : level.getObstacles())
            addObstacle(data);

        goalX = level.getGoalX();
        goal.setGoalX(goalX);

        if (world == World.ICY_MOUNTAINS) {
            enviromentParticles = new ParticleSource(new Vector(), particleSystem.snow);
            enviromentParticles.start();
        } else if (enviromentParticles != null) {
            enviromentParticles.kill();
        }
        GameLog.d("Level " + level.getId() + " successfully loaded");
    }

    public void onStarCollision(Star collisionStar) {
        collisionStar.destroy(DestroyEffect.STAR_EXPLOSION);
    }

    public void onEnergyCollision(Energy energy) {
        energy.destroy(DestroyEffect.ENERGY_COLLECT);
    }

    public void addObstacle(ObstacleData data) {
        Obstacle obstacle = new Obstacle(currentWorld, data, terrain.getEdge(), player);
        obstacles.add(obstacle);
    }

    public Tool addTool(ToolType type, Vector position, Physics physics) throws Exception {
        Tool tool = type.newInstance(position, particleSystem, gameActivity.getSoundManager());
        physics.checkSingleToolCollision(tool, this);

        if (tool == null)
            throw new Exception(
                    "Current ToolType(" + type + ") returns null at method newInstance()");
        tools.add(tool);
        return tool;
    }

    public Obstacle getObstacleAtPoint(Vector point) {
        synchronized (obstacles) {
            for (Obstacle obstacle : obstacles) {
                if (collisionDetector.isPointQuadCollision(point, obstacle))
                    return obstacle;
            }
        }
        return null;
    }

    public void update(Timer timer) {
        player.setSpeedByProgress(player.getProgress() / goalX);

        if (!player.getStases().isEmpty()) {
            synchronized (obstacles) {
                for (Stasis stasis : player.getStases()) {
                    for (Obstacle obstacle : obstacles) {
                        if (obstacle.isMoving()) {
                            obstacle.slowMovementForOneFrame(stasis.getCurrentXSlowFactor());
                        }
                    }
                }
            }
        }

        player.preMoveUpdate(timer);

        if (player.hasSuperPower() && player.getBottomEdge() < terrain.getEdge()) {
            player.setToTerrain(terrain.getEdge());
            if (player.getMovement().y < 0)
                player.getMovement().setY(0);
        }

        super.update(timer);

        player.postMoveUpdate();

        synchronized (tools) {
            for (Tool tool : tools) {
                if (tool instanceof Bomb) {
                    Bomb bomb = (Bomb) tool;
                    if (bomb.isExploding())
                        bomb.explode();
                } else if (tool instanceof Stasis) {
                    Stasis stasis = (Stasis) tool;
                    stasis.updateSoundVolume(player);
                } else if (tool instanceof Magnet) {
                    Magnet magnet = (Magnet) tool;
                    magnet.updateSoundVolume(player);
                }
            }
        }

    }

    public float getGoalX() {
        return goalX;
    }

}
