local libfolder = os.getenv('HOME') .. '/.config/awesome/lib/'
package.path = (libfolder .. '?/init.lua;') .. (libfolder .. '?.lua;') .. package.path

pcall(require, 'luarocks.loader')

local gears = require('gears')
local awful = require('awful')

require('awful.autofocus')

local wibox = require('wibox')
local beautiful = require('beautiful')
local naughty = require('naughty')
local lain = require('lain')
local freedesktop = require('freedesktop')
local hotkeys_popup = require('awful.hotkeys_popup')
require('awful.hotkeys_popup.keys')
local theme = require('theme')
local constrain = require('rc_parts.constrain')
local globals = require('rc_parts.globals')

local mytable = awful.util.table or gears.table -- 4.{0,1} compatibility

-- Check if awesome encountered an error during startup and fell back to
-- another config (This code will only ever execute for the fallback config)
if awesome.startup_errors then
	naughty.notify({
		preset = naughty.config.presets.critical,
		title = 'Oops, there were errors during startup!',
		text = awesome.startup_errors,
	})
end

-- Handle runtime errors after startup
do
	local in_error = false

	awesome.connect_signal('debug::error', function(err)
		if in_error then
			return
		end

		in_error = true

		naughty.notify({
			preset = naughty.config.presets.critical,
			title = 'Oops, an error happened!',
			text = tostring(err),
		})

		in_error = false
	end)
end

-- This function will run once every time Awesome is started
--[[ local function run_once(cmd_arr)
    for _, cmd in ipairs(cmd_arr) do
        awful.spawn.with_shell(string.format("pgrep -u $USER -fx '%s' > /dev/null || (%s)", cmd, cmd))
    end
end ]]
--

local terminal = globals.terminal
local modkey = globals.modkey
local altkey = globals.altkey

awful.util.terminal = terminal
awful.util.tagnames = { '1', '2', '3', '4', '5' }
awful.layout.layouts = {
	awful.layout.suit.tile,
	awful.layout.suit.tile.left,
	awful.layout.suit.tile.bottom,
	awful.layout.suit.tile.top,
	awful.layout.suit.fair,
	awful.layout.suit.fair.horizontal,
	awful.layout.suit.spiral,
	awful.layout.suit.spiral.dwindle,
	awful.layout.suit.max,
	awful.layout.suit.max.fullscreen,
	awful.layout.suit.magnifier,
	awful.layout.suit.corner.nw,
	awful.layout.suit.floating,
}

awful.util.taglist_buttons = mytable.join(
	awful.button({}, 1, function(t)
		t:view_only()
	end),
	awful.button({ modkey }, 1, function(t)
		if client.focus then
			client.focus:move_to_tag(t)
		end
	end),
	awful.button({}, 3, awful.tag.viewtoggle),
	awful.button({ modkey }, 3, function(t)
		if client.focus then
			client.focus:toggle_tag(t)
		end
	end),
	awful.button({}, 4, function(t)
		awful.tag.viewnext(t.screen)
	end),
	awful.button({}, 5, function(t)
		awful.tag.viewprev(t.screen)
	end)
)

awful.util.tasklist_buttons = mytable.join(
	awful.button({}, 1, function(c)
		if c == client.focus then
			c.minimized = true
		else
			c:emit_signal('request::activate', 'tasklist', { raise = true })
		end
	end),
	awful.button({}, 3, function()
		awful.menu.client_list({ theme = { width = 250 } })
	end),
	awful.button({}, 4, function()
		awful.client.focus.byidx(1)
	end),
	awful.button({}, 5, function()
		awful.client.focus.byidx(-1)
	end)
)

beautiful.init(theme)

local myawesomemenu = {
	{
		'Hotkeys',
		function()
			hotkeys_popup.show_help(nil, awful.screen.focused())
		end,
	},
	{ 'Manual', string.format('%s -e man awesome', terminal) },
	{ 'Edit config', string.format('%s -e %s %s', terminal, globals.editor, awesome.conffile) },
	{ 'Restart', awesome.restart },
	{
		'Quit',
		function()
			awesome.quit()
		end,
	},
}

awful.util.mymainmenu = freedesktop.menu.build({
	before = {
		{ 'Awesome', myawesomemenu, beautiful.awesome_icon },
		-- other triads can be put here
	},
	after = {
		{ 'Open terminal', terminal },
		-- other triads can be put here
	},
})

-- Re-set wallpaper when a screen's geometry changes (e.g. different resolution)
screen.connect_signal('property::geometry', function(s)
	-- Wallpaper
	if beautiful.wallpaper then
		local wallpaper = beautiful.wallpaper
		-- If wallpaper is a function, call it with the screen
		if type(wallpaper) == 'function' then
			wallpaper = wallpaper(s)
		end
		gears.wallpaper.maximized(wallpaper, s, true)
	end
end)

-- No borders when rearranging only 1 non-floating or maximized client
screen.connect_signal('arrange', function(s)
	local only_one = #s.tiled_clients == 1
	for _, c in pairs(s.clients) do
		if only_one and not c.floating or c.maximized or c.fullscreen then
			c.border_width = 0
		else
			c.border_width = beautiful.border_width
		end
	end
end)

-- Create a wibox for each screen and add it
awful.screen.connect_for_each_screen(function(s)
	beautiful.at_screen_connect(s)
end)

local clientkeys = mytable.join(
	awful.key({ altkey, 'Shift' }, 'm', lain.util.magnify_client, { description = 'magnify client', group = 'client' }),
	awful.key({ modkey }, 'f', function(c)
		c.fullscreen = not c.fullscreen
		c:raise()
	end, { description = 'toggle fullscreen', group = 'client' }),
	awful.key({ modkey, 'Shift' }, 'c', function(c)
		c:kill()
	end, { description = 'close', group = 'client' }),
	awful.key({ modkey, 'Shift', 'Control', altkey }, 'c', function(c)
		awesome.kill(c.pid, awesome.unix_signal['SIGKILL'])
	end, { description = 'send sigkill', group = 'client' }),
	awful.key(
		{ modkey, 'Control' },
		'space',
		awful.client.floating.toggle,
		{ description = 'toggle floating', group = 'client' }
	),
	awful.key({ modkey, 'Control' }, 'Return', function(c)
		c:swap(awful.client.getmaster())
	end, { description = 'move to master', group = 'client' }),
	awful.key({ modkey }, 'o', function(c)
		c:move_to_screen()
	end, { description = 'move to screen', group = 'client' }),
	awful.key({ modkey }, 't', function(c)
		c.ontop = not c.ontop
	end, { description = 'toggle keep on top', group = 'client' }),
	awful.key({ modkey }, 'n', function(c)
		-- The client currently has the input focus, so it cannot be
		-- minimized, since minimized clients can't have the focus.
		c.minimized = true
	end, { description = 'minimize', group = 'client' }),
	awful.key({ modkey }, 'm', function(c)
		c.maximized = not c.maximized
		c:raise()
	end, { description = '(un)maximize', group = 'client' }),
	awful.key({ modkey, 'Control' }, 'm', function(c)
		c.maximized_vertical = not c.maximized_vertical
		c:raise()
	end, { description = '(un)maximize vertically', group = 'client' }),
	awful.key({ modkey, 'Shift' }, 'm', function(c)
		c.maximized_horizontal = not c.maximized_horizontal
		c:raise()
	end, { description = '(un)maximize horizontally', group = 'client' }),
	-- Show/hide titlebar
	awful.key({ modkey, 'Control' }, 's', function(c)
		awful.titlebar.toggle(c)
		c:raise()
	end, { description = 'toggle titlebar', group = 'client' }),
	-- Toggle constrain mouse to window
	awful.key({ modkey, 'Control' }, 'F10', function(c)
		constrain.toggle(c)
	end, { description = 'toggle mouse constrain', group = 'client' })
)

local clientbuttons = mytable.join(
	awful.button({}, 1, function(c)
		c:emit_signal('request::activate', 'mouse_click', { raise = true })
	end),
	awful.button({ modkey }, 1, function(c)
		c:emit_signal('request::activate', 'mouse_click', { raise = true })
		awful.mouse.client.move(c)
	end),
	awful.button({ modkey }, 3, function(c)
		c:emit_signal('request::activate', 'mouse_click', { raise = true })
		awful.mouse.client.resize(c)
	end)
)

-- Set keys
root.keys(require('rc_parts.global_keys'))

-- }}}

-- {{{ Rules

-- Rules to apply to new clients (through the "manage" signal).
awful.rules.rules = {
	-- All clients will match this rule.
	{
		rule = {},
		properties = {
			border_width = beautiful.border_width,
			border_color = beautiful.border_normal,
			callback = awful.client.setslave,
			focus = awful.client.focus.filter,
			raise = true,
			keys = clientkeys,
			buttons = clientbuttons,
			screen = awful.screen.preferred,
			placement = awful.placement.no_overlap + awful.placement.no_offscreen,
			size_hints_honor = false,
		},
	},

	-- Floating clients.
	{
		rule_any = {
			instance = {
				'DTA', -- Firefox addon DownThemAll.
				'copyq', -- Includes session name in class.
				'pinentry',
			},
			class = {
				'Arandr',
				'Blueman-manager',
				'Gpick',
				'Kruler',
				'MessageWin', -- kalarm.
				'Sxiv',
				'Tor Browser', -- Needs a fixed window size to avoid fingerprinting by screen size.
				'Wpa_gui',
				'veromix',
				'xtightvncviewer',
			},

			-- Note that the name property shown in xprop might be set slightly after creation of the client
			-- and the name shown there might not match defined rules here.
			name = {
				'Event Tester', -- xev.
			},
			role = {
				'AlarmWindow', -- Thunderbird's calendar.
				'ConfigManager', -- Thunderbird's about:config.
				'pop-up', -- e.g. Google Chrome's (detached) Developer Tools.
			},
		},
		properties = { floating = true },
	},

	{
		rule_any = { class = { 'firefox', 'factorio' } },
		properties = { opacity = 1, maximized = false, floating = false },
	},

	-- Add titlebars to normal clients and dialogs
	{ rule_any = { type = { 'normal', 'dialog' } }, properties = { titlebars_enabled = true } },
	{
		rule = { class = 'mpv' },
		properties = { fullscreen = true },
	},

	-- Set Firefox to always map on the tag named "2" on screen 1.
	-- { rule = { class = "Firefox" },
	--   properties = { screen = 1, tag = "2" } },
}

-- Signal function to execute when a new client appears.
client.connect_signal('manage', function(c)
	-- Set the windows at the slave,
	-- i.e. put it at the end of others instead of setting it master.
	-- if not awesome.startup then awful.client.setslave(c) end

	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
end)

-- Add a titlebar if titlebars_enabled is set to true in the rules.
client.connect_signal('request::titlebars', function(c)
	-- Custom
	if beautiful.titlebar_fun then
		beautiful.titlebar_fun(c)
		return
	end

	-- Default
	-- buttons for the titlebar
	local buttons = mytable.join(
		awful.button({}, 1, function()
			c:emit_signal('request::activate', 'titlebar', { raise = true })
			awful.mouse.client.move(c)
		end),
		awful.button({}, 2, function()
			--c:emit_signal("request::activate", "titlebar", {raise = true})
			awesome.kill(c.pid, awesome.unix_signal['SIGTERM'])
		end),
		awful.button({}, 3, function()
			c:emit_signal('request::activate', 'titlebar', { raise = true })
			awful.mouse.client.resize(c)
		end)
	)

	awful.titlebar(c, { size = 16 }):setup({
		{ -- Left
			awful.titlebar.widget.iconwidget(c),
			buttons = buttons,
			layout = wibox.layout.fixed.horizontal,
		},
		{ -- Middle
			{ -- Title
				align = 'center',
				widget = awful.titlebar.widget.titlewidget(c),
			},
			buttons = buttons,
			layout = wibox.layout.flex.horizontal,
		},
		{ -- Right
			awful.titlebar.widget.floatingbutton(c),
			awful.titlebar.widget.maximizedbutton(c),
			awful.titlebar.widget.stickybutton(c),
			awful.titlebar.widget.ontopbutton(c),
			awful.titlebar.widget.closebutton(c),
			layout = wibox.layout.fixed.horizontal(),
		},
		layout = wibox.layout.align.horizontal,
	})
end)

-- Enable sloppy focus, so that focus follows mouse.
client.connect_signal('mouse::enter', function(c)
	c:emit_signal('request::activate', 'mouse_enter', { raise = globals.vi_focus })
end)

client.connect_signal('focus', function(c)
	c.border_color = beautiful.border_focus
end)
client.connect_signal('unfocus', function(c)
	c.border_color = beautiful.border_normal
end)
