#!/usr/local/bin/perl

# ========================
# =====    ===============
# ======  ================
# ======  ================
# ======  ====   ====   ==
# ======  ===     ==  =  =
# ======  ===  =  ==     =
# =  ===  ===  =  ==  ====
# =  ===  ===  =  ==  =  =
# ==     =====   ====   ==
# ========================
#
# SPDX-License-Identifier: BSD-3-Clause
#
# Copyright © 2020 Joe
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
# 1. Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in the
#    documentation and/or other materials provided with the distribution.
# 3. Neither the name of the organization nor the
#    names of its contributors may be used to endorse or promote products
#    derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY JOE ''AS IS'' AND ANY
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL JOE BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# bspwmrc
# 2020-11-05 22:34
# Joe

use strict;
use warnings;
use Capture::Tiny qw(capture);
use Time::HiRes;
use WWW::Curl::Easy;

use constant {
	TERMINAL	=> 'st',
	TERM_PATH	=> '/usr/local/bin/st'
};
use constant {
	SXHKD_PATH				=> '/usr/local/bin/sxhkd',
	PGREP_PATH				=> '/bin/pgrep',
	PKILL_PATH				=> '/bin/pkill',
	XRANDR_PATH				=> '/usr/local/bin/xrandr',
	MAINSCREEN_PATH			=> '/usr/home/jozan/.local/bin/mainscreen',
	DUALSCREEN_PATH			=> '/usr/home/jozan/.local/bin/dualscreen',
	TRIPLESCREEN_PATH		=> '/usr/home/jozan/.local/bin/triplescreen',
	BSPC_PATH				=> '/usr/local/bin/bspc',
	COMPTON_PATH			=> '/usr/local/bin/compton',
	XSET_PATH				=> '/usr/local/bin/xset',
	SETXKBMAP_PATH			=> '/usr/local/bin/setxkbmap',
	DUNST_PATH				=> '/usr/local/bin/dunst',
	LOWBAT_PATH				=> '/usr/local/bin/lowbat',
	EMACS_PATH				=> '/usr/local/bin/emacs',
	NEOVIM_PATH				=> '/usr/local/bin/nvim',
	PGREP_PATH				=> '/bin/pgrep',
	ESPEAK_PATH				=> '/usr/local/bin/espeak',
	SH_PATH					=> '/bin/sh',
	ZSH_PATH				=> '/usr/local/bin/zsh',
	DASH_PATH				=> '/usr/local/bin/dash',
	FISH_PATH				=> '/usr/local/bin/fish',
	COWSAY_PATH				=> '/usr/local/bin/cowsay',
	HTOP_PATH				=> '/usr/local/bin/htop',
	GOTOP_PATH				=> '/usr/local/bin/gotop',
	VIFM_PATH				=> '/usr/local/bin/vifm',
	GIT_PATH				=> '/usr/local/bin/git',
	XSETROOT_PATH			=> '/usr/local/bin/xsetroot',
	XINPUT_PATH				=> '/usr/local/bin/xinput',
	SETWP_PATH				=> '/usr/home/jozan/.local/bin/setwp',
	BSPSWALLOW_PATH			=> '/usr/home/jozan/.local/bin/bspswallow',
	NEOMUTT_PATH			=> '/usr/local/bin/neomutt',
	SCLI_PATH				=> '/usr/local/bin/scli',
	VIMPC_PATH				=> '/usr/local/bin/vimpc',
	MPD_NOTIFICATION_PATH	=> '/usr/local/bin/mpd-notification',
	XMODMAP_PATH			=> '/usr/local/bin/xmodmap'
};
use constant {
	BSP_BORDER_WIDTH		=> 1,
	BSP_WINDOW_GAP			=> 0,
	BSP_BORDER_COLOR		=> '#9d2121',
	BSP_PRESEL_COLOR		=> '#9d2121',
	BSP_SPLIT_RATIO			=> '0.50',
	BSP_BORDERLESS_MONOCLE	=> 'true',
	BSP_GAPLESS_MONOCLE		=> 'true',
	BSP_SINGLE_MONOCLE		=> 'true',
	XSET_R_RATE_DELAY		=> 200,
	XSET_R_RATE_RATE		=> 150
};
use constant COWSAY_WELCOME		=> 'Welcome back, partner! And remember to try glest!';
use constant NETWORK_TEST_URL	=> 'https://www.freebsd.org/';
use constant SLEEP_TIME			=> 3.5;

sub run_if_dead
{
	my @argv = @_;
	my $bin;
	my $pid;

	if ($argv[0] =~ /SXHKD_SHELL/) {
		$bin = $argv[1];
	}
	else {
		$bin = $argv[0];
	}
	$bin =~ s/.+\///g;
	my (undef, undef, $retval) = capture {
		system(
			PGREP_PATH,
			$bin
			);
	};
	$retval = ($retval >> 8) & 0xff;
	if ($retval != 0) {
		$pid = fork();
		if (not $pid) {
			if ($argv[0] =~ /SXHKD_SHELL/) {
				exec($argv[0] . ' ' . $argv[1]);
				exit;
			}
			else {
				exec(@argv);
				exit;
			}
		}
	}
	return;
}

sub kill_some
{
	system(PKILL_PATH, TERMINAL);
	return;
}

sub enable_screens
{
	my $stdout;
	my $screens;

	$screens = 1;
	($stdout, undef, undef) = capture {
		system(XRANDR_PATH);
	};
	if ($stdout =~ m/HDMI-1 connected/ && $stdout =~ m/VGA-1 connected/ == 1) {
		$screens = 3;
		system(TRIPLESCREEN_PATH);
	}
	elsif ($stdout =~ m/HDMI-1 connected/) {
		$screens = 2;
		system(DUALSCREEN_PATH);
	}
	else {
		system(MAINSCREEN_PATH);
	}
	return $screens;
}

sub bspc_configs
{
	system(BSPC_PATH, 'config', 'border_width',			BSP_BORDER_WIDTH);
	system(BSPC_PATH, 'config', 'window_gap',			BSP_WINDOW_GAP);
	system(BSPC_PATH, 'config', 'focused_border_color',	BSP_BORDER_COLOR);
	system(BSPC_PATH, 'config', 'focused_border_color',	BSP_PRESEL_COLOR);
	system(BSPC_PATH, 'config', 'split_ratio',			BSP_SPLIT_RATIO);
	system(BSPC_PATH, 'config', 'borderless_monocle',	BSP_BORDERLESS_MONOCLE);
	system(BSPC_PATH, 'config', 'gapless_monocle',		BSP_GAPLESS_MONOCLE);
	system(BSPC_PATH, 'config', 'single_monocle',		BSP_SINGLE_MONOCLE);
	return;
}

sub bspc_rules
{
	system(BSPC_PATH, 'rule', '-a', 'Emacs',			'state=tiled');
	system(BSPC_PATH, 'rule', '-a', 'Firefox',			'desktop=03', 'follow=true');
	system(BSPC_PATH, 'rule', '-a', 'Wine',				'desktop=04', 'state=floating');
	system(BSPC_PATH, 'rule', '-a', 'Dunst',			'layer=above');
	system(BSPC_PATH, 'rule', '-a', 'Zathura',			'state=tiled');
	system(BSPC_PATH, 'rule', '-a', 'qTox',				'desktop=10');
	system(BSPC_PATH, 'rule', '-a', 'DergodsRealmII',	'state=floating');
	system(BSPC_PATH, 'rule', '-a', 'obs',				'desktop=10', 'follow=true');
	return;
}

sub run_bg_programs
{
	run_if_dead('SXHKD_SHELL=' . DASH_PATH, SXHKD_PATH);
	run_if_dead(COMPTON_PATH);
	run_if_dead(DUNST_PATH);
	run_if_dead(LOWBAT_PATH);
	run_if_dead(BSPSWALLOW_PATH);
	run_if_dead(MPD_NOTIFICATION_PATH);
	system(SETWP_PATH);
	system(XSETROOT_PATH, '-cursor_name', 'left_ptr');
	system(XSET_PATH, 'r', 'rate', XSET_R_RATE_DELAY, XSET_R_RATE_RATE);
	system(SETXKBMAP_PATH, '-layout', 'us,fr', '-option', 'grp:alt_shift_toggle');
	system(XMODMAP_PATH, '-e', 'keycode 9 = Tab');
	system(XMODMAP_PATH, '-e', 'keycode 23 = Escape');
	return;
}

sub run_espeak
{
	my $espeak_pid;

	$espeak_pid = fork();
	if (not $espeak_pid) {
		exec(ESPEAK_PATH, COWSAY_WELCOME);
	}
	return;
}

sub fg_on_three_screens
{
	my @term_pid;

	$term_pid[0] = fork();
	if (not $term_pid[0]) {
		exec(
			TERM_PATH, '-e', SH_PATH, '-c',
			COWSAY_PATH . ' "' . COWSAY_WELCOME . '"; ' . ZSH_PATH
			);
		exit;
	}
	Time::HiRes::sleep(SLEEP_TIME);
	$term_pid[1] = fork();
	if (not $term_pid[1]) {
		exec(TERM_PATH, '-e', HTOP_PATH);
		exit;
	}
	Time::HiRes::sleep(SLEEP_TIME);
	$term_pid[2] = fork();
	if (not $term_pid[2]) {
		exec(TERM_PATH, '-e', GOTOP_PATH);
		exit;
	}
	Time::HiRes::sleep(SLEEP_TIME);
	system(BSPC_PATH, 'node', '-f', 'west');
	$term_pid[3] = fork();
	if (not $term_pid[3]) {
		exec(TERM_PATH, '-e', VIFM_PATH);
		exit;
	}
	Time::HiRes::sleep(SLEEP_TIME);
	system(BSPC_PATH, 'node', '-z', 'right', '180', '0');
	system(BSPC_PATH, 'node', '-z', 'top', '0', '70');
	system(BSPC_PATH, 'node', '-f', 'east');
	system(BSPC_PATH, 'node', '-f', 'north');
	system(BSPC_PATH, 'node', '-z', 'bottom', '0', '-280');
	system(BSPC_PATH, 'node', '-f', 'west');
	return;
}

sub fg_on_two_screens
{
	my @term_pid;

	$term_pid[0] = fork();
	if (not $term_pid[0]) {
		exec(
			TERM_PATH, '-e', SH_PATH, '-c',
			COWSAY_PATH . ' "' . COWSAY_WELCOME . '"; ' . ZSH_PATH
			);
		exit;
	}
	Time::HiRes::sleep(SLEEP_TIME);
	$term_pid[1] = fork();
	if (not $term_pid[1]) {
		exec(TERM_PATH, '-e', HTOP_PATH);
		exit;
	}
	Time::HiRes::sleep(SLEEP_TIME);
	$term_pid[2] = fork();
	if (not $term_pid[2]) {
		exec(TERM_PATH, '-e', GOTOP_PATH);
		exit;
	}
	Time::HiRes::sleep(SLEEP_TIME);
	system(BSPC_PATH, 'node', '-f', 'west');
	$term_pid[3] = fork();
	if (not $term_pid[3]) {
		exec(TERM_PATH, '-e', VIFM_PATH);
		exit;
	}
	Time::HiRes::sleep(SLEEP_TIME);
	system(BSPC_PATH, 'node', '-z', 'right', '180', '0');
	system(BSPC_PATH, 'node', '-z', 'top', '0', '70');
	system(BSPC_PATH, 'node', '-f', 'east');
	system(BSPC_PATH, 'node', '-f', 'north');
	system(BSPC_PATH, 'node', '-z', 'bottom', '0', '-280');
	system(BSPC_PATH, 'node', '-f', 'west');
	return;
}

sub fg_on_one_screen
{
	my @term_pid;

	$term_pid[0] = fork();
	if (not $term_pid[0]) {
		exec(
			TERM_PATH, '-e', SH_PATH, '-c',
			COWSAY_PATH . ' "' . COWSAY_WELCOME . '"; ' . ZSH_PATH
			);
		exit;
	}
	Time::HiRes::sleep(SLEEP_TIME);
	system(BSPC_PATH, 'node', '-p', 'west');
	$term_pid[1] = fork();
	if (not $term_pid[1]) {
		exec(TERM_PATH, '-e', HTOP_PATH);
		exit;
	}
	Time::HiRes::sleep(SLEEP_TIME);
	$term_pid[2] = fork();
	if (not $term_pid[2]) {
		exec(TERM_PATH, '-e', GOTOP_PATH);
	}
	Time::HiRes::sleep(SLEEP_TIME);
	system(BSPC_PATH, 'node', '-f', 'east');
	$term_pid[3] = fork();
	if (not $term_pid[3]) {
		exec(TERM_PATH, '-e', VIFM_PATH);
	}
	Time::HiRes::sleep(SLEEP_TIME);
	system(BSPC_PATH, 'node', '-f', 'west');
	system(BSPC_PATH, 'node', '-f', 'north');
	system(BSPC_PATH, 'node', '-z', 'bottom', '0', '-200');
	system(BSPC_PATH, 'node', '-z', 'right', '-220', '0');
	system(BSPC_PATH, 'node', '-f', 'east');
	system(BSPC_PATH, 'node', '-z', 'bottom', '0', '70');
	return;
}

sub run_terms
{
	my ($screens) = @_;

	Time::HiRes::sleep(1);
	system(BSPC_PATH, 'desktop', '-f', '12');
	if ($screens == 3) {
		fg_on_three_screens();
	}
	elsif ($screens == 2) {
		fg_on_two_screens();
	}
	else {
		fg_on_one_screen();
	}
	return;
}

sub run_fg_programs
{
	my ($screens) = @_;
	my @pid;

	run_espeak();
	run_terms($screens);
	system(BSPC_PATH, 'desktop', '-f', '11');
	$pid[0] = fork();
	if (not $pid[0]) {
		exec(TERM_PATH, '-e', NEOMUTT_PATH);
	}
	Time::HiRes::sleep(SLEEP_TIME);
	system(BSPC_PATH, 'desktop', '-f', '10');
	$pid[1] = fork();
	if (not $pid[1]) {
		exec(TERM_PATH, '-e', SCLI_PATH);
	}
	Time::HiRes::sleep(SLEEP_TIME);
	system(BSPC_PATH, 'desktop', '-f', '09');
	$pid[2] = fork();
	if (not $pid[2]) {
		exec(TERM_PATH, '-e', VIMPC_PATH);
	}
	Time::HiRes::sleep(SLEEP_TIME);
	system(BSPC_PATH, 'desktop', '-f', '01');
	$pid[3] = fork();
	if (not $pid[3]) {
		exec(TERM_PATH, '-e', NEOVIM_PATH);
	}
	Time::HiRes::sleep(SLEEP_TIME);
	system(BSPC_PATH, 'desktop', '-f', '12');
	return;
}

sub run_network_programs
{
	my $curl;
	my $response_body;

	$curl = WWW::Curl::Easy->new;
	$curl->setopt(CURLOPT_URL, NETWORK_TEST_URL);
	$curl->setopt(CURLOPT_WRITEDATA, \$response_body);
	if ($curl->perform == 0) {
		system(GIT_PATH, '-C', '/usr/home/jozan/.elfeed', 'pull', 'origin', 'master');
	}
	return;
}

sub main
{
	my $screens;

	kill_some();
	$screens = enable_screens();
	bspc_configs();
	bspc_rules();
	run_bg_programs();
	run_fg_programs($screens);
	run_network_programs();
	return;
}

main();

__END__