<commit_before>/*
 * Copyright (c) 2006-2007 <NAME>, <NAME>, <NAME>
 *
 * 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 uk.org.ownage.dmdirc.ui.messages;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.InvalidPropertiesFormatException;
import java.util.Properties;
import java.util.Set;

import uk.org.ownage.dmdirc.Config;
import uk.org.ownage.dmdirc.logger.ErrorLevel;
import uk.org.ownage.dmdirc.logger.Logger;

/**
 * The Formatter provides a standard way to format messages for display.
 */
public final class Formatter {
    
    /**
     * The format strings used by the formatter.
     */
    private static Properties properties;
    
    /**
     * The default properties we fall back to if the user hasn't defined their
     * own. */
    private static Properties defaultProperties;
    
    /**
     * Creates a new instance of Formatter.
     */
    private Formatter() {
    }
    
    /**
     * Inserts the supplied arguments into a format string for the specified
     * message type.
     * @param messageType The message type that the arguments should be formatted as
     * @param arguments The arguments to this message type
     * @return A formatted string
     */
    public static String formatMessage(final String messageType,
            final Object... arguments) {
        if (properties == null) {
            initialise();
        }
        
        final String res = properties.getProperty(messageType);
        
        if (res == null) {
            Logger.error(ErrorLevel.ERROR, "Format string not found: " + messageType);
            return "<No format string for message type " + messageType + ">";
        } else {
            return String.format(res, arguments);
        }
    }
    
    
    public static Set<String> getFormats() {
        if (properties == null) {
            initialise();
        }
        
        return properties.stringPropertyNames();
    }
    /**
     * Determines whether the formatter knows of a specific message type.
     * @param messageType the message type to check
     * @return True iff there is a matching format, false otherwise
     */
    public static boolean hasFormat(final String messageType) {
        if (properties == null) {
            initialise();
        }
        
        return properties.getProperty(messageType) != null;
    }
    
    /**
     * Returns the default format strings for the client.
     */
    private static void loadDefaults() {
        defaultProperties = new Properties();
        
        final char colour = Styliser.CODE_COLOUR;
        final char stop = Styliser.CODE_STOP;
        final char fixed = Styliser.CODE_FIXED;
        
        // Type: Timestamp
        //    1: Current timestamp
        defaultProperties.setProperty("timestamp", "%1$tH:%1$tM:%1$tS | ");
        
        // Type: Channel Message
        //    1: User mode prefixes
        //    2: User nickname
        //    3: User ident
        //    4: User host
        //    5: Message content
        //    6: Channel name
        defaultProperties.setProperty("channelMessage", "<%1$s%2$s> %5$s");
        defaultProperties.setProperty("channelHighlight", colour + "4<%1$s%2$s> %5$s");
        defaultProperties.setProperty("channelAction", colour + "6* %1$s%2$s %5$s");
        defaultProperties.setProperty("channelSelfMessage", "<%1$s%2$s> %5$s");
        defaultProperties.setProperty("channelSelfAction", colour + "6* %1$s%2$s %5$s");
        defaultProperties.setProperty("channelSelfExternalMessage", "<%1$s%2$s> %5$s");
        defaultProperties.setProperty("channelSelfExternalAction", colour + "6* %1$s%2$s %5$s");
        
        // Type: Channel CTCP
        //    1: User mode prefixes
        //    2: User nickname
        //    3: User ident
        //    4: User host
        //    5: CTCP type
        //    6: CTCP content
        //    7: Channel name
        defaultProperties.setProperty("channelCTCP", colour + "4-!- CTCP %5$S from %1$s%2$s");
        
        // Type: Channel Event
        //    1: User mode prefixes
        //    2: User nickname
        //    3: User ident
        //    4: User host
        //    5: Channel name
        defaultProperties.setProperty("channelJoin", colour + "3* %2$s (%3$s@%4$s) has joined %5$s.");
        defaultProperties.setProperty("channelPart", colour + "3* %1$s%2$s (%3$s@%4$s) has left %5$s.");
        defaultProperties.setProperty("channelQuit", colour + "2* %1$s%2$s (%3$s@%4$s) has quit IRC.");
        defaultProperties.setProperty("channelSelfJoin", colour + "3* You are now talking in %5$s.");
        defaultProperties.setProperty("channelSelfPart", colour + "3* You have left the channel.");
        
        // Type: Channel Event with content
        //    1: User mode prefixes
        //    2: User nickname
        //    3: User ident
        //    4: User host
        //    5: Channel name
        //    6: Content
        defaultProperties.setProperty("channelPartReason", colour + "3* %1$s%2$s (%3$s@%4$s) has left %5$s (%6$s" + stop + ").");
        defaultProperties.setProperty("channelQuitReason", colour + "2* %1$s%2$s (%3$s@%4$s) has quit IRC (%6$s" + stop + ").");
        defaultProperties.setProperty("channelTopicChange", colour + "3* %1$s%2$s has changed the topic to '%6$s" + stop + "'.");
        defaultProperties.setProperty("channelNickChange", colour + "3* %1$s%2$s is now know as %6$s.");
        defaultProperties.setProperty("channelModeChange", colour + "3* %1$s%2$s sets mode: %6$s.");
        defaultProperties.setProperty("channelSelfNickChange", colour + "3* You are now know as %6$s.");
        defaultProperties.setProperty("channelSelfModeChange", colour + "3* You set mode: %6$s.");
        defaultProperties.setProperty("channelSelfPartReason", colour + "3* You have left the channel.");
        
        // Type: Binary Channel Event
        //    1: Source user mode prefixes
        //    2: Source user nickname
        //    3: Source user ident
        //    4: Source user host
        //    5: Target user mode prefixes
        //    6: Target user nickname
        //    7: Target user ident
        //    8: Target user host
        //    9: Channel name
        defaultProperties.setProperty("channelKick", colour + "3* %1$s%2$s has kicked %5$s%6$s from %9$s.");
        
        // Type: Binary Channel Event with content
        //    1: Source user mode prefixes
        //    2: Source user nickname
        //    3: Source user ident
        //    4: Source user host
        //    5: Target user mode prefixes
        //    6: Target user nickname
        //    7: Target user ident
        //    8: Target user host
        //    9: Channel name
        //   10: Content        
        defaultProperties.setProperty("channelKickReason", colour + "3* %1$s%2$s has kicked %5$s%6$s from %9$s (%10$s" + stop + ").");
        defaultProperties.setProperty("channelUserMode_default", colour + "3* %1$s%2$s sets mode %10$s on %6$s.");
        
        // Type: Channel topic sync
        //    1: Topic
        //    2: User responsible
        //    3: Time last changed
        //    4: Channel name
        defaultProperties.setProperty("channelJoinTopic", colour + "3* The topic for %4$s is '%1$s" + stop + "'.\n" + colour + "3* Topic was set by %2$s.");
        
        // Type: Channel mode discovery
        //     1: Channel modes
        //     2: Channel name
        defaultProperties.setProperty("channelModeDiscovered", colour + "3* Channel modes for %2$s are: %1$s.");
        
        // Type: Private CTCP
        //    1: User nickname
        //    2: User ident<commit_msg>BUG: Illegal formats are now handled marginally nicer<commit_after>/*
 * Copyright (c) 2006-2007 <NAME>, <NAME>, <NAME>
 *
 * 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 uk.org.ownage.dmdirc.ui.messages;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.IllegalFormatConversionException;
import java.util.InvalidPropertiesFormatException;
import java.util.Properties;
import java.util.Set;

import uk.org.ownage.dmdirc.Config;
import uk.org.ownage.dmdirc.logger.ErrorLevel;
import uk.org.ownage.dmdirc.logger.Logger;

/**
 * The Formatter provides a standard way to format messages for display.
 */
public final class Formatter {
    
    /**
     * The format strings used by the formatter.
     */
    private static Properties properties;
    
    /**
     * The default properties we fall back to if the user hasn't defined their
     * own. */
    private static Properties defaultProperties;
    
    /**
     * Creates a new instance of Formatter.
     */
    private Formatter() {
    }
    
    /**
     * Inserts the supplied arguments into a format string for the specified
     * message type.
     * @param messageType The message type that the arguments should be formatted as
     * @param arguments The arguments to this message type
     * @return A formatted string
     */
    public static String formatMessage(final String messageType,
            final Object... arguments) {
        if (properties == null) {
            initialise();
        }
        
        final String res = properties.getProperty(messageType);
        
        if (res == null) {
            Logger.error(ErrorLevel.ERROR, "Format string not found: " + messageType);
            return "<No format string for message type " + messageType + ">";
        } else {
            try {
                return String.format(res, arguments);
            } catch (IllegalFormatConversionException ex) {
                return "<Invalid format string for message type " + messageType + ">";
            }
        }
    }
    
    
    public static Set<String> getFormats() {
        if (properties == null) {
            initialise();
        }
        
        return properties.stringPropertyNames();
    }
    /**
     * Determines whether the formatter knows of a specific message type.
     * @param messageType the message type to check
     * @return True iff there is a matching format, false otherwise
     */
    public static boolean hasFormat(final String messageType) {
        if (properties == null) {
            initialise();
        }
        
        return properties.getProperty(messageType) != null;
    }
    
    /**
     * Returns the default format strings for the client.
     */
    private static void loadDefaults() {
        defaultProperties = new Properties();
        
        final char colour = Styliser.CODE_COLOUR;
        final char stop = Styliser.CODE_STOP;
        final char fixed = Styliser.CODE_FIXED;
        
        // Type: Timestamp
        //    1: Current timestamp
        defaultProperties.setProperty("timestamp", "%1$tH:%1$tM:%1$tS | ");
        
        // Type: Channel Message
        //    1: User mode prefixes
        //    2: User nickname
        //    3: User ident
        //    4: User host
        //    5: Message content
        //    6: Channel name
        defaultProperties.setProperty("channelMessage", "<%1$s%2$s> %5$s");
        defaultProperties.setProperty("channelHighlight", colour + "4<%1$s%2$s> %5$s");
        defaultProperties.setProperty("channelAction", colour + "6* %1$s%2$s %5$s");
        defaultProperties.setProperty("channelSelfMessage", "<%1$s%2$s> %5$s");
        defaultProperties.setProperty("channelSelfAction", colour + "6* %1$s%2$s %5$s");
        defaultProperties.setProperty("channelSelfExternalMessage", "<%1$s%2$s> %5$s");
        defaultProperties.setProperty("channelSelfExternalAction", colour + "6* %1$s%2$s %5$s");
        
        // Type: Channel CTCP
        //    1: User mode prefixes
        //    2: User nickname
        //    3: User ident
        //    4: User host
        //    5: CTCP type
        //    6: CTCP content
        //    7: Channel name
        defaultProperties.setProperty("channelCTCP", colour + "4-!- CTCP %5$S from %1$s%2$s");
        
        // Type: Channel Event
        //    1: User mode prefixes
        //    2: User nickname
        //    3: User ident
        //    4: User host
        //    5: Channel name
        defaultProperties.setProperty("channelJoin", colour + "3* %2$s (%3$s@%4$s) has joined %5$s.");
        defaultProperties.setProperty("channelPart", colour + "3* %1$s%2$s (%3$s@%4$s) has left %5$s.");
        defaultProperties.setProperty("channelQuit", colour + "2* %1$s%2$s (%3$s@%4$s) has quit IRC.");
        defaultProperties.setProperty("channelSelfJoin", colour + "3* You are now talking in %5$s.");
        defaultProperties.setProperty("channelSelfPart", colour + "3* You have left the channel.");
        
        // Type: Channel Event with content
        //    1: User mode prefixes
        //    2: User nickname
        //    3: User ident
        //    4: User host
        //    5: Channel name
        //    6: Content
        defaultProperties.setProperty("channelPartReason", colour + "3* %1$s%2$s (%3$s@%4$s) has left %5$s (%6$s" + stop + ").");
        defaultProperties.setProperty("channelQuitReason", colour + "2* %1$s%2$s (%3$s@%4$s) has quit IRC (%6$s" + stop + ").");
        defaultProperties.setProperty("channelTopicChange", colour + "3* %1$s%2$s has changed the topic to '%6$s" + stop + "'.");
        defaultProperties.setProperty("channelNickChange", colour + "3* %1$s%2$s is now know as %6$s.");
        defaultProperties.setProperty("channelModeChange", colour + "3* %1$s%2$s sets mode: %6$s.");
        defaultProperties.setProperty("channelSelfNickChange", colour + "3* You are now know as %6$s.");
        defaultProperties.setProperty("channelSelfModeChange", colour + "3* You set mode: %6$s.");
        defaultProperties.setProperty("channelSelfPartReason", colour + "3* You have left the channel.");
        
        // Type: Binary Channel Event
        //    1: Source user mode prefixes
        //    2: Source user nickname
        //    3: Source user ident
        //    4: Source user host
        //    5: Target user mode prefixes
        //    6: Target user nickname
        //    7: Target user ident
        //    8: Target user host
        //    9: Channel name
        defaultProperties.setProperty("channelKick", colour + "3* %1$s%2$s has kicked %5$s%6$s from %9$s.");
        
        // Type: Binary Channel Event with content
        //    1: Source user mode prefixes
        //    2: Source user nickname
        //    3: Source user ident
        //    4: Source user host
        //    5: Target user mode prefixes
        //    6: Target user nickname
        //    7: Target user ident
        //    8: Target user host
        //    9: Channel name
        //   10: Content
        defaultProperties.setProperty("channelKickReason", colour + "3* %1$s%2$s has kicked %5$s%6$s from %9$s (%10$s" + stop + ").");
        defaultProperties.setProperty("channelUserMode_default", colour + "3* %1$s%2$s sets mode %10$s on %6$s.");
        
        // Type: Channel topic sync
        //    1: Topic
        //    2: User responsible
        //    3: Time last changed
        //    4: Channel name
        defaultProperties.setProperty("channelJoinTopic", colour + "3* The topic for %4$s is '%1$s" + stop + "'.\n" + colour + "3* Topic was set by %2$s.");
        
        // Type: Channel mode discovery
        //     1: Channel modes
        //     2: Channel name
        defaultProperties.setProperty("channelModeDiscovered", colour + "3* Channel modes for %2$s are: %1$s.");
        
        // Type: Private CTCP
        //    1: User nickname
        //    2: User ident
{'fraction_non_alphanumeric': 0.11555281453240637, 'fraction_numerical': 0.019062570082978247, 'mean_word_length': 2.2620702267739574, 'pattern_counts': {'":': 0, '<': 22, '<?xml version=': 0, '>': 22, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3828539', 'n_tokens_mistral': 5033, 'n_tokens_neox': 4916, 'n_words': 1654}