//# 1 errors, 557 messages
//#
/*
    //#ProgramError.java:1:1: class: com.dmdirc.logger.ProgramError
 * Copyright (c) 2006-2009 Chris Smith, Shane Mc Cormack, Gregory Holmes
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

package com.dmdirc.logger;

import com.dmdirc.Main;
import com.dmdirc.config.IdentityManager;
import com.dmdirc.util.Downloader;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.Serializable;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Semaphore;

/**
 * Stores a program error.
 */
public final class ProgramError implements Serializable {
    
    /**
     * A version number for this class. It should be changed whenever the class
     * structure is changed (or anything else that would prevent serialized
     * objects being unserialized with the new class).
     */
    private static final long serialVersionUID = 3;

    /** Directory used to store errors. */
    private static File errorDir;

    /** Semaphore used to serialise write access. */
    private static final Semaphore writingSem = new Semaphore(1);
    //#ProgramError.java:60: method: com.dmdirc.logger.ProgramError.com.dmdirc.logger.ProgramError__static_init
    //#output(com.dmdirc.logger.ProgramError__static_init): __Descendant_Table[com/dmdirc/logger/ProgramError]
    //#output(com.dmdirc.logger.ProgramError__static_init): __Dispatch_Table.checkResponses(Ljava/util/List;)V
    //#output(com.dmdirc.logger.ProgramError__static_init): __Dispatch_Table.equals(Ljava/lang/Object;)Z
    //#output(com.dmdirc.logger.ProgramError__static_init): __Dispatch_Table.getDate()Ljava/util/Date;
    //#output(com.dmdirc.logger.ProgramError__static_init): __Dispatch_Table.getErrorFile()Ljava/io/OutputStream;
    //#output(com.dmdirc.logger.ProgramError__static_init): __Dispatch_Table.getFixedStatus()Lcom/dmdirc/logger/ErrorFixedStatus;
    //#output(com.dmdirc.logger.ProgramError__static_init): __Dispatch_Table.getID()J
    //#output(com.dmdirc.logger.ProgramError__static_init): __Dispatch_Table.getLevel()Lcom/dmdirc/logger/ErrorLevel;
    //#output(com.dmdirc.logger.ProgramError__static_init): __Dispatch_Table.getMessage()Ljava/lang/String;
    //#output(com.dmdirc.logger.ProgramError__static_init): __Dispatch_Table.getReportStatus()Lcom/dmdirc/logger/ErrorReportStatus;
    //#output(com.dmdirc.logger.ProgramError__static_init): __Dispatch_Table.getSourceLine()Ljava/lang/String;
    //#output(com.dmdirc.logger.ProgramError__static_init): __Dispatch_Table.getTrace()[Ljava/lang/String;
    //#output(com.dmdirc.logger.ProgramError__static_init): __Dispatch_Table.hashCode()I
    //#output(com.dmdirc.logger.ProgramError__static_init): __Dispatch_Table.isValidSource()Z
    //#output(com.dmdirc.logger.ProgramError__static_init): __Dispatch_Table.save()V
    //#output(com.dmdirc.logger.ProgramError__static_init): __Dispatch_Table.send()V
    //#output(com.dmdirc.logger.ProgramError__static_init): __Dispatch_Table.setFixedStatus(Lcom/dmdirc/logger/ErrorFixedStatus;)V
    //#output(com.dmdirc.logger.ProgramError__static_init): __Dispatch_Table.setReportStatus(Lcom/dmdirc/logger/ErrorReportStatus;)V
    //#output(com.dmdirc.logger.ProgramError__static_init): __Dispatch_Table.toString()Ljava/lang/String;
    //#output(com.dmdirc.logger.ProgramError__static_init): new Semaphore(ProgramError__static_init#1) num objects
    //#output(com.dmdirc.logger.ProgramError__static_init): writingSem
    //#new obj(com.dmdirc.logger.ProgramError__static_init): new Semaphore(ProgramError__static_init#1)
    //#post(com.dmdirc.logger.ProgramError__static_init): __Descendant_Table[com/dmdirc/logger/ProgramError] == &__Dispatch_Table
    //#post(com.dmdirc.logger.ProgramError__static_init): __Dispatch_Table.checkResponses(Ljava/util/List;)V == &checkResponses
    //#post(com.dmdirc.logger.ProgramError__static_init): __Dispatch_Table.equals(Ljava/lang/Object;)Z == &equals
    //#post(com.dmdirc.logger.ProgramError__static_init): __Dispatch_Table.getDate()Ljava/util/Date; == &getDate
    //#post(com.dmdirc.logger.ProgramError__static_init): __Dispatch_Table.getErrorFile()Ljava/io/OutputStream; == &getErrorFile
    //#post(com.dmdirc.logger.ProgramError__static_init): __Dispatch_Table.getFixedStatus()Lcom/dmdirc/logger/ErrorFixedStatus; == &getFixedStatus
    //#post(com.dmdirc.logger.ProgramError__static_init): __Dispatch_Table.getID()J == &getID
    //#post(com.dmdirc.logger.ProgramError__static_init): __Dispatch_Table.getLevel()Lcom/dmdirc/logger/ErrorLevel; == &getLevel
    //#post(com.dmdirc.logger.ProgramError__static_init): __Dispatch_Table.getMessage()Ljava/lang/String; == &getMessage
    //#post(com.dmdirc.logger.ProgramError__static_init): __Dispatch_Table.getReportStatus()Lcom/dmdirc/logger/ErrorReportStatus; == &getReportStatus
    //#post(com.dmdirc.logger.ProgramError__static_init): __Dispatch_Table.getSourceLine()Ljava/lang/String; == &getSourceLine
    //#post(com.dmdirc.logger.ProgramError__static_init): __Dispatch_Table.getTrace()[Ljava/lang/String; == &getTrace
    //#post(com.dmdirc.logger.ProgramError__static_init): __Dispatch_Table.hashCode()I == &hashCode
    //#post(com.dmdirc.logger.ProgramError__static_init): __Dispatch_Table.isValidSource()Z == &isValidSource
    //#post(com.dmdirc.logger.ProgramError__static_init): __Dispatch_Table.save()V == &save
    //#post(com.dmdirc.logger.ProgramError__static_init): __Dispatch_Table.send()V == &send
    //#post(com.dmdirc.logger.ProgramError__static_init): __Dispatch_Table.setFixedStatus(Lcom/dmdirc/logger/ErrorFixedStatus;)V == &setFixedStatus
    //#post(com.dmdirc.logger.ProgramError__static_init): __Dispatch_Table.setReportStatus(Lcom/dmdirc/logger/ErrorReportStatus;)V == &setReportStatus
    //#post(com.dmdirc.logger.ProgramError__static_init): __Dispatch_Table.toString()Ljava/lang/String; == &toString
    //#post(com.dmdirc.logger.ProgramError__static_init): writingSem == &new Semaphore(ProgramError__static_init#1)
    //#post(com.dmdirc.logger.ProgramError__static_init): new Semaphore(ProgramError__static_init#1) num objects == 1
    //#ProgramError.java:60: end of method: com.dmdirc.logger.ProgramError.com.dmdirc.logger.ProgramError__static_init
    
    /** Error ID. */
    private final long id;
    
    /** Error icon. */
    private final ErrorLevel level;
    
    /** Error message. */
    private final String message;
    
    /** Error trace. */
    private final String[] trace;
    
    /** Date/time error occurred. */
    private final Date date;
    
    /** Error report Status. */
    private ErrorReportStatus reportStatus;
    
    /** Error fixed Status. */
    private ErrorFixedStatus fixedStatus;
    
    /**
     * Creates a new instance of ProgramError.
     *
     * @param id error id
     * @param level Error level
     * @param message Error message
     * @param trace Error trace
     * @param date Error time and date
     */
    public ProgramError(final long id, final ErrorLevel level,
            final String message, final String[] trace, final Date date) {
    //#ProgramError.java:93: method: void com.dmdirc.logger.ProgramError.com.dmdirc.logger.ProgramError(long, ErrorLevel, String, String[], Date)
    //#input(void com.dmdirc.logger.ProgramError(long, ErrorLevel, String, String[], Date)): "ID must be a positive integer: "._tainted
    //#input(void com.dmdirc.logger.ProgramError(long, ErrorLevel, String, String[], Date)): com/dmdirc/logger/ErrorFixedStatus.UNKNOWN
    //#input(void com.dmdirc.logger.ProgramError(long, ErrorLevel, String, String[], Date)): com/dmdirc/logger/ErrorReportStatus.WAITING
    //#input(void com.dmdirc.logger.ProgramError(long, ErrorLevel, String, String[], Date)): date
    //#input(void com.dmdirc.logger.ProgramError(long, ErrorLevel, String, String[], Date)): id
    //#input(void com.dmdirc.logger.ProgramError(long, ErrorLevel, String, String[], Date)): level
    //#input(void com.dmdirc.logger.ProgramError(long, ErrorLevel, String, String[], Date)): message
    //#input(void com.dmdirc.logger.ProgramError(long, ErrorLevel, String, String[], Date)): this
    //#input(void com.dmdirc.logger.ProgramError(long, ErrorLevel, String, String[], Date)): trace
    //#input(void com.dmdirc.logger.ProgramError(long, ErrorLevel, String, String[], Date)): trace.length
    //#output(void com.dmdirc.logger.ProgramError(long, ErrorLevel, String, String[], Date)): this.date
    //#output(void com.dmdirc.logger.ProgramError(long, ErrorLevel, String, String[], Date)): this.fixedStatus
    //#output(void com.dmdirc.logger.ProgramError(long, ErrorLevel, String, String[], Date)): this.id
    //#output(void com.dmdirc.logger.ProgramError(long, ErrorLevel, String, String[], Date)): this.level
    //#output(void com.dmdirc.logger.ProgramError(long, ErrorLevel, String, String[], Date)): this.message
    //#output(void com.dmdirc.logger.ProgramError(long, ErrorLevel, String, String[], Date)): this.reportStatus
    //#output(void com.dmdirc.logger.ProgramError(long, ErrorLevel, String, String[], Date)): this.trace
    //#pre[1] (void com.dmdirc.logger.ProgramError(long, ErrorLevel, String, String[], Date)): date != null
    //#pre[2] (void com.dmdirc.logger.ProgramError(long, ErrorLevel, String, String[], Date)): id >= 0
    //#pre[3] (void com.dmdirc.logger.ProgramError(long, ErrorLevel, String, String[], Date)): level != null
    //#pre[4] (void com.dmdirc.logger.ProgramError(long, ErrorLevel, String, String[], Date)): message != null
    //#pre[6] (void com.dmdirc.logger.ProgramError(long, ErrorLevel, String, String[], Date)): trace != null
    //#pre[7] (void com.dmdirc.logger.ProgramError(long, ErrorLevel, String, String[], Date)): trace.length <= 4_294_967_295
    //#presumption(void com.dmdirc.logger.ProgramError(long, ErrorLevel, String, String[], Date)): java.lang.String:isEmpty(...)@103 == 0
    //#post(void com.dmdirc.logger.ProgramError(long, ErrorLevel, String, String[], Date)): this.date != null
    //#post(void com.dmdirc.logger.ProgramError(long, ErrorLevel, String, String[], Date)): this.fixedStatus == &com.dmdirc.logger.ErrorFixedStatus__static_init.new ErrorFixedStatus(ErrorFixedStatus__static_init#7)
    //#post(void com.dmdirc.logger.ProgramError(long, ErrorLevel, String, String[], Date)): this.id == id
    //#post(void com.dmdirc.logger.ProgramError(long, ErrorLevel, String, String[], Date)): this.id >= 0
    //#post(void com.dmdirc.logger.ProgramError(long, ErrorLevel, String, String[], Date)): this.level == level
    //#post(void com.dmdirc.logger.ProgramError(long, ErrorLevel, String, String[], Date)): this.level != null
    //#post(void com.dmdirc.logger.ProgramError(long, ErrorLevel, String, String[], Date)): this.message == message
    //#post(void com.dmdirc.logger.ProgramError(long, ErrorLevel, String, String[], Date)): this.message != null
    //#post(void com.dmdirc.logger.ProgramError(long, ErrorLevel, String, String[], Date)): this.reportStatus == &com.dmdirc.logger.ErrorReportStatus__static_init.new ErrorReportStatus(ErrorReportStatus__static_init#6)
    //#post(void com.dmdirc.logger.ProgramError(long, ErrorLevel, String, String[], Date)): init'ed(this.trace)
        
        if (id < 0) {
            throw new IllegalArgumentException("ID must be a positive integer: " + id);
        }
        
        if (level == null) {
            throw new IllegalArgumentException("Level cannot be null");
        }
        
        if (message == null || message.isEmpty()) {
            throw new IllegalArgumentException("Message cannot be null or an empty string");
        }
        
        if (trace == null) {
            throw new IllegalArgumentException("Trace cannot be null");
        }
        
        if (date == null) {
            throw new IllegalArgumentException("date cannot be null");
        }
        
        this.id = id;
        this.level = level;
        this.message = message;
        this.trace = Arrays.copyOf(trace, trace.length);
        this.date = (Date) date.clone();
        this.reportStatus = ErrorReportStatus.WAITING;
        this.fixedStatus = ErrorFixedStatus.UNKNOWN;
    }
    //#ProgramError.java:122: end of method: void com.dmdirc.logger.ProgramError.com.dmdirc.logger.ProgramError(long, ErrorLevel, String, String[], Date)
    
    /**
     * Returns this errors level.
     *
     * @return Error level
     */
    public ErrorLevel getLevel() {
        return level;
    //#ProgramError.java:130: method: ErrorLevel com.dmdirc.logger.ProgramError.getLevel()
    //#input(ErrorLevel getLevel()): this
    //#input(ErrorLevel getLevel()): this.level
    //#output(ErrorLevel getLevel()): return_value
    //#post(ErrorLevel getLevel()): return_value == this.level
    //#post(ErrorLevel getLevel()): init'ed(return_value)
    //#ProgramError.java:130: end of method: ErrorLevel com.dmdirc.logger.ProgramError.getLevel()
    }
    
    /**
     * Returns this errors message.
     *
     * @return Error message
     */
    public String getMessage() {
        return message;
    //#ProgramError.java:139: method: String com.dmdirc.logger.ProgramError.getMessage()
    //#input(String getMessage()): this
    //#input(String getMessage()): this.message
    //#output(String getMessage()): return_value
    //#post(String getMessage()): return_value == this.message
    //#post(String getMessage()): init'ed(return_value)
    //#ProgramError.java:139: end of method: String com.dmdirc.logger.ProgramError.getMessage()
    }
    
    /**
     * Returns this errors trace.
     *
     * @return Error trace
     */
    public String[] getTrace() {
        return Arrays.copyOf(trace, trace.length);
    //#ProgramError.java:148: method: String[] com.dmdirc.logger.ProgramError.getTrace()
    //#input(String[] getTrace()): this
    //#input(String[] getTrace()): this.trace
    //#input(String[] getTrace()): this.trace.length
    //#output(String[] getTrace()): return_value
    //#pre[2] (String[] getTrace()): this.trace != null
    //#pre[3] (String[] getTrace()): this.trace.length <= 4_294_967_295
    //#post(String[] getTrace()): init'ed(return_value)
    //#ProgramError.java:148: end of method: String[] com.dmdirc.logger.ProgramError.getTrace()
    }
    
    /**
     * Returns this errors time.
     *
     * @return Error time
     */
    public Date getDate() {
        return (Date) date.clone();
    //#ProgramError.java:157: method: Date com.dmdirc.logger.ProgramError.getDate()
    //#input(Date getDate()): this
    //#input(Date getDate()): this.date
    //#output(Date getDate()): return_value
    //#pre[2] (Date getDate()): this.date != null
    //#post(Date getDate()): return_value != null
    //#ProgramError.java:157: end of method: Date com.dmdirc.logger.ProgramError.getDate()
    }
    
    /**
     * Returns the reportStatus of this error.
     * 
     * @return Error reportStatus
     */
    public ErrorReportStatus getReportStatus() {
        return reportStatus;
    //#ProgramError.java:166: method: ErrorReportStatus com.dmdirc.logger.ProgramError.getReportStatus()
    //#input(ErrorReportStatus getReportStatus()): this
    //#input(ErrorReportStatus getReportStatus()): this.reportStatus
    //#output(ErrorReportStatus getReportStatus()): return_value
    //#pre[2] (ErrorReportStatus getReportStatus()): init'ed(this.reportStatus)
    //#post(ErrorReportStatus getReportStatus()): return_value == this.reportStatus
    //#post(ErrorReportStatus getReportStatus()): init'ed(return_value)
    //#ProgramError.java:166: end of method: ErrorReportStatus com.dmdirc.logger.ProgramError.getReportStatus()
    }
    
    /**
     * Returns the fixed status of this error.
     * 
     * @return Error fixed status
     */
    public ErrorFixedStatus getFixedStatus() {
        return fixedStatus;
    //#ProgramError.java:175: method: ErrorFixedStatus com.dmdirc.logger.ProgramError.getFixedStatus()
    //#input(ErrorFixedStatus getFixedStatus()): this
    //#input(ErrorFixedStatus getFixedStatus()): this.fixedStatus
    //#output(ErrorFixedStatus getFixedStatus()): return_value
    //#pre[2] (ErrorFixedStatus getFixedStatus()): init'ed(this.fixedStatus)
    //#post(ErrorFixedStatus getFixedStatus()): return_value == this.fixedStatus
    //#post(ErrorFixedStatus getFixedStatus()): init'ed(return_value)
    //#ProgramError.java:175: end of method: ErrorFixedStatus com.dmdirc.logger.ProgramError.getFixedStatus()
    }
    
    /**
     * Sets the report Status of this error.
     * 
     * @param newStatus new ErrorReportStatus for the error
     */
    public void setReportStatus(final ErrorReportStatus newStatus) {
        if (newStatus != null && !reportStatus.equals(newStatus)) {
    //#ProgramError.java:184: method: void com.dmdirc.logger.ProgramError.setReportStatus(ErrorReportStatus)
    //#ProgramError.java:184: Warning: method not available - call not analyzed
    //#    call on bool com.dmdirc.logger.ErrorReportStatus:equals(Object)
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.logger.ProgramError
    //#    method: void setReportStatus(ErrorReportStatus)
    //#    unanalyzed callee: bool com.dmdirc.logger.ErrorReportStatus:equals(Object)
    //#input(void setReportStatus(ErrorReportStatus)): __Descendant_Table[com/dmdirc/logger/ProgramError]
    //#input(void setReportStatus(ErrorReportStatus)): __Descendant_Table[others]
    //#input(void setReportStatus(ErrorReportStatus)): com.dmdirc.logger.ErrorManager__static_init.new ErrorManager(ErrorManager__static_init#1).errorListeners
    //#input(void setReportStatus(ErrorReportStatus)): com.dmdirc.ui.FatalErrorDialog$4__static_init.new int[](FatalErrorDialog$4__static_init#1).length
    //#input(void setReportStatus(ErrorReportStatus)): com.dmdirc.ui.FatalErrorDialog$4__static_init.new int[](FatalErrorDialog$4__static_init#1)[0..4_294_967_295]
    //#input(void setReportStatus(ErrorReportStatus)): com/dmdirc/logger/ErrorListener.__Descendant_Table[com/dmdirc/logger/ErrorListener]
    //#input(void setReportStatus(ErrorReportStatus)): com/dmdirc/logger/ErrorListener.__Descendant_Table[com/dmdirc/ui/FatalErrorDialog]
    //#input(void setReportStatus(ErrorReportStatus)): com/dmdirc/logger/ErrorListener.__Descendant_Table[others]
    //#input(void setReportStatus(ErrorReportStatus)): com/dmdirc/logger/ErrorListener.__Dispatch_Table.errorStatusChanged(Lcom/dmdirc/logger/ProgramError;)V
    //#input(void setReportStatus(ErrorReportStatus)): com/dmdirc/logger/ErrorManager.me
    //#input(void setReportStatus(ErrorReportStatus)): com/dmdirc/ui/FatalErrorDialog$4.$SwitchMap$com$dmdirc$logger$ErrorReportStatus
    //#input(void setReportStatus(ErrorReportStatus)): com/dmdirc/ui/FatalErrorDialog.__Dispatch_Table.errorStatusChanged(Lcom/dmdirc/logger/ProgramError;)V
    //#input(void setReportStatus(ErrorReportStatus)): newStatus
    //#input(void setReportStatus(ErrorReportStatus)): newStatus.terminal
    //#input(void setReportStatus(ErrorReportStatus)): this
    //#input(void setReportStatus(ErrorReportStatus)): this.__Lock
    //#input(void setReportStatus(ErrorReportStatus)): this.__Tag
    //#input(void setReportStatus(ErrorReportStatus)): this.level
    //#input(void setReportStatus(ErrorReportStatus)): this.message
    //#input(void setReportStatus(ErrorReportStatus)): this.reportStatus
    //#input(void setReportStatus(ErrorReportStatus)): this.reportStatus.terminal
    //#input(void setReportStatus(ErrorReportStatus)): this.trace
    //#output(void setReportStatus(ErrorReportStatus)): this.reportStatus
    //#pre[2] (void setReportStatus(ErrorReportStatus)): (soft) init'ed(com.dmdirc.ui.FatalErrorDialog$4__static_init.new int[](FatalErrorDialog$4__static_init#1)[0..4_294_967_295])
    //#pre[6] (void setReportStatus(ErrorReportStatus)): (soft) this.reportStatus != null
    //#pre[8] (void setReportStatus(ErrorReportStatus)): (soft) this.__Tag == com/dmdirc/logger/ProgramError
    //#post(void setReportStatus(ErrorReportStatus)): this.reportStatus == One-of{old this.reportStatus, newStatus}
    //#post(void setReportStatus(ErrorReportStatus)): this.reportStatus != null
    //#unanalyzed(void setReportStatus(ErrorReportStatus)): Effects-of-calling:java.lang.Object:getClass
    //#unanalyzed(void setReportStatus(ErrorReportStatus)): Effects-of-calling:java.lang.String:equals
    //#unanalyzed(void setReportStatus(ErrorReportStatus)): Effects-of-calling:java.util.Arrays:equals
    //#unanalyzed(void setReportStatus(ErrorReportStatus)): Effects-of-calling:java.lang.Throwable:__curr_excep_obj
    //#unanalyzed(void setReportStatus(ErrorReportStatus)): Effects-of-calling:com.dmdirc.util.ListenerList:get
    //#unanalyzed(void setReportStatus(ErrorReportStatus)): Effects-of-calling:java.util.List:iterator
    //#unanalyzed(void setReportStatus(ErrorReportStatus)): Effects-of-calling:java.util.Iterator:hasNext
    //#unanalyzed(void setReportStatus(ErrorReportStatus)): Effects-of-calling:java.util.Iterator:next
    //#unanalyzed(void setReportStatus(ErrorReportStatus)): Effects-of-calling:com.dmdirc.logger.ErrorReportStatus:ordinal
    //#unanalyzed(void setReportStatus(ErrorReportStatus)): Effects-of-calling:javax.swing.JButton:setText
    //#unanalyzed(void setReportStatus(ErrorReportStatus)): Effects-of-calling:javax.swing.JButton:setEnabled
    //#unanalyzed(void setReportStatus(ErrorReportStatus)): Effects-of-calling:equals
    //#unanalyzed(void setReportStatus(ErrorReportStatus)): Effects-of-calling:getReportStatus
    //#unanalyzed(void setReportStatus(ErrorReportStatus)): Effects-of-calling:errorStatusChanged
    //#test_vector(void setReportStatus(ErrorReportStatus)): newStatus: Addr_Set{null}, Inverse{null}
    //#test_vector(void setReportStatus(ErrorReportStatus)): com.dmdirc.logger.ErrorReportStatus:equals(...)@184: {1}, {0}
            reportStatus = newStatus;
            ErrorManager.getErrorManager().fireErrorStatusChanged(this);

            synchronized (this) {
                notifyAll();
            }
        }
    }
    //#ProgramError.java:192: end of method: void com.dmdirc.logger.ProgramError.setReportStatus(ErrorReportStatus)
    
    /**
     * Sets the fixed status of this error.
     * 
     * @param newStatus new ErrorFixedStatus for the error
     */
    public void setFixedStatus(final ErrorFixedStatus newStatus) {
        if (newStatus != null && !fixedStatus.equals(newStatus)) {
    //#ProgramError.java:200: method: void com.dmdirc.logger.ProgramError.setFixedStatus(ErrorFixedStatus)
    //#ProgramError.java:200: Warning: method not available - call not analyzed
    //#    call on bool com.dmdirc.logger.ErrorFixedStatus:equals(Object)
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.logger.ProgramError
    //#    method: void setFixedStatus(ErrorFixedStatus)
    //#    unanalyzed callee: bool com.dmdirc.logger.ErrorFixedStatus:equals(Object)
    //#input(void setFixedStatus(ErrorFixedStatus)): __Descendant_Table[com/dmdirc/logger/ProgramError]
    //#input(void setFixedStatus(ErrorFixedStatus)): __Descendant_Table[others]
    //#input(void setFixedStatus(ErrorFixedStatus)): com.dmdirc.logger.ErrorManager__static_init.new ErrorManager(ErrorManager__static_init#1).errorListeners
    //#input(void setFixedStatus(ErrorFixedStatus)): com.dmdirc.ui.FatalErrorDialog$4__static_init.new int[](FatalErrorDialog$4__static_init#1).length
    //#input(void setFixedStatus(ErrorFixedStatus)): com.dmdirc.ui.FatalErrorDialog$4__static_init.new int[](FatalErrorDialog$4__static_init#1)[0..4_294_967_295]
    //#input(void setFixedStatus(ErrorFixedStatus)): com/dmdirc/logger/ErrorListener.__Descendant_Table[com/dmdirc/logger/ErrorListener]
    //#input(void setFixedStatus(ErrorFixedStatus)): com/dmdirc/logger/ErrorListener.__Descendant_Table[com/dmdirc/ui/FatalErrorDialog]
    //#input(void setFixedStatus(ErrorFixedStatus)): com/dmdirc/logger/ErrorListener.__Descendant_Table[others]
    //#input(void setFixedStatus(ErrorFixedStatus)): com/dmdirc/logger/ErrorListener.__Dispatch_Table.errorStatusChanged(Lcom/dmdirc/logger/ProgramError;)V
    //#input(void setFixedStatus(ErrorFixedStatus)): com/dmdirc/logger/ErrorManager.me
    //#input(void setFixedStatus(ErrorFixedStatus)): com/dmdirc/ui/FatalErrorDialog$4.$SwitchMap$com$dmdirc$logger$ErrorReportStatus
    //#input(void setFixedStatus(ErrorFixedStatus)): com/dmdirc/ui/FatalErrorDialog.__Dispatch_Table.errorStatusChanged(Lcom/dmdirc/logger/ProgramError;)V
    //#input(void setFixedStatus(ErrorFixedStatus)): newStatus
    //#input(void setFixedStatus(ErrorFixedStatus)): this
    //#input(void setFixedStatus(ErrorFixedStatus)): this.__Lock
    //#input(void setFixedStatus(ErrorFixedStatus)): this.__Tag
    //#input(void setFixedStatus(ErrorFixedStatus)): this.fixedStatus
    //#input(void setFixedStatus(ErrorFixedStatus)): this.level
    //#input(void setFixedStatus(ErrorFixedStatus)): this.message
    //#input(void setFixedStatus(ErrorFixedStatus)): this.reportStatus
    //#input(void setFixedStatus(ErrorFixedStatus)): this.reportStatus.terminal
    //#input(void setFixedStatus(ErrorFixedStatus)): this.trace
    //#output(void setFixedStatus(ErrorFixedStatus)): this.fixedStatus
    //#pre[2] (void setFixedStatus(ErrorFixedStatus)): (soft) init'ed(com.dmdirc.ui.FatalErrorDialog$4__static_init.new int[](FatalErrorDialog$4__static_init#1)[0..4_294_967_295])
    //#pre[4] (void setFixedStatus(ErrorFixedStatus)): (soft) this.fixedStatus != null
    //#pre[6] (void setFixedStatus(ErrorFixedStatus)): (soft) this.__Tag == com/dmdirc/logger/ProgramError
    //#pre[9] (void setFixedStatus(ErrorFixedStatus)): (soft) this.reportStatus != null
    //#post(void setFixedStatus(ErrorFixedStatus)): this.fixedStatus == One-of{old this.fixedStatus, newStatus}
    //#post(void setFixedStatus(ErrorFixedStatus)): this.fixedStatus != null
    //#unanalyzed(void setFixedStatus(ErrorFixedStatus)): Effects-of-calling:java.lang.Object:getClass
    //#unanalyzed(void setFixedStatus(ErrorFixedStatus)): Effects-of-calling:java.lang.String:equals
    //#unanalyzed(void setFixedStatus(ErrorFixedStatus)): Effects-of-calling:java.util.Arrays:equals
    //#unanalyzed(void setFixedStatus(ErrorFixedStatus)): Effects-of-calling:java.lang.Throwable:__curr_excep_obj
    //#unanalyzed(void setFixedStatus(ErrorFixedStatus)): Effects-of-calling:com.dmdirc.util.ListenerList:get
    //#unanalyzed(void setFixedStatus(ErrorFixedStatus)): Effects-of-calling:java.util.List:iterator
    //#unanalyzed(void setFixedStatus(ErrorFixedStatus)): Effects-of-calling:java.util.Iterator:hasNext
    //#unanalyzed(void setFixedStatus(ErrorFixedStatus)): Effects-of-calling:java.util.Iterator:next
    //#unanalyzed(void setFixedStatus(ErrorFixedStatus)): Effects-of-calling:com.dmdirc.logger.ErrorReportStatus:ordinal
    //#unanalyzed(void setFixedStatus(ErrorFixedStatus)): Effects-of-calling:javax.swing.JButton:setText
    //#unanalyzed(void setFixedStatus(ErrorFixedStatus)): Effects-of-calling:javax.swing.JButton:setEnabled
    //#unanalyzed(void setFixedStatus(ErrorFixedStatus)): Effects-of-calling:equals
    //#unanalyzed(void setFixedStatus(ErrorFixedStatus)): Effects-of-calling:getReportStatus
    //#unanalyzed(void setFixedStatus(ErrorFixedStatus)): Effects-of-calling:errorStatusChanged
    //#test_vector(void setFixedStatus(ErrorFixedStatus)): newStatus: Addr_Set{null}, Inverse{null}
    //#test_vector(void setFixedStatus(ErrorFixedStatus)): com.dmdirc.logger.ErrorFixedStatus:equals(...)@200: {1}, {0}
            fixedStatus = newStatus;
            ErrorManager.getErrorManager().fireErrorStatusChanged(this);

            synchronized (this) {
                notifyAll();
            }
        }
    }
    //#ProgramError.java:208: end of method: void com.dmdirc.logger.ProgramError.setFixedStatus(ErrorFixedStatus)
    
    /**
     * Returns the ID of this error.
     *
     * @return Error ID
     */
    public long getID() {
        return id;
    //#ProgramError.java:216: method: long com.dmdirc.logger.ProgramError.getID()
    //#input(long getID()): this
    //#input(long getID()): this.id
    //#output(long getID()): return_value
    //#post(long getID()): return_value == this.id
    //#post(long getID()): init'ed(return_value)
    //#ProgramError.java:216: end of method: long com.dmdirc.logger.ProgramError.getID()
    }

    /**
     * Saves this error to disk.
     */
    public void save() {
        final PrintWriter out = new PrintWriter(getErrorFile(), true);
    //#ProgramError.java:223: method: void com.dmdirc.logger.ProgramError.save()
    //#input(void save()): "-"._tainted
    //#input(void save()): ".log"._tainted
    //#input(void save()): "Date:"._tainted
    //#input(void save()): "Description: "._tainted
    //#input(void save()): "Level: "._tainted
    //#input(void save()): "errors"._tainted
    //#input(void save()): errorDir
    //#input(void save()): java.lang.System.err
    //#input(void save()): this
    //#input(void save()): this.date
    //#input(void save()): this.level
    //#input(void save()): this.level._tainted
    //#input(void save()): this.message
    //#input(void save()): this.message._tainted
    //#input(void save()): this.trace
    //#input(void save()): this.trace.length
    //#input(void save()): writingSem
    //#output(void save()): errorDir
    //#output(void save()): new File(getErrorFile#1) num objects
    //#new obj(void save()): new File(getErrorFile#1)
    //#pre[1] (void save()): init'ed(errorDir)
    //#pre[3] (void save()): this.date != null
    //#pre[8] (void save()): this.trace != null
    //#pre[9] (void save()): this.trace.length <= 4_294_967_295
    //#presumption(void save()): arr$.length <= 4_294_967_295
    //#presumption(void save()): java.util.Arrays:copyOf(...)@148 != null
    //#post(void save()): errorDir == One-of{old errorDir, &new File(getErrorFile#1)}
    //#post(void save()): errorDir != null
    //#post(void save()): new File(getErrorFile#1) num objects <= 1
    //#unanalyzed(void save()): Effects-of-calling:java.lang.StringBuilder
    //#unanalyzed(void save()): Effects-of-calling:java.lang.StringBuilder:append
    //#unanalyzed(void save()): Effects-of-calling:java.lang.StringBuilder:toString
    //#unanalyzed(void save()): Effects-of-calling:java.util.Arrays:copyOf
    //#unanalyzed(void save()): Effects-of-calling:java.util.Date:clone
    //#unanalyzed(void save()): Effects-of-calling:java.lang.Throwable:__curr_excep_obj
    //#unanalyzed(void save()): Effects-of-calling:java.util.concurrent.Semaphore:acquireUninterruptibly
    //#unanalyzed(void save()): Effects-of-calling:java.io.File:exists
    //#unanalyzed(void save()): Effects-of-calling:com.dmdirc.Main:getConfigDir
    //#unanalyzed(void save()): Effects-of-calling:java.io.File
    //#unanalyzed(void save()): Effects-of-calling:java.io.File:mkdirs
    //#unanalyzed(void save()): Effects-of-calling:java.util.Date:getTime
    //#unanalyzed(void save()): Effects-of-calling:java.io.File:renameTo
    //#unanalyzed(void save()): Effects-of-calling:java.io.File:createNewFile
    //#unanalyzed(void save()): Effects-of-calling:java.io.FileOutputStream
    //#unanalyzed(void save()): Effects-of-calling:java.util.concurrent.Semaphore:release
    //#unanalyzed(void save()): Effects-of-calling:java.io.PrintStream:println
    //#unanalyzed(void save()): Effects-of-calling:java.io.IOException:printStackTrace
    //#unanalyzed(void save()): Effects-of-calling:java.io.OutputStream
        out.println("Date:" + getDate());
        out.println("Level: " + getLevel());
        out.println("Description: " + getMessage());
        out.println("Details:");

        for (String traceLine : getTrace()) {
            out.println('\t' + traceLine);
        }
        
        out.close();
    }
    //#ProgramError.java:234: end of method: void com.dmdirc.logger.ProgramError.save()

    /**
     * Creates a new file for an error and returns the output stream.
     *
     * @return BufferedOutputStream to write to the error file
     */
    @SuppressWarnings("PMD.SystemPrintln")
    private OutputStream getErrorFile() {
        writingSem.acquireUninterruptibly();
    //#ProgramError.java:243: method: OutputStream com.dmdirc.logger.ProgramError.getErrorFile()
    //#input(OutputStream getErrorFile()): "-"._tainted
    //#input(OutputStream getErrorFile()): ".log"._tainted
    //#input(OutputStream getErrorFile()): "errors"._tainted
    //#input(OutputStream getErrorFile()): errorDir
    //#input(OutputStream getErrorFile()): java.lang.System.err
    //#input(OutputStream getErrorFile()): this
    //#input(OutputStream getErrorFile()): this.date
    //#input(OutputStream getErrorFile()): this.level
    //#input(OutputStream getErrorFile()): this.level._tainted
    //#input(OutputStream getErrorFile()): writingSem
    //#output(OutputStream getErrorFile()): errorDir
    //#output(OutputStream getErrorFile()): new File(getErrorFile#1) num objects
    //#output(OutputStream getErrorFile()): new FileOutputStream(getErrorFile#8) num objects
    //#output(OutputStream getErrorFile()): new NullOutputStream(getErrorFile#9) num objects
    //#output(OutputStream getErrorFile()): new NullOutputStream(getErrorFile#9).__Tag
    //#output(OutputStream getErrorFile()): return_value
    //#new obj(OutputStream getErrorFile()): new File(getErrorFile#1)
    //#new obj(OutputStream getErrorFile()): new FileOutputStream(getErrorFile#8)
    //#new obj(OutputStream getErrorFile()): new NullOutputStream(getErrorFile#9)
    //#pre[1] (OutputStream getErrorFile()): init'ed(errorDir)
    //#pre[3] (OutputStream getErrorFile()): this.date != null
    //#presumption(OutputStream getErrorFile()): java.lang.System.err != null
    //#post(OutputStream getErrorFile()): errorDir == One-of{old errorDir, &new File(getErrorFile#1)}
    //#post(OutputStream getErrorFile()): errorDir != null
    //#post(OutputStream getErrorFile()): return_value in Addr_Set{&new FileOutputStream(getErrorFile#8),&new NullOutputStream(getErrorFile#9)}
    //#post(OutputStream getErrorFile()): new File(getErrorFile#1) num objects <= 1
    //#post(OutputStream getErrorFile()): new FileOutputStream(getErrorFile#8) num objects <= 1
    //#post(OutputStream getErrorFile()): new NullOutputStream(getErrorFile#9) num objects <= 1
    //#post(OutputStream getErrorFile()): new NullOutputStream(getErrorFile#9).__Tag == com/dmdirc/logger/NullOutputStream
    //#unanalyzed(OutputStream getErrorFile()): Effects-of-calling:java.util.Date:clone
    //#unanalyzed(OutputStream getErrorFile()): Effects-of-calling:java.io.OutputStream
    //#test_vector(OutputStream getErrorFile()): errorDir: Addr_Set{null}, Inverse{null}
    //#test_vector(OutputStream getErrorFile()): java.io.File:exists(...)@245: {1}, {0}
    //#test_vector(OutputStream getErrorFile()): java.io.File:exists(...)@247: {1}, {0}
    //#test_vector(OutputStream getErrorFile()): java.io.File:exists(...)@256: {0}, {1}
        
        if (errorDir == null || !errorDir.exists()) {
            errorDir = new File(Main.getConfigDir() + "errors");
    //#ProgramError.java:246: Warning: method not available - call not analyzed
    //#    call on String com.dmdirc.Main:getConfigDir()
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.logger.ProgramError
    //#    method: OutputStream getErrorFile()
    //#    unanalyzed callee: String com.dmdirc.Main:getConfigDir()
            if (!errorDir.exists()) {
                errorDir.mkdirs();
            }
        }

        final String logName = getDate().getTime() + "-" + getLevel();

        final File errorFile = new File(errorDir, logName + ".log");

        if (errorFile.exists()) {
            boolean rename = false;
            int i = 0;
            while (!rename) {
                i++;
    //#ProgramError.java:260: ?overflow
    //#    i in {-2_147_483_649..4_294_967_294}
    //#    severity: LOW
    //#    class: com.dmdirc.logger.ProgramError
    //#    method: OutputStream getErrorFile()
    //#    basic block: bb_8
    //#    assertion: i in {-2_147_483_649..4_294_967_294}
    //#    VN: i + 1
    //#    Expected: {-2_147_483_648..4_294_967_295, Invalid}
    //#    Bad: {4_294_967_296}
    //#    Attribs:  Int  Bad singleton  Bad > Exp
                rename = errorFile.renameTo(new File(errorDir, logName + "-" + i + ".log"));
            }
        }

        try {
            errorFile.createNewFile();
            return new FileOutputStream(errorFile);
        } catch (IOException ex) {
            System.err.println("Error creating new file: ");
            ex.printStackTrace();
            return new NullOutputStream();
        } finally {
            writingSem.release();
    //#ProgramError.java:273: end of method: OutputStream com.dmdirc.logger.ProgramError.getErrorFile()
        }
    }

    /**
     * Sends this error report to the DMDirc developers.
     */
    public void send() {
        final Map<String, String> postData = new HashMap<String, String>();
    //#ProgramError.java:281: method: void com.dmdirc.logger.ProgramError.send()
    //#input(void send()): __Descendant_Table[com/dmdirc/logger/ProgramError]
    //#input(void send()): __Descendant_Table[others]
    //#input(void send()): com.dmdirc.logger.ErrorManager__static_init.new ErrorManager(ErrorManager__static_init#1).errorListeners
    //#input(void send()): com.dmdirc.logger.ErrorReportStatus__static_init.new ErrorReportStatus(ErrorReportStatus__static_init#2).terminal
    //#input(void send()): com.dmdirc.logger.ErrorReportStatus__static_init.new ErrorReportStatus(ErrorReportStatus__static_init#3).terminal
    //#input(void send()): com.dmdirc.logger.ErrorReportStatus__static_init.new ErrorReportStatus(ErrorReportStatus__static_init#4).terminal
    //#input(void send()): com.dmdirc.ui.FatalErrorDialog$4__static_init.new int[](FatalErrorDialog$4__static_init#1).length
    //#input(void send()): com.dmdirc.ui.FatalErrorDialog$4__static_init.new int[](FatalErrorDialog$4__static_init#1)[0..4_294_967_295]
    //#input(void send()): com/dmdirc/logger/ErrorFixedStatus.FIXED
    //#input(void send()): com/dmdirc/logger/ErrorFixedStatus.INVALID
    //#input(void send()): com/dmdirc/logger/ErrorFixedStatus.KNOWN
    //#input(void send()): com/dmdirc/logger/ErrorFixedStatus.NEW
    //#input(void send()): com/dmdirc/logger/ErrorFixedStatus.TOOOLD
    //#input(void send()): com/dmdirc/logger/ErrorListener.__Descendant_Table[com/dmdirc/logger/ErrorListener]
    //#input(void send()): com/dmdirc/logger/ErrorListener.__Descendant_Table[com/dmdirc/ui/FatalErrorDialog]
    //#input(void send()): com/dmdirc/logger/ErrorListener.__Descendant_Table[others]
    //#input(void send()): com/dmdirc/logger/ErrorListener.__Dispatch_Table.errorStatusChanged(Lcom/dmdirc/logger/ProgramError;)V
    //#input(void send()): com/dmdirc/logger/ErrorManager.me
    //#input(void send()): com/dmdirc/logger/ErrorReportStatus.ERROR
    //#input(void send()): com/dmdirc/logger/ErrorReportStatus.FINISHED
    //#input(void send()): com/dmdirc/logger/ErrorReportStatus.SENDING
    //#input(void send()): com/dmdirc/ui/FatalErrorDialog$4.$SwitchMap$com$dmdirc$logger$ErrorReportStatus
    //#input(void send()): com/dmdirc/ui/FatalErrorDialog.__Dispatch_Table.errorStatusChanged(Lcom/dmdirc/logger/ProgramError;)V
    //#input(void send()): this
    //#input(void send()): this.__Tag
    //#input(void send()): this.fixedStatus
    //#input(void send()): this.level
    //#input(void send()): this.message
    //#input(void send()): this.reportStatus
    //#input(void send()): this.reportStatus.terminal
    //#input(void send()): this.trace
    //#input(void send()): this.trace.length
    //#output(void send()): this.fixedStatus
    //#output(void send()): this.reportStatus
    //#pre[11] (void send()): this.trace != null
    //#pre[12] (void send()): this.trace.length <= 4_294_967_295
    //#pre[2] (void send()): (soft) init'ed(com.dmdirc.ui.FatalErrorDialog$4__static_init.new int[](FatalErrorDialog$4__static_init#1)[0..4_294_967_295])
    //#pre[3] (void send()): (soft) this.fixedStatus != null
    //#pre[4] (void send()): (soft) this.reportStatus != null
    //#pre[7] (void send()): (soft) this.__Tag == com/dmdirc/logger/ProgramError
    //#presumption(void send()): com.dmdirc.config.IdentityManager:getGlobalConfig(...)@287 != null
    //#presumption(void send()): com.dmdirc.util.Downloader:getPage(...)@300 != null
    //#presumption(void send()): java.util.List:get(...)@310 != null
    //#presumption(void send()): java.util.List:size(...)@310 >= -2_147_483_647
    //#presumption(void send()): this.fixedStatus@294 != null
    //#presumption(void send()): this.reportStatus@294 != null
    //#post(void send()): this.fixedStatus != null
    //#post(void send()): this.reportStatus != null
    //#unanalyzed(void send()): Effects-of-calling:java.util.Arrays:copyOf
    //#unanalyzed(void send()): Effects-of-calling:com.dmdirc.logger.ErrorReportStatus:equals
    //#unanalyzed(void send()): Effects-of-calling:getErrorManager
    //#unanalyzed(void send()): Effects-of-calling:fireErrorStatusChanged
    //#unanalyzed(void send()): Effects-of-calling:java.lang.Object:notifyAll
    //#unanalyzed(void send()): Effects-of-calling:java.lang.Throwable:__curr_excep_obj
    //#unanalyzed(void send()): Effects-of-calling:com.dmdirc.logger.ErrorFixedStatus:equals
    //#unanalyzed(void send()): Effects-of-calling:java.util.List:isEmpty
    //#unanalyzed(void send()): Effects-of-calling:java.util.List:size
    //#unanalyzed(void send()): Effects-of-calling:java.util.List:get
    //#unanalyzed(void send()): Effects-of-calling:java.lang.String:equalsIgnoreCase
    //#unanalyzed(void send()): Effects-of-calling:java.lang.String:matches
    //#unanalyzed(void send()): Effects-of-calling:java.lang.Object:getClass
    //#unanalyzed(void send()): Effects-of-calling:java.lang.String:equals
    //#unanalyzed(void send()): Effects-of-calling:java.util.Arrays:equals
    //#unanalyzed(void send()): Effects-of-calling:com.dmdirc.util.ListenerList:get
    //#unanalyzed(void send()): Effects-of-calling:java.util.List:iterator
    //#unanalyzed(void send()): Effects-of-calling:java.util.Iterator:hasNext
    //#unanalyzed(void send()): Effects-of-calling:java.util.Iterator:next
    //#unanalyzed(void send()): Effects-of-calling:com.dmdirc.logger.ErrorReportStatus:ordinal
    //#unanalyzed(void send()): Effects-of-calling:javax.swing.JButton:setText
    //#unanalyzed(void send()): Effects-of-calling:javax.swing.JButton:setEnabled
    //#unanalyzed(void send()): Effects-of-calling:equals
    //#unanalyzed(void send()): Effects-of-calling:getReportStatus
    //#unanalyzed(void send()): Effects-of-calling:errorStatusChanged
    //#test_vector(void send()): java.lang.String:equalsIgnoreCase(...)@310: {1}, {0}
    //#test_vector(void send()): java.util.List:isEmpty(...)@310: {1}, {0}
        List<String> response = new ArrayList<String>();
        int tries = 0;

        postData.put("message", getMessage());
        postData.put("trace", Arrays.toString(getTrace()));
        postData.put("version", IdentityManager.getGlobalConfig().getOption("version", "version"));
    //#ProgramError.java:287: Warning: method not available - call not analyzed
    //#    call on ConfigManager com.dmdirc.config.IdentityManager:getGlobalConfig()
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.logger.ProgramError
    //#    method: void send()
    //#    unanalyzed callee: ConfigManager com.dmdirc.config.IdentityManager:getGlobalConfig()
    //#ProgramError.java:287: Warning: method not available - call not analyzed
    //#    call on String com.dmdirc.config.ConfigManager:getOption(String, String)
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.logger.ProgramError
    //#    method: void send()
    //#    unanalyzed callee: String com.dmdirc.config.ConfigManager:getOption(String, String)

        setReportStatus(ErrorReportStatus.SENDING);

        do {
            if (tries != 0) {
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException ex) {
                    //Ignore
                }
            }
            try {
                response = Downloader.getPage("http://www.dmdirc.com/error.php", postData);
    //#ProgramError.java:300: Warning: method not available - call not analyzed
    //#    call on List com.dmdirc.util.Downloader:getPage(String, Map)
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.logger.ProgramError
    //#    method: void send()
    //#    unanalyzed callee: List com.dmdirc.util.Downloader:getPage(String, Map)
            } catch (MalformedURLException ex) {
                //Ignore, wont happen
            } catch (IOException ex) {
                //Ignore being handled
            }

            tries++;
        } while ((response.isEmpty() || !response.get(response.size() - 1).
                equalsIgnoreCase("Error report submitted. Thank you."))
                && tries <= 5);

        checkResponses(response);
    }
    //#ProgramError.java:313: end of method: void com.dmdirc.logger.ProgramError.send()

    /**
     * Checks the responses and sets status accordingly.
     *
     * @param error Error to check response
     * @param response Response to check
     */
    private void checkResponses(final List<String> response) {
        if (!response.isEmpty() && response.get(response.size() - 1).
    //#ProgramError.java:322: method: void com.dmdirc.logger.ProgramError.checkResponses(List)
    //#input(void checkResponses(List)): __Descendant_Table[com/dmdirc/logger/ProgramError]
    //#input(void checkResponses(List)): __Descendant_Table[others]
    //#input(void checkResponses(List)): com.dmdirc.logger.ErrorManager__static_init.new ErrorManager(ErrorManager__static_init#1).errorListeners
    //#input(void checkResponses(List)): com.dmdirc.logger.ErrorReportStatus__static_init.new ErrorReportStatus(ErrorReportStatus__static_init#2).terminal
    //#input(void checkResponses(List)): com.dmdirc.logger.ErrorReportStatus__static_init.new ErrorReportStatus(ErrorReportStatus__static_init#4).terminal
    //#input(void checkResponses(List)): com.dmdirc.ui.FatalErrorDialog$4__static_init.new int[](FatalErrorDialog$4__static_init#1).length
    //#input(void checkResponses(List)): com.dmdirc.ui.FatalErrorDialog$4__static_init.new int[](FatalErrorDialog$4__static_init#1)[0..4_294_967_295]
    //#input(void checkResponses(List)): com/dmdirc/logger/ErrorFixedStatus.FIXED
    //#input(void checkResponses(List)): com/dmdirc/logger/ErrorFixedStatus.INVALID
    //#input(void checkResponses(List)): com/dmdirc/logger/ErrorFixedStatus.KNOWN
    //#input(void checkResponses(List)): com/dmdirc/logger/ErrorFixedStatus.NEW
    //#input(void checkResponses(List)): com/dmdirc/logger/ErrorFixedStatus.TOOOLD
    //#input(void checkResponses(List)): com/dmdirc/logger/ErrorListener.__Descendant_Table[com/dmdirc/logger/ErrorListener]
    //#input(void checkResponses(List)): com/dmdirc/logger/ErrorListener.__Descendant_Table[com/dmdirc/ui/FatalErrorDialog]
    //#input(void checkResponses(List)): com/dmdirc/logger/ErrorListener.__Descendant_Table[others]
    //#input(void checkResponses(List)): com/dmdirc/logger/ErrorListener.__Dispatch_Table.errorStatusChanged(Lcom/dmdirc/logger/ProgramError;)V
    //#input(void checkResponses(List)): com/dmdirc/logger/ErrorManager.me
    //#input(void checkResponses(List)): com/dmdirc/logger/ErrorReportStatus.ERROR
    //#input(void checkResponses(List)): com/dmdirc/logger/ErrorReportStatus.FINISHED
    //#input(void checkResponses(List)): com/dmdirc/ui/FatalErrorDialog$4.$SwitchMap$com$dmdirc$logger$ErrorReportStatus
    //#input(void checkResponses(List)): com/dmdirc/ui/FatalErrorDialog.__Dispatch_Table.errorStatusChanged(Lcom/dmdirc/logger/ProgramError;)V
    //#input(void checkResponses(List)): response
    //#input(void checkResponses(List)): this
    //#input(void checkResponses(List)): this.__Tag
    //#input(void checkResponses(List)): this.fixedStatus
    //#input(void checkResponses(List)): this.level
    //#input(void checkResponses(List)): this.message
    //#input(void checkResponses(List)): this.reportStatus
    //#input(void checkResponses(List)): this.reportStatus.terminal
    //#input(void checkResponses(List)): this.trace
    //#output(void checkResponses(List)): this.fixedStatus
    //#output(void checkResponses(List)): this.reportStatus
    //#pre[5] (void checkResponses(List)): response != null
    //#pre[2] (void checkResponses(List)): (soft) init'ed(com.dmdirc.ui.FatalErrorDialog$4__static_init.new int[](FatalErrorDialog$4__static_init#1)[0..4_294_967_295])
    //#pre[3] (void checkResponses(List)): (soft) this.fixedStatus != null
    //#pre[4] (void checkResponses(List)): (soft) this.reportStatus != null
    //#pre[8] (void checkResponses(List)): (soft) this.__Tag == com/dmdirc/logger/ProgramError
    //#presumption(void checkResponses(List)): java.util.List:get(...)@322 != null
    //#presumption(void checkResponses(List)): java.util.List:get(...)@335 != null
    //#presumption(void checkResponses(List)): java.util.List:size(...)@322 >= -2_147_483_647
    //#post(void checkResponses(List)): this.fixedStatus == One-of{old this.fixedStatus, &com.dmdirc.logger.ErrorFixedStatus__static_init.new ErrorFixedStatus(ErrorFixedStatus__static_init#1), &com.dmdirc.logger.ErrorFixedStatus__static_init.new ErrorFixedStatus(ErrorFixedStatus__static_init#3), &com.dmdirc.logger....
    //#post(void checkResponses(List)): this.fixedStatus != null
    //#post(void checkResponses(List)): this.reportStatus == One-of{old this.reportStatus, &com.dmdirc.logger.ErrorReportStatus__static_init.new ErrorReportStatus(ErrorReportStatus__static_init#4), &com.dmdirc.logger.ErrorReportStatus__static_init.new ErrorReportStatus(ErrorReportStatus__static_init#2)}
    //#post(void checkResponses(List)): this.reportStatus != null
    //#unanalyzed(void checkResponses(List)): Effects-of-calling:com.dmdirc.logger.ErrorReportStatus:equals
    //#unanalyzed(void checkResponses(List)): Effects-of-calling:getErrorManager
    //#unanalyzed(void checkResponses(List)): Effects-of-calling:fireErrorStatusChanged
    //#unanalyzed(void checkResponses(List)): Effects-of-calling:java.lang.Object:notifyAll
    //#unanalyzed(void checkResponses(List)): Effects-of-calling:java.lang.Throwable:__curr_excep_obj
    //#unanalyzed(void checkResponses(List)): Effects-of-calling:com.dmdirc.logger.ErrorFixedStatus:equals
    //#unanalyzed(void checkResponses(List)): Effects-of-calling:java.lang.Object:getClass
    //#unanalyzed(void checkResponses(List)): Effects-of-calling:java.lang.String:equals
    //#unanalyzed(void checkResponses(List)): Effects-of-calling:java.util.Arrays:equals
    //#unanalyzed(void checkResponses(List)): Effects-of-calling:com.dmdirc.util.ListenerList:get
    //#unanalyzed(void checkResponses(List)): Effects-of-calling:java.util.List:iterator
    //#unanalyzed(void checkResponses(List)): Effects-of-calling:java.util.Iterator:hasNext
    //#unanalyzed(void checkResponses(List)): Effects-of-calling:java.util.Iterator:next
    //#unanalyzed(void checkResponses(List)): Effects-of-calling:com.dmdirc.logger.ErrorReportStatus:ordinal
    //#unanalyzed(void checkResponses(List)): Effects-of-calling:javax.swing.JButton:setText
    //#unanalyzed(void checkResponses(List)): Effects-of-calling:javax.swing.JButton:setEnabled
    //#unanalyzed(void checkResponses(List)): Effects-of-calling:equals
    //#unanalyzed(void checkResponses(List)): Effects-of-calling:getReportStatus
    //#unanalyzed(void checkResponses(List)): Effects-of-calling:errorStatusChanged
    //#test_vector(void checkResponses(List)): java.lang.String:equalsIgnoreCase(...)@322: {0}, {1}
    //#test_vector(void checkResponses(List)): java.lang.String:matches(...)@336: {0}, {1}
    //#test_vector(void checkResponses(List)): java.lang.String:matches(...)@338: {0}, {1}
    //#test_vector(void checkResponses(List)): java.lang.String:matches(...)@340: {0}, {1}
    //#test_vector(void checkResponses(List)): java.lang.String:matches(...)@342: {0}, {1}
    //#test_vector(void checkResponses(List)): java.util.List:isEmpty(...)@322: {1}, {0}
    //#test_vector(void checkResponses(List)): java.util.List:size(...)@330: {-2_147_483_648..0, 2..4_294_967_295}, {1}
                equalsIgnoreCase("Error report submitted. Thank you.")) {
            setReportStatus(ErrorReportStatus.FINISHED);
        } else {
            setReportStatus(ErrorReportStatus.ERROR);
            return;
        }

        if (response.size() == 1) {
            setFixedStatus(ErrorFixedStatus.NEW);
            return;
        }

        final String responseToCheck = response.get(0);
        if (responseToCheck.matches(".*fixed.*")) {
            setFixedStatus(ErrorFixedStatus.FIXED);
        } else if (responseToCheck.matches(".*more recent version.*")) {
            setFixedStatus(ErrorFixedStatus.TOOOLD);
        } else if (responseToCheck.matches(".*invalid.*")) {
            setFixedStatus(ErrorFixedStatus.INVALID);
        } else if (responseToCheck.matches(".*previously.*")) {
            setFixedStatus(ErrorFixedStatus.KNOWN);
        } else {
            setFixedStatus(ErrorFixedStatus.NEW);
        }
    }
    //#ProgramError.java:347: end of method: void com.dmdirc.logger.ProgramError.checkResponses(List)

    /**
     * Determines whether or not the stack trace associated with this error
     * is from a valid source. A valid source is one that is within a DMDirc
     * package (com.dmdirc), and is not the DMDirc event queue.
     *
     * @return True if the source is valid, false otherwise
     */
    public boolean isValidSource() {
        final String line = getSourceLine();
    //#ProgramError.java:357: method: bool com.dmdirc.logger.ProgramError.isValidSource()
    //#input(bool isValidSource()): this
    //#input(bool isValidSource()): this.trace
    //#input(bool isValidSource()): this.trace.length
    //#input(bool isValidSource()): this.trace[0]
    //#input(bool isValidSource()): this.trace[1..4_294_967_295]
    //#output(bool isValidSource()): return_value
    //#pre[2] (bool isValidSource()): this.trace != null
    //#pre[3] (bool isValidSource()): this.trace.length in {1..4_294_967_295}
    //#pre[4] (bool isValidSource()): (soft) this.trace[0] != null
    //#pre[5] (bool isValidSource()): (soft) this.trace[1..4_294_967_295] != null
    //#post(bool isValidSource()): init'ed(return_value)
    //#unanalyzed(bool isValidSource()): Effects-of-calling:java.lang.String:startsWith

        return line.startsWith("com.dmdirc")
    //#ProgramError.java:359: end of method: bool com.dmdirc.logger.ProgramError.isValidSource()
                && !line.startsWith("com.dmdirc.addons.ui_swing.DMDircEventQueue");
    }

    /**
     * Returns the "source line" of this error, which is defined as the first
     * line starting with a DMDirc package name (com.dmdirc). If no such line
     * is found, returns the first line of the message.
     *
     * @return This error's source line
     */
    public String getSourceLine() {
        for (String line : trace) {
    //#ProgramError.java:371: method: String com.dmdirc.logger.ProgramError.getSourceLine()
    //#input(String getSourceLine()): this
    //#input(String getSourceLine()): this.trace
    //#input(String getSourceLine()): this.trace.length
    //#input(String getSourceLine()): this.trace[0]
    //#input(String getSourceLine()): this.trace[1..4_294_967_295]
    //#output(String getSourceLine()): return_value
    //#pre[2] (String getSourceLine()): this.trace != null
    //#pre[3] (String getSourceLine()): this.trace.length in {1..4_294_967_295}
    //#pre[4] (String getSourceLine()): (soft) this.trace[0] != null
    //#pre[5] (String getSourceLine()): (soft) this.trace[1..4_294_967_295] != null
    //#post(String getSourceLine()): return_value != null
    //#test_vector(String getSourceLine()): java.lang.String:startsWith(...)@372: {0}, {1}
            if (line.startsWith("com.dmdirc")) {
                return line;
            }
        }

        return trace[0];
    //#ProgramError.java:377: end of method: String com.dmdirc.logger.ProgramError.getSourceLine()
    }
    
    /** {@inheritDoc} */
    @Override
    public String toString() {
        return "ID" + id + " Level: " + getLevel() + " Status: " + getReportStatus()
    //#ProgramError.java:383: method: String com.dmdirc.logger.ProgramError.toString()
    //#input(String toString()): " Level: "._tainted
    //#input(String toString()): " Message: '"._tainted
    //#input(String toString()): " Status: "._tainted
    //#input(String toString()): "'"._tainted
    //#input(String toString()): "ID"._tainted
    //#input(String toString()): this
    //#input(String toString()): this.id
    //#input(String toString()): this.level
    //#input(String toString()): this.level._tainted
    //#input(String toString()): this.message
    //#input(String toString()): this.message._tainted
    //#input(String toString()): this.reportStatus
    //#input(String toString()): this.reportStatus._tainted
    //#output(String toString()): java.lang.StringBuilder:toString(...)._tainted
    //#output(String toString()): return_value
    //#new obj(String toString()): java.lang.StringBuilder:toString(...)
    //#pre[7] (String toString()): init'ed(this.reportStatus)
    //#post(String toString()): init'ed(java.lang.StringBuilder:toString(...)._tainted)
    //#post(String toString()): return_value == &java.lang.StringBuilder:toString(...)
    //#ProgramError.java:383: end of method: String com.dmdirc.logger.ProgramError.toString()
        + " Message: '" + getMessage() + "'";
    }

    /** {@inheritDoc} */
    @Override
    public boolean equals(final Object obj) {
        if (obj == null) {
    //#ProgramError.java:390: method: bool com.dmdirc.logger.ProgramError.equals(Object)
    //#input(bool equals(Object)): __Descendant_Table[com/dmdirc/logger/ProgramError]
    //#input(bool equals(Object)): __Descendant_Table[others]
    //#input(bool equals(Object)): obj
    //#input(bool equals(Object)): obj.__Tag
    //#input(bool equals(Object)): obj.level
    //#input(bool equals(Object)): obj.message
    //#input(bool equals(Object)): obj.trace
    //#input(bool equals(Object)): this
    //#input(bool equals(Object)): this.level
    //#input(bool equals(Object)): this.message
    //#input(bool equals(Object)): this.trace
    //#output(bool equals(Object)): return_value
    //#pre[2] (bool equals(Object)): (soft) obj.__Tag == com/dmdirc/logger/ProgramError
    //#pre[9] (bool equals(Object)): (soft) this.message != null
    //#post(bool equals(Object)): init'ed(return_value)
    //#test_vector(bool equals(Object)): obj: Inverse{null}, Addr_Set{null}
    //#test_vector(bool equals(Object)): this.level == obj.level: {1}, {0}
    //#test_vector(bool equals(Object)): java.lang.String:equals(...)@403: {1}, {0}
    //#test_vector(bool equals(Object)): java.util.Arrays:equals(...)@407: {1}, {0}
            return false;
        }
        
        if (getClass() != obj.getClass()) {
            return false;
        }
        
        final ProgramError other = (ProgramError) obj;
        if (this.level != other.level) {
            return false;
        }
        
        if (!this.message.equals(other.message)) {
            return false;
        }
        
        if (!Arrays.equals(this.trace, other.trace)) {
            return false;
        }
        
        return true;
    //#ProgramError.java:411: end of method: bool com.dmdirc.logger.ProgramError.equals(Object)
    }

    /** {@inheritDoc} */
    @Override
    public int hashCode() {
        int hash = 7;
    //#ProgramError.java:417: method: int com.dmdirc.logger.ProgramError.hashCode()
    //#input(int hashCode()): this
    //#input(int hashCode()): this.level
    //#input(int hashCode()): this.message
    //#input(int hashCode()): this.trace
    //#output(int hashCode()): return_value
    //#pre[2] (int hashCode()): this.level != null
    //#pre[3] (int hashCode()): this.message != null
    //#presumption(int hashCode()): (com.dmdirc.logger.ErrorLevel:hashCode(...)@418*67 + java.lang.String:hashCode(...)@419)*67 + java.util.Arrays:hashCode(...)@420 in {-2_149_588_989..4_292_861_954}
    //#presumption(int hashCode()): (com.dmdirc.logger.ErrorLevel:hashCode(...)@418*67 + java.lang.String:hashCode(...)@419)*67 + java.util.Arrays:hashCode(...)@420 in {-2_149_588_989..4_292_861_954}
    //#presumption(int hashCode()): com.dmdirc.logger.ErrorLevel:hashCode(...)@418 in {-65_539_622..33_486_689}
    //#presumption(int hashCode()): com.dmdirc.logger.ErrorLevel:hashCode(...)@418*67 + java.lang.String:hashCode(...)@419 in {-96_187_407..96_124_561}
    //#post(int hashCode()): init'ed(return_value)
        hash = 67 * hash + this.level.hashCode();
    //#ProgramError.java:418: Warning: method not available - call not analyzed
    //#    call on int com.dmdirc.logger.ErrorLevel:hashCode()
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.logger.ProgramError
    //#    method: int hashCode()
    //#    unanalyzed callee: int com.dmdirc.logger.ErrorLevel:hashCode()
        hash = 67 * hash + this.message.hashCode();
        hash = 67 * hash + Arrays.hashCode(this.trace);
        return hash;
    //#ProgramError.java:421: end of method: int com.dmdirc.logger.ProgramError.hashCode()
    }
    
}
    //#ProgramError.java:: end of class: com.dmdirc.logger.ProgramError
