/*
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.j2objc.util.logging;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.logging.Formatter;
import java.util.logging.Handler;
import java.util.logging.LogRecord;

/*-[
// TODO(tball): update ASL use to iOS 10's os_log and remove clang pragmas.
#pragma clang diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"

#import <asl.h>

// Simple value holder, so aslclient is closed when thread dictionary is deallocated.
@interface ASLClientHolder : NSObject {
 @public
  aslclient _client;
}
@end

@implementation ASLClientHolder
- (instancetype)initWithClient:(aslclient)client {
  self = [super init];
  if (self) {
    _client = client;
  }
  return self;
}

- (void)dealloc {
  asl_close(_client);
#if !__has_feature(objc_arc)
  [super dealloc];
#endif
}
@end
]-*/

/**
 * Handler implementation that calls iOS asl_log().
 *
 * @author Tom Ball
 */
public class IOSLogHandler extends Handler {

  static class IOSLogFormatter extends Formatter {

    /**
     * Very simple formatter, since asl_log adds its own text.
     */
    @Override
    public String format(LogRecord record) {
      return formatMessage(record);
    }
  }

  // TODO(tball): Replace this with a system property that defines a java.util.logging.config.class.
  public static final String IOS_LOG_MANAGER_DEFAULTS =
      ".level=INFO\nhandlers=com.google.j2objc.util.logging.IOSLogHandler\n";

  private static final String ASLCLIENT = "IOSLogHandler-aslclient";

  public IOSLogHandler() {
    setFormatter(new IOSLogFormatter());
  }

  @Override
  public void close() {
    // No action needed
  }

  @Override
  public void flush() {
    // No action needed
  }

  @Override
  public void publish(LogRecord record) {
    if (!isLoggable(record)) {
      return;
    }
    StringBuilder sb = new StringBuilder(getFormatter().format(record));
    int aslLevel;
    switch (record.getLevel().intValue()) {
      case 1000:       // Level.SEVERE
        aslLevel = 3;  // ASL_LEVEL_ERR
        break;
      case 900:        // Level.WARNING
        aslLevel = 4;  // ASL_LEVEL_WARNING
        break;
      case 800:        // Level.INFO
      case 700:        // Level.CONFIG
        aslLevel = 5;  // ASL_LEVEL_NOTICE
        break;
      default:
        aslLevel = 6;  // ASL_LEVEL_INFO
    }

    if (record.getThrown() != null) {
      sb.append('\n');
      StringWriter stringWriter = new StringWriter();
      record.getThrown().printStackTrace(new PrintWriter(stringWriter));
      sb.append(stringWriter.toString());
    }
    log(sb.toString(), aslLevel);
  }

  private native void log(String logMessage, int aslLevel) /*-[
    // Add stderr as a log file, so that log messages are seen on the debug log,
    // and not just the device log.
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        asl_add_log_file(NULL, STDERR_FILENO);
    });

    NSThread *currentThread = [NSThread currentThread];
    NSMutableDictionary *threadData = [currentThread threadDictionary];
    ASLClientHolder *logClient =
        [threadData objectForKey:ComGoogleJ2objcUtilLoggingIOSLogHandler_ASLCLIENT];
    if (!logClient) {
      aslclient aslClient = asl_open([[currentThread name] UTF8String],
          [[[NSBundle mainBundle] bundleIdentifier] UTF8String], ASL_OPT_NO_DELAY | ASL_OPT_STDERR);
      logClient = AUTORELEASE([[ASLClientHolder alloc] initWithClient:aslClient]);
      [threadData setObject:logClient forKey:ComGoogleJ2objcUtilLoggingIOSLogHandler_ASLCLIENT];
    }
    asl_log(logClient->_client, NULL, aslLevel, "%s", [logMessage UTF8String]);
  ]-*/;

/*-[
#pragma clang diagnostic pop
]-*/
}
