/*
 *  eXist Open Source Native XML Database
 *  Copyright (C) 2012 The eXist Project
 *  http://exist-db.org
 *
 *  This program is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public License
 *  as published by the Free Software Foundation; either version 2
 *  of the License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *  $Id$
 */
package org.exist.replication.shared;

import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.Map;
import java.util.Properties;
import java.util.zip.GZIPOutputStream;
import javax.xml.transform.OutputKeys;
import org.apache.commons.io.output.ByteArrayOutputStream;
import org.apache.log4j.Logger;
import org.exist.dom.BinaryDocument;
import org.exist.dom.DocumentImpl;
import org.exist.dom.DocumentMetadata;
import org.exist.security.Permission;
import org.exist.storage.DBBroker;
import org.exist.storage.serializers.EXistOutputKeys;
import org.exist.storage.serializers.Serializer;
import org.xml.sax.SAXException;

/**
 *  Helper class for retrieving (meta)data from an in eXist stored document.
 * 
 * @author Dannes Wessels
 */
public class MessageHelper {
    
    public static final String EXIST_RESOURCE_CONTENTLENGTH = "exist.resource.contentlength";
    public static final String EXIST_RESOURCE_DOCUMENTID = "exist.resource.documentid";
    public static final String EXIST_RESOURCE_GROUP = "exist.resource.group";
    public static final String EXIST_RESOURCE_MIMETYPE = "exist.resource.mimetype";
    public static final String EXIST_RESOURCE_OWNER = "exist.resource.owner";
    public static final String EXIST_RESOURCE_TYPE = "exist.resource.type";
    public static final String EXIST_RESOURCE_MODE = "exist.resource.permission.mode";
    public static final String EXIST_MESSAGE_CONTENTENCODING = "exist.message.content-encoding";

    private final static Logger LOG = Logger.getLogger(MessageHelper.class);
    
    //	Copied from webdav interface ; there is a better one
    public final static Properties OUTPUT_PROPERTIES = new Properties();

    static {
        OUTPUT_PROPERTIES.setProperty(OutputKeys.INDENT, "yes");
        OUTPUT_PROPERTIES.setProperty(OutputKeys.ENCODING, "UTF-8");
        OUTPUT_PROPERTIES.setProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
        OUTPUT_PROPERTIES.setProperty(EXistOutputKeys.EXPAND_XINCLUDES, "no");
        OUTPUT_PROPERTIES.setProperty(EXistOutputKeys.PROCESS_XSL_PI, "no");
    }
    

    /**
     *  Serialize document to byte array as gzipped document.
     * 
     * @param broker
     * @param document
     * @return
     * @throws IOException 
     */
    public static byte[] serialize(DBBroker broker, DocumentImpl document) throws IOException {
        
        // This is the weak spot, the data is serialized into
        // a byte array. Better to have an overloap to a file,
        byte[] payload;

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        GZIPOutputStream gos = new GZIPOutputStream(baos);


        if (document.getResourceType() == DocumentImpl.XML_FILE) {

            // Stream XML document
            Serializer serializer = broker.getSerializer();
            serializer.reset();
            try {
                serializer.setProperties(OUTPUT_PROPERTIES);

                Writer w = new OutputStreamWriter(gos, "UTF-8");
                serializer.serialize(document, w);
                w.flush();
                w.close();

                payload = baos.toByteArray();


            } catch (SAXException e) {
                LOG.error(e);
                throw new IOException("Error while serializing XML document: " + e.getMessage(), e);

            } catch (Throwable e) {
                System.gc(); // recover from out of memory exception
                LOG.error(e);
                throw new IOException("Error while serializing XML document: " + e.getMessage(), e);
            }

        } else {
            // Stream NON-XML document

            try {
                broker.readBinaryResource((BinaryDocument) document, gos);
                gos.flush();
                gos.close();

                payload = baos.toByteArray();

            } catch (IOException e) {
                LOG.error(e);
                throw new IOException("Error while serializing binary document: " + e.getMessage(), e);

            } catch (Throwable e) {
                System.gc(); // recover from out of memory exception
                LOG.error(e);
                throw new IOException("Error while serializing binary document: " + e.getMessage(), e);
            }
        }


        return payload;

    }

    public static void retrieveDocMetadata(Map<String, Object> props, DocumentMetadata docMetadata) {
        if (docMetadata == null) {
            LOG.error("no metadata supplied");

        } else {
            props.put(EXIST_RESOURCE_MIMETYPE, docMetadata.getMimeType()); 
        }
    }
    
    public static void retrievePermission(Map<String, Object> props, Permission perm){

            if (perm == null) {
                LOG.error("no permissions supplied");
                
            } else {
                props.put(EXIST_RESOURCE_OWNER, perm.getOwner().getName());
                props.put(EXIST_RESOURCE_GROUP, perm.getGroup().getName());
                props.put(EXIST_RESOURCE_MODE, perm.getMode());
            }
    }
    
    
    public static void retrieveFromDocument(Map<String, Object> props, DocumentImpl document){
            // We do not differ between DOCUMENT subtypes,
	    // mime-type is set in document metadata EXIST_RESOURCE_MIMETYPE. /ljo
            props.put(EXIST_RESOURCE_TYPE, eXistMessage.ResourceType.DOCUMENT); 
            props.put(EXIST_RESOURCE_DOCUMENTID, document.getDocId()); 
            props.put(EXIST_RESOURCE_CONTENTLENGTH, document.getContentLength()); 
        
    }
}

@@ -3173,17 +3173,21 @@
  byte%5B%5D 
-s
+gzipS
 erialize
@@ -4059,32 +4059,71 @@
 XException e) %7B%0A
+                payload = new byte%5B0%5D;%0A
                 
@@ -4266,32 +4266,71 @@
 (Throwable e) %7B%0A
+                payload = new byte%5B0%5D;%0A
                 
@@ -4814,32 +4814,71 @@
 OException e) %7B%0A
+                payload = new byte%5B0%5D;%0A
                 
@@ -5024,32 +5024,71 @@
 (Throwable e) %7B%0A
+                payload = new byte%5B0%5D;%0A
                 
@@ -5718,17 +5718,16 @@
  perm)%7B%0A
-%0A
         
@@ -6246,13 +6246,17 @@
 es,%0A
-
 %09    
+    
 // m

update of replication extension ; free-up memory if possible