-- Offers window tiling functionnality

local awful = require("awful")
local grect = require("gears.geometry").rectangle

-- Placements
local leftTileGeometry = awful.placement.scale
    + awful.placement.left
    + awful.placement['maximize_vertically']
local rightTileGeometry = awful.placement.scale
    + awful.placement.right
    + awful.placement['maximize_vertically']
local maximizedTileGeometry = awful.placement.scale
    + awful.placement['maximize']


-- Check if geometries are the same
local geometryEquals = function(geo1, geo2)
    return geo1.width == geo2.width and geo1.height == geo2.height and 
        geo1.x == geo2.x and geo1.y == geo2.y
end

-- Try to apply a tile placement to a client
-- return false if it changed nothing
local applyTile = function(c, geometry)
    local initialGeometry = {
        x = c.x,
        y = c.y,
        width = c.width,
        height = c.height
    }
    local newGeometry = geometry(c, {honor_workarea=true, to_percent = 0.5})
    return not geometryEquals(initialGeometry, newGeometry)
end

local screenLeft = function(geo)
    return function (c)
        local newScreen = c.screen.get_next_in_direction(c.screen, "left")
        if newScreen ~= nil then
            c.screen = newScreen
            applyTile(c, geo)
        end
    end
end

local screenRight = function(geo)
    return function (c)
        local newScreen = c.screen.get_next_in_direction(c.screen, "right")
        if newScreen ~= nil then
            c.screen = newScreen
            applyTile(c, geo)
        end
    end
end

local swapClient = function(c, dir)
    local sel = c or capi.client.focus
    if sel then
        local cltbl = sel.screen.tiled_clients
        local geomtbl = {}
        for i,cl in ipairs(cltbl) do
        	if not cl.maximized then
            	geomtbl[i] = cl:geometry()
           	end
        end
        local target = grect.get_in_direction(dir, geomtbl, sel:geometry())

        -- If we found a client to swap with, then go for it
        if target then
            cltbl[target]:swap(sel)
            return true
        end
    end
    
    return false
end

client.connect_signal("manage", function (c)
    if awesome.startup
      and not c.size_hints.user_position
      and not c.size_hints.program_position then
        -- Prevent clients from being unreachable after screen count changes.
        awful.placement.no_offscreen(c)
    end

    if c.maximized then
        applyTile(c, maximizedTileGeometry)
    end
end)

return {
    key = {
        tileRight = function (c)
        	if c.maximized then
        		c:raise()
	            if not applyTile(c, rightTileGeometry) then
	                screenRight(leftTileGeometry)(c)
	            end
            else
            	swapClient(c, 'right')
            end
        end,
        tileLeft = function (c)
            if c.maximized then
        		c:raise()
	            if not applyTile(c, leftTileGeometry) then
	                screenLeft(rightTileGeometry)(c)
	            end
            else
            	swapClient(c, 'left')
            end
        end,
        screenLeft = screenLeft(maximizedTileGeometry),
        screenRight = screenRight(maximizedTileGeometry),
        toggleMaximized = function (c)
            if not c.maximized then
            	if not swapClient(c, 'up') then
                	c.maximized = true
                	c:raise()
               	end
            else
                if not applyTile(c, maximizedTileGeometry) then 
                    c.maximized = false
                end
            end
        end,
        minimize = function(c)
           	if c.maximized or not swapClient(c, 'down') then
           		c.minimized = true
        	end
        end
    }
}