package massone.web.controllers.common;

import org.apache.commons.logging.LogFactory;
import org.apache.commons.logging.Log;
import org.apache.commons.beanutils.BeanUtils;

import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.IOException;
import java.util.*;
import java.lang.reflect.InvocationTargetException;

import http.utils.multipartrequest.MultipartRequest;
import http.utils.multipartrequest.ServletMultipartRequest;
import massone.web.common.MultipartContent;

public abstract class AbstractPreprocessingController extends AbstractController {

    private static Log log = LogFactory.getLog(AbstractPreprocessingController.class);

    private static final String MULTIPART_CONTENT_TYPE = "multipart/form-data";

    protected List multipartRequest = Collections.EMPTY_LIST;

    protected String preprocess() throws Exception {

        log.info("AbstractPreprocessingController.preprocess() started.");

        try {

            if (this.getRequest().getContentType() != null) {

                String contentType = this.getRequest().getContentType().toLowerCase();

                if (contentType.startsWith(MULTIPART_CONTENT_TYPE)) {
                    log.debug("Processing " + MULTIPART_CONTENT_TYPE + ".");
                    this.processMultipart();
                    log.debug("Processing " + MULTIPART_CONTENT_TYPE + " finished.");
                }
            }

        } catch (Exception e) {
            log.info("AbstractPreprocessingController.preprocess() failed.");
            throw e;
        }

        log.info("AbstractPreprocessingController.preprocess() ended.");

        return super.preprocess();
    }

    private void processMultipart() throws IOException, InvocationTargetException, IllegalAccessException {

        log.debug("Starting to process " + MULTIPART_CONTENT_TYPE + ".");

        byte[] bytes;

        MultipartContent multipartContent;
        String name;
        String value = "";
        InputStream is;

        MultipartRequest parser = new ServletMultipartRequest(this.getRequest(), MultipartRequest.MAX_READ_BYTES);

        log.debug("Starting to enumerate multipart request files.");

        for (Enumeration e = parser.getFileParameterNames(); e.hasMoreElements();) {

            name = (String) e.nextElement();
            is = parser.getFileContents(name);

            if (is != null) {

                if (this.multipartRequest == Collections.EMPTY_LIST)
                    this.multipartRequest = new ArrayList();

                log.debug("Reading file '" + parser.getFileSize("name") + "'.");
                log.debug("Reading " + parser.getFileSize(name) + " byte(s).");
                bytes = read(parser.getFileContents(name));
                log.debug("Finished reading a total of " + bytes.length + " byte(s).");
                log.debug("File '" + parser.getFileSize("name") + "' was read successfully.");

                log.debug("Creating MultipartContent bean.");
                multipartContent = new MultipartContent(name, parser.getContentType(name), bytes, new Long(parser.getFileSize(name)).intValue(), parser.getFileSystemName(name));
                log.debug("MultipartContent created successfully.");

                log.debug("Adding MultipartContent to a list.");
                this.multipartRequest.add(multipartContent);
                log.debug("MultipartContent successfully added to a list.");

            }

            is.close();
        }

        log.debug("Finished enumerating multipart request files.");
        log.debug("Starting to enumerate multipart parameters.");

        Map multipartRequestParameters = Collections.EMPTY_MAP;
        int i;

        for (Enumeration e = parser.getParameterNames(); e.hasMoreElements();) {

            if (multipartRequestParameters == Collections.EMPTY_MAP)
                multipartRequestParameters = new HashMap();

            name = (String) e.nextElement();
            i = 0;

            for (Enumeration f = parser.getURLParameters(name); f.hasMoreElements();) {
                i++;
                value = (String) f.nextElement();
            }

            if (i > 1) {

                String[] pars = new String[i];

                i = 0;

                for (Enumeration f = parser.getURLParameters(name); f.hasMoreElements();) {
                    pars[i] = (String) f.nextElement();
                    i++;
                }

                multipartRequestParameters.put(name, pars);

            } else {
                multipartRequestParameters.put(name, value);
            }

        }

        log.debug("Finished enumerating multipart parameters.");

        if (!multipartRequestParameters.isEmpty()) {
            log.debug("Populating Controller with BeanUtils (multipart parameters).");
            BeanUtils.populate(this, multipartRequestParameters);
            log.debug("Populating Controller with BeanUtils finished (multipart parameters).");
        }

        log.debug("Finished processing " + MULTIPART_CONTENT_TYPE + ".");

    }

    private byte[] read(InputStream is) throws IOException {

        int bytesRead = -1;

        byte[] bytes = new byte[8192];

        BufferedInputStream bis = new BufferedInputStream(is);
        ByteArrayOutputStream baos = new ByteArrayOutputStream();

        while ((bytesRead = bis.read(bytes, 0, bytes.length)) != -1) {
            if (bytesRead > 0) {
                log.debug("Read " + bytesRead + " byte(s).");
                baos.write(bytes, 0, bytesRead);
            }
        }

        bis.close();

        return baos.toByteArray();

    }

}