local SRS = require 'tetris.rulesets.ti_srs'

local KRS = SRS:extend()

KRS.name = "K.R.S."
KRS.hash = "KRS"
KRS.colourscheme = {
	I = "M",
	L = "R",
	J = "C",
	S = "O",
	Z = "B",
	O = "Y",
	T = "G",
}

KRS.wallkicks_3x3 = {
    [0]={
        [1]={{-1,0},{-1,-1}},
        [2]={{0,-1},{0,-2}},
        [3]={{1,0},{1,-1}},
    },
    [1]={
        [0]={{1,0},{1,1}},
        [2]={{1,0},{1,-1}},
        [3]={{1,0},{2,0}},
    },
    [2]={
        [0]={{0,1},{0,2}},
        [1]={{-1,0},{-1,1}},
        [3]={{1,0},{1,1}},
    },
    [3]={
        [0]={{-1,0},{-1,1}},
        [1]={{-1,0},{-2,0}},
        [2]={{-1,0},{-1,-1}},
    },
}

KRS.wallkicks_line = {
    [0]={
        [1]={{-1,0},{-1,-1},{1,0},{1,1}},
        [2]={{0,-1},{0,-2}},
        [3]={{1,0},{1,-1},{-1,0},{-1,1}},
    },
    [1]={
        [0]={{1,0},{1,1},{-1,0},{-1,-1}},
        [2]={{1,0},{1,-1},{-1,0},{-1,1}},
        [3]={{2,0}},
    },
    [2]={
        [0]={{0,1},{0,2}},
        [1]={{-1,0},{-1,1},{1,0},{1,-1}},
        [3]={{1,0},{1,1},{-1,0},{-1,-1}},
    },
    [3]={
        [0]={{-1,0},{-1,1},{1,0},{1,-1}},
        [1]={{-2,0}},
        [2]={{-1,0},{-1,-1},{1,0},{1,1}},
    },
}

function KRS:onPieceCreate(piece)
    piece.das_kicked = false
    piece.recovery_frames = self.game:getLockDelay() * 15
end

function KRS:onPieceDrop() end

function KRS:onPieceMove(piece)
    while piece.lock_delay > 0 and piece.recovery_frames > 0 do
        piece.recovery_frames = piece.recovery_frames - 1
        piece.lock_delay = piece.lock_delay - 1
    end
end

function KRS:onPieceRotate(piece)
    while piece.lock_delay > 0 and piece.recovery_frames > 0 do
        piece.recovery_frames = piece.recovery_frames - 1
        piece.lock_delay = piece.lock_delay - 1
    end
end

function KRS:canPieceMove(piece) return not piece.das_kicked end
function KRS:canPieceRotate(piece) return true end

function KRS:attemptRotate(new_inputs, piece, grid, initial)
	piece.das_kicked = false
    local rot_dir = 0
	
	if (new_inputs["rotate_left"] or new_inputs["rotate_left2"]) then
		rot_dir = 3
	elseif (new_inputs["rotate_right"] or new_inputs["rotate_right2"]) then
		rot_dir = 1
	elseif (new_inputs["rotate_180"]) then
		rot_dir = self:get180RotationValue()
	end

	if rot_dir == 0 then return end
    if config.gamesettings.world_reverse == 3 or (self.world and config.gamesettings.world_reverse == 2) then
        rot_dir = 4 - rot_dir
    end

	local new_piece = piece:withRelativeRotation(rot_dir)

    if initial then
        if grid:canPlacePiece(new_piece) then
            piece:setRelativeRotation(rot_dir)
            self:onPieceRotate(piece)
        end
    else
	    self:attemptWallkicks(piece, new_piece, rot_dir, grid, new_inputs)
    end
end

function KRS:attemptWallkicks(piece, new_piece, rot_dir, grid, new_inputs)
    local kicks = (
        piece.shape == "I" and
        KRS.wallkicks_line[piece.rotation][new_piece.rotation] or
        KRS.wallkicks_3x3[piece.rotation][new_piece.rotation]
    )
    local priority = 0
    local das_charged = (
        self.game.das.frames >= self.game:getDasLimit() - self.game:getARR()
    )
    if (
        new_inputs.left or
        (self.game.das.direction == "left" and
        (das_charged or piece:isMoveBlocked(grid, {x=-1, y=0})))
    ) then
        priority = -1
    elseif (
        new_inputs.right or
        (self.game.das.direction == "right" and
        (das_charged or piece:isMoveBlocked(grid, {x=1, y=0})))
    ) then
        priority = 1
    end

    -- base rotation with offset
    if grid:canPlacePiece(new_piece:withOffset({x=priority, y=0})) then
        piece:setRelativeRotation(rot_dir)
        piece:setOffset({x=priority, y=0})
        self:onPieceRotate(piece)
        piece.das_kicked = priority ~= 0
        return
    end

    -- das kicks
    for idx, offset in pairs(kicks) do
        kicked_piece = new_piece:withOffset({x=offset[1]+priority, y=offset[2]})
        if grid:canPlacePiece(kicked_piece) then
			piece:setRelativeRotation(rot_dir)
			piece:setOffset({x=offset[1]+priority, y=offset[2]})
			self:onPieceRotate(piece)
            piece.das_kicked = priority ~= 0
			return
		end
    end

    -- base rotation
    if grid:canPlacePiece(new_piece) then
        piece:setRelativeRotation(rot_dir)
        self:onPieceRotate(piece)
        return
    end

    -- regular kicks
    for idx, offset in pairs(kicks) do
        kicked_piece = new_piece:withOffset({x=offset[1], y=offset[2]})
        if grid:canPlacePiece(kicked_piece) then
			piece:setRelativeRotation(rot_dir)
			piece:setOffset({x=offset[1], y=offset[2]})
			self:onPieceRotate(piece)
			return
		end
    end
end

function KRS:get180RotationValue() return 2 end

return KRS