package me.hammerle.supersnuvi.entity.components.animator;

import me.hammerle.supersnuvi.entity.Entity;
import me.hammerle.supersnuvi.entity.components.Health;
import me.hammerle.supersnuvi.javafx.Image;
import me.hammerle.supersnuvi.javafx.KeyHandler;
import me.hammerle.supersnuvi.rendering.IRenderer;
import me.hammerle.supersnuvi.util.Utils;

public class HeroAnimator extends EntityAnimator
{
    private final static Image[] WALK = new Image[]
    {
        Utils.getImage("snuvi/walk/walk_f1", true),
        Utils.getImage("snuvi/walk/walk_f2", true),
        Utils.getImage("snuvi/walk/walk_f3", true),
        Utils.getImage("snuvi/walk/walk_f4", true),
        Utils.getImage("snuvi/walk/walk_f5", true),
        Utils.getImage("snuvi/walk/walk_f6", true),
        Utils.getImage("snuvi/walk/walk_f7", true),
        Utils.getImage("snuvi/walk/walk_f8", true),
        Utils.getImage("snuvi/walk/walk_f9", true)
    };
    
    private final Image JUMP = Utils.getImage("snuvi/jump", true);
    
    private final static Image[] BLOCK = new Image[]
    {
        Utils.getImage("snuvi/block/block_f1", true),
        Utils.getImage("snuvi/block/block_f2", true),
        Utils.getImage("snuvi/block/block_f3", true)
    };
    
    private final static Image[] DEATH = new Image[]
    {
        Utils.getImage("snuvi/death/cbat_death_f1"),
        Utils.getImage("snuvi/death/cbat_death_f2"),
        Utils.getImage("snuvi/death/cbat_death_f3"),
        Utils.getImage("snuvi/death/cbat_death_f4"),
        Utils.getImage("snuvi/death/cbat_death_f5"),
        Utils.getImage("snuvi/death/cbat_death_f6"),
        Utils.getImage("snuvi/death/cbat_death_f7"),
        Utils.getImage("snuvi/death/cbat_death_f8"),
        Utils.getImage("snuvi/death/cbat_death_f9"),
        Utils.getImage("snuvi/death/cbat_death_f10"),
        Utils.getImage("snuvi/death/cbat_death_f11"),
        Utils.getImage("snuvi/death/cbat_death_f12"),
        Utils.getImage("snuvi/death/cbat_death_f13"),
        Utils.getImage("snuvi/death/cbat_death_f14"),
        Utils.getImage("snuvi/death/cbat_death_f15"),
        Utils.getImage("snuvi/death/cbat_death_f16"),
        Utils.getImage("snuvi/death/cbat_death_f17")
    };
    
    private final static Image[] COMBAT_DEATH = new Image[]
    {
        Utils.getImage("snuvi/combat_death/death_f1"),
        Utils.getImage("snuvi/combat_death/death_f2"),
        Utils.getImage("snuvi/combat_death/death_f3"),
        Utils.getImage("snuvi/combat_death/death_f4"),
        Utils.getImage("snuvi/combat_death/death_f5"),
        Utils.getImage("snuvi/combat_death/death_f6"),
        Utils.getImage("snuvi/combat_death/death_f7"),
        Utils.getImage("snuvi/combat_death/death_f8"),
        Utils.getImage("snuvi/combat_death/death_f9"),
        Utils.getImage("snuvi/combat_death/death_f10"),
        Utils.getImage("snuvi/combat_death/death_f11"),
        Utils.getImage("snuvi/combat_death/death_f12"),
        Utils.getImage("snuvi/combat_death/death_f13"),
        Utils.getImage("snuvi/combat_death/death_f14"),
        Utils.getImage("snuvi/combat_death/death_f15"),
        Utils.getImage("snuvi/combat_death/death_f16"),
        Utils.getImage("snuvi/combat_death/death_f17")
    };
    
    private final static Image[] IDLE = new Image[]
    {
        Utils.getImage("snuvi/idle/idle_f1", true),
        Utils.getImage("snuvi/idle/idle_f2", true),
        Utils.getImage("snuvi/idle/idle_f3", true),
        Utils.getImage("snuvi/idle/idle_f4", true),
        Utils.getImage("snuvi/idle/idle_f5", true),
        Utils.getImage("snuvi/idle/idle_f6", true),
        Utils.getImage("snuvi/idle/idle_f7", true),
        Utils.getImage("snuvi/idle/idle_f8", true),
        Utils.getImage("snuvi/idle/idle_f9", true),
        Utils.getImage("snuvi/idle/idle_f10", true),
        Utils.getImage("snuvi/idle/idle_f11", true),
        Utils.getImage("snuvi/idle/idle_f12", true),
        Utils.getImage("snuvi/idle/idle_f13", true),
        Utils.getImage("snuvi/idle/idle_f14", true)
    };
    
    private final static Image[] COMBAT_HEAD = new Image[]
    {
        Utils.getImage("snuvi/combat/cbat_head_f1", true),
        Utils.getImage("snuvi/combat/cbat_head_f2", true),
        Utils.getImage("snuvi/combat/cbat_head_f3", true),
        Utils.getImage("snuvi/combat/cbat_head_f4", true),
        Utils.getImage("snuvi/combat/cbat_head_f5", true),
        Utils.getImage("snuvi/combat/cbat_head_f6", true),
        Utils.getImage("snuvi/combat/cbat_head_f7", true),
        Utils.getImage("snuvi/combat/cbat_head_f8", true),
        Utils.getImage("snuvi/combat/cbat_head_f9", true),
        Utils.getImage("snuvi/combat/cbat_head_f10", true),
        Utils.getImage("snuvi/combat/cbat_head_f11", true),
        Utils.getImage("snuvi/combat/cbat_head_f12", true),
        Utils.getImage("snuvi/combat/cbat_head_f13", true),
        Utils.getImage("snuvi/combat/cbat_head_f14", true)
    };
    
    private final static Image[] COMBAT_HEAD_HIT = new Image[]
    {
        Utils.getImage("snuvi/combat/cbat_hit_f1", true),
        Utils.getImage("snuvi/combat/cbat_hit_f2", true),
        Utils.getImage("snuvi/combat/cbat_hit_f3", true)
    };
    
    private final Image COMBAT_ARMS_IDLE = Utils.getImage("snuvi/combat/cbat_arms_idle", true);
    
    private final static Image[][] COMBAT_ARMS_SWING = new Image[][]
    {
        {
            Utils.getImage("snuvi/combat/cbat_swing1_f1", true),
            Utils.getImage("snuvi/combat/cbat_swing1_f2", true),
            Utils.getImage("snuvi/combat/cbat_swing1_f3", true)
        }, 
        {
            Utils.getImage("snuvi/combat/cbat_swing2_f1", true),
            Utils.getImage("snuvi/combat/cbat_swing2_f2", true),
            Utils.getImage("snuvi/combat/cbat_swing2_f3", true)
        }, 
        {
            Utils.getImage("snuvi/combat/cbat_swing3_f1", true),
            Utils.getImage("snuvi/combat/cbat_swing3_f2", true),
            Utils.getImage("snuvi/combat/cbat_swing3_f3", true)
        }
    };
    
    private final Image COMBAT_BODY_IDLE = Utils.getImage("snuvi/combat/cbat_idle_body", true);    
    
    private final static Image[] COMBAT_BODY_WALK = new Image[]
    {
        Utils.getImage("snuvi/combat/cbat_walk_f1", true),
        Utils.getImage("snuvi/combat/cbat_walk_f2", true),
        Utils.getImage("snuvi/combat/cbat_walk_f3", true),
        Utils.getImage("snuvi/combat/cbat_walk_f4", true)
    };
    
    private final static Image[] COMBAT_SWITCH = new Image[]
    {
        Utils.getImage("snuvi/combat/switch_f1", true),
        Utils.getImage("snuvi/combat/switch_f2", true),
        Utils.getImage("snuvi/combat/switch_f3", true),
        Utils.getImage("snuvi/combat/switch_f4", true),
        Utils.getImage("snuvi/combat/switch_f5", true),
        Utils.getImage("snuvi/combat/switch_f6", true),
        Utils.getImage("snuvi/combat/switch_f7", true),
        Utils.getImage("snuvi/combat/switch_f8", true)
    };
    
    private final Image COMBAT_BODY_DODGE = Utils.getImage("snuvi/dodge", true);    
    private final Image COMBAT_BODY_DASH = Utils.getImage("snuvi/dash", true);    
    private final Image COMBAT_BODY_JUMP = Utils.getImage("snuvi/cbat_jump", true);    
    
    
    private int counter = 0;
    private int frameBody = 0;
    private int frameHead = 0;
    private int frameArms = 0;
    
    private int attackCounter = 0;

    private boolean flipped = false;
    private int blink = 0;
    
    public HeroAnimator(Entity ent) 
    {
        super(ent);
    }

    @Override
    public int getCombatStartTicks() 
    {
        return COMBAT_SWITCH.length * 5;
    }

    @Override
    public int getAttackTicks() 
    {
        return COMBAT_ARMS_SWING[0].length * 5;
    }
    
    @Override
    public int getBlockTicks() 
    {
        return BLOCK.length * 5;
    }
    
    @Override
    public int getDeathTicks() 
    {
        return DEATH.length * 5;
    }

    @Override
    public void resetFrames() 
    {
        counter = 0;
        frameBody = 0;
        frameHead = 0;
        frameArms = 0;
    }

    @Override
    public void render(IRenderer renderer) 
    {
        double x = ent.getX();
        double y = ent.getY() + ent.getHeight() - 2;
        
        if(ent.getHealth().isDead())
        {
            if(frameBody >= DEATH.length)
            {
                frameBody = 0;
            }
            if(ent.getController().isInCombatMode())
            {
                renderer.drawImage(COMBAT_DEATH[frameBody], x, y, drawImageFlipped());
            }
            else
            {
                renderer.drawImage(DEATH[frameBody], x, y, drawImageFlipped());
            }
        }
        else if(ent.getController().isInCombatMode())
        {
            x -= (drawImageFlipped() ? ent.getWidth() : 0);
            if(ent.getController().isBlocking())
            {
                if(frameBody >= BLOCK.length)
                {
                    frameBody = 0;
                }
                bindSlot(BLOCK[frameBody]);
                renderer.drawImage(BLOCK[frameBody], x, y, drawImageFlipped());
            }
            else
            {
                // body rendering
                if(!ent.isOnGround())
                {
                    bindSlot(COMBAT_BODY_JUMP);
                    renderer.drawImage(COMBAT_BODY_JUMP, x, y, drawImageFlipped());
                }
                else if(ent.getController().isDashing())
                {
                    bindSlot(COMBAT_BODY_DASH);
                    renderer.drawImage(COMBAT_BODY_DASH, x, y, drawImageFlipped());
                }
                else if(ent.getController().isDodging())
                {
                    bindSlot(COMBAT_BODY_DODGE);
                    renderer.drawImage(COMBAT_BODY_DODGE, x, y, drawImageFlipped());
                }
                else if(ent.getPreviousMotionX() != 0)
                {
                    if(frameBody >= COMBAT_BODY_WALK.length)
                    {
                        frameBody = 0;
                    }
                    bindSlot(COMBAT_BODY_WALK[frameBody]);
                    renderer.drawImage(COMBAT_BODY_WALK[frameBody], x, y, drawImageFlipped());
                }
                else
                {
                    bindSlot(COMBAT_BODY_IDLE);
                    renderer.drawImage(COMBAT_BODY_IDLE, x, y, drawImageFlipped());
                }

                // arms rendering
                int combatStart = ent.getController().getCombatTimer();
                if(combatStart != 0)
                {
                    combatStart /= 5;
                    if(combatStart < 0)
                    {
                        combatStart += COMBAT_SWITCH.length;
                    }
                    bindSlot(COMBAT_SWITCH[combatStart]);
                    renderer.drawImage(COMBAT_SWITCH[combatStart], x, y, drawImageFlipped());
                }
                else if(ent.getController().isAttacking())
                {
                    Image[] attack = COMBAT_ARMS_SWING[attackCounter];
                    if(frameArms >= attack.length)
                    {
                        frameArms = 0;
                        attackCounter++;
                        if(attackCounter >= COMBAT_ARMS_SWING.length)
                        {
                            attackCounter = 0;
                        }
                    }
                    bindSlot(attack[frameArms]);
                    renderer.drawImage(attack[frameArms], x, y, drawImageFlipped());
                }
                else
                {
                    bindSlot(COMBAT_ARMS_IDLE);
                    renderer.drawImage(COMBAT_ARMS_IDLE, x, y, drawImageFlipped());
                }

                // head rendering
                if(ent.getHealth().wasHurt())
                {
                    if(frameHead >= COMBAT_HEAD_HIT.length)
                    {
                        frameHead = 0;
                    }
                    bindSlot(COMBAT_HEAD_HIT[frameHead]);
                    renderer.drawImage(COMBAT_HEAD_HIT[frameHead], x, y, drawImageFlipped());
                }
                else
                {
                    if(frameHead >= COMBAT_HEAD.length)
                    {
                        frameHead = 0;
                    }
                    bindSlot(COMBAT_HEAD[frameHead]);
                    renderer.drawImage(COMBAT_HEAD[frameHead], x, y, drawImageFlipped());
                }
            }
        }
        else if(ent.isOnGround())
        {
            if(ent.getPreviousMotionX() != 0)
            {
                if(frameBody >= WALK.length)
                {
                    frameBody = 0;
                }
                bindSlot(WALK[frameBody]);
                renderer.drawImage(WALK[frameBody], x, y, drawImageFlipped());
            }
            else
            {
                if(frameBody >= IDLE.length)
                {
                    frameBody = 0;
                }
                bindSlot(IDLE[frameBody]);
                renderer.drawImage(IDLE[frameBody], x, y, drawImageFlipped());
            }
        }
        else
        {
            bindSlot(JUMP);
            renderer.drawImage(JUMP, x, y, drawImageFlipped());
        }
    }
    
    @Override
    public boolean drawImageFlipped() 
    {
        return flipped;
    }

    @Override
    public void tick() 
    {
        counter++;
        if(counter >= 6)
        {
            counter = 0;
            frameBody++;
            frameHead++;
            frameArms++;
        }
        
        if(frameBody < 0)
        {
            frameBody = 0;
        }
        
        if(frameHead < 0)
        {
            frameHead = 0;
        }
        
        if(frameArms < 0)
        {
            frameArms = 0;
        }
        
        blink++;
        if(blink > 9)
        { 
            blink = 0;
        }
        
        if(ent.getController().isInCombatMode())
        {
            if(KeyHandler.COMBAT_SWITCH_FACE.wasJustReleased())
            {
                flipped = !flipped;
            }
        }
        else
        {
            if(ent.getMotionX() < 0)
            {
                flipped = true;
            }
            else if(ent.getMotionX() > 0)
            {
                flipped = false;
            }
        }
    }
    
    private void bindSlot(Image image)
    {
        if(image != null)
        {
            Health h = ent.getHealth();
            if(h.wasHealed())
            {
                image.bindSlot(1);
            }
            else if(h.wasHurt())
            {
                if(blink >= 5)
                {
                    image.bindSlot(0);
                }
                else
                {
                    image.bindSlot(-1);
                }
            }
            else
            {
                image.bindSlot(-1);
            }
        }
    }
}
