#!/usr/bin/perl

require "/home/pi/smarthome/library.pl";
$SEP = ";";
@actions = ("show", "caption", "add", "delete", "edit", "swap", "sort", "merge");
$allowEmptyValues = 1;
use utf8::all;


# rownr starts with 1, fieldnr starts with 1
# the first row is the caption line
($csvfile, $action, $rownr, $fieldnr, $value) = @ARGV;
printAndDie("usage: $myself <csv-file> <action> [row-nr] [field-nr>] [value]
- action: ". join(" | ", @actions) ."
	- show: prints the whole file
	- caption: prints the caption line
	- add: adds the given row at the bottom
	- delete: deletes the row of the given number. Note: number 1 is the caption line and cannot be deleted!
	- edit: updates the field of row (row-number) and field (field-number) by the given value ($value)
	- swap: swaps (for the whole file) the column of row-number with the column of given value ($value)
	- sort: sorts the file body by the column of row-nr (if omitted, number 1 is taken) - the captions are untouched. You may also specify 'asc' (default) or 'desc' for sorting
	- merge: merges the given column number range (e.g. 2-4) into one column, joined by value (default: ', ')
") if($csvfile!~/\S/ or $csvfile eq "-h" or $csvfile eq "-help" or $csvfile eq "--help");

printAndDie("ERROR: csv-file $csvfile does not exist!") if(! -f $csvfile);
printAndDie("ERROR: action must be one of '". join("', '", @actions) ."'!") if(!inArray($action, @actions));

#open(F, "<$csvfile") or printAndDie("ERROR: cannot read csv-file $csvfile: $!");
open F, "<:encoding(utf-8)", $csvfile or printAndDie("ERROR: cannot read csv-file $csvfile: $!");
$lnr = 0; $colnr = "";
while(<F>){
	$lnr++;
	chomp($_);
	$line = trim($_);
	@fields = split(/\s*$SEP\s*/, $line);
	if($action eq "swap"){
		if($colnr eq ""){
			$colnr = $rownr;
			printAndDie("ERROR: no column 1 number given!") if($colnr!~/\S/);
			printAndDie("ERROR: column 1 number ($colnr) is not a correct number!") if($colnr=~/\D/);
			printAndDie("ERROR: column 1 number ($colnr) must be between 1 and ". ($#fields+1) ."!") if($colnr<1 or $colnr>$#fields+1);
			$colnr2 = "";
			$colnr2 = $fieldnr if($colnr2 eq "" and $fieldnr=~/\S/);
			$colnr2 = $value if($colnr2 eq "" and $value=~/\S/);
			printAndDie("ERROR: no column 2 number given!") if($colnr2!~/\S/);
			printAndDie("ERROR: column 2 number ($colnr2) is not a correct number!") if($colnr2=~/\D/);
			printAndDie("ERROR: column 2 number ($colnr2) must be between 1 and ". ($#fields+1) ."!") if($colnr2<1 or $colnr2>$#fields+1);
		}
		$tmp = $fields[$colnr-1];
		$fields[$colnr-1] = $fields[$colnr2-1];
		$fields[$colnr2-1] = $tmp;
		$line = join($SEP, @fields);
	}
	if($lnr==1){
		@captions = @fields;
		if($action eq "caption"){
			println(join($SEP, @captions));
			exit;
		}
	}
	push(@body, $line) if($lnr>1);
	println($line) if($action eq "show");
}
close(F);

exit if($action eq "show");

println("- called with: ". join(" ", @ARGV));
$newcode = "";

if($action eq "sort"){
	$sortby = "";
	$sortby = $rownr if($sortby eq "" and $rownr=~/\d/);
	$sortby = $fieldnr if($sortby eq "" and $fieldnr=~/\d/);
	$sortby = $value if($sortby eq "" and $value=~/\d/);
	$sortby = 1 if($sortby!~/\S/);
	printAndDie("ERROR: the column number for sorting ($sortby) is not a correct number!") if($sortby=~/\D/);
	printAndDie("ERROR: the column number for sorting ($sortby) must be between 1 and ". ($#captions+1) ."!") if($sortby<1 or $sortby>$#captions+1);
	$sortmode = "asc";
	$sortmode = "desc" if($rownr eq "desc");
	$sortmode = "desc" if($fieldnr eq "desc");
	$sortmode = "desc" if($value eq "desc");
	for($b=0;$b<$#body+1;$b++){
		@fields = split(/\s*$SEP\s*/, $body[$b]);
		push(@newbody, $fields[$sortby-1]. $SEP . join($SEP, @fields));
	}
	@newbody = sort(@newbody);
	@newbody = reverse(@newbody) if($sortmode eq "desc");
	@body = ();
	for($b=0;$b<$#newbody+1;$b++){
		@fields = split(/\s*$SEP\s*/, $newbody[$b]);
		shift(@fields);
		push(@body, join($SEP, @fields));
	}
}

if($action eq "merge"){
	$merge = "";
	$merge = $rownr if($merge eq "" and $rownr=~/\d/);
	$merge = $fieldnr if($merge eq "" and $fieldnr=~/\d/);
	$merge = $value if($merge eq "" and $value=~/\d/);
	$joiner = "";
	$joiner = $fieldnr if($merge ne "" and $joiner eq "" and $fieldnr=~/\S/);
	$joiner = $value if($merge ne "" and $joiner eq "" and $value=~/\S/);
	if($joiner eq ""){
		$joiner = ", ";
		$joiner = "; " if($SEP eq ",");
	}
	printAndDie("ERROR: no column number range given!") if($merge!~/\S/);
	printAndDie("ERROR: given column number range is wrong (expected: e.g. 2.4)!") if($merge!~/\-/);
	($merge1, $merge2) = split(/\D+/, $merge);
	printAndDie("ERROR: the column number range ($merge) is not correct (expected: e.g. 2-4)!") if($merge1=~/\D/ or $merge2=~/\D/);
	printAndDie("ERROR: each number of the column number range ($merge) must be between 1 and ". ($#captions+1) ."!") if($merge1<1 or $merge1>$#captions+1 or $merge2<1 or $merge2>$#captions+1);
	printAndDie("ERROR: the column number range ($merge) is not correct (expected: e.g. 2-4)!") if($merge1==$merge2);
	$merge1--;
	$merge2--;
	unshift(@body, join($SEP, @captions));
	for($b=0;$b<$#body+1;$b++){
		@fields = split(/\s*$SEP\s*/, $body[$b]);
		@mergefields = ();
		for($f=$merge1;$f<=$merge2;$f++){
			push(@mergefields, $fields[$f]);
		}
		$fields[$merge1] = join($joiner, @mergefields);
		for($f=$merge2;$f>=$merge1+1;$f--){
			splice(@fields, $f, 1);
		}
		if($b==0){
			@captions = @fields;
		} else{
			push(@newbody, join($SEP, @fields));
		}
	}
	@body = @newbody;
}

if($action eq "delete"){
	printAndDie("ERROR: no row number given!") if($rownr!~/\S/);
	printAndDie("ERROR: row number ($rownr) is not a correct number!") if($rownr=~/\D/);
	printAndDie("ERROR: row number ($rownr) must be between 2 and $lnr!") if($rownr<2 or $rownr>$lnr);
	$newcode = join($SEP, @captions);
	for($n=2;$n<=$lnr;$n++){
		$newcode .= "\n". $body[$n-2] if($n!=$rownr);
	}
}

if($action eq "add"){
	$arg2 = "";
	$arg2 = $rownr if($arg2 eq "" and $rownr=~/\S/);
	$arg2 = $fieldnr if($arg2 eq "" and $fieldnr=~/\S/);
	$arg2 = $value if($arg2 eq "" and $value=~/\S/);
	printAndDie("ERROR: no row to add given!") if($arg2!~/\S/);
	push(@body, $arg2);
}

if($action eq "edit"){
	printAndDie("ERROR: no row number given!") if($rownr!~/\S/);
	printAndDie("ERROR: row number ($rownr) is not a correct number!") if($rownr=~/\D/);
	printAndDie("ERROR: row number ($rownr) must be between 2 and $lnr!") if($rownr<2 or $rownr>$lnr);
	$fieldlen = $#captions+1;
	printAndDie("ERROR: no field number given!") if($fieldnr!~/\S/);
	printAndDie("ERROR: field number ($fieldnr) is not a correct number!") if($fieldnr=~/\D/);
	printAndDie("ERROR: field number ($fieldnr) must be between 1 and $fieldlen!") if($fieldnr<1 or $fieldnr>$fieldlen);
	printAndDie("ERROR: no new value given!") if(!$allowEmptyValues and $value!~/\S/);
	$currline = $body[$rownr-2];
	@fields = split(/\s*$SEP\s*/, $currline);
	$fields[$fieldnr-1] = $value;
	$body[$rownr-2] = join($SEP, @fields);
}


$newcode = join($SEP, @captions) ."\n". join("\n", @body) ."\n" if($newcode eq "");


open F, ">:encoding(utf-8)", $csvfile or printAndDie("ERROR: cannot write csv-file $csvfile: $!");
#open(F, ">$csvfile") or printAndDie("ERROR: cannot write csv-file $csvfile: $!");
binmode(F, ":utf8");
print F $newcode;
close(F);

println("OK");
