/* Zadatak 0.
 
   Kazemo da je tekst dobro formatiran ako vrijedi:
   a) Rijeci su odvojene tocno jednim razmakom.
   b) Recenice istog paragrafa odvojene su tocno dvama razmacima.
      (Smatramo da recenica zavrsava interpunkcijskim znakovima . ! ? iza kojih 
      slijedi barem jedan razmak.)
   c) Paragrafi su odvojeni tocno jednom praznom linijom.
   d) Zadan je N kao maksimalna duljina linija teksta. Niti jedna linija nije dulja od N
      i za svaku liniju vrijedi da je potpuno ispunjena.

   Linija L je potpuno ispunjena ako je prazna ili joj se ne moze nadopisati pocetna rijec
   (ili vise njih) iz sljedece linije, tako da je L još uvijek duljine najvise N.

   Neka je 66 <= N <= 132.
   Napisite program myFmt, koji prima N kao opcionalni parametar.
   Validni su pozivi, dakle:
   myFmt 72
   myFmt 80
   myFmt
   Poziv "myFmt 54" nije validan jer krsi dogovor o dozvoljenom rasponu od N. 
   Ako opcionalni parametar N nije naveden, podrazumijeva se da iznosi 75.

   Program ucitava tekst sa standardnog ulaza, liniju po liniju, do EOF i potom ispisuje 
   taj tekst dobro formatiran. */

#include <iostream>
#include <string>

#include <cctype>

using std::cin;
using std::cout;
using std::endl;
using std::string;

bool kriterij_paragraf( string const &pomoc){
  // provjerava da li se dani string sastoji samo
  // od space-ova te da li je prazan
  if( pomoc.size()==0) return true;
  if( pomoc.find_first_not_of(' ')==string::npos ) return true;

  return false;
}

void verzija1( string &tekst){
  // modificira string tako da mijenja:
  // '. ' -> '.  ' , '? ' -> '?  ' , '! ' -> '!  '
  for( string::size_type i=0; i<tekst.size()-1; ++i){
    if( tekst[i]=='.' && tekst[i+1]==' ' ){
      tekst.replace( i, 1, ". ", 0, 2);
    }
    else if( tekst[i]=='?' && tekst[i+1]==' ' ){
      tekst.replace( i, 1, "? ", 0, 2);
    }
    else if( tekst[i]=='!' && tekst[i+1]==' ' ){
      tekst.replace( i, 1, "! ", 0, 2);
    }
  }
}

void verzija2( string &tekst){
  string novi;

  // modificira string tako da mijenja:
  // '. ' -> '.  ' , '? ' -> '?  ' , '! ' -> '!  '
  string::size_type prethodni=0;
  string::size_type end=tekst.size()-1;
  for( string::size_type i=0; i<end; ++i){
    if( ( tekst[i]=='.' || tekst[i]=='!' || tekst[i]=='?' ) && tekst[i+1]==' '){
      novi+=tekst.substr( prethodni, i+1 - prethodni )+" ";
      prethodni=i+1;
      ++i;
    }
  }

  novi+=tekst.substr( prethodni);

  tekst=novi;
}

bool modificiraj( string &tekst, int const verzija=2){

  if( verzija!=1 && verzija!=2 ) return false;
  verzija==1 ? verzija1( tekst) : verzija2( tekst);

  // modificira string tako da "ubija" visetruke
  // uzastopne space-ove
  // kod pocetka recenice ostavlja 2 inace 1
  string::size_type brojac=0;
  while ( ( brojac=tekst.find("  ", brojac) ) != string::npos ){
    if( tekst[brojac-1]!='.' && tekst[brojac-1]!='?' && tekst[brojac-1]!='!' ){
      tekst.erase( brojac, 1);
      continue;
    }
    ++brojac;
  }
 
  // modificira string tako da mijenja '  \n\n' -> '\n\n'
  brojac=0;
  while ( ( brojac=tekst.find("  \n\n", brojac) ) != string::npos ){
    tekst.replace( brojac, 3, "\n ", 0, 1);
    ++brojac;
  }

  // modificira string tako da mijenja '\n ' -> '\n'
  brojac=0;
  while ( ( brojac=tekst.find("\n ", brojac) ) != string::npos ){
    tekst.replace( brojac, 2, "\n", 0, 1);
    ++brojac;
  }

  // brise posljednj dva znaka u stringu koji su space-ovi
  // zbog nacina stvaranja stringa "tekst"
  // u main-u ( tekst+=pomoc+" " )
  // i gore izvedene konverzije
  if( tekst[tekst.size()-2]==' ' ){
    tekst.erase( tekst.size()-2, 2 );
  }
  // odnosno samo zadnji znak ako korisnik nije zavrsio s . ? !
  else{
    tekst.erase( tekst.size()-1, 1);
  }

  // brise prvi znak teksta ako je space
  if( tekst[0]==' ' ){
    tekst.erase( 0, 1);
  }

  return true;
}

void razlomi( string &tekst, int const broj){
  // "kida" tekst na linije velicine varijable broj
  // dodajuci '\n' character
  // prethodni pamti polozaj najblizeg space-a kojeg smo prosli
  // brojac broji koliko smo karaktera prosli
  string::size_type brojac=0, prethodni=0;
  for( string::size_type i=0; i<tekst.size(); ++i){

    // ako smo prosli broj karaktera a nismo se prebacili
    // u novu liniju onda se prebacujemo
    // dodavanjem '\n' charactera na mjesto
    // sa indeksom prethodni, tj. na najblizi prodjen space
    if( brojac==broj ){
     tekst.replace( prethodni, 1, "\n", 0, 1);
     brojac=0;

     // vracamo se na indeks prethodni+1
     // jer smo na indeksu prethodni prekinuli liniju
     i=prethodni+1;
     
     continue;
    }
   
    // ako je trenutni character space postavi prethodni
    if( tekst[i]==' ' ) prethodni=i;
    // ako je trenutni character '\n' resetiraj brojac
    // jer se tu prebacujemo u novu liniju
    else if( tekst[i]=='\n' ) brojac=0;
   
    ++brojac;
  }
}

int main( int argc, char *argv[]){

  if(argc>2){
    cout << "Nepravilan poziv programa!!!\n> Previse argumenata." << endl;
    return 1;
  }

  int broj=75;
  if( argc==2 ){
    string pomoc(argv[1]);
    for( string::size_type i=0; i<pomoc.size(); ++i){
      if( !isdigit(pomoc[i]) ){
	cout << "Nepravilan poziv programa!!!\n> Drugi argument nije broj." << endl;
	return 2;
      }
    }

    broj=atoi(argv[1]);
  }

  if( broj<66 || broj>132){
    cout << "Nepravilan poziv programa!!!\n> Drugi argument mora biti broj izmedju 66 i 132." << endl;
    return 3;
  }

  // ucitiva tekst sa standardong ulaza liniju po liniju
  // te ga lijepi na vec prije uneseni tekst
  string pomoc, tekst;
  bool paragraf=false;
  while( getline( cin, pomoc) ){

    // ako zadovoljava kriterije za paragraf
    // tj. sadrzi samo praznine ili je prazan
    if( kriterij_paragraf( pomoc) ){

      // ako je do sada uneseni tekst velicine 0, tj. na pocetku smo
      // onda zanemari sve prazne linije
      if( tekst.size()==0 ) continue;     
      else{
	// inace vec postoji tekst pa je prazna
	// linija oznaka za novi paragraf
	paragraf=true;
	continue;
      }
    }

    // ako smo ucitali tekst (ne zadovoljava kriterije paragrafa,
    // pogledati gore funkciju) i prije je bila unesena prazna
    // linija (ili vise), tj. paragraf=true
    // onda lijepi '\n\n' na kraj "tekst"-a
    if( pomoc.size()!=0 && paragraf ){     
      tekst+="\n\n";
      paragraf=false;
    }

    // lijepi unesenu liniju na prije ucitani tekst
    tekst+=pomoc+" ";
  }
  
  modificiraj( tekst);
  razlomi( tekst, broj);
 
  cout << tekst << endl;

  return 0;
}


