001    package net.minecraft.src;
002    
003    import cpw.mods.fml.common.FMLCommonHandler;
004    import cpw.mods.fml.common.Side;
005    import cpw.mods.fml.common.asm.SideOnly;
006    import java.io.File;
007    import java.io.FileWriter;
008    import java.io.IOException;
009    import java.io.PrintWriter;
010    import java.io.StringWriter;
011    import java.text.SimpleDateFormat;
012    import java.util.Date;
013    import java.util.Iterator;
014    import java.util.LinkedHashMap;
015    import java.util.Map;
016    import java.util.Map.Entry;
017    import java.util.concurrent.Callable;
018    import java.util.logging.Level;
019    import java.util.logging.Logger;
020    
021    public class CrashReport
022    {
023        /** Description of the crash report. */
024        private final String description;
025    
026        /** The Throwable that is the "cause" for this crash and Crash Report. */
027        private final Throwable cause;
028    
029        /** Holds the keys and values of all crash report sections. */
030        private final Map crashReportSections = new LinkedHashMap();
031    
032        /** File of crash report. */
033        private File crashReportFile = null;
034    
035        public CrashReport(String par1Str, Throwable par2Throwable)
036        {
037            this.description = par1Str;
038            this.cause = par2Throwable;
039            this.func_71504_g();
040        }
041    
042        private void func_71504_g()
043        {
044            this.addCrashSectionCallable("Minecraft Version", new CallableMinecraftVersion(this));
045            this.addCrashSectionCallable("Operating System", new CallableOSInfo(this));
046            this.addCrashSectionCallable("Java Version", new CallableJavaInfo(this));
047            this.addCrashSectionCallable("Java VM Version", new CallableJavaInfo2(this));
048            this.addCrashSectionCallable("Memory", new CallableMemoryInfo(this));
049            this.addCrashSectionCallable("JVM Flags", new CallableJVMFlags(this));
050            this.addCrashSectionCallable("AABB Pool Size", new CallableCrashMemoryReport(this));
051            FMLCommonHandler.instance().enhanceCrashReport(this);
052        }
053    
054        /**
055         * Adds a Crashreport section with the given name with the value set to the result of the given Callable;
056         */
057        public void addCrashSectionCallable(String par1Str, Callable par2Callable)
058        {
059            try
060            {
061                this.addCrashSection(par1Str, par2Callable.call());
062            }
063            catch (Throwable var4)
064            {
065                this.addCrashSectionThrowable(par1Str, var4);
066            }
067        }
068    
069        /**
070         * Adds a Crashreport section with the given name with the given value (convered .toString())
071         */
072        public void addCrashSection(String par1Str, Object par2Obj)
073        {
074            this.crashReportSections.put(par1Str, par2Obj == null ? "null" : par2Obj.toString());
075        }
076    
077        /**
078         * Adds a Crashreport section with the given name with the given Throwable
079         */
080        public void addCrashSectionThrowable(String par1Str, Throwable par2Throwable)
081        {
082            this.addCrashSection(par1Str, "~ERROR~ " + par2Throwable.getClass().getSimpleName() + ": " + par2Throwable.getMessage());
083        }
084    
085        /**
086         * Returns the description of the Crash Report.
087         */
088        public String getDescription()
089        {
090            return this.description;
091        }
092    
093        /**
094         * Returns the Throwable object that is the cause for the crash and Crash Report.
095         */
096        public Throwable getCrashCause()
097        {
098            return this.cause;
099        }
100    
101        @SideOnly(Side.CLIENT)
102    
103        /**
104         * Gets a string representation of all sections in the crash report.
105         */
106        public String getSections()
107        {
108            StringBuilder var1 = new StringBuilder();
109            this.getSectionsInStringBuilder(var1);
110            return var1.toString();
111        }
112    
113        /**
114         * Gets the various sections of the crash report into the given StringBuilder
115         */
116        public void getSectionsInStringBuilder(StringBuilder par1StringBuilder)
117        {
118            boolean var2 = true;
119    
120            for (Iterator var3 = this.crashReportSections.entrySet().iterator(); var3.hasNext(); var2 = false)
121            {
122                Entry var4 = (Entry)var3.next();
123    
124                if (!var2)
125                {
126                    par1StringBuilder.append("\n");
127                }
128    
129                par1StringBuilder.append("- ");
130                par1StringBuilder.append((String)var4.getKey());
131                par1StringBuilder.append(": ");
132                par1StringBuilder.append((String)var4.getValue());
133            }
134        }
135    
136        /**
137         * Gets the stack trace of the Throwable that caused this crash report, or if that fails, the cause .toString().
138         */
139        public String getCauseStackTraceOrString()
140        {
141            StringWriter var1 = null;
142            PrintWriter var2 = null;
143            String var3 = this.cause.toString();
144    
145            try
146            {
147                var1 = new StringWriter();
148                var2 = new PrintWriter(var1);
149                this.cause.printStackTrace(var2);
150                var3 = var1.toString();
151            }
152            finally
153            {
154                try
155                {
156                    if (var1 != null)
157                    {
158                        var1.close();
159                    }
160    
161                    if (var2 != null)
162                    {
163                        var2.close();
164                    }
165                }
166                catch (IOException var10)
167                {
168                    ;
169                }
170            }
171    
172            return var3;
173        }
174    
175        /**
176         * Gets the complete report with headers, stack trace, and different sections as a string.
177         */
178        public String getCompleteReport()
179        {
180            StringBuilder var1 = new StringBuilder();
181            var1.append("---- Minecraft Crash Report ----\n");
182            var1.append("// ");
183            var1.append(getWittyComment());
184            var1.append("\n\n");
185            var1.append("Time: ");
186            var1.append((new SimpleDateFormat()).format(new Date()));
187            var1.append("\n");
188            var1.append("Description: ");
189            var1.append(this.description);
190            var1.append("\n\n");
191            var1.append(this.getCauseStackTraceOrString());
192            var1.append("\n");
193            var1.append("Relevant Details:");
194            var1.append("\n");
195            this.getSectionsInStringBuilder(var1);
196            return var1.toString();
197        }
198    
199        @SideOnly(Side.CLIENT)
200    
201        /**
202         * Gets the file this crash report is saved into.
203         */
204        public File getFile()
205        {
206            return this.crashReportFile;
207        }
208    
209        /**
210         * Saves the complete crash report to the given File.
211         */
212        public boolean saveToFile(File par1File)
213        {
214            if (this.crashReportFile != null)
215            {
216                return false;
217            }
218            else
219            {
220                if (par1File.getParentFile() != null)
221                {
222                    par1File.getParentFile().mkdirs();
223                }
224    
225                try
226                {
227                    FileWriter var2 = new FileWriter(par1File);
228                    var2.write(this.getCompleteReport());
229                    var2.close();
230                    this.crashReportFile = par1File;
231                    return true;
232                }
233                catch (Throwable var3)
234                {
235                    Logger.getLogger("Minecraft").log(Level.SEVERE, "Could not save crash report to " + par1File, var3);
236                    return false;
237                }
238            }
239        }
240    
241        /**
242         * Gets a random witty comment for inclusion in this CrashReport
243         */
244        private static String getWittyComment()
245        {
246            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 :("};
247    
248            try
249            {
250                return var0[(int)(System.nanoTime() % (long)var0.length)];
251            }
252            catch (Throwable var2)
253            {
254                return "Witty comment unavailable :(";
255            }
256        }
257    }