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