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            FMLCommonHandler.instance().enhanceCrashReport(this);
051        }
052    
053        /**
054         * Adds a Crashreport section with the given name with the value set to the result of the given Callable;
055         */
056        public void addCrashSectionCallable(String par1Str, Callable par2Callable)
057        {
058            try
059            {
060                this.addCrashSection(par1Str, par2Callable.call());
061            }
062            catch (Throwable var4)
063            {
064                this.addCrashSectionThrowable(par1Str, var4);
065            }
066        }
067    
068        /**
069         * Adds a Crashreport section with the given name with the given value (convered .toString())
070         */
071        public void addCrashSection(String par1Str, Object par2Obj)
072        {
073            this.crashReportSections.put(par1Str, par2Obj == null ? "null" : par2Obj.toString());
074        }
075    
076        /**
077         * Adds a Crashreport section with the given name with the given Throwable
078         */
079        public void addCrashSectionThrowable(String par1Str, Throwable par2Throwable)
080        {
081            this.addCrashSection(par1Str, "~ERROR~ " + par2Throwable.getClass().getSimpleName() + ": " + par2Throwable.getMessage());
082        }
083    
084        /**
085         * Returns the description of the Crash Report.
086         */
087        public String getDescription()
088        {
089            return this.description;
090        }
091    
092        public Throwable func_71505_b()
093        {
094            return this.cause;
095        }
096    
097        @SideOnly(Side.CLIENT)
098    
099        /**
100         * Gets a string representation of all sections in the crash report.
101         */
102        public String getSections()
103        {
104            StringBuilder var1 = new StringBuilder();
105            this.getSectionsInStringBuilder(var1);
106            return var1.toString();
107        }
108    
109        /**
110         * Gets the various sections of the crash report into the given StringBuilder
111         */
112        public void getSectionsInStringBuilder(StringBuilder par1StringBuilder)
113        {
114            boolean var2 = true;
115    
116            for (Iterator var3 = this.crashReportSections.entrySet().iterator(); var3.hasNext(); var2 = false)
117            {
118                Entry var4 = (Entry)var3.next();
119    
120                if (!var2)
121                {
122                    par1StringBuilder.append("\n");
123                }
124    
125                par1StringBuilder.append("- ");
126                par1StringBuilder.append((String)var4.getKey());
127                par1StringBuilder.append(": ");
128                par1StringBuilder.append((String)var4.getValue());
129            }
130        }
131    
132        /**
133         * Gets the stack trace of the Throwable that caused this crash report, or if that fails, the cause .toString().
134         */
135        public String getCauseStackTraceOrString()
136        {
137            StringWriter var1 = null;
138            PrintWriter var2 = null;
139            String var3 = this.cause.toString();
140    
141            try
142            {
143                var1 = new StringWriter();
144                var2 = new PrintWriter(var1);
145                this.cause.printStackTrace(var2);
146                var3 = var1.toString();
147            }
148            finally
149            {
150                try
151                {
152                    if (var1 != null)
153                    {
154                        var1.close();
155                    }
156    
157                    if (var2 != null)
158                    {
159                        var2.close();
160                    }
161                }
162                catch (IOException var10)
163                {
164                    ;
165                }
166            }
167    
168            return var3;
169        }
170    
171        /**
172         * Gets the complete report with headers, stack trace, and different sections as a string.
173         */
174        public String getCompleteReport()
175        {
176            StringBuilder var1 = new StringBuilder();
177            var1.append("---- Minecraft Crash Report ----\n");
178            var1.append("// ");
179            var1.append(getWittyComment());
180            var1.append("\n\n");
181            var1.append("Time: ");
182            var1.append((new SimpleDateFormat()).format(new Date()));
183            var1.append("\n");
184            var1.append("Description: ");
185            var1.append(this.description);
186            var1.append("\n\n");
187            var1.append(this.getCauseStackTraceOrString());
188            var1.append("\n");
189            var1.append("Relevant Details:");
190            var1.append("\n");
191            this.getSectionsInStringBuilder(var1);
192            return var1.toString();
193        }
194    
195        @SideOnly(Side.CLIENT)
196    
197        /**
198         * Gets the file this crash report is saved into.
199         */
200        public File getFile()
201        {
202            return this.crashReportFile;
203        }
204    
205        /**
206         * Saves the complete crash report to the given File.
207         */
208        public boolean saveToFile(File par1File)
209        {
210            if (this.crashReportFile != null)
211            {
212                return false;
213            }
214            else
215            {
216                if (par1File.getParentFile() != null)
217                {
218                    par1File.getParentFile().mkdirs();
219                }
220    
221                try
222                {
223                    FileWriter var2 = new FileWriter(par1File);
224                    var2.write(this.getCompleteReport());
225                    var2.close();
226                    this.crashReportFile = par1File;
227                    return true;
228                }
229                catch (Throwable var3)
230                {
231                    Logger.getLogger("Minecraft").log(Level.SEVERE, "Could not save crash report to " + par1File, var3);
232                    return false;
233                }
234            }
235        }
236    
237        /**
238         * Gets a random witty comment for inclusion in this CrashReport
239         */
240        private static String getWittyComment()
241        {
242            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 :("};
243    
244            try
245            {
246                return var0[(int)(System.nanoTime() % (long)var0.length)];
247            }
248            catch (Throwable var2)
249            {
250                return "Witty comment unavailable :(";
251            }
252        }
253    }