package charactermanaj.model.io;

import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.nio.charset.Charset;
import java.util.Map;
import java.util.Properties;

import charactermanaj.graphics.io.ImageResource;
import charactermanaj.graphics.io.ImageSaveHelper;
import charactermanaj.model.AppConfig;
import charactermanaj.model.CharacterData;
import charactermanaj.model.Layer;
import charactermanaj.model.PartsFiles;
import charactermanaj.model.PartsIdentifier;
import charactermanaj.model.PartsManageData;
import charactermanaj.model.PartsManageDataConverter;
import charactermanaj.model.PartsSpec;

public abstract class AbstractCharacterDataArchivedFileWriter extends AbstractCharacterDataFileWriter {

	protected AbstractCharacterDataArchivedFileWriter(File outFile) throws IOException {
		super(outFile);
	}
	
	protected abstract OutputStream getOutputStream() throws IOException;
	
	protected abstract void putNextEntry(String name, long lastModified) throws IOException;
	
	protected abstract void closeEntry() throws IOException;

	@Override
	protected void internalWriteExportProp(Properties prop) throws IOException {
		// export prop
		putNextEntry("export-info.xml", 0);
		prop.storeToXML(getOutputStream(), "exportProp");
	}

	@Override
	protected void internalWriteCharacterData(CharacterData characterData)
			throws IOException {
		CharacterDataPersistent persist = CharacterDataPersistent.getInstance();
		
		// character data
		putNextEntry("character.xml", 0);
		persist.writeXMLCharacterData(characterData, getOutputStream());
		closeEntry();
	}
	
	@Override
	protected void internalWriteTextUTF16LE(String name, String contents) throws IOException {
		if (contents == null) {
			contents = "";
		}

		// LFまたはCR改行であればCR/LF改行に変換.
		contents = contents.replace("\r\n", "\n");
		contents = contents.replace("\r", "\n");
		contents = contents.replace("\n", "\r\n");
		
		putNextEntry(name, 0);
		OutputStream os = getOutputStream();
		os.write((byte) 0xff);
		os.write((byte) 0xfe);
		os.flush();
		OutputStreamWriter wr = new OutputStreamWriter(os, Charset.forName("UTF-16LE"));
		try {
			wr.append(contents);
			wr.flush();
		} finally {
			closeEntry();
		}
	}
	
	@Override
	protected void internalWriteSamplePicture(BufferedImage samplePicture)
			throws IOException {
		putNextEntry("preview.png", 0);
		ImageSaveHelper imageSaveHelper = new ImageSaveHelper();
		imageSaveHelper.savePicture(samplePicture, Color.white, getOutputStream(), "image/png", null);
		closeEntry();
	}
	
	@Override
	protected void internalWritePartsImages(
			Map<PartsIdentifier, PartsSpec> partsImages) throws IOException {
		AppConfig appConfig = AppConfig.getInstance();
		byte[] buf = new byte[appConfig.getJarTransferBufferSize()];
		
		for (Map.Entry<PartsIdentifier, PartsSpec> entry : partsImages.entrySet()) {
			PartsIdentifier partsIdentifier = entry.getKey();
			PartsSpec partsSpec = entry.getValue();
			PartsFiles partsFiles = partsSpec.getPartsFiles();
			
			for (Map.Entry<Layer, ImageResource> imageEntry : partsFiles.entrySet()) {
				Layer layer = imageEntry.getKey();
				ImageResource imageResource = imageEntry.getValue();

				String name = layer.getDir() + "/" + partsIdentifier.getPartsName() + ".png";
				name = name.replace("//", "/");
				
				putNextEntry(name, imageResource.lastModified());
				OutputStream os = getOutputStream();
				InputStream is = imageResource.openStream();
				try {
					int rd;
					while ((rd = is.read(buf)) >= 0) {
						os.write(buf, 0, rd);
					}
				} finally {
					is.close();
				}
				closeEntry();
			}
		}
	}
	
	@Override
	protected void internalWritePartsManageData(
			Map<PartsIdentifier, PartsSpec> partsImages) throws IOException {
		
		PartsManageDataConverter partsManageDataConverter = new PartsManageDataConverter();
		
		for (Map.Entry<PartsIdentifier, PartsSpec> entry : partsImages.entrySet()) {
			PartsIdentifier partsIdentifier = entry.getKey();
			PartsSpec partsSpec = entry.getValue();
			partsManageDataConverter.convert(partsIdentifier, partsSpec);
		}
		
		PartsManageData partsManageData = partsManageDataConverter.getPartsManageData();
		CharacterDataPersistent persist = CharacterDataPersistent.getInstance();

		putNextEntry("parts-info.xml", 0);
		persist.savePartsManageData(partsManageData, getOutputStream());
		closeEntry();
	}
}
