if (word(2 $loadinfo()) != [pf]) {
	load -pf $word(1 $loadinfo());
	return;
};

if (J !~ [EPIC5*]) {
	xecho -b ERROR: layout: load: EPIC5 is required;
	return;
};

package layout;


## Layout script for EPIC5
## Written by zlonix@efnet, public domain.
##
## Version: 1.0 (March, 2015)
##  - Initial roll-out

## This script introduce concept of profiles, relating to window, channel and
## server associations. You can scan current layout, save it and restore it.
## It's particularly useful when client starts up and you want quickly connect
## to your servers and join your favourite channels.
##
## For usage issue /layout command without arguments after loading this script
## or simply read it below.

alias layout.help (void) {
	xecho -b Help on layout system:;
	xecho -b;
	xecho -b /layout scan [profile] - scan current layout into [profile];
	xecho -b /layout restore [profile] - restore [profile], all windows are killed,;
	xecho -b         chans are left and servers are disconnected beforehand;
	xecho -b /layout save [file] - save all current profiles into [file], by default;
	xecho -b         ~/.layout_irc is used;
	xecho -b;
	xecho -b By default profile named "default" is used if you don't supply the name;
	xecho -b You can edit layout file by hand if you're careful;
	xecho -b;
	xecho -b Basic usage: create windows, join servers and channels, issue;
	xecho -b /layout scan efnet and /layout save. Now you can start fresh client,;
	xecho -b load ~/.layout_irc (don't use PF loader) and execute /layout restore efnet;
	xecho -b everything should come back into place.;
	xecho -b With this approach you can have several layouts, start several clients and;
	xecho -b issue only /layout restore <profile> to reconnect to proper networks;
};

alias layout (verb, args) {
	switch ($verb) {
	(restore) {
		layout.restore $args;
	};
	(scan) {
		layout.scan $args;
	};
	(save) {
		layout.save $args;
	};
	(*) {
		layout.help;
	};
	};
};

alias layout.clean (void) {
	fe ($windowctl(REFNUMS)) ii {
		^window $ii kill;
	};
	^window noserv;
};

alias layout.restore (profile default "default") {
	layout.clean;

	fe ($layoutctl(GET $profile SCREENS)) ss {
		layout.restore.screen $profile $ss;
	};
};

alias layout.restore.screen (profile, screen) {
	^window number $word(0 $layoutctl(GET $profile $screen WINDOWS));

	## restore "physical" level
	fe ($layoutctl(GET $profile $screen WINDOWS)) ww {
		if (ww == winnum()) {
			continue;
		};

		^window new_hide number $ww $layoutctl(GET $profile $screen $ww OPTIONS);
	};

	## restore server level
	fe ($layoutctl(GET $profile $screen WINDOWS)) ww {
		if ((:serv = layoutctl(GET $profile $screen $ww SERVER_DESC)) == [noserv]) {
			^window $ww noserv;
		} else {
			^window $ww server $serv;

			^on #-004 ${100+ww} '% $before(: $serv) *' layout.restore.targets $profile $screen $ww;
		};
	};
};

alias layout.restore.targets (profile, screen, window) {
	fe ($layoutctl(GET $profile $screen $window CHANNELS)) tt {
		## look for layoutctl CHANNELS switch to understand this sneaky sar()
		window $window rejoin $sar(/,/ /$tt);
	};

	fe ($layoutctl(GET $profile $screen $window NICKLIST)) tt {
		window $window add $tt;
	};

	## remove current hook in which we're running
	@ hookctl(REMOVE -1);
};

alias layoutctl (verb, ...) {
	switch ($verb) {
	(GET) {
		switch ($0) {
		(PROFILES) {
			return $layout;
		};
		(*) {
			switch ($1) {
			(SCREENS) {
				return $layout[$0];
			};
			(*) {
				switch ($2) {
				(ARRANGEMENT) {
					return $layout[$0][$1][arrangement];
				};
				(WINDOWS) {
					return $layout[$0][$1];
				};
				(*) {
					switch ($3) {
					(SERVER_DESC) {
						return $getitem(layout.$0.$1.$2 0);
					};
					(OPTIONS) {
						return $getitem(layout.$0.$1.$2 1);
					};
					(TARGETS) (NICKLIST) (CHANNELS) {
						fe ($jot(0 ${numitems(layout.$0.$1.$2.targets)-1})) ii {
							@ :tmp = getitem(layout.$0.$1.$2.targets $ii);
							if (ischannel($tmp)) {
								## we put , in <chan>,<key> pair so we could separate it
								## in fe loop for decoding otherwise fe will treat chan
								## and key as separate things
								push :chans $sar(/ /,/$tmp);
							} else {
								push :nicks $tmp;
							};
						};
						if (*3 == [NICKLIST]) {
							return $nicks;
						} else if (*3 == [CHANNELS]) {
							return $chans;
						} else {
							return $nicks $chans;
						};
					};
					};
				};
				};
			};
			};
		};
		};
	};
	};
};

alias layout.addprofile (profile) {
	if (findw($profile $layout) == -1)
		push layout $profile;
};

alias layout.delprofile (profile) {
	fe (${layout.$profile}) ss {
#		echo delprofile => $profile $ss;
		layout.delscreen $profile $ss;
	};

	@ layout = remw($profile $layout);
};

alias layout.addscreen (profile, id, wins) {
#	echo addscreen => $profile $id $wins;
#	echo addscreen => check1: $layout[$profile];
	push layout.$profile $id;
#	echo addscreen => check2: $layout[$profile];
	^assign layout.${profile}.${id} $wins;
};

alias layout.delscreen (profile, id) {
#	echo delscreen ==> start: $layout[$profile];
#	echo delscreen ==> $profile $id;
	fe (${layout[$profile][$id]}) ww {
#		echo delscreen ====> ww: $ww;
		layout.delwindow $profile $id $ww;
	};
	layout.delarrangement $profile $id;

#	echo delscreen ==> check1: $layout[$profile];
	@ layout[$profile] = remw($id $layout[$profile]);
#	echo delscreen ==> check2: $layout[$profile];

	if (!layout[$profile]) {
		^assign -layout.$profile;
	};
};

alias layout.addwindow (profile, id, window) {
	push layout.${profile}.${id} $window;
};

alias layout.delwindow (profile, id, window) {
#	echo delwindow ===> $profile $id $window;
	@ delarray(layout.${profile}.${id}.${window});
	@ delarray(layout.${profile}.${id}.${window}.targets);
	^assign layout.${profile}.${id} $remw($window $::layout.${profile}.${id});
};

alias layout.addarrangement (profile, id, args) {
	^assign layout.${profile}.${id}.arrangement $args;
};

alias layout.delarrangement (profile, id) {
	^assign -layout.${profile}.${id}.arrangement;
};

alias layout.addwinopt (profile, id, window, opt) {
	@ setitem(layout.${profile}.${id}.${window} 1 $opt);
};

alias layout.addserver (profile, id, window, server) {
	@ setitem(layout.${profile}.${id}.${window} 0 $server);
};

alias layout.addtarget (profile, id, win, target) {
	@ setitem(layout.${profile}.${id}.${win}.targets $numitems(layout.${profile}.${id}.${win}.targets) $target)
};

alias layout.purge (void) {
	fe ($layout) pp {
		layout.delprofile $pp;
	};
};

alias layout.scan (profile default "default") {
	layout.delprofile $profile;

	layout.addprofile $profile;
	## XXX: we support only one screen for now
	@ :screen = 0;
	layout.addscreen $profile $screen $windowctl(REFNUMS);
	layout.addarrangement $profile $screen $windowctl(REFNUMS_ON_SCREEN $screen);

	fe ($numsort($windowctl(REFNUMS))) ww {

		@ :winopts = [];

		@ :server = serverctl(GET $windowctl(GET $ww SERVER) FULLDESC);
		if (!server) {
			@ :server = [NOSERV];
		};
		layout.addserver $profile $screen $ww $server;

		if (:name = windowctl(GET $ww NAME)) {
			push :winopts NAME $name;
		};
		push :winopts NOTIFY_LEVEL $sar(g/ /,/$tolower($windowctl(GET $ww NOTIFY_LEVEL)));
		push :winopts LASTLOG_LEVEL $sar(g/ /,/$tolower($windowctl(GET $ww LASTLOG_LEVEL)));
		push :winopts DOUBLE ${windowctl(GET $ww DOUBLE) ? [on] : [off]};

		layout.addwinopt $profile $screen $ww $winopts;

		fe ($windowctl(GET $ww NICKLIST)) nn {
			layout.addtarget $profile $screen $ww $nn;
		};
		fe ($windowctl(GET $ww CHANNELS)) cc {
			@ :key = chankey($windowctl(get $ww server) $cc);
			if (!key) {
				@ :key = [*];
			};
			layout.addtarget $profile $screen $ww $cc $key;
		};
	};	
};

alias layout.save (file default "~/.layout_irc") {
	@ unlink($file);
	@ :fd = open($file W);

	if (isfilevalid($fd) == 1) {
		@ :data = [@ layout = \[$layout\]];
		@ write($fd $data);

		fe ($layout) pp {
			@ :data = [@ layout.$pp = \[${layout.$pp}\]];
			@ write($fd $data);
			
			fe (${layout.$pp}) ss {
				@ :data = [@ layout.${pp}.${ss} = \[${layout[$pp][$ss]}\]];
				@ write($fd $data);

				@ :data = [@ layout.${pp}.${ss}.arrangement = \[${layout[$pp][$ss][arrangement]}\]];
				@ write($fd $data);

				fe ($numsort(${layout[$pp][$ss]})) ww {
					@ :data = [@ setitem\(layout.${pp}.${ss}.${ww} 0 $getitem(layout.${pp}.${ss}.${ww} 0)\)];
					@ write($fd $data);
				};

				fe ($numsort(${layout[$pp][$ss]})) ww {
					@ :data = [@ setitem\(layout.${pp}.${ss}.${ww} 1 $getitem(layout.${pp}.${ss}.${ww} 1)\)];
					@ write($fd $data);
				};

				fe ($numsort(${layout[$pp][$ss]})) ww {
					fe ($jot(0 ${numitems(layout.${pp}.${ss}.${ww}.targets)-1})) tt {
						if (:item = getitem(layout.${pp}.${ss}.${ww}.targets $tt)) {
							@ :data = [@ setitem\(layout.${pp}.${ss}.${ww}.targets $tt $item\)];
							@ write($fd $data);
						};
					};
				};
			};
		};

		@ close($fd);
	} else {
		xecho -b ERROR: layout.save: $file: fd cannot be used;
	};
};

alias layout.load (file default "~/.layout_irc") {
	if (fexist($file)) {
		load $file;
	} else {
		xecho -b ERROR: layout.load: $file: file doesn't exist;
	};
};

alias layout.dump (void) {
	echo ==> LAYOUTS: $layout;
	fe ($layout) pp {
		echo layout.$pp: $layout[$pp];
		echo layout.${pp}.0: $layout[$pp][0];
		echo layout.${pp}.0.arrangement: $layout[$pp][0][arrangement];
	};

	fe ($getarrays(layout.*)) aa {
		echo $aa ==> $listarray($aa !);
	};
};

#layout.purge;
#layout.load;
#layout.dump;
#layout.save;
#alias lr layout.restore default 0;
