/*
 * Copyright (c) 2013 Team Trinidad and contributors http://github.com/trinidad
 *
 * 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 rb.trinidad.logging;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Field;
import java.text.DateFormat;
import java.text.FieldPosition;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;
import java.util.logging.Formatter;
import java.util.logging.LogRecord;

/**
 * Default logging record formatter for Trinidad.
 *
 * @author kares
 */
public class DefaultFormatter extends Formatter {

    private final FieldPosition dummyPosition;

    {
        FieldPosition fieldPosition;
        try {
            Class klass = Class.forName("java.text.DontCareFieldPosition");
            Field instance = klass.getDeclaredField("INSTANCE");
            instance.setAccessible(true);
            fieldPosition = (FieldPosition) instance.get(null);
        }
        catch (Exception e) {
            fieldPosition = new FieldPosition(0);
        }
        dummyPosition = fieldPosition;
    }

    private final DateFormat dateFormat;

    public DefaultFormatter(String format) {
        this( format != null ? new SimpleDateFormat(format) : new SimpleDateFormat() );
    }

    public DefaultFormatter(String format, String timeZone) {
        this( format );
        if ( timeZone != null ) {
            dateFormat.setTimeZone( TimeZone.getTimeZone(timeZone) );
        }
    }

    public DefaultFormatter(String format, int timeZoneOffset) {
        this( format );
        String[] timeZones = TimeZone.getAvailableIDs(timeZoneOffset);
        if ( timeZones.length > 0 ) {
            dateFormat.setTimeZone( TimeZone.getTimeZone(timeZones[0]) );
        }
    }

    public DefaultFormatter(String format, Calendar calendar) {
        this( format );
        if ( calendar != null ) {
            dateFormat.setCalendar( calendar );
        }
    }

    public DefaultFormatter(DateFormat dateFormat) {
        if ( dateFormat == null ) {
            throw new IllegalArgumentException("no format given");
        }
        this.dateFormat = dateFormat;
    }

    public DateFormat getDateFormat() {
        return dateFormat;
    }

    @Override
    public String format(final LogRecord record) {
        String message = record.getMessage();
        StringBuffer msg = new StringBuffer(32 + 2 + 7 + 1 + message.length());
        Date millis = new Date(record.getMillis());
        synchronized(dateFormat) {
            dateFormat.format(millis, msg, dummyPosition);
        }
        msg.append(' ').append(record.getLevel().getName()).append(':'); // WARNING:
        msg.append(' ').append(formatMessage(record)); // message
        if ( ! endsWithLineSeparator(msg) ) msg.append(LINE_SEPARATOR);
        final String thrown = formatThrown(record);
        if ( thrown != null ) msg.append(thrown);
        return msg.toString();
    }

    protected String formatThrown(final LogRecord record) {
        return formatThrown( record.getThrown() );
    }

    static String formatThrown(final Throwable thrown) {
        if ( thrown == null ) return null;
        StringWriter stringWriter = new StringWriter(512);
        PrintWriter printWriter = new PrintWriter(stringWriter);
        thrown.printStackTrace(printWriter);
        printWriter.println();
        printWriter.close();
        return stringWriter.toString();
    }

    static final String LINE_SEPARATOR = System.getProperty("line.separator");

    static boolean endsWithLineSeparator(final CharSequence msg) {
        final int len = msg.length();
        final String ls = LINE_SEPARATOR;
        if ( ls != null && len > ls.length() ) {
            final int end = len - ls.length();
            return ls.equals( msg.subSequence(end, len) );
        }
        return false;
    }

}

@@ -1193,65 +1193,8 @@
 g;%0A%0A
-import java.io.PrintWriter;%0Aimport java.io.StringWriter;%0A
 impo
@@ -1467,16 +1467,69 @@
 ecord;%0A%0A
+import static rb.trinidad.logging.LoggingHelpers.*;%0A%0A
 /**%0A * D
@@ -3881,22 +3881,28 @@
   final 
-String
+CharSequence
  thrown 
@@ -4027,22 +4027,28 @@
 otected 
-String
+CharSequence
  formatT
@@ -4094,16 +4094,31 @@
  return 
+LoggingHelpers.
 formatTh
@@ -4147,805 +4147,8 @@
 () )
-;%0A    %7D%0A%0A    static String formatThrown(final Throwable thrown) %7B%0A        if ( thrown == null ) return null;%0A        StringWriter stringWriter = new StringWriter(512);%0A        PrintWriter printWriter = new PrintWriter(stringWriter);%0A        thrown.printStackTrace(printWriter);%0A        printWriter.println();%0A        printWriter.close();%0A        return stringWriter.toString();%0A    %7D%0A%0A    static final String LINE_SEPARATOR = System.getProperty(%22line.separator%22);%0A%0A    static boolean endsWithLineSeparator(final CharSequence msg) %7B%0A        final int len = msg.length();%0A        final String ls = LINE_SEPARATOR;%0A        if ( ls != null && len %3E ls.length() ) %7B%0A            final int end = len - ls.length();%0A            return ls.equals( msg.subSequence(end, len) );%0A        %7D%0A        return false
 ;%0A  

use the LoggingHelpers with DefaultFormatter