#!/usr/bin/python
"""
This script converts the log statements in the given file from log4j format to slf4j format.
Please see the ExampleInput.java file to see the sample input and ExampleInput.java.output
for how the converted file will look like.

For conversion purposes, the following are considered to be log statements:
    logger.trace
    logger.debug
    logger.info
    logger.error
    logger.warn
    logger.fatal
    log.trace
    log.debug
    log.info
    log.error
    log.warn
    log.fatal

The case is ignored. There can be one or more white spaces between tokens. For instance "logger   .    info" will
also be converted.

 Copyright (c) 2014 Roy <roysolvesproblems at gmail dot com>
 All rights reserved.

 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *   * Redistributions of source code must retain the above copyright notice,
 *     this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *   * Neither the name of Redis nor the names of its contributors may be used
 *     to endorse or promote products derived from this software without
 *     specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
"""

import os
import logging
import argparse
import re

# Customization section.
# Logger names to look for in the input Java file. If you have any other logger names in your input file,
# you should specify them here. THIS LIST IS CASE INSENSITIVE.
LOGGER_NAMES = ['logger', 'log']

# Log levels
LOG_LEVELS = ['trace', 'debug', 'info', 'error', 'warn', 'fatal']

# This the maximum statement length that is supported.
# This is used while replacing import statements and variable declarations.
MAX_STMT_LEN = 200

# This is the pattern for log statements.
LOG_STMT_RE = '(' + '|'.join(LOGGER_NAMES) + ')\s*\.\s*(' + '|'.join(LOG_LEVELS) + ')\s*'
print '*** Log statement regex: [%s]'%LOG_STMT_RE
LOG_STMT_CRE = re.compile(LOG_STMT_RE, re.DOTALL|re.MULTILINE)

# This is the pattern for import statements.
IMPORT_STMT_RE = r'import\s+org\s*\.\s*apache\s*\.\s*log4j\s*\..+?;'
IMPORT_STMT_CRE = re.compile(IMPORT_STMT_RE, re.DOTALL|re.MULTILINE)

# This is the pattern for getLogger statements.
GET_LOGGER_RE = r'Logger\s*\.\s*getLogger\s*'
GET_LOGGER_CRE = re.compile(GET_LOGGER_RE, re.DOTALL|re.MULTILINE)

# Don't confuse this logger with the logger_name that appears in the Java program.
# This logger is for our debugging purposes.
logger = None

debug = False
input_files = []

slf4j_imports_added = False

content = None
offset = 0
logger_name = None
log_level = None

def parse_cmdline_args():
    global debug, input_files
    parser = argparse.ArgumentParser(description='Convert log4j style log statements to slf4j style statements.')
    parser.add_argument('--debug', help='Runs the program in debug mode. Writes tons of debug logs.', action='store_true')
    parser.add_argument('input_files', help='List of input files.', nargs = '+')
    args = parser.parse_args()
    debug = args.debug
    input_files = args.input_files

def setup_logging():
    global logger, debug
    # create logger
    logger = logging.getLogger('log4jtoslf4j')
    logger.setLevel(logging.DEBUG)

    # create console handler and set level to debug
    ch = logging.StreamHandler()
    if debug: ch.setLevel(logging.DEBUG)
    else: ch.setLevel(logging.INFO)

    # create formatter
    formatter = logging.Formatter('%(asctime)s - %(levelname)4.4s - %(funcName)-20s - %(message)s')

    # add formatter to ch
    ch.setFormatter(formatter)

    # add ch to logger
    logger.addHandler(ch)

def clear_globals():
    """
    Clears the globals, except content and offset.
    :return:
    """
    global logger_name, log_level
    logger_name = None
    log_level = None

def read_file(file_name):
    with open(file_name) as f:
        return f.read()

def backup_file(file_name):
    logger.info("Taking a back up of [%s] with .orig extension."%file_name)
    os.rename(file_name, file_name + '.orig')

def write_file(file_name, content):