/*
 * $Id: RequestProcessor.java,v 1.17 2007/08/16 11:11:00 marbobo Exp $
 *
 * Copyright (c) Siemens AG 2008 
 *           (c) Universität Paderborn 2008 
 * Licensed under EUPL 1.1. 
 *
 * $Log: RequestProcessor.java,v $
 * Revision 1.17  2007/08/16 11:11:00  marbobo
 * + Bugfixes
 * + Refactorings
 *
 * Revision 1.16  2006/03/23 11:41:47  marbobo
 * + Mögliche NPE abgefangen
 *
 */
package vkc.server;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.util.Collection;
import java.util.Iterator;

import vkc.converter.common.ConversionRequest;
import vkc.converter.common.ConversionResponse;
import vkc.converter.common.Status;
import vkc.converter.common.StreamConversionRequest;
import vkc.db.common.ConversionStatus;
import vkc.db.entities.VKCAdditionalDocumentFormat;
import vkc.db.entities.VKCDocument;
import vkc.db.serializer.VKCDocumentFormatSerializer;
import vkc.db.serializer.VKCDocumentSerializer;
import vkc.exception.DBException;
import vkc.misc.VKCLogManager;
import vkc.server.archive.DataStoreException;
import vkc.util.FileUtils;
import vkc.util.SocketUtils;
import vkc.util.VKCInputStream;
import vkc.view.WebShare;

/**
 * This class...
 * 
 * @created 07.01.2004
 * @author Andreas Koop
 */
public class RequestProcessor implements Runnable {
    private Socket client;

    private ObjectInputStream is;

    private ObjectOutputStream os;

    private VKCServer server = null;

    /**
     * Constructor
     * 
     * @param server
     *            the corresponding server
     * @param s
     *            the socket
     */
    public RequestProcessor(VKCServer server, Socket s) {
        this.server = server;
        client = s;

        try {
            os = SocketUtils.getObjectOutputStream(client);
            os.flush();
            is = SocketUtils.getObjectInputStream(client);
        } catch (IOException e) {
            VKCLogManager.errorLog(this, "", "Exception occured while obtaining IO-Streams from " + s.getInetAddress().getHostName(), e);
        }
    }

    public String getHostnameOfClient() {
        return client.getInetAddress().getHostName();
    }

    /**
     * Main thread loop
     */
    public void run() {
        Object o = null;
        server.incJobsCount(1);

        try {
            o = is.readObject();

            // Anfrage nach dem ConversionRequest (by DOCUMENT_ID)
            processConversionRequest((Integer) o);

            // Workaround
            while (!((o = is.readObject()) instanceof ConversionResponse)) {
                // Leer
            }

            processConversionResponse((ConversionResponse) o);

            // Der Rest des InputStreams muss immer gelesen werden,
            // sonst kann der Client ggfs. blockieren
            FileUtils.write(is, null);
        } catch (Exception e) {
            VKCLogManager.errorLog(this, "", "Exception occured while processing client request from " + getHostnameOfClient(), e);
            VKCLogManager.errorLog(this, "", "Last read object was: " + (o != null ? o : "null"), e);
        } finally {
            if (client != null) {
                SocketUtils.close(client);
            }

            server.decJobsCount();
        }
    }

    /**
     * @param response
     */
    private void processConversionResponse(ConversionResponse response) throws DataStoreException, DBException {
        VKCDocument document = VKCDocumentSerializer.retrieveDocument(response.getDocumentId());

        if (document == null) {
            VKCLogManager.errorLog(this, "Process response", "Document not found for DOCUMENTID = " + response.getDocumentId());

            return;
        }

        if (response.getStatus().equals(Status.FAILED)) {
            VKCLogManager.errorLog(this, "Process response", "Conversion failed for " + document.getName() + " (" + document.getDocumentId() + ")");
            // Suchindex aktualisieren und Mails zu registrierten Dok's verschicken
            VKCDocumentSerializer.saveDocument(document, true, response.isSendmail());

            return;
        }

        // Konvertierte Streams auslesen und im VKCArchiv ablegen
        Collection addDocFormats = response.getAdditionalDocFormats();

        if (addDocFormats != null) {
            for (Iterator it = addDocFormats.iterator(); it.hasNext();) {
                VKCAdditionalDocumentFormat f = (VKCAdditionalDocumentFormat) it.next();
                String archiveId = WebShare.archive.store(new VKCInputStream(is, f.getDocSize().longValue()));
                f.setArchiveId(archiveId);
            }
        }

        // Konvertierung ist schon erfolgt --> zusätzliche Formate in DB ablegen
        document.setAdditionalDocumentFormats(response.getAdditionalDocFormats());
        
        // Suchindex aktualisieren und Mails zu registrierten Dok's verschicken
        if (document.getCategoryId() != null) {
            VKCDocumentSerializer.saveDocument(document, true, response.isSendmail());
        }

        VKCDocumentFormatSerializer.saveAdditionalDocumentFormats(document.getDocumentId(), response.getAdditionalDocFormats());

        ConversionStatus cs = new ConversionStatus();
        cs.setId(response.getDocumentId());
        cs.deletePersistent();

        VKCLogManager.debug(this, "Conversions for " + document.getName() + " (" + document.getDocumentId() + ") successfully saved!");
    }

    /**
     * @param documentId
     */
    private void processConversionRequest(Integer documentId) throws DataStoreException, DBException, IOException {
        VKCDocument document = VKCDocumentSerializer.retrieveDocument(documentId);

        // Send a converter request
        ConversionRequest request = ConverterProxy.createConversionRequest(document);

        os.writeObject(request);

        if (request instanceof StreamConversionRequest) {
            // Send the inputstream to be converted
            VKCInputStream is = ((StreamConversionRequest) request).getInputStream();
            FileUtils.write(is, os);
            is.close();
        }

        os.flush();
        client.shutdownOutput();

        VKCLogManager.debug(this, "Streams of document \"" + document.getName() + "\" (" + documentId + ") sent!");
    }

    /**
     * (non-Javadoc)
     * 
     * @see java.lang.Object#finalize()
     */
    protected void finalize() throws Throwable {
        this.is = null;
        this.os = null;
        super.finalize();
    }
}