/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.commons.imaging.formats.icns;

import java.awt.Dimension;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.imaging.ImageFormat;
import org.apache.commons.imaging.ImageFormats;
import org.apache.commons.imaging.ImageInfo;
import org.apache.commons.imaging.ImageParser;
import org.apache.commons.imaging.ImageReadException;
import org.apache.commons.imaging.ImageWriteException;
import org.apache.commons.imaging.common.BinaryOutputStream;
import org.apache.commons.imaging.common.ByteOrder;
import org.apache.commons.imaging.common.IImageMetadata;
import org.apache.commons.imaging.common.bytesource.ByteSource;
import org.apache.commons.imaging.util.IoUtils;
import org.apache.commons.imaging.util.ParamMap;

public class IcnsImageParser extends ImageParser {
    public static final int ICNS_MAGIC = IcnsType.typeAsInt("icns");

    public IcnsImageParser() {
        super.setByteOrder(ByteOrder.BIG_ENDIAN);
    }

    @Override
    public String getName() {
        return "icns-Custom";
    }

    @Override
    public String getDefaultExtension() {
        return DEFAULT_EXTENSION;
    }

    private static final String DEFAULT_EXTENSION = ".icns";

    private static final String ACCEPTED_EXTENSIONS[] = { ".icns", };

    @Override
    protected String[] getAcceptedExtensions() {
        return ACCEPTED_EXTENSIONS;
    }

    @Override
    protected ImageFormat[] getAcceptedTypes() {
        return new ImageFormat[] { ImageFormats.ICNS };
    }

    @Override
    public boolean embedICCProfile(final File src, final File dst, final byte profile[]) {
        return false;
    }

    @Override
    public IImageMetadata getMetadata(final ByteSource byteSource, final Map<String,Object> params)
            throws ImageReadException, IOException {
        return null;
    }

    @Override
    public ImageInfo getImageInfo(final ByteSource byteSource, Map<String,Object> params)
            throws ImageReadException, IOException {
        // make copy of params; we'll clear keys as we consume them.
        params = (params == null) ? new HashMap<String,Object>() : new HashMap<String,Object>(params);

        ParamMap.getParamBoolean(params, PARAM_KEY_VERBOSE, false);

        if (params.containsKey(PARAM_KEY_VERBOSE)) {
            params.remove(PARAM_KEY_VERBOSE);
        }

        if (params.size() > 0) {
            final Object firstKey = params.keySet().iterator().next();
            throw new ImageReadException("Unknown parameter: " + firstKey);
        }

        final IcnsContents contents = readImage(byteSource);
        final List<BufferedImage> images = IcnsDecoder
                .decodeAllImages(contents.icnsElements);
        if (images.isEmpty()) {
            throw new ImageReadException("No icons in ICNS file");
        }
        final BufferedImage image0 = images.get(0);
        return new ImageInfo("Icns", 32, new ArrayList<String>(),
                ImageFormats.ICNS, "ICNS Apple Icon Image",
                image0.getHeight(), "image/x-icns", images.size(), 0, 0, 0, 0,
                image0.getWidth(), false, true, false,
                ImageInfo.COLOR_TYPE_RGB,
                ImageInfo.COMPRESSION_ALGORITHM_UNKNOWN);
    }

    @Override
    public Dimension getImageSize(final ByteSource byteSource, Map<String,Object> params)
            throws ImageReadException, IOException {
        // make copy of params; we'll clear keys as we consume them.
        params = (params == null) ? new HashMap<String,Object>() : new HashMap<String,Object>(params);

        ParamMap.getParamBoolean(params, PARAM_KEY_VERBOSE, false);

        if (params.containsKey(PARAM_KEY_VERBOSE)) {
            params.remove(PARAM_KEY_VERBOSE);
        }

        if (params.size() > 0) {
            final Object firstKey = params.keySet().iterator().next();
            throw new ImageReadException("Unknown parameter: " + firstKey);
        }

        final IcnsContents contents = readImage(byteSource);
        final List<BufferedImage> images = IcnsDecoder
                .decodeAllImages(contents.icnsElements);
        if (images.isEmpty()) {
            throw new ImageReadException("No icons in ICNS file");
        }
        final BufferedImage image0 = images.get(0);
        return new Dimension(image0.getWidth(), image0.getHeight());
    }

    @Override
    public byte[] getICCProfileBytes(final ByteSource byteSource, final Map<String,Object> params)
            throws ImageReadException, IOException {
        return null;
    }

    private static class IcnsHeader {
        public final int magic; // Magic literal (4 bytes), always "icns"
        public final int fileSize; // Length of file (4 bytes), in bytes.

        public IcnsHeader(final int magic, final int fileSize) {
            this.magic = magic;
            this.fileSize = fileSize;
        }

        public void dump(final PrintWriter pw) {
            pw.println("IcnsHeader");
            pw.println("Magic: 0x" + Integer.toHexString(magic) + " ("
                    + IcnsType.describeType(magic) + ")");
            pw.println("FileSize: " + fileSize);
            pw.println("");
        }
    }

    private IcnsHeader readIcnsHeader(final InputStream is)
            throws ImageReadException, IOException {
        final int Magic = read4Bytes("Magic", is, "Not a Valid ICNS File");
        final int FileSize = read4Bytes("FileSize", is, "Not a Valid ICNS File");

        if (Magic != ICNS_MAGIC) {
            throw new ImageReadException("Not a Valid ICNS File: "
                    + "magic is 0x" + Integer.toHexString(Magic));
        }

        return new IcnsHeader(Magic, FileSize);
    }

    public static class IcnsElement {
        public final int type;
        public final int elementSize;
        public final byte[] data;

        public IcnsElement(final int type, final int elementSize, final byte[] data) {
            this.type = type;
            this.elementSize = elementSize;
            this.data = data;
        }

        public void dump(final PrintWriter pw) {
            pw.println("IcnsElement");
            final IcnsType icnsType = IcnsType.findAnyType(type);
            String typeDescription;
            if (icnsType == null) {
                typeDescription = "";
            } else {
                typeDescription = " " + icnsType.toString();
            }
            pw.println("Type: 0x" + Integer.toHexString(type) + " ("
                    + IcnsType.describeType(type) + ")" + typeDescription);
            pw.println("ElementSize: " + elementSize);
            pw.println("");
        }
    }

    private IcnsElement readIcnsElement(final InputStream is) throws IOException {
        final int type = read4Bytes("Type", is, "Not a Valid ICNS File"); // Icon type
                                                                    // (4 bytes)
        final int elementSize = read4Bytes("ElementSize", is, "Not a Valid ICNS File"); // Length
                                                                                  // of
                                                                                  // data
                                                                                  // (4
                                                                                  // bytes),
                                                                                  // in
                                                                                  // bytes,
                                                                                  // including
                                                                                  // this
                                                                                  // header
        final byte[] data = readBytes("Data", is, elementSize - 8,
                "Not a Valid ICNS File");

        return new IcnsElement(type, elementSize, data);
    }

    private static class IcnsContents {
        public final IcnsHeader icnsHeader;
        public final IcnsElement icnsElements[];

        public IcnsContents(final IcnsHeader icnsHeader,
                final IcnsElement[] icnsElements) {
            super();
            this.icnsHeader = icnsHeader;
            this.icnsElements = icnsElements;
        }
    }

    private IcnsContents readImage(final ByteSource byteSource)
            throws ImageReadException, IOException {
        InputStream is = null;
        boolean canThrow = false;
        try {
            is = byteSource.getInputStream();
            final IcnsHeader icnsHeader = readIcnsHeader(is);

            final List<IcnsElement> icnsElementList = new ArrayList<IcnsElement>();
            for (int remainingSize = icnsHeader.fileSize - 8; remainingSize > 0;) {
                final IcnsElement icnsElement = readIcnsElement(is);
                icnsElementList.add(icnsElement);
                remainingSize -= icnsElement.elementSize;
            }

            final IcnsElement[] icnsElements = new IcnsElement[icnsElementList.size()];
            for (int i = 0; i < icnsElements.length; i++) {
                icnsElements[i] = icnsElementList.get(i);
            }

            final IcnsContents ret = new IcnsContents(icnsHeader, icnsElements);
            canThrow = true;
            return ret;
        } finally {
            IoUtils.closeQuietly(canThrow, is);
        }
    }

    @Override
    public boolean dumpImageFile(final PrintWriter pw, final ByteSource byteSource)
            throws ImageReadException, IOException {
        final IcnsContents icnsContents = readImage(byteSource);
        icnsContents.icnsHeader.dump(pw);
        for (final IcnsElement icnsElement : icnsContents.icnsElements) {
            icnsElement.dump(pw);
        }
        return true;
    }

    @Override
    public final BufferedImage getBufferedImage(final ByteSource byteSource,
            final Map<String,Object> params) throws ImageReadException, IOException {
        final IcnsContents icnsContents = readImage(byteSource);
        final List<BufferedImage> result = IcnsDecoder
                .decodeAllImages(icnsContents.icnsElements);
        if (result.size() > 0) {
            return result.get(0);
        } else {
            throw new ImageReadException("No icons in ICNS file");
        }
    }

    @Override
    public List<BufferedImage> getAllBufferedImages(final ByteSource byteSource)
            throws ImageReadException, IOException {
        final IcnsContents icnsContents = readImage(byteSource);
        return IcnsDecoder.decodeAllImages(icnsContents.icnsElements);
    }

    @Override
    public void writeImage(final BufferedImage src, final OutputStream os, Map<String,Object> params)
            throws ImageWriteException, IOException {
        // make copy of params; we'll clear keys as we consume them.
        params = (params == null) ? new HashMap<String,Object>() : new HashMap<String,Object>(params);

        // clear format key.
        if (params.containsKey(PARAM_KEY_FORMAT)) {
            params.remove(PARAM_KEY_FORMAT);
        }

        if (params.size() > 0) {
            final Object firstKey = params.keySet().iterator().next();
            throw new ImageWriteException("Unknown parameter: " + firstKey);
        }

        IcnsType imageType;
        if (src.getWidth() == 16 && src.getHeight() == 16) {
            imageType = IcnsType.ICNS_16x16_32BIT_IMAGE;
        } else if (src.getWidth() == 32 && src.getHeight() == 32) {
            imageType = IcnsType.ICNS_32x32_32BIT_IMAGE;
        } else if (src.getWidth() == 48 && src.getHeight() == 48) {
            imageType = IcnsType.ICNS_48x48_32BIT_IMAGE;
        } else if (src.getWidth() == 128 && src.getHeight() == 128) {
            imageType = IcnsType.ICNS_128x128_32BIT_IMAGE;
        } else {
            throw new ImageWriteException("Invalid/unsupported source width "
                    + src.getWidth() + " and height " + src.getHeight());
        }

        final BinaryOutputStream bos = new BinaryOutputStream(os,
                ByteOrder.BIG_ENDIAN);
        bos.write4Bytes(ICNS_MAGIC);
        bos.write4Bytes(4 + 4 + 4 + 4 + 4 * imageType.getWidth()
                * imageType.getHeight() + 4 + 4 + imageType.getWidth()
                * imageType.getHeight());

        bos.write4Bytes(imageType.getType());
        bos.write4Bytes(4 + 4 + 4 * imageType.getWidth()
                * imageType.getHeight());
        for (int y = 0; y < src.getHeight(); y++) {
            for (int x = 0; x < src.getWidth(); x++) {
                final int argb = src.getRGB(x, y);
                bos.write(0);
                bos.write(argb >> 16);
                bos.write(argb >> 8);
                bos.write(argb);
            }
        }

        final IcnsType maskType = IcnsType.find8BPPMaskType(imageType);
        bos.write4Bytes(maskType.getType());
        bos.write4Bytes(4 + 4 + imageType.getWidth() * imageType.getWidth());
        for (int y = 0; y < src.getHeight(); y++) {
            for (int x = 0; x < src.getWidth(); x++) {
                final int argb = src.getRGB(x, y);
                bos.write(argb >> 24);
            }
        }
    }

    /**
     * Extracts embedded XML metadata as XML string.
     * <p>
     * 
     * @param byteSource
     *            File containing image data.
     * @param params
     *            Map of optional parameters, defined in ImagingConstants.
     * @return Xmp Xml as String, if present. Otherwise, returns null.
     */
    @Override
    public String getXmpXml(final ByteSource byteSource, final Map<String,Object> params)
            throws ImageReadException, IOException {
        return null;
    }
}
