/**
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 2010 Bull S.A.S.
 * Contact: jonas-team@ow2.org
 *
 * This library 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.1 of the License, or any later version.
 *
 * This library 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307
 * USA
 *
 * --------------------------------------------------------------------------
 * $Id$
 * --------------------------------------------------------------------------
 */

package org.ow2.jonas.web.tomcat6.versioning;

import java.io.IOException;

import org.apache.catalina.connector.OutputBuffer;
import org.apache.catalina.connector.Response;
import org.ow2.jonas.versioning.VersioningService;

/**
 * Output stream with content filtering.
 *
 * @author tokmen-sa
 */
public class FilteredOutputStream extends OutputBuffer {

    private Response response;

    public FilteredOutputStream(Response response) {
        super();
        this.response = response;
    }

    public FilteredOutputStream(Response response, int size) {
        super(size);
        this.response = response;
    }

    /**
     * Replaces all versioned paths with the user path in the response output
     * stream.
     */
    @Override
    public void write(String s, int off, int cnt) throws IOException {
        if (s == null) {
            super.write(s, off, cnt);
            return;
        }

        VersionedPathBean vpb = this.findVersionedPathBean(response.getContentType());

        // Now rewriting, for example:
        //
        //  <img src="/path-version-1.0.0/image.gif">
        // into
        //  <img src="/path/image.gif">
        if (vpb != null) {
            final int originalOffset = off;
            final int originalCount = cnt;
            final int originalLength = originalOffset + originalCount;

            for (int i = originalOffset; i < originalLength; i++) {
                if (vpb.getVersionedPath().charAt(0) == s.charAt(i)) {
                    boolean isVersionedPath = true;
                    for (int j = i + 1; j < Math.min(i + vpb.getVersionedPath().length(), originalLength); j++) {
                        if (vpb.getVersionedPath().charAt(j - i) != s.charAt(j)) {
                            isVersionedPath = false;
                            break;
                        }
                    }

                    if (isVersionedPath) {
                        // We've found a /path-version-1.0.0
                        // Write out the beginning: <img src="
                        super.write(s, off, i - off);

                        // Write out user path: /path
                        super.write(vpb.getUserPath());
                        i += vpb.getVersionedPath().length();

                        // If userPath is /
                        // and path is /-version1.0.0/image.gif
                        // return /image.gif and not //image.gif
                        if ("/".equals(vpb.getUserPath())) {
                            while(i < originalLength && s.charAt(i) == '/') {
                                i++;
                            }
                        }

                        // Prepare to write the rest
                        off = i;
                        cnt = originalCount - i;
                    }
                }
            }
        }

        // Write out the end: /image.gif">
        super.write(s, off, cnt);
    }

    /**
     * Replaces all versioned paths with the user path in the response output
     * stream.
     */
    @Override
    public void write(char buf[], int off, int cnt) throws IOException {
        if (buf == null) {
            super.write(buf, off, cnt);
            return;
        }

        VersionedPathBean vpb = this.findVersionedPathBean(response.getContentType());

        // Now rewriting, for example:
        //
        //  <img src="/path-version-1.0.0/image.gif">
        // into
        //  <img src="/path/image.gif">
        if (vpb != null) {
            final int originalOffset = off;
            final int originalCount = cnt;
            final int originalLength = originalOffset + originalCount;

            for (int i = originalOffset; i < originalLength; i++) {
                if (vpb.getVersionedPath().charAt(0) == buf[i]) {
                    boolean isVersionedPath = true;
                    for (int j = i + 1; j < Math.min(i + vpb.getVersionedPath().length(), originalLength); j++) {
                        if (vpb.getVersionedPath().charAt(j - i) != buf[j]) {
                            isVersionedPath = false;
                            break;
                        }
                    }

                    if (isVersionedPath) {
                        // We've found a /path-version-1.0.0
                        // Write out the beginning: <img src="
                        super.write(buf, off, i - off);

                        // Write out user path: /path
                        super.write(vpb.getUserPath());
                        i += vpb.getVersionedPath().length();

                        // If userPath is /
                        // and path is /-version1.0.0/image.gif
                        // return /image.gif and not //image.gif
                        if ("/".equals(vpb.getUserPath())) {
                            while(i < originalLength && buf[i] == '/') {
                                i++;
                            }
                        }

                        // Prepare to write the rest
                        off = i;
                        cnt = originalCount - i;
                    }
                }
            }
        }

        // Write out the end: /image.gif">
        super.write(buf, off, cnt);
    }

    private VersionedPathBean findVersionedPathBean(String contentType) {
        // Get path information and whether we should overwrite the stream.
        if (contentType != null && ContextFinder.getParent() != null) {
            VersioningService versioning = ContextFinder.getParent().getVersioningService();
            VersionedPathBean vpb = response.getVersionedPathBean();

            // Is this a versioned request?
            if (vpb != null && vpb.getUserPath() != null && vpb.getVersionedPath() != null && versioning != null
                && versioning.isVersioningEnabled()) {

                String[] filteredContentTypes = versioning.getFilteredContentTypesArray();
                if (filteredContentTypes != null && filteredContentTypes.length > 0) {
                    // For this versioned request, is this response type
                    // supposed to be rewritten?
                    for (String filteredContentType : filteredContentTypes) {
                        if (contentType.startsWith(filteredContentType)) {
                            return vpb;
                        }
                    }
                }
            }
        }

        return null;
    }
}
