001package net.minecraft.crash;
002
003import cpw.mods.fml.common.FMLCommonHandler;
004import cpw.mods.fml.relauncher.Side;
005import cpw.mods.fml.relauncher.SideOnly;
006import java.io.File;
007import java.io.FileWriter;
008import java.io.IOException;
009import java.io.PrintWriter;
010import java.io.StringWriter;
011import java.text.SimpleDateFormat;
012import java.util.ArrayList;
013import java.util.Date;
014import java.util.Iterator;
015import java.util.List;
016import java.util.logging.Level;
017import java.util.logging.Logger;
018import net.minecraft.util.ReportedException;
019
020public class CrashReport
021{
022    /** Description of the crash report. */
023    private final String description;
024
025    /** The Throwable that is the "cause" for this crash and Crash Report. */
026    private final Throwable cause;
027    private final CrashReportCategory field_85061_c = new CrashReportCategory(this, "System Details");
028
029    /** Holds the keys and values of all crash report sections. */
030    private final List crashReportSections = new ArrayList();
031
032    /** File of crash report. */
033    private File crashReportFile = null;
034    private boolean field_85059_f = true;
035    private StackTraceElement[] field_85060_g = new StackTraceElement[0];
036
037    public CrashReport(String par1Str, Throwable par2Throwable)
038    {
039        this.description = par1Str;
040        this.cause = par2Throwable;
041        this.populateEnvironment();
042    }
043
044    /**
045     * Populates this crash report with initial information about the running server and operating system / java
046     * environment
047     */
048    private void populateEnvironment()
049    {
050        this.field_85061_c.addCrashSectionCallable("Minecraft Version", new CallableMinecraftVersion(this));
051        this.field_85061_c.addCrashSectionCallable("Operating System", new CallableOSInfo(this));
052        this.field_85061_c.addCrashSectionCallable("Java Version", new CallableJavaInfo(this));
053        this.field_85061_c.addCrashSectionCallable("Java VM Version", new CallableJavaInfo2(this));
054        this.field_85061_c.addCrashSectionCallable("Memory", new CallableMemoryInfo(this));
055        this.field_85061_c.addCrashSectionCallable("JVM Flags", new CallableJVMFlags(this));
056        this.field_85061_c.addCrashSectionCallable("AABB Pool Size", new CallableCrashMemoryReport(this));
057        this.field_85061_c.addCrashSectionCallable("Suspicious classes", new CallableSuspiciousClasses(this));
058        this.field_85061_c.addCrashSectionCallable("IntCache", new CallableIntCache(this));
059        FMLCommonHandler.instance().enhanceCrashReport(this, this.field_85061_c);
060    }
061
062    /**
063     * Returns the description of the Crash Report.
064     */
065    public String getDescription()
066    {
067        return this.description;
068    }
069
070    /**
071     * Returns the Throwable object that is the cause for the crash and Crash Report.
072     */
073    public Throwable getCrashCause()
074    {
075        return this.cause;
076    }
077
078    @SideOnly(Side.CLIENT)
079    public String func_90021_c()
080    {
081        StringBuilder var1 = new StringBuilder();
082        this.getSectionsInStringBuilder(var1);
083        return var1.toString();
084    }
085
086    /**
087     * Gets the various sections of the crash report into the given StringBuilder
088     */
089    public void getSectionsInStringBuilder(StringBuilder par1StringBuilder)
090    {
091        if (this.field_85060_g != null && this.field_85060_g.length > 0)
092        {
093            par1StringBuilder.append("-- Head --\n");
094            par1StringBuilder.append("Stacktrace:\n");
095            StackTraceElement[] var2 = this.field_85060_g;
096            int var3 = var2.length;
097
098            for (int var4 = 0; var4 < var3; ++var4)
099            {
100                StackTraceElement var5 = var2[var4];
101                par1StringBuilder.append("\t").append("at ").append(var5.toString());
102                par1StringBuilder.append("\n");
103            }
104
105            par1StringBuilder.append("\n");
106        }
107
108        Iterator var6 = this.crashReportSections.iterator();
109
110        while (var6.hasNext())
111        {
112            CrashReportCategory var7 = (CrashReportCategory)var6.next();
113            var7.func_85072_a(par1StringBuilder);
114            par1StringBuilder.append("\n\n");
115        }
116
117        this.field_85061_c.func_85072_a(par1StringBuilder);
118    }
119
120    /**
121     * Gets the stack trace of the Throwable that caused this crash report, or if that fails, the cause .toString().
122     */
123    public String getCauseStackTraceOrString()
124    {
125        StringWriter var1 = null;
126        PrintWriter var2 = null;
127        String var3 = this.cause.toString();
128
129        try
130        {
131            var1 = new StringWriter();
132            var2 = new PrintWriter(var1);
133            this.cause.printStackTrace(var2);
134            var3 = var1.toString();
135        }
136        finally
137        {
138            try
139            {
140                if (var1 != null)
141                {
142                    var1.close();
143                }
144
145                if (var2 != null)
146                {
147                    var2.close();
148                }
149            }
150            catch (IOException var10)
151            {
152                ;
153            }
154        }
155
156        return var3;
157    }
158
159    /**
160     * Gets the complete report with headers, stack trace, and different sections as a string.
161     */
162    public String getCompleteReport()
163    {
164        StringBuilder var1 = new StringBuilder();
165        var1.append("---- Minecraft Crash Report ----\n");
166        var1.append("// ");
167        var1.append(getWittyComment());
168        var1.append("\n\n");
169        var1.append("Time: ");
170        var1.append((new SimpleDateFormat()).format(new Date()));
171        var1.append("\n");
172        var1.append("Description: ");
173        var1.append(this.description);
174        var1.append("\n\n");
175        var1.append(this.getCauseStackTraceOrString());
176        var1.append("\n\nA detailed walkthrough of the error, its code path and all known details is as follows:\n");
177
178        for (int var2 = 0; var2 < 87; ++var2)
179        {
180            var1.append("-");
181        }
182
183        var1.append("\n\n");
184        this.getSectionsInStringBuilder(var1);
185        return var1.toString();
186    }
187
188    @SideOnly(Side.CLIENT)
189
190    /**
191     * Gets the file this crash report is saved into.
192     */
193    public File getFile()
194    {
195        return this.crashReportFile;
196    }
197
198    /**
199     * Saves the complete crash report to the given File.
200     */
201    public boolean saveToFile(File par1File)
202    {
203        if (this.crashReportFile != null)
204        {
205            return false;
206        }
207        else
208        {
209            if (par1File.getParentFile() != null)
210            {
211                par1File.getParentFile().mkdirs();
212            }
213
214            try
215            {
216                FileWriter var2 = new FileWriter(par1File);
217                var2.write(this.getCompleteReport());
218                var2.close();
219                this.crashReportFile = par1File;
220                return true;
221            }
222            catch (Throwable var3)
223            {
224                Logger.getLogger("Minecraft").log(Level.SEVERE, "Could not save crash report to " + par1File, var3);
225                return false;
226            }
227        }
228    }
229
230    public CrashReportCategory func_85056_g()
231    {
232        return this.field_85061_c;
233    }
234
235    /**
236     * Creates a CrashReportCategory
237     */
238    public CrashReportCategory makeCategory(String par1Str)
239    {
240        return this.makeCategoryDepth(par1Str, 1);
241    }
242
243    /**
244     * Creates a CrashReportCategory for the given stack trace depth
245     */
246    public CrashReportCategory makeCategoryDepth(String par1Str, int par2)
247    {
248        CrashReportCategory var3 = new CrashReportCategory(this, par1Str);
249
250        if (this.field_85059_f)
251        {
252            int var4 = var3.func_85073_a(par2);
253            StackTraceElement[] var5 = this.cause.getStackTrace();
254            StackTraceElement var6 = null;
255            StackTraceElement var7 = null;
256
257            if (var5 != null && var5.length - var4 < var5.length)
258            {
259                var6 = var5[var5.length - var4];
260
261                if (var5.length + 1 - var4 < var5.length)
262                {
263                    var7 = var5[var5.length + 1 - var4];
264                }
265            }
266
267            this.field_85059_f = var3.func_85069_a(var6, var7);
268
269            if (var4 > 0 && !this.crashReportSections.isEmpty())
270            {
271                CrashReportCategory var8 = (CrashReportCategory)this.crashReportSections.get(this.crashReportSections.size() - 1);
272                var8.func_85070_b(var4);
273            }
274            else if (var5 != null && var5.length >= var4)
275            {
276                this.field_85060_g = new StackTraceElement[var5.length - var4];
277                System.arraycopy(var5, 0, this.field_85060_g, 0, this.field_85060_g.length);
278            }
279            else
280            {
281                this.field_85059_f = false;
282            }
283        }
284
285        this.crashReportSections.add(var3);
286        return var3;
287    }
288
289    /**
290     * Gets a random witty comment for inclusion in this CrashReport
291     */
292    private static String getWittyComment()
293    {
294        String[] var0 = new String[] {"Who set us up the TNT?", "Everything\'s going to plan. No, really, that was supposed to happen.", "Uh... Did I do that?", "Oops.", "Why did you do that?", "I feel sad now :(", "My bad.", "I\'m sorry, Dave.", "I let you down. Sorry :(", "On the bright side, I bought you a teddy bear!", "Daisy, daisy...", "Oh - I know what I did wrong!", "Hey, that tickles! Hehehe!", "I blame Dinnerbone.", "You should try our sister game, Minceraft!", "Don\'t be sad. I\'ll do better next time, I promise!", "Don\'t be sad, have a hug! <3", "I just don\'t know what went wrong :(", "Shall we play a game?", "Quite honestly, I wouldn\'t worry myself about that.", "I bet Cylons wouldn\'t have this problem.", "Sorry :(", "Surprise! Haha. Well, this is awkward.", "Would you like a cupcake?", "Hi. I\'m Minecraft, and I\'m a crashaholic.", "Ooh. Shiny.", "This doesn\'t make any sense!", "Why is it breaking :(", "Don\'t do that.", "Ouch. That hurt :(", "You\'re mean.", "This is a token for 1 free hug. Redeem at your nearest Mojangsta: [~~HUG~~]", "There are four lights!"};
295
296        try
297        {
298            return var0[(int)(System.nanoTime() % (long)var0.length)];
299        }
300        catch (Throwable var2)
301        {
302            return "Witty comment unavailable :(";
303        }
304    }
305
306    /**
307     * Creates a crash report for the exception
308     */
309    public static CrashReport makeCrashReport(Throwable par0Throwable, String par1Str)
310    {
311        CrashReport var2;
312
313        if (par0Throwable instanceof ReportedException)
314        {
315            var2 = ((ReportedException)par0Throwable).getCrashReport();
316        }
317        else
318        {
319            var2 = new CrashReport(par1Str, par0Throwable);
320        }
321
322        return var2;
323    }
324}