----------------------------------------------------------------------------------
-- Company: 
-- Engineer: 
-- 
-- Create Date: 30.11.2021 10:35:30
-- Design Name: 
-- Module Name: Gene_Snake - Behavioral
-- Project Name: 
-- Target Devices: 
-- Tool Versions: 
-- Description: 
-- 
-- Dependencies: 
-- 
-- Revision:
-- Revision 0.01 - File Created
-- Additional Comments:
-- 
----------------------------------------------------------------------------------
-- a faire:
--  - faire bouger le snake
--  - ajouter une clk

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
use IEEE.NUMERIC_STD.ALL;

library ourTypes;
use ourTypes.types.all;

-- Uncomment the following library declaration if instantiating
-- any Xilinx leaf cells in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

entity Gene_Snake is
generic( addressSize : integer:=10);
Port ( X : in unsigned (9 downto 0);
       Y : in unsigned (8 downto 0);
       clk: in std_logic;
       reset: in std_logic;
       
       currentSnakes : in nSnakes;
       listRefs : in addresses;
       tailIndex : in unsigned(SNAKE_ADDRESS_SIZE-1 downto 0);
       updateOrder : in std_logic;
       dataReady : in std_logic;

       cCaseX : out unsigned(5 downto 0);
       cCaseY : out unsigned(4 downto 0);
       dataRequest : out std_logic := '0';

       colorOut : out color;
        
       ROMAddress : out unsigned(SPRITES_ADDRESS_SIZE-1 downto 0) := (others => '0');
       ROMData : in std_logic_vector(SPRITES_DATA_SIZE-1 downto 0)
       );
end Gene_Snake;

architecture Behavioral of Gene_Snake is

-- D???claration des signaux
signal snakeHere: std_logic := '0'; --1 si on doit afficher le pixel 0 sinon
signal startUpdate : std_logic := '0';
signal request :std_logic := '0';
signal snakeColor : color := (others => (others => '0'));

begin

process(reset,updateOrder,clk)
variable sX,sY,sOff,iterInd : integer;
begin
    if(reset = '0') then
        snakeHere <= '0';
        snakeColor <= (others => (others => '0'));
    else
    
    
    if(updateOrder'event and updateOrder = '1') then
        if(snakeHere = '1') then
	        --snakeColor <= (others => (others => '1'));
	        snakeColor <= to_color(ROMData);
        else
            snakeColor <= (others => (others => '0'));
        end if;
        startUpdate <= '1';
    end if;
    
    
    if(clk'event and clk = '1') then
        if(dataReady = '1') then
            request <= '0';
            for j in currentSnakes'LOW to currentSnakes'HIGH loop
                iterInd := (j + 5) rem 9;
                if(currentSnakes(iterInd).isDefined = '1' and X>=currentSnakes(iterInd).X-8 and X<currentSnakes(iterInd).X+8 and Y>=currentSnakes(iterInd).Y-8 and Y<currentSnakes(iterInd).Y+8) then
                    snakeHere <= '1';
                    sX := to_integer(currentSnakes(iterInd).dirX or "01") * (to_integer(X) - to_integer(currentSnakes(iterInd).X)) + 8 + to_integer(shift_right(currentSnakes(iterInd).dirX,1));
                    sY := to_integer(currentSnakes(iterInd).dirY or "01") * (to_integer(Y) - to_integer(currentSnakes(iterInd).Y)) + 8 + to_integer(shift_right(currentSnakes(iterInd).dirY,1));
                    if(listRefs(iterInd) = 0) then
                        sOff := HEAD_SPRITE_OFFSET;
                    elsif(listRefs(iterInd) = tailIndex) then
                        sOff := TAIL_SPRITE_OFFSET;
                    else
                        sOff := BODY_SPRITE_OFFSET;
                    end if;
                    case currentSnakes(iterInd).dirY(0) is
                        when '1' => ROMAddress <= to_unsigned(sX*16+sY+sOff,SPRITES_ADDRESS_SIZE);
                        when '0' => ROMAddress <= to_unsigned(sY*16+sX+sOff,SPRITES_ADDRESS_SIZE);
                        when others => NULL;
                    end case;
                end if;
            end loop;
        end if;
        
        if(startUpdate = '1') then
            snakeHere <= '0';
            cCaseX <= X(9 downto 4);
            cCaseY <= Y(8 downto 4);
            request <= '1';
        end if;
    end if;
    
    if(request = '1') then
        startUpdate <= '0';
    end if;
    end if;
end process;

dataRequest <= request;
colorOut <= snakeColor;
end Behavioral;
