/*
 * $Header: /home/cvspublic/jakarta-slide/proposals/tamino/src/store/org/apache/slide/store/tamino/tools/repairer/XRepairLogWriter.java,v 1.4 2004/12/15 10:38:27 pnever Exp $
 * $Revision: 1.4 $
 * $Date: 2004/12/15 10:38:27 $
 *
 * ====================================================================
 *
 * Copyright 1999-2004 The Apache Software Foundation.
 *
 * 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 org.apache.slide.store.tamino.tools.repairer;

import com.softwareag.common.instrumentation.logging.Level;
import com.softwareag.common.instrumentation.logging.Logger;
import com.softwareag.common.instrumentation.logging.LoggerFactory;
import com.softwareag.common.instrumentation.logging.LoggerUtil;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.text.DecimalFormat;
import java.text.MessageFormat;
import java.text.NumberFormat;
import java.util.Calendar;
import org.apache.commons.httpclient.methods.PutMethod;
import org.apache.slide.store.tamino.common.XGlobals;
import org.apache.slide.store.tamino.tools.Env;
import org.apache.slide.store.tamino.tools.stores.XStore;
import org.apache.slide.store.tamino.tools.stores.XStoreGroup;
import org.apache.slide.util.JDom;
import org.apache.slide.util.XUri;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.output.XMLOutputter;

/**
 ** This class writes tht log messages of the Check and Repair Tool.
 ** Class description.
 **
 ** @author    Hardy.Kiefer@softwareag.com
 ** @author    Peter.Nevermann@softwareag.com
 ** @version   $Revision: 1.4 $
 **
 **/
public class XRepairLogWriter implements RepairConstants {
    
    /**
     * Logging
     */
    private static final String LOGNAME = LoggerUtil.getThisClassName();
    private static Logger logger = LoggerFactory.getLogger(LOGNAME);
    
    // id's which controls the building of the tree
    
    
    /**
     ** tags of log file
     */
    private static final String TAG_ROOT = "repair";
    private static final String TAG_UNIT = "unit";
    private static final String TAG_STORE = "store";
    private static final String TAG_MSG = "msg";
    private static final String TAG_CHECKLIST = "checklist";
    private static final String TAG_CHECK = "check";
    private static final String TAG_DESCRIPTION = "description";
    private static final String TAG_STATISTIC = "statistics";
    private static final String TAG_COUNT = "count";
    private static final String TAG_TIME = "time";
    private static final String TAG_RESULT = "result";
    private static final String TAG_ERROR = "error";
    private static final String TAG_DETAILS = "details";
    
    private static final String ATT_ASPECT = "aspect";
    private static final String ATT_UNIT = "unit";
    private static final String ATT_TAMINOCOLL = "collection";
    private static final String ATT_STORETYPE = "type";
    private static final String ATT_CHECKONLY = "checkonly";

    private final String catalinaContext;
    private String storeName;
    private boolean serverIsRunning = false;
    private String host = "localhost";
    private final int port;
    private String user;
    private String pwd;
    private boolean console;
    
    private Document logDocument;
    private Element rootElm;
    private Element checklistElm;
    private Element totalResultElm;
    private Element checkElm;
    private Element detailsElm;
    private boolean detailsElmExists = false;
    private Element statisticsElm;
    private boolean statisticsElmExists = false;
    private Element msgElm;
    private Element countElm;
    private Element timeElm;
    private Element totalStatisticsElm;
    private XMLOutputter outputter = null;
    private boolean logFileOpen = false;
    
    
    
    /**
     * Default constructor
     *
     * @param      host          name of the host, i.e. "localhost"
     * @param      port          port
     * @param      user          user
     * @param      pwd           pwd
     * @param      console       set true if console output is desired
     */
    public XRepairLogWriter( String catalinaContext, String host, int port, String user, String pwd, boolean console, boolean serverIsRunning ) {
        this.catalinaContext = catalinaContext;
        this.outputter = JDom.outputter();
        this.host = host;
        this.port = port;
        this.user = user;
        this.pwd = pwd;
        this.console = console;
        this.serverIsRunning = serverIsRunning;
        initialize();
    }

    protected void initialize() {
        this.logDocument = new Document( new Element( TAG_ROOT ) );
        this.rootElm = logDocument.getRootElement();
        this.checklistElm = new Element(TAG_CHECKLIST);
        this.totalResultElm = new Element(TAG_RESULT);
        this.totalStatisticsElm = new Element(TAG_STATISTIC);
        this.rootElm.addContent(checklistElm);
        this.rootElm.addContent(totalResultElm);
        this.rootElm.addContent(totalStatisticsElm);
    }
    
    /**
     ** Initializes the log file for the specified store.
     * @param    logical             the unit to repair
     * @param    checkOnly           check only?
     *
     */
    protected void openLogFile( XStoreGroup logical, boolean checkOnly ) {
        if( logger.isLoggable(Level.FINE) )
            logger.entering( LOGNAME, "openLogFile", new Object[]{logical, new Boolean(checkOnly)}  );
        
        XStore main = logical.getMainStore();
        this.storeName = main.getName();
        this.rootElm.setAttribute( ATT_CHECKONLY, String.valueOf(checkOnly) );
        Element ruElm = new Element(TAG_UNIT);
        ruElm.setAttribute( ATT_TAMINOCOLL, main.getTaminoCollectionUrl());
        rootElm.addContent(ruElm);
        
        logFileOpen = true;
        
        if( logger.isLoggable(Level.FINE) )
            logger.exiting( LOGNAME, "openLogFile" );
    }
    
    /**
     *
     */
    protected boolean isLogFileOpen() {
        return logFileOpen;
    }
    
    /**
     ** Write log file to disk if server is not available or PUT failed.
     **/
    private String writeLogFileToDisk() {
        String fsep = File.separator;
        String logdirPath = Env.get().home+fsep+XGlobals.REPAIRER_DIR_NAME+fsep+storeName;
        File logdir = new File( logdirPath );
        if( !logdir.exists() )
            logdir.mkdir();
        String logfilePath = logdirPath+fsep+getLogFileName();
        File logfile = new File( logfilePath );
        
        try {
            OutputStreamWriter out = new OutputStreamWriter(new FileOutputStream(logfile), "utf-8");
            outputter.output( logDocument, out );
            out.flush();
            out.close();
        }
        catch( Exception e ) {
            e.printStackTrace();
        }
        return logfilePath;
    }
    
    /**
     ** Close the current log file.
     ** This method closes the file and put the output to the destination
     ** concerning the used store name. It must be called at the end of
     ** logging the store.
     **
     ** @pre        true
     ** @post       true
     **
     **/
    protected void closeLogFile() {
        if( logger.isLoggable(Level.FINE) )
            logger.entering( LOGNAME, "closeLogFile");
        
        logFileOpen = false;
        if( serverIsRunning ) {
            String uri = XUri.SEP+catalinaContext+XGlobals.REPAIRER_URI+
                XUri.SEP+storeName+XUri.SEP+getLogFileName();
            
            if( logger.isLoggable(Level.FINE) )
                logger.fine(LOGNAME, "closeLogFile", "targetPath = " + uri );
            
            PutMethod pm = new PutMethod (uri);
            
            try {
                pm.setRequestBody( outputter.outputString(logDocument) );
                pm.addRequestHeader( "Content-Type", "text/xml; charset=\"utf-8\"" );
                
                XHttpClient client = new XHttpClient(host, port, user, pwd);
                client.executeMethod(pm);
                int psc = pm.getStatusCode();
                if( psc < 400 ) {
                    println( TC_CONSOLE_ONLY, "Log: "+uri );
                }
                else {
                    String logfilePath = writeLogFileToDisk();
                    println( TC_CONSOLE_ONLY, "Log: "+logfilePath );
                }
            }
            catch (Exception e ) {
                String logfilePath = writeLogFileToDisk();
                println( TC_CONSOLE_ONLY, "Log: "+logfilePath );
            }
            
            if( logger.isLoggable(Level.FINE) ) {
                logger.fine(LOGNAME, "closeLogFile", "PutMethod status code = " + pm.getStatusCode() );
                logger.fine(LOGNAME, "closeLogFile", "PutMethod status text = " + pm.getStatusText() );
            }
        }
        else {
            String logfilePath = writeLogFileToDisk();
            println( TC_CONSOLE_ONLY, "Log: "+logfilePath );
        }
        
        if( logger.isLoggable(Level.FINE) )
            logger.exiting( LOGNAME, "closeLogFile" );
    }
    
    /**
     ** Print log message with string argument.
     **
     ** @pre        (msg != null)
     ** @pre        (args != null)
     ** @post       true
     **
     ** @param      token    correspond to the xml tag in the log file
     ** @param      msg      message to be print
     ** @param      strVar   variable part to the message as string
     **/
    public void println( int token, String msg, String strVar ) {
        Object[] args = { strVar };
        println(token, msg, args);
    }
    
    
    /**
     ** Print log message with arguments.
     **
     ** @pre        (msg != null)
     ** @pre        (args != null)
     ** @post       true
     **
     ** @param      token correspond to the xml tag in the log file
     ** @param      msg   message to be print
     ** @param      args   variable parts to the message to be print
     **/
    public void println( int token, String msg, Object[] args ) {
        println(token, format(msg, args));
    }
    
    public static String format(String msg, Object[] args) {
        MessageFormat form = new MessageFormat(msg);
        return form.format(args);
    }
    
    
    /**
     ** Print log message.
     **
     ** @pre        (msg != null)
     ** @post       true
     **
     ** @param      token correspond to the xml tag in the log file
     ** @param      msg   message to be print
     **/
    protected void println( int token, String msg ) {
        if( console && token <= TC_CONSOLE_MAX ) {
            String prefix = (TC_TOKEN_NAMES[token] == "" ? "" : TC_TOKEN_NAMES[token]+": ");
            System.out.println(prefix+msg);
        }
        
        switch (token) {
            case TC_CHECK:
                detailsElmExists   = false;
                statisticsElmExists = false;
                checkElm         = new Element(TAG_CHECK);
                checkElm.setAttribute("Name", msg);
                checklistElm.addContent(checkElm);
                break;
            case TC_CHECK_DESCRIPTION:
                Element dElem = new Element(TAG_DESCRIPTION);
                dElem.addContent(msg);
                checkElm.addContent(dElem);
                break;
            case TC_CHECK_RESULT:
                Element rElem = new Element(TAG_RESULT);
                rElem.addContent(msg);
                checkElm.addContent(rElem);
                break;
            case TC_TOTAL_RESULT:
                totalResultElm.addContent(msg);
                break;
            case TC_ERROR:
                Element wElem = new Element(TAG_ERROR);
                wElem.addContent(msg);
                rootElm.addContent(wElem);
                break;
            case TC_CHECK_DETAILS:
                if (!detailsElmExists) {
                    detailsElm = new Element(TAG_DETAILS);
                    checkElm.addContent(detailsElm);
                    detailsElmExists = true;
                }
                msgElm = new Element(TAG_MSG);
                msgElm.addContent(msg);
                detailsElm.addContent(msgElm);
                break;
            default:
                break;
        }
    }
    
    /**
     ** Print log message.
     **
     ** @pre        (info != null)
     **
     ** @param      token correspond to the xml tag in the log file
     ** @param      info   message to be print
     **/
    protected void println( int token, String info, long amount ) {
        if( console && token <= TC_CONSOLE_MAX ) {
            String prefix = (TC_TOKEN_NAMES[token] == "" ? "" : TC_TOKEN_NAMES[token]+": ");
            System.out.println(prefix+amount+" "+info);
        }
        
        switch (token) {
            case TC_CHECK_COUNT:
                countElm = new Element(TAG_COUNT);
                countElm.addContent( String.valueOf(amount) );
                countElm.setAttribute( ATT_ASPECT, info );
                if (!statisticsElmExists) {
                    statisticsElm = new Element(TAG_STATISTIC);
                    checkElm.addContent( statisticsElm );
                    statisticsElmExists = true;
                }
                statisticsElm.addContent(countElm);
                break;
            case TC_CHECK_TIME:
                timeElm = new Element(TAG_TIME);
                timeElm.addContent( String.valueOf(amount) );
                timeElm.setAttribute( ATT_UNIT, info );
                if (!statisticsElmExists) {
                    statisticsElm = new Element(TAG_STATISTIC);
                    checkElm.addContent( statisticsElm );
                    statisticsElmExists = true;
                }
                statisticsElm.addContent(timeElm);
                break;
            case TC_TOTAL_COUNT:
                countElm = new Element(TAG_COUNT);
                countElm.addContent( String.valueOf(amount) );
                countElm.setAttribute( ATT_ASPECT, info );
                totalStatisticsElm.addContent(countElm);
                break;
            case TC_TOTAL_TIME:
                timeElm = new Element(TAG_TIME);
                timeElm.addContent( String.valueOf(amount) );
                timeElm.setAttribute( ATT_UNIT, info );
                totalStatisticsElm.addContent(timeElm);
                break;
            default:
                break;
        }
    }
    
    /**
     ** Get name of log file.
     **
     ** @pre        true
     ** @post       true
     **
     ** @return     log file name
     **/
    private String getLogFileName() {
        String logFileName = new String("Log_");
        Calendar cal = Calendar.getInstance();
        NumberFormat nf = new DecimalFormat();
        nf.setMinimumIntegerDigits(2);
        int month = cal.get(Calendar.MONTH) + 1;
        int day = cal.get(Calendar.DAY_OF_MONTH);
        int hour = cal.get(Calendar.HOUR_OF_DAY);
        int min = cal.get(Calendar.MINUTE);
        int sec = cal.get(Calendar.SECOND);
        int msec = cal.get(Calendar.MILLISECOND);
        logFileName = logFileName + cal.get(Calendar.YEAR) + "_";
        logFileName = logFileName + nf.format(month) + "_";
        logFileName = logFileName + nf.format(day) + "_";
        logFileName = logFileName + nf.format(hour) + "_";
        logFileName = logFileName + nf.format(min) + "_";
        logFileName = logFileName + nf.format(sec) + nf.format(msec);
        logFileName = logFileName + XUri.XML_SUFF;
        return logFileName;
    }
    
}


