/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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 org.apache.jena.fuseki.server;

import java.text.DateFormat ;
import java.text.SimpleDateFormat ;
import java.util.Collection ;
import java.util.Date ;
import java.util.Enumeration ;
import java.util.TimeZone ;

import javax.servlet.http.HttpServletRequest ;
import javax.servlet.http.HttpServletResponse ;

import org.apache.jena.atlas.logging.Log ;
import org.apache.jena.fuseki.servlets.HttpAction ;

/** Create standard request logs (NCSA etc) */ 
public class RequestLog {
    /*
      http://httpd.apache.org/docs/current/mod/mod_log_config.html
Common Log Format (CLF)
    "%h %l %u %t \"%r\" %>s %b"
Common Log Format with Virtual Host
    "%v %h %l %u %t \"%r\" %>s %b"
NCSA extended/combined log format
    "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\""
     */
    /*
        %l -- Identity or -
        %u -- Remote user or -
        %t -- Timestamp
        "%r" -- Request line
        %>s -- Final request status
        %b -- Size in bytes
        Headers.
        %{}i for request header.
        %{}o for response header.
      */  
    
    private static DateFormat dateFormatter ; 
    static {
        dateFormatter = new SimpleDateFormat("dd/MMM/yyyy:HH:mm:ss Z") ;
        dateFormatter.setTimeZone(TimeZone.getTimeZone("UTC"));
    }

    /** NCSA combined log format *
     * LogFormat "%{X-Forwarded-For}i %l %u %t \"%r\" %&gt;s %b  \"%{Referer}i\" \"%{User-Agent}i\"" combinedfwd
     * XXX.XXX.XXX.XXX - - [01/Feb/2014:03:19:09 +0000] "GET / HTTP/1.1" 200 6190  "-" "check_http/v1.4.16 (nagios-plugins 1.4.16)"
     */
    public static String combinedNCSA(HttpAction action) {
        HttpServletRequest request = action.request ;
        HttpServletResponse response = action.response ;
        return combinedNCSA(request, response) ;
    }
    
    public static String combinedNCSA(HttpServletRequest request, HttpServletResponse response) {
        StringBuilder builder = new StringBuilder() ;
        // Remote
        String remote = get(request, "X-Forwarded-For", request.getRemoteAddr()) ;
        builder.append(remote) ;
        builder.append(" ") ;
        
        // %l %u : User identity (unrelaible)
        builder.append("- - ") ;
        
        // %t
        // Expensive? 
        builder.append("[");
        // Better?
        builder.append(dateFormatter.format(new Date())) ;
        builder.append("] ");
        
        // "%r"
        builder.append("\"")  ;
        builder.append(request.getMethod()) ;
        builder.append(" ") ;
        // No query string - they are long and logged readably elsewhere
        builder.append(request.getRequestURI()) ; 
        builder.append("\"")  ;
        //%>s -- Final request status
        builder.append(" ")  ;
        builder.append(response.getStatus())  ;
        
        //%b -- Size in bytes
        builder.append(" ")  ;
        //String size = getField()
        String size = get(response, "Content-Length", "-") ;
        builder.append(size)  ;
        
        // "%{Referer}i" 
        builder.append(" \"")  ;
        builder.append(get(request, "Referer", "")) ;
        builder.append("\"")  ;
        // "%{User-Agent}i"
        builder.append(" \"")  ;
        builder.append(get(request, "User-Agent", "")) ;
        builder.append("\"")  ;
        
        return builder.toString() ;
    }
    
    private static String get(HttpServletRequest request, String name, String dft) {
        String x = get(request, name) ;
        if ( x == null )
            x = dft ;
        return x ;
    }
    
    private static String get(HttpServletRequest request, String name) {
        Enumeration<String> en = request.getHeaders(name) ;
        if ( ! en.hasMoreElements() ) return null ;
        String x = en.nextElement() ;
        if ( en.hasMoreElements() ) {
            Log.warn(RequestLog.class, "Multiple request header values") ;
        }
        return x ;
    }

    private static String get(HttpServletResponse response, String name, String dft) {
        String x = get(response, name) ;
        if ( x == null )
            x = dft ;
        return x ;
    }

    
    private static String get(HttpServletResponse response, String name) {
        Collection<String> en = response.getHeaders(name) ;
        if ( en.isEmpty() )return null ;
        if ( en.size() != 1 ) Log.warn(RequestLog.class, "Multiple response header values") ;
        return response.getHeader(name) ;
    }

}
