package com.infoteria.asteria.flowlibrary2.component.format;

import com.infoteria.asteria.flowengine2.EngineConstant;
import com.infoteria.asteria.flowengine2.execute.ExecuteContext;
import com.infoteria.asteria.flowengine2.flow.InputConnector;
import com.infoteria.asteria.flowlibrary2.component.ComponentException;
import com.infoteria.asteria.flowlibrary2.component.SimpleComponent;
import com.infoteria.asteria.flowlibrary2.FlowException;
import com.infoteria.asteria.flowlibrary2.property.EncodingProperty;
import com.infoteria.asteria.flowlibrary2.stream.StreamDataObject;
import com.infoteria.asteria.flowlibrary2.stream.StreamFactory;
import com.infoteria.asteria.flowlibrary2.stream.StreamFactoryBinary;
import com.infoteria.asteria.flowlibrary2.stream.StreamType;
import com.infoteria.asteria.flowlibrary2.stream.strategy.IStreamStrategy;
import com.infoteria.asteria.flowlibrary2.stream.strategy.StreamStrategyFB;

import java.io.IOException;
import java.io.OutputStream;
import java.io.File;
import java.io.BufferedInputStream;

import org.apache.tools.zip.ZipEntry;
import org.apache.tools.zip.ZipOutputStream;

/**
 * Zipを作成するコンポーネント
 */
public class ZipComponent extends SimpleComponent {
	
	public static final String COMPONENT_NAME = "Zip";
	public String getComponentName() { return COMPONENT_NAME;}
	public String getLicenseStr() { return EngineConstant.LICENSE_COREPLUS; }
	private EncodingProperty _filenameEncoding = new EncodingProperty("FilenameEncoding", true, true, "(System)");
	
	public ZipComponent() {
		getInputConnector().setAcceptLinkCount(InputConnector.LINK_UNBOUNDED);
		getInputConnector().setAcceptType(StreamType.ALL);
		getInputConnector().setAcceptContainer(true);
		getInputConnector().setExpandContainer(true);
		getOutputConnector().setAcceptType(StreamType.BINARY);

		registerProperty(_filenameEncoding);
	}
	
	public boolean execute(ExecuteContext context) throws FlowException {
		StreamDataObject ret;
		StreamDataObject[] streams = getInputConnector().getStreamArray();
		IStreamStrategy strategy = null;
		if (context.useFileBasedStreams()) {
			strategy = StreamStrategyFB.getStrategyForType(StreamType.BINARY);
		}
		StreamFactoryBinary factory = (StreamFactoryBinary)StreamFactory.getInstance(StreamType.BINARY, strategy);
		factory.initialize();
		try (OutputStream os = factory.getFactoryOutputStream()) {
			ZipOutputStream zos = new ZipOutputStream(os);
			String filenameEncoding = _filenameEncoding.strValue();
			if (filenameEncoding != null && filenameEncoding.length() > 0
				&& !filenameEncoding.equals("(System)")) {
				zos.setEncoding(filenameEncoding); 
			}
			try {
				int cnt = 0;
				for (int i=0; i<streams.length; i++) {
					String filename = streams[i].getFileName();
					if (filename == null)
						filename = "Asteria-Stream" + Integer.toString(++cnt) + getFileExtension(streams[i].getType());
					else
						filename = new File(filename).getName();
					ZipEntry entry = new ZipEntry(filename);
					
					zos.putNextEntry(entry);
					try (BufferedInputStream bis = new BufferedInputStream(streams[i].getDataInputStream())) {
						byte[] buffer = new byte[8192];
						int read;
						while((read = bis.read(buffer)) > -1) {
							zos.write(buffer, 0, read);
						}
					}
					zos.closeEntry();
				}
				//zos.finish();
			} finally {
				zos.close();
			}
			ret = factory.create();
		} catch (IOException e) {
			@SuppressWarnings("deprecation")
			ComponentException ex = new ComponentException(e);
			throw ex;
		} finally {
			factory.terminate();
		}
		setOutputStream(ret);
		return true;
	}
	
	private static String getFileExtension(int type) {
		switch (type) {
			case StreamType.BINARY:
			case StreamType.FIXED_STRING:
			case StreamType.MIME:
				return ".bin";
			case StreamType.TEXT:
				return ".txt";
			case StreamType.HTML:
				return ".html";
			case StreamType.CSV:
				return ".csv";
			case StreamType.PARAMETER_LIST:
			case StreamType.RECORDS:
			case StreamType.XML:
				return ".xml";
			case StreamType.JSON:
				return ".json";
			default:
				throw new IllegalStateException();
		}
	}
}

