(* sarakkeet.p SJ *)

Program siisti_sarakkeet(input, output);

(* Ohjelma lukee syötetta loppuun ja tulostaa syötteen siististi
   sarakkeihin kokonaisluvut oikealle tasattuna ja muut vasemmalle.
   Sarakkeiden leveydet leveimmän mukaan, sarakkeiden tyypit viimeisen
   rivin mukaan
*)

(* Kehitettävää:
   - talletusrakenteet kannattaisi vaihtaa selkeämmiksi (tietuiksi) ja
     joustavammiksi (dynaamisiksi) kunhan kurssilla edetään siihen asti
   - desimaalilukuja ei tunnisteta luvuiksi, eikä tasata
*)

(* pääalgoritmi:

	toista kaikille syöteriveille
		lue rivi
		erota rivit sanoiksi, poista tyhjeet
		muista sarakkeiden maksimileveys, saraketyyppi

	toista kaikille riveille
		tulosta kukin kenttä (sana) sarakkeen maksimileveyden ja tyypin
		mukaan tasattuna oikealle tai vasemmalle
*)

(* käyttöesimerkki: ls -la | sed -e 's/  / /g' | a.out *)

(* vakioiden ja tyyppien esittelyt *)
(* ------------------------------- *)

const	maxkentat = 20;	(* sarakkeiden määrä *)
		maxrivit = 100;	(* rivien määrä *)
		maxpit = 50;	(* kentän maksimileveys *)
		vali = ' ';		(* kenttien erotin tulostettaessa *)
		tyhje = ' ';	(* sananerotin syötteessä *)

type	kentta = string[maxpit];				(* yksi kenttä *)
		rivi = array[1..maxkentat] of kentta;	(* rivi kenttiä *)
		teksti = array[1..maxrivit] of rivi;	(* monta riviä *)

		leveydet = array[1..maxkentat] of integer; (* sarakk. leveys *)
		tasaus = (vasen, oikea);
		tasaukset = array[1..maxkentat] of tasaus; (* sar. tasaussuunta *)


(* kaikkien aliohjelmien ennakkoesittelyt *)
(* -------------------------------------- *)

procedure PoistaAlkuJaLoppuTyhjeet(var rivi: string); forward;
procedure ErotaSana(var rivi : string; var sana : kentta); forward;
procedure LueRivi(var R : rivi; var klkm : integer); forward;
procedure TutkiKentat(var R : rivi; var klkm : integer;
						var lev : leveydet; var tas : tasaukset); forward;
procedure TulostaVasen(tieto: string; kentta : integer); forward;
procedure Tulosta(var T : teksti; lkm, sar : integer;
						var lev : leveydet; var tas : tasaukset); forward;
procedure Alusta(var T : teksti; var lev : leveydet); forward;

(* aliohjelmien toteutukset *)
(* ------------------------ *)

(* poistaa rivin alussa ja lopussa olevat tyhjeet, rivi voi siis muuttua *)
(* esimerkki 19 *)
procedure PoistaAlkuJaLoppuTyhjeet(var rivi: string);
begin
	while Pos(tyhje, rivi) = 1 do		(* poistetaan etutyhjeet *)
		Delete(rivi, 1, 1);				(* hieman tehoton ratkaisu *)
	while Copy(rivi, Length(rivi), 1) = tyhje do (* tyhjeet pois lopusta *)
		Delete(rivi, Length(rivi), 1)
end; (* PoistaAlkuJaLoppuTyhjeet() *)

(* Etsii annetusta syötteestärivi  seuraavan sanan ja palauttaa sanan ja  *)
(* poistaa ko sanan annetulta riviltä  *)
(* esimerkki 21 *)
procedure ErotaSana(var rivi : string; var sana : kentta);
	var	i : integer;
begin
	i := Pos(tyhje , rivi);
	if  i = 0 then begin (* viimeinen sana rivillä *)
		sana := rivi;
		Delete(rivi, 1, Length(rivi))
	end
	else begin (*  i > 0, rivillä on sanan lisäksi vielä muuta  *)
		sana := Copy(rivi, 1, i - 1);
		Delete(rivi, 1, i);  (* poistetaan tyhje samalla *)
	   	PoistaAlkuJaLoppuTyhjeet(rivi);   (* + muut mahdolliset  tyhjeet *)
	end;
end; (* ErotaSana() *)


(* lukee yhden rivin syötettä ja erottelee sen kentiksi *)
procedure LueRivi(var R : rivi; var klkm : integer);
	var	syote : string[255];
begin
	readln(syote);
	PoistaAlkuJaLoppuTyhjeet(syote);
	klkm := 0;
	while ((length(syote) > 0) and (klkm < maxkentat)) do begin
		klkm := klkm + 1;
		ErotaSana(syote, R[klkm]);
	end;
end; (* LueRivi() *)


(* tutkii yhden rivin kentät josko löytyisi leveämpiä kenttiä kun on
   aiemmin löydetty, määrää kunkin sarakkeen tasaussuunnan *)
procedure TutkiKentat(var R : rivi; var klkm : integer;
						var lev : leveydet; var tas : tasaukset);
	var i, l, x, koodi : integer;
begin
	for i := 1 to klkm do begin
	
		(* tarkastetaan löytyikö aiempia leveämpi kenttä *)
		l := length(R[i]);
		if (l > lev[i]) then
			lev[i] := l;
	
		(* tarkastetaan tasaussuunta *)
		val(R[i], x, koodi);
		if (koodi = 0) then
			(* kokonaislukukenttä *)
			tas[i] := oikea
		else
			(* muu kenttä *)
			tas[i] := vasen;
	end; (* for *)
end; (* TutkiKentat() *)
		

(* tulostaa halutun levyisen kentän vasempaan reunaan kentta merkkiä *)
(* esim. TulostaVasen('APUA',8) tulostaa APUAxxxx, missä x = tyhje *)
(* esimerkki 20 *)
procedure TulostaVasen(tieto: string; kentta : integer);
var pituus : integer;
begin
   pituus := Length (tieto);
   if pituus < kentta then (* loppuun tyhjeitä tarvittava määrä *) 
      write(tieto, ' ' : kentta - pituus)
   else begin  (* poistetaan ylimääräiset merkkijonon lopusta *)
      Delete(tieto, kentta + 1,   pituus - kentta );
      write(tieto)
   end;
end; (* TulostaVasen() *)


(* tulostaa koko tekstin *)
procedure Tulosta(var T : teksti; lkm, sar : integer;
						var lev : leveydet; var tas : tasaukset);
	var r, s : integer;
begin
	for r := 1 to lkm do begin (* kaikki rivit *)

		for s := 1 to sar do begin	(* kaikki sarakkeet *)
			
			if (tas[s] = vasen) then
				TulostaVasen(T[r][s], lev[s])
			else
				write(T[r][s]:lev[s]);

			write(vali);
		end;

		writeln;
	end;
end; (* Tulosta() *)


(* nollaa tekstitaulukon ja sarakeleveydet *)
procedure Alusta(var T : teksti; var lev : leveydet);
	var r, s : integer;
begin
	for r := 1 to maxrivit do
		for s := 1 to maxkentat do
			T[r][s] := '';
	for s := 1 to maxkentat do
		lev[s] := 0;
end; (* Alusta() *)


(* Pääohjelman muuttujat *)
(* --------------------- *)

var	T : teksti; 			(* koko teksti *)
	lev : leveydet;			(* sarakeleveydet *)
	tas : tasaukset;		(* tasaussuunnat *)
	r, k, maxk : integer;	(* rivinro, kenttien_määrä, max kenttien määrä *)

begin (* pääohjelma alkaa *)

	Alusta(T, lev);

	(* tulostukset jätetään tekemättä ettei sotketa *)
	(* writeln('Anna tulla:'); *)

	r := 0;
	maxk := 0;

	(* luetaan koko syöte (tai niin paljon kun pystytään *)
	while ((not eof) and (r < maxrivit)) do begin

		r := r + 1;

		LueRivi(T[r], k);
		if (k > maxk) then	(* aiempaa enemmän sarakkeita *)
			maxk := k;

		TutkiKentat(T[r], k, lev, tas);

	end;

	(* writeln('Tässäpä nämä'); *)

	Tulosta(T, r, maxk, lev, tas);

end.

