/*
 * FindBugs - Find Bugs in Java programs
 * Copyright (C) 2006, University of Maryland
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

package edu.umd.cs.findbugs.tools;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.Writer;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Set;

import edu.umd.cs.findbugs.charsets.SourceCharset;

/**
 * @author pugh
 */
public class FixIndentation {
    static final String SPACES = "                                                                                                                                            ";

    public static void main(String args[]) throws Exception {
        recursiveFix(new File(args[0]), true);
    }

    static void recursiveFix(File root, boolean partial) throws IOException {
        String rootPath = root.getAbsolutePath();
        Set<File> seen = new HashSet<File>();
        Queue<File> todo = new LinkedList<File>();
        seen.add(root);
        todo.add(root);
        while (!todo.isEmpty()) {
            File next = todo.remove().getAbsoluteFile();
            String nextPath = next.getAbsolutePath();
            if (!nextPath.startsWith(rootPath))
                continue;

            if (next.isDirectory()) {
                File[] contents = next.listFiles();
                if (contents != null)
                    for (File c : contents)
                        if (seen.add(c))
                            todo.add(c);
            } else if (nextPath.endsWith(".java") || nextPath.endsWith(".xml"))
                fix(next, partial);
        }
    }

    static String fix(String s) {
        if (s.length() == 0)
            return s;
        if (s.trim().length() == 0)
            return "";
        int spaces = 0;
        int pos = 0;
        int indentation = 0;
        for (; pos < s.length(); pos++) {
            char c = s.charAt(pos);
            if (c == ' ') {
                indentation++;
                spaces++;
            } else if (c == '\t') {
                indentation += 4;
            } else
                break;
        }

        if (pos >= s.length())
            return "";
        return SPACES.substring(0, indentation) + s.substring(pos).trim();

    }

    static void fix(File fileToUpdate, boolean partial) throws IOException {
        boolean anyChanges = false;
        BufferedReader in = new BufferedReader(new FileReader(fileToUpdate));
        StringWriter stringWriter = new StringWriter();
        PrintWriter out = new PrintWriter(stringWriter);
        int consecutiveFixes = 0;
        try {
            while (true) {
                String s = in.readLine();
                if (s == null)
                    break;
                String s2 = fix(s);
                if (!s2.equals(s)) {
                    consecutiveFixes++;
                    if (consecutiveFixes > 3 && partial) {
                        s2 = s;
                        consecutiveFixes = 0;
                    } else
                        anyChanges = true;
                } else
                    consecutiveFixes = 0;
                out.println(s2);
            }
        } finally {
            in.close();
        }
        if (!anyChanges)
            return;
        StringReader stringReader = new StringReader(stringWriter.toString());
        Writer outFile = SourceCharset.fileWriter(fileToUpdate);
        char[] buffer = new char[1000];
        try {
            while (true) {
                int sz = stringReader.read(buffer);
                if (sz < 0)
                    break;
                outFile.write(buffer, 0, sz);
            }
        } finally {
            outFile.close();
        }
        System.out.println("Updated " + fileToUpdate);
    }

}

@@ -2453,32 +2453,77 @@
        %7D%0A    %7D%0A%0A
+    static boolean TRIM_TRAILING_WS = false;%0A
     static Strin
@@ -2603,16 +2603,36 @@
     if (
+TRIM_TRAILING_WS && 
 s.trim()
@@ -2674,32 +2674,8 @@
 %22%22;%0A
-        int spaces = 0;%0A
     
@@ -2716,24 +2716,46 @@
 tation = 0;%0A
+        int tabs = 0;%0A
         for 
@@ -2883,34 +2883,8 @@
 ++;%0A
-                spaces++;%0A
     
@@ -2949,16 +2949,40 @@
 n += 4;%0A
+                tabs++;%0A
         
@@ -3022,24 +3022,72 @@
 %0A        %7D%0A%0A
+        if (TRIM_TRAILING_WS %7C%7C tabs %3E 0) %7B%0A    
         if (
@@ -3109,32 +3109,36 @@
 ())%0A            
+    
 return %22%22;%0A     
@@ -3124,32 +3124,36 @@
      return %22%22;%0A
+    
         return S
@@ -3212,16 +3212,184 @@
 rim();%0A%0A
+        %7D else %7B%0A            if (pos %3E= s.length())%0A                return s;%0A            return SPACES.substring(0, indentation) + s.substring(pos);%0A        %7D%0A      %0A%0A
     %7D%0A%0A 
@@ -4397,16 +4397,111 @@
 return;%0A
+        System.out.println(%22Updating %22 + fileToUpdate);%0A        if (false)%0A            return;%0A
         
@@ -4955,54 +4955,8 @@
     
-System.out.println(%22Updated %22 + fileToUpdate);
 %0A   

Update tab fixing tool