/***************************************************************************
                        PreFormatter.cpp  -  description
                             -------------------
    begin                : Mo Jan 03 2005
    copyright            : (C) 2005-2007 by Andre Simon
    email                : andre.simon1@gmx.de
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

#include "preformatter.h"

#include <iostream>
#include "stringtools.h"

namespace highlight {

const std::string PreFormatter::LB_CHARS = " \t[](){}-+<>.:,;";
const std::string PreFormatter::WS_CHARS = " \n\r\t";
const std::string PreFormatter::INDENT_MARKERS = "{(=";

PreFormatter::PreFormatter():
 maxLineLength(80),
 index(0),
 numberSpaces(0),
 lineNumber(0),
 wsPrefixLength(string::npos),
 hasMore(false),
 indentAfterOpenBraces(true),
 redefineWsPrefix(false),
 wrapLines(false),
 replaceTabs(false)
{
}

PreFormatter::~PreFormatter()
{
}

bool PreFormatter::hasMoreLines(){
  return hasMore;
}

bool PreFormatter::indentCode(){
  return indentAfterOpenBraces;
}

void PreFormatter::setLine(const std::string& newLine){

  line=newLine;

  if (replaceTabs && numberSpaces) {
    size_t tabPos=line.find('\t');
    while (tabPos!=string::npos){
       line.replace(tabPos , 1, numberSpaces - (tabPos % numberSpaces) , ' ');
       tabPos = line.find('\t', tabPos+1);
    }
  }

  if (wrapLines){
    wsPrefix.clear();
    index=0;
    wsPrefixLength=string::npos;
    hasMore=true;
    redefineWsPrefix=false;
  }
}

std::string PreFormatter::getNextLine(){

   if (!wrapLines){
     hasMore = false;
     return line;
   }

   ++lineNumber;

   if (!index && line.length() > maxLineLength){ // erster Durchlauf...
      // wenn moeglich an oeffnender Klammer oder Geichheitszeichen ausrichten
      if (indentAfterOpenBraces){
          wsPrefixLength=line.find_first_of(INDENT_MARKERS);
      }
      // sonst die Einrckung der Originalzeile beibehalten
      if (wsPrefixLength==string::npos || wsPrefixLength-index>maxLineLength){
          wsPrefixLength=line.find_first_not_of(WS_CHARS);
      }
      else {
          // wsPrefix in allen neu umgebrochenen Zeilen durch Spaces ersetzen
          redefineWsPrefix=true;
          //  Position hinter oeffnende Klammer springen
          wsPrefixLength=line.find_first_not_of(WS_CHARS,wsPrefixLength+1);
      }

      if (wsPrefixLength!=string::npos){
        index = wsPrefixLength;
        // Falls Anzahl der Whitespaces am beginn der ersten zeile groesser
        // als Max. Zeilenlaenge, Whitespaces verwerfen
        if (wsPrefixLength>maxLineLength){
          wsPrefixLength=0;
          return string();
        }
        else{
           wsPrefix=line.substr(0, wsPrefixLength);
        }
      }
      // Zeile enthaelt nur Whitespace; verwerfen
      else {
       hasMore= false;
       return string();
      }
   } else {
     if (redefineWsPrefix){
       wsPrefix.clear();
       wsPrefix.append(wsPrefixLength, ' ');
     }
     redefineWsPrefix=false;
   }

   string resultString;

   // Position, ab der rueckwaerts nach Umbruchmglichkeit gesucht wird
   unsigned int searchEndPos = maxLineLength - wsPrefixLength;

   // letztes Teilstueck der Zeile ausgeben; Parsen beenden
   if (line.length()-index < searchEndPos) {
     hasMore=false;
     resultString=(index>0) ? wsPrefix + line.substr(index) : line.substr(index);
     return resultString;
   }

   wrappedLines.insert(lineNumber); // diese Zeile wurde umgebrochen

   // Umbrechposition suchen
   size_t lbPos = line.find_last_of(LB_CHARS, index+searchEndPos);
   if (lbPos <= index || lbPos == string::npos) {
     // nichts gefunden, hart umbrechen
     lbPos = index + searchEndPos;
   }
   // Einrckung der Originalzeile erhalten
   resultString+=wsPrefix;
   // Neue Zeile erzeugen
   resultString += line.substr(index, lbPos-index+1);

   // Whitespace am neuen Zeilenbeginn ignorieren, ausser beim ersten Durchlauf
   size_t newIndex=line.find_first_not_of(WS_CHARS, lbPos+1);
   index=(newIndex!=string::npos)?newIndex:line.length();

   hasMore=index!=line.length(); // unnoetigen Leerstring vermeiden

   return resultString;
}

void PreFormatter::setWrapLineLength(unsigned int maxLineLength){
    this->maxLineLength = maxLineLength;
}
void PreFormatter::setWrapIndentBraces( bool indentAfterOpenBraces){
    this->indentAfterOpenBraces = indentAfterOpenBraces;
}

void PreFormatter::setNumberSpaces(unsigned int num){
    numberSpaces = num;
}

}
