module viewtube_sprite_table (
	input logic         clk,
	input logic 	    reset,
	input logic	[7:0]   sprite_index,
	input logic 		sprite_increment_x,
	input logic [4:0]   sprite_row_offset,
	input logic			shift_current_sprite,
	input logic [23:0]  sprite_writedata,
    input logic [1:0]   sprite_io_address,
    input logic			sprite_io_write,
	output logic [4:0]  sprite_col_offset,
	output logic [11:0] sprite_cur_x_pos,
	output logic [11:0] sprite_cur_y_pos,
	output logic [11:0] sprite_start_x_pos,
    output logic [11:0] sprite_start_y_pos,
	output logic [9:0]  sprite_width,
	output logic [9:0]  sprite_height,
	output logic        sprite_ready,
	output logic        sprite_active,
	output logic [7:0]  out_VGA_R, out_VGA_G, out_VGA_B
);

	parameter MAX_SPRITE_ENTRIES = 256;


	logic [7:0]  letter_VGA_R, letter_VGA_G, letter_VGA_B,
				  color_VGA_R,  color_VGA_G,  color_VGA_B;
	logic [11:0] sprite_letter_start_x_pos, sprite_letter_start_y_pos,
				 sprite_color_start_x_pos,  sprite_color_start_y_pos;
					 
	logic [9:0]  sprite_letter_width, sprite_letter_height,
				 sprite_color_width,  sprite_color_height;
	
	logic [11:0] sprite_new_x_pos;
	logic [11:0] sprite_new_y_pos;

	logic sprite_letter_active, sprite_color_active;
	
	logic  [4:0] active_color;
	logic  [4:0] color_sprite_color;
	
	logic	[7:0]  prev_sprite_index;

	logic [4:0] prev_sprite_row_offset;
	logic [1:0] delay;
	logic write_single_cycle;


	initial sprite_col_offset = 5'b0;
	initial prev_sprite_row_offset = 5'b0;
	initial prev_sprite_index = 8'b0;
	initial delay = 0;
	initial write_single_cycle = 0;


	// memory for sprite table
	// each row can be configured
	parameter SPRITE_TABLE_MEM_WIDTH=64;
	parameter SPRITE_TABLE_MEM_ROW=MAX_SPRITE_ENTRIES;
	parameter SPRITE_TABLE_MEM_ROW_ADDR_W=$clog2(SPRITE_TABLE_MEM_ROW);
	parameter SPRITE_TABLE_ROM="roms/sprite_table.mem";
	logic [SPRITE_TABLE_MEM_WIDTH-1:0] sprite_table_data_in;
	logic [SPRITE_TABLE_MEM_WIDTH-1:0] sprite_table_data_out;
	logic [SPRITE_TABLE_MEM_ROW_ADDR_W-1:0] sprite_table_ptr;
	logic sprite_table_write;


	viewtube_dynamic_memory #(
        .WIDTH(SPRITE_TABLE_MEM_WIDTH),  
        .ROW(SPRITE_TABLE_MEM_ROW),
		.ROM_FILE(SPRITE_TABLE_ROM)
	) sprite_table_memory (
        .addr(sprite_table_ptr),
        .data_out(sprite_table_data_out),
		.data_in(sprite_table_data_in),
		.clk(clk),
		.write(sprite_table_write)
    );

	// memory for the sprite letters
	// read only
	// every letter is 8x16 bits
	parameter SPRITE_LETTERS_MEM_WIDTH=8;
	parameter SPRITE_LETTERS_MEM_ROW=1472;
	parameter SPRITE_LETTERS_MEM_ROW_ADDR_W=$clog2(SPRITE_LETTERS_MEM_ROW);
	parameter SPRITE_LETTERS_ROM="roms/letter-sprites.mem";
	logic [SPRITE_LETTERS_MEM_WIDTH-1:0] sprite_letters_data_out;
	logic [SPRITE_LETTERS_MEM_ROW_ADDR_W-1:0] sprite_letters_ptr;
	

	viewtube_static_memory #(
        .WIDTH(SPRITE_LETTERS_MEM_WIDTH),  
        .ROW(SPRITE_LETTERS_MEM_ROW),
        .ROM_FILE(SPRITE_LETTERS_ROM)
	) sprite_letters (
        .addr(sprite_letters_ptr),
        .data_out(sprite_letters_data_out),
		.clk(clk)
    );

	// memory for the 4-bit color sprites
	// read-only
	// every pixel is 4 bits
	parameter FOUR_BIT_COLOR_SPRITES_MEM_WIDTH=128;
	parameter FOUR_BIT_COLOR_SPRITES_MEM_ROW=2048;
	parameter FOUR_BIT_COLOR_SPRITES_MEM_ROW_ADDR_W=$clog2(FOUR_BIT_COLOR_SPRITES_MEM_ROW);
	parameter FOUR_BIT_COLOR_SPRITES_ROM="roms/4-bit-color-sprites.mem";
	logic [FOUR_BIT_COLOR_SPRITES_MEM_WIDTH-1:0] four_bit_color_sprites_data_out;
	logic [FOUR_BIT_COLOR_SPRITES_MEM_ROW_ADDR_W-1:0] four_bit_color_sprites_ptr;

	viewtube_static_memory #(
        .WIDTH(FOUR_BIT_COLOR_SPRITES_MEM_WIDTH),  
        .ROW(FOUR_BIT_COLOR_SPRITES_MEM_ROW),
        .ROM_FILE(FOUR_BIT_COLOR_SPRITES_ROM)
	) four_bit_color_sprites (
        .addr(four_bit_color_sprites_ptr),
        .data_out(four_bit_color_sprites_data_out),
		.clk(clk)
    );


	always_ff @(posedge clk) begin

		prev_sprite_index <= sprite_index;
		prev_sprite_row_offset <= sprite_row_offset;
		if (sprite_io_write) begin
			sprite_col_offset <= 0;
			sprite_ready <= 0;
			delay <= 2'd2;
		end else if ( delay != 2'b0) begin
			delay <= delay -1;
		end else if ( sprite_ready ) begin

			if (prev_sprite_index != sprite_index || prev_sprite_row_offset != sprite_row_offset) begin
				sprite_col_offset <= 0;
				sprite_ready <= 0;
				delay <= 2'd2;
			end else begin
				if (sprite_increment_x) begin
					if (sprite_col_offset +1 == sprite_width[4:0]) begin
						sprite_col_offset <= 0;
					end else begin
						sprite_col_offset <= sprite_col_offset +1;
					end
				end
			end
		end else begin
			// delay for one cycle
			// sprite_ready also delays for one cycle
			if (prev_sprite_index != sprite_index || prev_sprite_row_offset != sprite_row_offset) begin
				sprite_col_offset <= 0;
				sprite_ready <= 0;
				delay <= 2'd2;
			end else begin
				sprite_ready <= 1;
			end
		end

	end


	always_ff @(posedge clk) begin

		if (sprite_io_write) begin
			case(sprite_io_address)
				2'd0 : begin //update
					sprite_table_write <=1;
					if (sprite_writedata[23]) begin // letter
						sprite_table_data_in <= {sprite_writedata[23], //   type = 1
												sprite_writedata[22:16], // sprite # = 
												sprite_writedata[11:8], //  red
												sprite_writedata[7:4], //   green
												sprite_writedata[3:0], //   blue
												sprite_table_data_out[43:0]};
					end else begin // color
						sprite_table_data_in <= {sprite_writedata[23], 
												sprite_writedata[20:16],
												4'b0,
												sprite_writedata[12:8],
												sprite_writedata[4:0],
												sprite_table_data_out[43:0]};
					end
				end
				2'd1 : begin  //move
					sprite_table_write <=1;
					if (sprite_writedata[23]) begin // jump
						sprite_table_data_in <= {sprite_table_data_out[63:44],
												sprite_writedata[10:0],
												sprite_writedata[21:11],
												sprite_writedata[10:0],
												sprite_writedata[21:11]};
					end else begin // don't jump
						sprite_table_data_in <= {sprite_table_data_out[63:22],
												sprite_writedata[10:0],
												sprite_writedata[21:11]};
					end
					
				end
				2'd2 : sprite_table_write <= 0;
				2'd3 : sprite_table_write <= 0;
			endcase
			write_single_cycle <= 0;
		end else if(shift_current_sprite) begin
			sprite_table_data_in[63:44] <= sprite_table_data_out[63:44];
			sprite_table_data_in[21:0] <= sprite_table_data_out[21:0];

			if(sprite_table_data_out[43:33] > sprite_table_data_out[21:11]) begin
				//cur_x > new_x
				sprite_table_data_in[43:33] <= sprite_table_data_out[43:33] - 1;
			end else if (sprite_table_data_out[43:33] < sprite_table_data_out[21:11]) begin
				// cur_x < new_x
				sprite_table_data_in[43:33] <= sprite_table_data_out[43:33] + 1;
			end else begin
				// ==
				sprite_table_data_in[43:33] <= sprite_table_data_out[43:33];
			end
			
			if (sprite_table_data_out[32:22] > sprite_table_data_out[10:0]) begin
				//cur_y > new_y
				sprite_table_data_in[32:22] <= sprite_table_data_out[32:22] - 1;
			end else if (sprite_table_data_out[32:22] < sprite_table_data_out[10:0]) begin
				//cur_y < new_y
				sprite_table_data_in[32:22] <= sprite_table_data_out[32:22] + 1;
			end else begin
				// ==
				sprite_table_data_in[32:22] <= sprite_table_data_out[32:22];
			end
			sprite_table_write <= 1;
			write_single_cycle <= 1;
		end else  if ( delay != 2'b0 || write_single_cycle) begin
			sprite_table_write <= 0;
			write_single_cycle <= 0;
		end /*else begin
			sprite_table_write <= 0;
			
		end*/
	end
	
	
	

	

	always_comb begin
		sprite_table_ptr = sprite_index[SPRITE_TABLE_MEM_ROW_ADDR_W-1:0];

		// 4-bit color sprite table
		four_bit_color_sprites_ptr = {1'b0, sprite_table_data_out[62:58], sprite_row_offset};
		// multiplies sprite index type by 32 to account for rows per sprite
		sprite_color_start_x_pos  = {1'b0, sprite_table_data_out[43:33]};
		sprite_color_start_y_pos = {1'b0, sprite_table_data_out[32:22]};
		sprite_color_width = {5'b0, sprite_table_data_out[53:49]};
		sprite_color_height = {5'b0, sprite_table_data_out[48:44]};
		
		// letter sprite table
		sprite_letters_ptr = {sprite_table_data_out[62:56], sprite_row_offset[3:0]};
		// multiplies sprite index type by 16 to account for rows per sprite
		sprite_letter_start_x_pos = {1'b0, sprite_table_data_out[43:33]};
		sprite_letter_start_y_pos = {1'b0, sprite_table_data_out[32:22]};
		sprite_letter_width = 10'd8;
		sprite_letter_height = 10'd16;
		{letter_VGA_R, letter_VGA_G, letter_VGA_B} = { {sprite_table_data_out[55:52],sprite_table_data_out[55:52]},
		  								   {sprite_table_data_out[51:48],sprite_table_data_out[51:48]}, 
										   {sprite_table_data_out[47:44],sprite_table_data_out[47:44]}};

		case(sprite_col_offset[2:0])
			3'd0 : sprite_letter_active = sprite_letters_data_out[7];
			3'd1 : sprite_letter_active = sprite_letters_data_out[6];
			3'd2 : sprite_letter_active = sprite_letters_data_out[5];
			3'd3 : sprite_letter_active = sprite_letters_data_out[4];
			3'd4 : sprite_letter_active = sprite_letters_data_out[3];
			3'd5 : sprite_letter_active = sprite_letters_data_out[2];
			3'd6 : sprite_letter_active = sprite_letters_data_out[1];
			3'd7 : sprite_letter_active = sprite_letters_data_out[0];
			default : sprite_letter_active = sprite_letters_data_out[7];
		endcase


		case(sprite_col_offset)
			5'd0 : color_sprite_color = {1'b0, four_bit_color_sprites_data_out[127:124]};
			5'd1 : color_sprite_color = {1'b0, four_bit_color_sprites_data_out[123:120]}; 
			5'd2 : color_sprite_color = {1'b0, four_bit_color_sprites_data_out[119:116]}; 
			5'd3 : color_sprite_color = {1'b0, four_bit_color_sprites_data_out[115:112]};
			5'd4 : color_sprite_color = {1'b0, four_bit_color_sprites_data_out[111:108]};
			5'd5 : color_sprite_color = {1'b0, four_bit_color_sprites_data_out[107:104]};
			5'd6 : color_sprite_color = {1'b0, four_bit_color_sprites_data_out[103:100]};
			5'd7 : color_sprite_color = {1'b0, four_bit_color_sprites_data_out[99:96]};
			5'd8 : color_sprite_color = {1'b0, four_bit_color_sprites_data_out[95:92]};
			5'd9 : color_sprite_color = {1'b0, four_bit_color_sprites_data_out[91:88]};
			5'd10 : color_sprite_color = {1'b0, four_bit_color_sprites_data_out[87:84]};
			5'd11 : color_sprite_color = {1'b0, four_bit_color_sprites_data_out[83:80]};
			5'd12 : color_sprite_color = {1'b0, four_bit_color_sprites_data_out[79:76]};
			5'd13 : color_sprite_color = {1'b0, four_bit_color_sprites_data_out[75:72]};
			5'd14 : color_sprite_color = {1'b0, four_bit_color_sprites_data_out[71:68]};
			5'd15 : color_sprite_color = {1'b0, four_bit_color_sprites_data_out[67:64]};
			5'd16 : color_sprite_color = {1'b0, four_bit_color_sprites_data_out[63:60]};
			5'd17 : color_sprite_color = {1'b0, four_bit_color_sprites_data_out[59:56]};
			5'd18 : color_sprite_color = {1'b0, four_bit_color_sprites_data_out[55:52]};
			5'd19 : color_sprite_color = {1'b0, four_bit_color_sprites_data_out[51:48]};
			5'd20 : color_sprite_color = {1'b0, four_bit_color_sprites_data_out[47:44]};
			5'd21 : color_sprite_color = {1'b0, four_bit_color_sprites_data_out[43:40]};
			5'd22 : color_sprite_color = {1'b0, four_bit_color_sprites_data_out[39:36]};
			5'd23 : color_sprite_color = {1'b0, four_bit_color_sprites_data_out[35:32]};
			5'd24 : color_sprite_color = {1'b0, four_bit_color_sprites_data_out[31:28]};
			5'd25 : color_sprite_color = {1'b0, four_bit_color_sprites_data_out[27:24]};
			5'd26 : color_sprite_color = {1'b0, four_bit_color_sprites_data_out[23:20]};
			5'd27 : color_sprite_color = {1'b0, four_bit_color_sprites_data_out[19:16]};
			5'd28 : color_sprite_color = {1'b0, four_bit_color_sprites_data_out[15:12]};
			5'd29 : color_sprite_color = {1'b0, four_bit_color_sprites_data_out[11:8]};
			5'd30 : color_sprite_color = {1'b0, four_bit_color_sprites_data_out[7:4]};
			5'd31 : color_sprite_color = {1'b0, four_bit_color_sprites_data_out[3:0]};
			default: color_sprite_color = {1'b0, four_bit_color_sprites_data_out[127:124]};
		endcase
				
		case (color_sprite_color)
			5'h0 : begin
				{color_VGA_R, color_VGA_G, color_VGA_B} = {8'h0, 8'h0, 8'h0};
				sprite_color_active = 0; 
			end
			5'h1 : begin 
				sprite_color_active = 1;
				{color_VGA_R, color_VGA_G, color_VGA_B} = {8'h0, 8'h0, 8'h0}; // black
			end
			5'h2 : begin 
				sprite_color_active = 1;
				{color_VGA_R, color_VGA_G, color_VGA_B} = { 8'hfe, 8'h0, 8'h0}; // red
			end
			5'h3 : begin 
				sprite_color_active = 1;
				{color_VGA_R, color_VGA_G, color_VGA_B} = { 8'hba, 8'he3, 8'ha9}; // land
			end
			5'h4 : begin 
				sprite_color_active = 1;
				{color_VGA_R, color_VGA_G, color_VGA_B} = { 8'hff, 8'hff, 8'hff}; // white
			end
			5'h5 : begin 
				sprite_color_active = 1;
				{color_VGA_R, color_VGA_G, color_VGA_B} = { 8'h78, 8'h81, 8'h7e}; //train_gray
			end
			5'h6 : begin 
				sprite_color_active = 1;
				{color_VGA_R, color_VGA_G, color_VGA_B} = { 8'h5b, 8'hac, 8'hbf}; //water
			end
			5'h7 : begin 
				sprite_color_active = 1;
				{color_VGA_R, color_VGA_G, color_VGA_B} = { 8'hf5, 8'h71, 8'h11}; //orange
			end
			5'h8 : begin 
				sprite_color_active = 1;
				{color_VGA_R, color_VGA_G, color_VGA_B} = { 8'h0b, 8'h67, 8'hbe}; //blue
			end
			5'h9 : begin 
				sprite_color_active = 1;
				{color_VGA_R, color_VGA_G, color_VGA_B} = { 8'h7e, 8'hce, 8'h49}; //green
			end
			5'ha : begin 
				sprite_color_active = 1;
				{color_VGA_R, color_VGA_G, color_VGA_B} = { 8'hff, 8'hd4, 8'h0d}; //yellow
			end
			5'hb : begin 
				sprite_color_active = 1;
				{color_VGA_R, color_VGA_G, color_VGA_B} = { 8'ha8, 8'h49, 8'ha4}; //purple
			end
			5'hc : begin 
				sprite_color_active = 1;
				{color_VGA_R, color_VGA_G, color_VGA_B} = { 8'h97, 8'h93, 8'h91}; //gray
			end
			5'hd : begin 
				sprite_color_active = 1;
				{color_VGA_R, color_VGA_G, color_VGA_B} = { 8'had, 8'h66, 8'h00}; //brown
			end
			5'he : begin 
				sprite_color_active = 1;
				{color_VGA_R, color_VGA_G, color_VGA_B} = { 8'h2d, 8'h2c, 8'h1a}; //dark_gray
			end
			5'hf : begin 
				sprite_color_active = 1;
				{color_VGA_R, color_VGA_G, color_VGA_B} = { 8'h00, 8'h9f, 8'h57}; //dark_green
			end
			default : begin
				{color_VGA_R, color_VGA_G, color_VGA_B} = {8'h0, 8'h0, 8'h0};
				sprite_color_active = 0;
			end
		endcase 

		if (sprite_table_data_out[63]) begin
			// letter sprite
			sprite_start_x_pos = sprite_letter_start_x_pos;
    		sprite_start_y_pos = sprite_letter_start_y_pos;
			sprite_width = sprite_letter_width;
			sprite_height = sprite_letter_height;
			{out_VGA_R, out_VGA_G, out_VGA_B} = {letter_VGA_R, letter_VGA_G, letter_VGA_B};
			sprite_active = sprite_letter_active;
		end else begin
			//4-bit color sprite
			sprite_start_x_pos = sprite_color_start_x_pos;
    		sprite_start_y_pos = sprite_color_start_y_pos;
			sprite_width = sprite_color_width;
			sprite_height = sprite_color_height;
			{out_VGA_R, out_VGA_G, out_VGA_B} = {color_VGA_R, color_VGA_G, color_VGA_B};
			sprite_active = sprite_color_active;
		end
	end
	    
endmodule
